{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "<img src=\"./pictures/logo-insa.png\" style=\"float:right; max-width: 60px; display: inline\" alt=\"INSA\" /></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Propeller selection\n",
    "*Written by Marc Budinger, INSA Toulouse, France*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "The purpose of this notebook is to structure the sizing procedure for the selection of a propeller.\n",
    "\n",
    "In general, the establishment of a sizing procedure involves the resolution of the following 3 problems:\n",
    "* a set of equations sub-constrained by the addition of a design variable in the optimization problem;\n",
    "* an over-constrained variable by adding a design variable (multiplier) and the transfer of the excess equation(s) in the constrained part of the optimization problem;\n",
    "* an algebraic loop by the use of a simplify equation weighted by a multiplying coefficient and a constraint representing the initial equation.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "\n",
    "Where possible:\n",
    "* the design variables must take the form of a normalized variable around 1 (oversize coef. for example) or easily bounded to facilitate the work of the optimization algorithm.\n",
    "* the constraints must take the form of inequality and not of equality more difficult to manage. The optimization of the objective (for example the total mass) will certainly force some (active) constraints to come to an end. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Design graph \n",
    "\n",
    "The following diagram represents the design graph of the propeller’s selection. The max thrust is assumed to be known here.\n",
    "\n",
    "\n",
    "![DesignGraph](pictures/PropellerDesignGraph.png)\n",
    "\n",
    "> **Questions:**\n",
    "* Give the main sizing problems you are able to detect.\n",
    "* Propose one or multiple solutions (which can request equation manipulation, addition of design variables, addition of constraints) \n",
    "* Orientate the arrows\n",
    "* Give equations order, inputs/outputs at each step of this part of sizing procedure\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Sizing code and optimization\n",
    "\n",
    "> Exercice: propose a sizing code for the selection of a propeller.\n",
    "\n",
    "The specifications and design assumptions are the following:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from utils.model_standard import CoreModel\n",
    "from utils.model_serializer import ModelSerializer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PropellerModel(CoreModel):\n",
    "    \"\"\"\n",
    "    Propeller model class.\n",
    "    ----------\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, **kwargs):\n",
    "        super(PropellerModel, self).__init__(**kwargs)\n",
    "        self.initialization()\n",
    "        self.execute()\n",
    "        self._update()\n",
    "\n",
    "    def initialization(self):\n",
    "        \n",
    "        # Input variables\n",
    "        inputs = {'k_ND': 1.0, 'beta': 0.5, 'Tpro_takeoff': 15.0, 'Tpro_hover': 5.0}\n",
    "        self.set_inputs(inputs)\n",
    "        \n",
    "        # Input parameters\n",
    "        \n",
    "        # Propeller selection\n",
    "        # ---\n",
    "        rho_air=1.18 # [kg/m^3] air density \n",
    "        NDmax=105000/60*.0254 # [Hz.m] max speed limit (N.D max)\n",
    "        Dpro_ref=11*.0254 # [m] diameter\n",
    "        Mpro_ref=0.53*0.0283 # [kg] mass\n",
    "        \n",
    "        inputs = {'rho_air': rho_air, 'NDmax': NDmax, 'Dpro_ref': Dpro_ref, 'Mpro_ref': Mpro_ref}\n",
    "        self.set_inputs(inputs)\n",
    "               \n",
    "        # Declare outputs\n",
    "        outputs = ['C_t', 'C_p', 'Dpro', 'n_pro_takeoff', 'Wpro_takeoff', 'Mpro', 'Ppro_takeoff', 'Qpro_takeoff', 'P_el_hover', 'n_pro_hover', 'Wpro_hover', 'Ppro_hover', 'Qpro_hover']   \n",
    "        self.declare_outputs(outputs)\n",
    "\n",
    "    def execute(self):\n",
    "        \n",
    "        # Get input values\n",
    "        k_ND, beta, Tpro_takeoff, Tpro_hover = self.get_values(['k_ND', 'beta', 'Tpro_takeoff', 'Tpro_hover'])\n",
    "        \n",
    "        rho_air, NDmax, Dpro_ref, Mpro_ref = self.get_values(['rho_air', 'NDmax', 'Dpro_ref', 'Mpro_ref'])\n",
    "\n",
    "        # Propeller characteristicss\n",
    "        # Ref : APC \n",
    "\n",
    "        C_t=4.27e-02 + 1.44e-01 * beta # Thrust coef with T=C_T.rho.n^2.D^4\n",
    "        C_p=-1.48e-03 + 9.72e-02 * beta  # Power coef with P=C_p.rho.n^3.D^5\n",
    "\n",
    "        # Propeller selection with take-off scenario\n",
    "\n",
    "        Dpro=(Tpro_takeoff/(C_t*rho_air*(NDmax/k_ND)**2))**0.5  # [m] Propeller diameter\n",
    "        n_pro_takeoff=NDmax/k_ND/Dpro # [Hz] Propeller speed \n",
    "        Wpro_takeoff=n_pro_takeoff*2*3.14 # [rad/s] Propeller speed\n",
    "\n",
    "        Mpro=Mpro_ref*(Dpro/Dpro_ref)**2 # [kg] Propeller mass\n",
    "\n",
    "        Ppro_takeoff=C_p*rho_air*n_pro_takeoff**3*Dpro**5# [W] Power per propeller\n",
    "        Qpro_takeoff=Ppro_takeoff/Wpro_takeoff # [N.m] Propeller torque\n",
    "\n",
    "        # Propeller torque & speed for hover\n",
    "\n",
    "        n_pro_hover=sqrt(Tpro_hover/(C_t*rho_air*Dpro**4)) # [Hz] hover speed\n",
    "        Wpro_hover=n_pro_hover*2*3.14 # [rad/s] Propeller speed    \n",
    "\n",
    "        Ppro_hover=C_p*rho_air*n_pro_hover**3*Dpro**5# [W] Power per propeller\n",
    "        Qpro_hover=Ppro_hover/Wpro_hover # [N.m] Propeller torque    \n",
    "    \n",
    "            \n",
    "        outputs = {'C_t': C_t, 'C_p': C_p, 'Dpro': Dpro, 'n_pro_takeoff': n_pro_takeoff, 'Wpro_takeoff': Wpro_takeoff, 'Mpro': Mpro}\n",
    "        self.set_outputs(outputs)\n",
    "        \n",
    "        outputs = {'Ppro_takeoff': Ppro_takeoff, 'Qpro_takeoff': Qpro_takeoff}\n",
    "        self.set_outputs(outputs)\n",
    "        \n",
    "        outputs = {'n_pro_hover': n_pro_hover, 'Wpro_hover': Wpro_hover, 'Ppro_hover': Ppro_hover, 'Qpro_hover': Qpro_hover}\n",
    "        self.set_outputs(outputs)\n",
    "        \n",
    "    def __str__(self):\n",
    "        \n",
    "        s =((\"* Propellers informations: \\n\") +\n",
    "            (\"** Global: \\n\") + \n",
    "            (\"    NxD takeoff = %.0f RPMxInch\"%(self.get_values(['n_pro_takeoff'])*60*self.get_values(['Dpro'])/.0254) + \"\\n\") +\n",
    "            (\"    Diameter Dpro = %.2g m or %.2f in\"%((self.get_values(['Dpro']), self.get_values(['Dpro'])/.0254)) + \"\\n\") +\n",
    "            (\"    Pitch  = %.2g m or %.2f in\"%(self.get_values(['beta'])*self.get_values(['Dpro']), self.get_values(['beta'])*self.get_values(['Dpro'])/.0254) + \"\\n\") +\n",
    "            (\"    Propeller mass (1x): %.3f kg\"%(self.get_values(['Mpro'])) + \"\\n\") +\n",
    "            (\"** Aerodynamics: \\n\") +\n",
    "            (\"    Power coefficient C_p: - for statics: %.4f \"%(self.get_values(['C_p'])) + \"\\n\") +\n",
    "            (\"    Thrust coefficient C_t: - for statics: %.4f \"%(self.get_values(['C_t']))+ \"\\n\") +\n",
    "            (\"** Rotational speeds: \\n\") +\n",
    "            (\"    - for hover: %.0f RPM \"%(self.get_values(['Wpro_hover'])*60/2/pi) + \"\\n\") +\n",
    "            (\"    - for vertical acceleration: %.0f RPM \"%(self.get_values(['Wpro_takeoff'])*60/2/3.14) + \"\\n\")\n",
    "           )\n",
    "        return s\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "* Propellers informations: \n",
      "** Global: \n",
      "    NxD takeoff = 105000 RPMxInch\n",
      "    Diameter Dpro = 0.24 m or 9.32 in\n",
      "    Pitch  = 0.12 m or 4.66 in\n",
      "    Propeller mass (1x): 0.011 kg\n",
      "** Aerodynamics: \n",
      "    Power coefficient C_p: - for statics: 0.0471 \n",
      "    Thrust coefficient C_t: - for statics: 0.1147 \n",
      "** Rotational speeds: \n",
      "    - for hover: 6498 RPM \n",
      "    - for vertical acceleration: 11261 RPM \n",
      "\n"
     ]
    }
   ],
   "source": [
    "propeller_model = PropellerModel()\n",
    "\n",
    "print(propeller_model)\n",
    "\n",
    "ms = ModelSerializer()\n",
    "path = './models/'\n",
    "file_name = 'propeller_model'\n",
    "ms.save_model(propeller_model, path + file_name)\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "* Propellers informations: \n",
      "** Global: \n",
      "    NxD takeoff = 105000 RPMxInch\n",
      "    Diameter Dpro = 0.24 m or 9.32 in\n",
      "    Pitch  = 0.12 m or 4.66 in\n",
      "    Propeller mass (1x): 0.011 kg\n",
      "** Aerodynamics: \n",
      "    Power coefficient C_p: - for statics: 0.0471 \n",
      "    Thrust coefficient C_t: - for statics: 0.1147 \n",
      "** Rotational speeds: \n",
      "    - for hover: 6498 RPM \n",
      "    - for vertical acceleration: 11261 RPM \n",
      "\n",
      "* Propellers informations: \n",
      "** Global: \n",
      "    NxD takeoff = 105000 RPMxInch\n",
      "    Diameter Dpro = 0.31 m or 12.04 in\n",
      "    Pitch  = 0.15 m or 6.02 in\n",
      "    Propeller mass (1x): 0.018 kg\n",
      "** Aerodynamics: \n",
      "    Power coefficient C_p: - for statics: 0.0471 \n",
      "    Thrust coefficient C_t: - for statics: 0.1147 \n",
      "** Rotational speeds: \n",
      "    - for hover: 3899 RPM \n",
      "    - for vertical acceleration: 8723 RPM \n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(propeller_model)\n",
    "\n",
    "inputs = {'Tpro_takeoff': 25.0}\n",
    "\n",
    "propeller_model.evaluate(inputs, [])\n",
    "\n",
    "print(propeller_model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
