From b033cb60b035ffa7820169e9356e0137aeb8422b Mon Sep 17 00:00:00 2001 From: Adrien Delsalle Date: Mon, 20 Feb 2023 11:41:10 +0100 Subject: [PATCH] rework atm integration to ease syntax (#89) split atmophere and turbofan to help cases where turbofan would be integrated in other contexts (test rig) add TurbofanWithAtm system for convenient use of Turbofan with Atmosphere change default psi value for booster using phiP update buggy demo notebook: set targets values before adding targets to the solver itself update tests add .html file to gitignore update HISTORY --- .gitignore | 3 + HISTORY.md | 3 +- pyturbo/notebooks/turbofan.ipynb | 404 ++++++++++++----------- pyturbo/systems/__init__.py | 2 + pyturbo/systems/compressor/compressor.py | 2 +- pyturbo/systems/turbofan/__init__.py | 4 +- pyturbo/systems/turbofan/turbofan.py | 50 +-- tests/test_turbofan.py | 8 +- 8 files changed, 246 insertions(+), 230 deletions(-) diff --git a/.gitignore b/.gitignore index 74df8df..a20c03a 100644 --- a/.gitignore +++ b/.gitignore @@ -247,4 +247,7 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk +# cosapp systems representations +*.html + # End of https://www.gitignore.io/api/git,linux,macos,python,windows,pycharm,jupyternotebook diff --git a/HISTORY.md b/HISTORY.md index d33f3ae..eccfa39 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,11 +4,12 @@ ### Features -- Add new system `Atmosphere` to ease computing of ambient conditions +- Add new system `Atmosphere` and `TurbofanWithAtm` to ease computing of ambient conditions (from altitude, Mach and delta tamb) ### Code quality & packaging - Add `Compressor` to public API of the `systems.compressor` and `systems` modules +- Fix demo turbofan notebook to set design target before adding targets to the non-linear solver ### Bug fix diff --git a/pyturbo/notebooks/turbofan.ipynb b/pyturbo/notebooks/turbofan.ipynb index 9cce1d8..6ebf255 100644 --- a/pyturbo/notebooks/turbofan.ipynb +++ b/pyturbo/notebooks/turbofan.ipynb @@ -40,8 +40,10 @@ "metadata": {}, "outputs": [], "source": [ - "from pyturbo.systems.turbofan import Turbofan\n", - "sys = Turbofan(\"tf\")" + "from pyturbo.systems.turbofan import TurbofanWithAtm\n", + "sys = TurbofanWithAtm(\"sys\")\n", + "tf = sys.tf\n", + "atm = sys.atm" ] }, { @@ -64,7 +66,7 @@ "# geometrical view\n", "sys.run_once()\n", "\n", - "sys.jupyter_view(options={\n", + "tf.jupyter_view(options={\n", " \"fan_module\": dict(opacity=0.7, face_color=\"#92B4EC\"),\n", " \"fan_module.spinner\": dict(face_color=\"#E1E5EA\", opacity=1.),\n", " \"fan_duct\": dict(opacity=0.7),\n", @@ -82,7 +84,9 @@ "id": "f1d08e45-272d-4ae3-a844-902853f6f2d5", "metadata": {}, "source": [ - "# Simulation" + "# Simulation\n", + "\n", + "The turbofan system has a couple of equations/unknowns to solve. We use `cosapp` non-linear solver for this purpose." ] }, { @@ -95,6 +99,18 @@ "from cosapp.drivers import NonLinearSolver" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "e58ec415-51ed-4926-9ebe-3aca8204503a", + "metadata": {}, + "outputs": [], + "source": [ + "from cosapp.utils import set_log, LogLevel\n", + "\n", + "set_log(level=LogLevel.INFO)" + ] + }, { "cell_type": "markdown", "id": "34ea90e8-ecac-4e4f-8c64-14eeb25d7084", @@ -123,25 +139,24 @@ "outputs": [], "source": [ "# environment conditions\n", - "alt = 0.\n", - "mach = 0.\n", - "dtamb = 15.\n", - "sys.init_environment(alt, mach, dtamb)\n", + "atm.altitude = 0.\n", + "atm.mach = 0.\n", + "atm.dtamb = 15.\n", "\n", "# use case\n", - "sys.fuel_W = .5\n", + "tf.fuel_W = .5\n", "\n", "sys.run_drivers()\n", "\n", - "print('mach =', mach)\n", - "print('pamb =', sys.pamb, 'Pa')\n", - "print('thrust =', round(sys.thrust * 0.224809/1e3, 1), 'klbf')\n", - "print('N1 =', round(sys.N1), \"rpm\")\n", - "print('N2 =', round(sys.N2), \"rpm\")\n", - "print('bpr =', round(sys.bpr, 1))\n", - "print('opr =', round(sys.opr, 1))\n", - "print('T41 =', round(sys.core.turbine.fl_in.Tt), 'K')\n", - "print('sfc =', round(sys.sfc, 3), 'kg/(h*kN)')" + "print('mach =', atm.mach)\n", + "print('pamb =', tf.pamb, 'Pa')\n", + "print('thrust =', round(tf.thrust * 0.224809/1e3, 1), 'klbf')\n", + "print('N1 =', round(tf.N1), \"rpm\")\n", + "print('N2 =', round(tf.N2), \"rpm\")\n", + "print('bpr =', round(tf.bpr, 1))\n", + "print('opr =', round(tf.opr, 1))\n", + "print('T41 =', round(tf.core.turbine.fl_in.Tt), 'K')\n", + "print('sfc =', round(tf.sfc, 3), 'kg/(h*kN)')" ] }, { @@ -173,8 +188,8 @@ "# control solver\n", "sys.drivers.clear()\n", "run = sys.add_driver(NonLinearSolver('run'))\n", - "run.runner.add_unknown('fuel_W')\n", - "run.runner.add_target('N1')" + "run.runner.add_unknown('tf.fuel_W')\n", + "run.runner.add_target('tf.N1')" ] }, { @@ -185,25 +200,24 @@ "outputs": [], "source": [ "# environment conditions\n", - "alt = 0.\n", - "mach = 0.\n", - "dtamb = 15.\n", - "sys.init_environment(alt, mach, dtamb)\n", + "atm.altitude = 0.\n", + "atm.mach = 0.\n", + "atm.dtamb = 15.\n", "\n", "# use case\n", - "sys.N1 = 5000.\n", + "tf.N1 = 5000.\n", "\n", "sys.run_drivers()\n", "\n", - "print('mach =', mach)\n", - "print('pamb =', sys.pamb, 'Pa')\n", - "print('thrust =', round(sys.thrust * 0.224809/1e3, 1), 'klbf')\n", - "print('N1 =', round(sys.N1), \"rpm\")\n", - "print('N2 =', round(sys.N2), \"rpm\")\n", - "print('bpr =', round(sys.bpr, 1))\n", - "print('opr =', round(sys.opr, 1))\n", - "print('T41 =', round(sys.core.turbine.fl_in.Tt), 'K')\n", - "print('sfc =', round(sys.sfc, 3), 'kg/(h*kN)')" + "print('mach =', atm.mach)\n", + "print('pamb =', atm.pamb, 'Pa')\n", + "print('thrust =', round(tf.thrust * 0.224809/1e3, 1), 'klbf')\n", + "print('N1 =', round(tf.N1), \"rpm\")\n", + "print('N2 =', round(tf.N2), \"rpm\")\n", + "print('bpr =', round(tf.bpr, 1))\n", + "print('opr =', round(tf.opr, 1))\n", + "print('T41 =', round(tf.core.turbine.fl_in.Tt), 'K')\n", + "print('sfc =', round(tf.sfc, 3), 'kg/(h*kN)')" ] }, { @@ -223,7 +237,9 @@ "source": [ "## design mode\n", "\n", - "Turbofan design characteristics are related to components and physical properties. " + "Turbofan design characteristics are related to components and physical properties.\n", + "\n", + "### Using design methods" ] }, { @@ -235,87 +251,76 @@ "source": [ "# design solver\n", "sys.drivers.clear()\n", - "run = sys.add_driver(NonLinearSolver('run', max_iter=50, factor=0.8))\n", - "run.runner.add_unknown('fuel_W')\n", - "run.runner.add_target('thrust')\n", - "\n", - "# design method\n", - "run.runner.design.extend(sys.design_methods['scaling'])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "907ec978-70fa-4a9f-8bdd-9cc8dc5f3b57", - "metadata": {}, - "outputs": [], - "source": [ - "# environment conditions\n", - "alt = 0.\n", - "mach = 0.\n", - "dtamb = 15.\n", - "sys.init_environment(alt, mach, dtamb)\n", + "design = sys.add_driver(NonLinearSolver('design', max_iter=50, factor=0.8))\n", + "design.runner.add_unknown('tf.fuel_W')\n", + "design.runner.add_target('tf.thrust')\n", "\n", "# engine\n", - "sys.thrust = 120e3\n", - "sys.bpr = 5.\n", - "sys.pr_nozzle = 1.1\n", + "tf.thrust = 120e3\n", + "tf.bpr = 5.\n", + "tf.pr_nozzle = 1.1\n", "\n", "# inlet\n", - "sys.inlet.aero.mach = 0.5\n", + "tf.inlet.aero.mach = 0.5\n", "\n", "# fan module\n", - "sys.fan_module.fan.aero.pcnr = 0.95\n", - "sys.fan_module.fan.aero.utip = 420.\n", + "tf.fan_module.fan.aero.pcnr = 0.95\n", + "tf.fan_module.fan.aero.utip = 420.\n", "\n", "# booster\n", - "sys.fan_module.booster.aero.phi = 0.45\n", - "sys.fan_module.booster.aero.psi = 0.35\n", - "sys.fan_module.booster.aero.spec_flow = 180.\n", - "sys.fan_module.booster.aero.pcnr = 95.\n", + "tf.fan_module.booster.aero.phi = 0.45\n", + "tf.fan_module.booster.aero.psi = 0.35\n", + "tf.fan_module.booster.aero.spec_flow = 180.\n", + "tf.fan_module.booster.aero.pcnr = 95.\n", "\n", "# lpt\n", - "sys.turbine.aero.Ncqdes = 100.\n", - "sys.turbine.aero.psi = 1.25\n", + "tf.turbine.aero.Ncqdes = 100.\n", + "tf.turbine.aero.psi = 1.25\n", "\n", "# hpc\n", - "sys.core.compressor.aero.pr = 11.\n", - "sys.core.compressor.aero.utip = 420.\n", - "sys.core.compressor.aero.phi = 0.5\n", - "sys.core.compressor.aero.pcnr = 95.\n", + "tf.core.compressor.aero.pr = 11.\n", + "tf.core.compressor.aero.utip = 420.\n", + "tf.core.compressor.aero.phi = 0.5\n", + "tf.core.compressor.aero.pcnr = 95.\n", "\n", "# hpt\n", - "sys.core.turbine.aero.psi = 1.2\n", - "sys.core.turbine.aero.Ncqdes = 100.\n", + "tf.core.turbine.aero.psi = 1.2\n", + "tf.core.turbine.aero.Ncqdes = 100.\n", "\n", "# combustor\n", - "sys.core.combustor.aero.Tcomb = 1700.\n", - "\n", - "sys.run_drivers()\n", + "tf.core.combustor.aero.Tcomb = 1700.\n", "\n", - "print('mach =', mach)\n", - "print('pamb =', sys.pamb, 'Pa')\n", - "print('W =', round(sys.fl_in.W), 'Kg/s')\n", - "print('thrust =', round(sys.thrust * 0.224809/1e3, 1), 'klbf')\n", - "print('N1 =', round(sys.N1), \"rpm\")\n", - "print('N2 =', round(sys.N2), \"rpm\")\n", - "print('bpr =', round(sys.bpr, 1))\n", - "print('opr =', round(sys.opr, 1))\n", - "print('T41 =', round(sys.core.turbine.fl_in.Tt), 'K')\n", - "print('sfc =', round(sys.sfc, 3), 'kg/(h*kN)')\n", - "print('psi fan =', round(sys.fan_module.fan.aero.psi, 2))\n", - "print('psi booster =', round(sys.fan_module.booster.aero.psi, 2))\n", - "print('psi hpc =', round(sys.core.compressor.aero.psi, 2))" + "# design method (using targets)\n", + "design.runner.design.extend(tf.design_methods['scaling'])" ] }, { "cell_type": "code", "execution_count": null, - "id": "392a52bf-7311-448e-9359-6cc5cf5b3c46", + "id": "4ea41fa5-3f9f-4181-9d5f-18c9b5608005", "metadata": {}, "outputs": [], "source": [ - "run.problem" + "# environment conditions\n", + "atm.altitude = 0.\n", + "atm.mach = 0.\n", + "atm.dtamb = 15.\n", + "\n", + "sys.run_drivers()\n", + "\n", + "print('mach =', atm.mach)\n", + "print('pamb =', atm.pamb, 'Pa')\n", + "print('W =', round(tf.fl_in.W), 'Kg/s')\n", + "print('thrust =', round(tf.thrust * 0.224809/1e3, 1), 'klbf')\n", + "print('N1 =', round(tf.N1), \"rpm\")\n", + "print('N2 =', round(tf.N2), \"rpm\")\n", + "print('bpr =', round(tf.bpr, 1))\n", + "print('opr =', round(tf.opr, 1))\n", + "print('T41 =', round(tf.core.turbine.fl_in.Tt), 'K')\n", + "print('sfc =', round(tf.sfc, 3), 'kg/(h*kN)')\n", + "print('psi fan =', round(tf.fan_module.fan.aero.psi, 2))\n", + "print('psi booster =', round(tf.fan_module.booster.aero.psi, 2))\n", + "print('psi hpc =', round(tf.core.compressor.aero.psi, 2))" ] }, { @@ -323,7 +328,7 @@ "id": "588a2015-ee95-4c0f-bcbb-e02ef2055a0b", "metadata": {}, "source": [ - "design mode (detailled)" + "### Using raw equations/unknowns (detailed)" ] }, { @@ -335,69 +340,104 @@ "source": [ "# design mode solver\n", "sys.drivers.clear()\n", - "run = sys.add_driver(NonLinearSolver('run', max_iter=50, factor=0.8))\n", + "design = sys.add_driver(NonLinearSolver('design', max_iter=50, factor=0.8))\n", + "\n", + "# engine\n", + "tf.thrust = 120e3\n", + "tf.bpr = 5.\n", + "tf.pr_nozzle = 1.1\n", + "\n", + "# inlet\n", + "tf.inlet.aero.mach = 0.5\n", + "\n", + "# fan module\n", + "tf.fan_module.fan.aero.pcnr = 0.95\n", + "tf.fan_module.fan.aero.utip = 420.\n", + "\n", + "# booster\n", + "tf.fan_module.booster.aero.phi = 0.45\n", + "tf.fan_module.booster.aero.psi = 0.35\n", + "tf.fan_module.booster.aero.spec_flow = 180.\n", + "tf.fan_module.booster.aero.pcnr = 95.\n", + "\n", + "# lpt\n", + "tf.turbine.aero.Ncqdes = 100.\n", + "tf.turbine.aero.psi = 1.25\n", + "\n", + "# hpc\n", + "tf.core.compressor.aero.pr = 11.\n", + "tf.core.compressor.aero.utip = 420.\n", + "tf.core.compressor.aero.phi = 0.5\n", + "tf.core.compressor.aero.pcnr = 95.\n", + "\n", + "# hpt\n", + "tf.core.turbine.aero.psi = 1.2\n", + "tf.core.turbine.aero.Ncqdes = 100.\n", + "\n", + "# combustor\n", + "tf.core.combustor.aero.Tcomb = 1700.\n", "\n", "# engine\n", - "run.runner.add_unknown('fuel_W')\n", - "run.runner.add_target('thrust')\n", - "run.add_unknown('fan_diameter')\n", + "design.runner.add_unknown('tf.fuel_W')\n", + "design.runner.add_target('tf.thrust')\n", + "design.add_unknown('tf.fan_diameter')\n", "\n", "# inlet\n", - "run.runner.add_target('inlet.aero.mach')\n", + "design.runner.add_target('tf.inlet.aero.mach')\n", "\n", "# fan\n", - "run.add_unknown(\"fan_module.fan.aero.xnd\", max_rel_step=0.5)\n", - "run.add_unknown('fan_module.fan.aero.phiP', lower_bound=0.1, upper_bound=1.5)\n", + "design.add_unknown(\"tf.fan_module.fan.aero.xnd\", max_rel_step=0.5)\n", + "design.add_unknown('tf.fan_module.fan.aero.phiP', lower_bound=0.1, upper_bound=1.5)\n", "\n", - "run.runner.add_target(\"fan_module.fan.aero.pcnr\")\n", - "run.runner.add_target('fan_module.fan.aero.utip')\n", - "run.runner.add_target('bpr')\n", + "design.runner.add_target(\"tf.fan_module.fan.aero.pcnr\")\n", + "design.runner.add_target('tf.fan_module.fan.aero.utip')\n", + "design.runner.add_target('tf.bpr')\n", "\n", "# booster\n", - "run.add_unknown('fan_module.geom.booster_radius_ratio')\n", - "run.add_unknown('fan_module.booster.geom.blade_hub_to_tip_ratio', lower_bound=1e-5, upper_bound=1.)\n", - "run.add_unknown('fan_module.booster.aero.phiP')\n", - "run.add_unknown(\"fan_module.booster.aero.xnd\", max_rel_step=0.5)\n", + "design.add_unknown('tf.fan_module.geom.booster_radius_ratio')\n", + "design.add_unknown('tf.fan_module.booster.geom.blade_hub_to_tip_ratio', lower_bound=1e-5, upper_bound=1.)\n", + "design.add_unknown('tf.fan_module.booster.aero.phiP')\n", + "design.add_unknown(\"tf.fan_module.booster.aero.xnd\", max_rel_step=0.5)\n", "\n", - "run.runner.add_target('fan_module.booster.aero.phi')\n", - "run.runner.add_target('fan_module.booster.aero.psi')\n", - "run.runner.add_target('fan_module.booster.aero.spec_flow')\n", - "run.runner.add_target(\"fan_module.booster.aero.pcnr\")\n", + "design.runner.add_target('tf.fan_module.booster.aero.phi')\n", + "design.runner.add_target('tf.fan_module.booster.aero.psi')\n", + "design.runner.add_target('tf.fan_module.booster.aero.spec_flow')\n", + "design.runner.add_target(\"tf.fan_module.booster.aero.pcnr\")\n", "\n", "# lpt\n", - "run.add_unknown('geom.turbine_radius_ratio')\n", - "run.add_unknown(\"turbine.geom.blade_height_ratio\", lower_bound=0., upper_bound=1.)\n", - "run.add_unknown('turbine.aero.Ncdes')\n", + "design.add_unknown('tf.geom.turbine_radius_ratio')\n", + "design.add_unknown(\"tf.turbine.geom.blade_height_ratio\", lower_bound=0., upper_bound=1.)\n", + "design.add_unknown('tf.turbine.aero.Ncdes')\n", "\n", - "run.runner.add_target('turbine.aero.psi')\n", - "run.runner.add_target('turbine.aero.Ncqdes')\n", + "design.runner.add_target('tf.turbine.aero.psi')\n", + "design.runner.add_target('tf.turbine.aero.Ncqdes')\n", "\n", "# hpc\n", - "run.add_unknown('geom.core_inlet_radius_ratio', max_rel_step=0.8)\n", - "run.add_unknown(\"core.compressor.aero.xnd\", max_rel_step=0.5)\n", - "run.add_unknown(\"core.compressor.aero.phiP\")\n", + "design.add_unknown('tf.geom.core_inlet_radius_ratio', max_rel_step=0.8)\n", + "design.add_unknown(\"tf.core.compressor.aero.xnd\", max_rel_step=0.5)\n", + "design.add_unknown(\"tf.core.compressor.aero.phiP\")\n", "\n", - "run.runner.add_target(\"core.compressor.aero.pcnr\")\n", - "run.runner.add_target(\"core.compressor.aero.phi\")\n", - "run.runner.add_target(\"core.compressor.aero.utip\")\n", - "run.runner.add_target(\"core.compressor.aero.pr\")\n", + "design.runner.add_target(\"tf.core.compressor.aero.pcnr\")\n", + "design.runner.add_target(\"tf.core.compressor.aero.phi\")\n", + "design.runner.add_target(\"tf.core.compressor.aero.utip\")\n", + "design.runner.add_target(\"tf.core.compressor.aero.pr\")\n", "\n", "# combustor\n", - "run.runner.add_target(\"core.combustor.aero.Tcomb\")\n", + "design.runner.add_target(\"tf.core.combustor.aero.Tcomb\")\n", "\n", "# hpt\n", - "run.add_unknown('geom.core_exit_radius_ratio', max_rel_step=0.8)\n", - "run.add_unknown(\"core.turbine.geom.blade_height_ratio\", lower_bound=0., upper_bound=1.)\n", - "run.add_unknown(\"core.turbine.aero.Ncdes\")\n", + "design.add_unknown('tf.geom.core_exit_radius_ratio', max_rel_step=0.8)\n", + "design.add_unknown(\"tf.core.turbine.geom.blade_height_ratio\", lower_bound=0., upper_bound=1.)\n", + "design.add_unknown(\"tf.core.turbine.aero.Ncdes\")\n", "\n", - "run.runner.add_target(\"core.turbine.aero.psi\")\n", - "run.runner.add_target(\"core.turbine.aero.Ncqdes\")\n", + "design.runner.add_target(\"tf.core.turbine.aero.psi\")\n", + "design.runner.add_target(\"tf.core.turbine.aero.Ncqdes\")\n", "\n", "# nozzle\n", - "run.add_unknown('geom.pri_nozzle_area_ratio', lower_bound=0.05)\n", - "run.add_unknown('geom.sec_nozzle_area_ratio', upper_bound=1.)\n", + "design.add_unknown('tf.geom.pri_nozzle_area_ratio', lower_bound=0.05)\n", + "design.add_unknown('tf.geom.sec_nozzle_area_ratio', upper_bound=1.)\n", "\n", - "run.runner.add_target('pr_nozzle')" + "design.runner.add_target('tf.pr_nozzle')" ] }, { @@ -408,62 +448,26 @@ "outputs": [], "source": [ "# environment conditions\n", - "alt = 0.\n", - "mach = 0.\n", - "dtamb = 15.\n", - "sys.init_environment(alt, mach, dtamb)\n", - "\n", - "# engine\n", - "sys.thrust = 120e3\n", - "sys.bpr = 5.\n", - "sys.pr_nozzle = 1.1\n", - "\n", - "# inlet\n", - "sys.inlet.aero.mach = 0.5\n", - "\n", - "# fan module\n", - "sys.fan_module.fan.aero.pcnr = 0.95\n", - "sys.fan_module.fan.aero.utip = 420.\n", - "\n", - "# booster\n", - "sys.fan_module.booster.aero.phi = 0.45\n", - "sys.fan_module.booster.aero.psi = 0.35\n", - "sys.fan_module.booster.aero.spec_flow = 180.\n", - "sys.fan_module.booster.aero.pcnr = 95.\n", - "\n", - "# lpt\n", - "sys.turbine.aero.Ncqdes = 100.\n", - "sys.turbine.aero.psi = 1.25\n", - "\n", - "# hpc\n", - "sys.core.compressor.aero.pr = 11.\n", - "sys.core.compressor.aero.utip = 420.\n", - "sys.core.compressor.aero.phi = 0.5\n", - "sys.core.compressor.aero.pcnr = 95.\n", - "\n", - "# hpt\n", - "sys.core.turbine.aero.psi = 1.2\n", - "sys.core.turbine.aero.Ncqdes = 100.\n", - "\n", - "# combustor\n", - "sys.core.combustor.aero.Tcomb = 1700.\n", + "atm.altitude = 0.\n", + "atm.mach = 0.\n", + "atm.dtamb = 15.\n", "\n", "sys.run_drivers()\n", "\n", - "print('mach =', mach)\n", - "print('pamb =', sys.pamb, 'Pa')\n", - "print('fan diameter =', round(sys.geom.fan_diameter / 0.0254, 1), 'in')\n", - "print('W =', round(sys.fl_in.W), 'Kg/s')\n", - "print('thrust =', round(sys.thrust * 0.224809/1e3, 1), 'klbf')\n", - "print('N1 =', round(sys.N1), \"rpm\")\n", - "print('N2 =', round(sys.N2), \"rpm\")\n", - "print('bpr =', round(sys.bpr, 1))\n", - "print('opr =', round(sys.opr, 1))\n", - "print('T41 =', round(sys.core.turbine.fl_in.Tt), 'K')\n", - "print('sfc =', round(sys.sfc, 3), 'kg/(h*kN)')\n", - "print('psi fan =', round(sys.fan_module.fan.aero.psi, 2))\n", - "print('psi booster =', round(sys.fan_module.booster.aero.psi, 2))\n", - "print('psi hpc =', round(sys.core.compressor.aero.psi, 2))" + "print('mach =', atm.mach)\n", + "print('pamb =', atm.pamb, 'Pa')\n", + "print('fan diameter =', round(tf.geom.fan_diameter / 0.0254, 1), 'in')\n", + "print('W =', round(tf.fl_in.W), 'Kg/s')\n", + "print('thrust =', round(tf.thrust * 0.224809/1e3, 1), 'klbf')\n", + "print('N1 =', round(tf.N1), \"rpm\")\n", + "print('N2 =', round(tf.N2), \"rpm\")\n", + "print('bpr =', round(tf.bpr, 1))\n", + "print('opr =', round(tf.opr, 1))\n", + "print('T41 =', round(tf.core.turbine.fl_in.Tt), 'K')\n", + "print('sfc =', round(tf.sfc, 3), 'kg/(h*kN)')\n", + "print('psi fan =', round(tf.fan_module.fan.aero.psi, 2))\n", + "print('psi booster =', round(tf.fan_module.booster.aero.psi, 2))\n", + "print('psi hpc =', round(tf.core.compressor.aero.psi, 2))" ] }, { @@ -473,7 +477,7 @@ "metadata": {}, "outputs": [], "source": [ - "sys.jupyter_view(options={\n", + "tf.jupyter_view(options={\n", " \"fan_module\": dict(opacity=0.7, face_color=\"#92B4EC\"),\n", " \"fan_module.spinner\": dict(face_color=\"#E1E5EA\", opacity=1.),\n", " \"fan_duct\": dict(opacity=0.3),\n", @@ -492,9 +496,9 @@ "id": "71866bce", "metadata": {}, "source": [ - "## off design mode\n", + "### off-design computation after design\n", "\n", - "Fuel comsumption for an altitude, a mach and a thrust. " + "Fuel comsumption for a given altitude/mach/dtamb and thrust. " ] }, { @@ -506,9 +510,7 @@ "source": [ "# off-design mode\n", "sys.drivers.clear()\n", - "run = sys.add_driver(NonLinearSolver('run'))\n", - "run.runner.add_unknown('fuel_W')\n", - "run.runner.add_target('thrust')" + "run = sys.add_driver(NonLinearSolver('run'))" ] }, { @@ -519,19 +521,23 @@ "outputs": [], "source": [ "# environment conditions\n", - "alt = 10000.\n", - "mach = 0.8\n", - "dtamb = 0.\n", - "sys.init_environment(alt, mach, dtamb)\n", + "atm.altitude = 10000.\n", + "atm.mach = 0.8\n", + "atm.dtamb = 0.\n", "\n", "# requirement\n", - "sys.thrust = 20e3\n", + "tf.thrust = 10e3 / 0.224809\n", + "# tf.N1 = 5000.\n", + "\n", + "run.runner.add_unknown('tf.fuel_W')\n", + "run.runner.add_target('tf.thrust')\n", + "# run.runner.add_target('tf.N1')\n", "\n", "sys.run_drivers()\n", "\n", - "print('fuel flow =', round(sys.fuel_W, 1), 'kg/s')\n", - "print('N1 =', round(sys.N1), \"rpm\")\n", - "print('sfc ', round(sys.sfc, 3), 'kg/(h*kN)')" + "print('fuel flow =', round(tf.fuel_W, 1), 'kg/s')\n", + "print('N1 =', round(tf.N1), \"rpm\")\n", + "print('sfc ', round(tf.sfc, 3), 'kg/(h*kN)')" ] } ], @@ -551,7 +557,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.10.8" }, "vscode": { "interpreter": { diff --git a/pyturbo/systems/__init__.py b/pyturbo/systems/__init__.py index 37da24b..11a07e3 100644 --- a/pyturbo/systems/__init__.py +++ b/pyturbo/systems/__init__.py @@ -20,6 +20,7 @@ from pyturbo.systems.gas_generator import GasGenerator, GasGeneratorGeom # isort: skip from pyturbo.systems.turbofan import ( # isort: skip Turbofan, + TurbofanWithAtm, TurbofanAero, TurbofanGeom, TurbofanWeight, @@ -63,4 +64,5 @@ "TurbofanGeom", "TurbofanWeight", "Turbofan", + "TurbofanWithAtm", ] diff --git a/pyturbo/systems/compressor/compressor.py b/pyturbo/systems/compressor/compressor.py index aa9dcf8..8d9ecd3 100644 --- a/pyturbo/systems/compressor/compressor.py +++ b/pyturbo/systems/compressor/compressor.py @@ -163,4 +163,4 @@ def setup(self): # init aero self.aero.eff_poly = 0.9 - self.aero.phiP = 0.35 + self.aero.phiP = 0.7 diff --git a/pyturbo/systems/turbofan/__init__.py b/pyturbo/systems/turbofan/__init__.py index 1cf4e2d..93ffbbd 100644 --- a/pyturbo/systems/turbofan/__init__.py +++ b/pyturbo/systems/turbofan/__init__.py @@ -2,6 +2,6 @@ from pyturbo.systems.turbofan.turbofan_geom import TurbofanGeom from pyturbo.systems.turbofan.turbofan_weight import TurbofanWeight -from pyturbo.systems.turbofan.turbofan import Turbofan # isort: skip +from pyturbo.systems.turbofan.turbofan import Turbofan, TurbofanWithAtm # isort: skip -__all__ = ["TurbofanAero", "TurbofanGeom", "TurbofanWeight", "Turbofan"] +__all__ = ["TurbofanAero", "TurbofanGeom", "TurbofanWeight", "Turbofan", "TurbofanWithAtm"] diff --git a/pyturbo/systems/turbofan/turbofan.py b/pyturbo/systems/turbofan/turbofan.py index 00fde6a..616e910 100644 --- a/pyturbo/systems/turbofan/turbofan.py +++ b/pyturbo/systems/turbofan/turbofan.py @@ -24,8 +24,6 @@ class Turbofan(System, JupyterViewable): Sub-systems ----------- - atmosphere: Atmosphere - evaluate Pt and Tt from altitude, mach and dtamb inlet: Inlet inlet before the fan fanmodule: FanModule @@ -52,16 +50,12 @@ class Turbofan(System, JupyterViewable): Inputs ------ - altitude[m]: float - engine altitude - mach[-]: float - engine speed - dtamb[K]: float - atmosphere dtamb - + fl_in: FluidPort + inlet flow + pamb[Pa]: float + ambiant static pressure fan_diameter[m]: float diameter of the fan - fuel_W[kg/s]: float fuel mass flow @@ -91,22 +85,19 @@ class Turbofan(System, JupyterViewable): """ def setup(self): - # atmosphere - self.add_child(Atmosphere("atmosphere"), pulling=["altitude", "mach", "dtamb", "pamb"]) - # physics self.add_child(TurbofanGeom("geom"), pulling=["fan_diameter", "frd_mount", "aft_mount"]) # component - self.add_child(Inlet("inlet")) + self.add_child(Inlet("inlet"), pulling=["fl_in", "pamb"]) self.add_child(FanModule("fan_module"), pulling={"bpr": "bpr", "N": "N1"}) self.add_child(FanDuct("fan_duct")) self.add_child(GasGenerator("core"), pulling={"fuel_W": "fuel_W", "N": "N2"}) self.add_child(Channel("tcf")) self.add_child(LPT("turbine")) self.add_child(Channel("trf")) - self.add_child(Nozzle("primary_nozzle")) - self.add_child(Nozzle("secondary_nozzle")) + self.add_child(Nozzle("primary_nozzle"), pulling=["pamb"]) + self.add_child(Nozzle("secondary_nozzle"), pulling=["pamb"]) self.add_child(Nacelle("nacelle")) self.add_child(Plug("plug")) self.add_child(CoreCowl("core_cowl")) @@ -118,16 +109,10 @@ def setup(self): ) self.add_child(TurbofanWeight("weight"), pulling=["ipps_weight"]) - # atmosphere connectors - self.connect(self.atmosphere.outwards, self.inlet.inwards, "pamb") - self.connect(self.atmosphere.outwards, self.primary_nozzle.inwards, "pamb") - self.connect(self.atmosphere.outwards, self.secondary_nozzle.inwards, "pamb") - # shaft connectors self.connect(self.turbine.sh_out, self.fan_module.sh_in) # fluid connectors - self.connect(self.atmosphere.outwards, self.inlet.fl_in, ["Pt", "Tt"]) self.connect(self.inlet.fl_out, self.fan_module.fl_in) self.connect(self.fan_module.fl_bypass, self.fan_duct.fl_in) self.connect(self.fan_duct.fl_out, self.secondary_nozzle.fl_in) @@ -199,7 +184,7 @@ def setup(self): self.connect(self.geom, self.weight, {"engine_length": "length"}) # solver - self.add_unknown("inlet.fl_in.W") + self.add_unknown("fl_in.W") # default value : CFM56-7 @@ -320,3 +305,22 @@ def _to_occt(self) -> Dict[str, TopoDS_Shape]: plug=self.plug.geom._to_occt(), core_cowl=self.core_cowl._to_occt(), ) + + +class TurbofanWithAtm(System): + """Turbofan assembly system used in atmosphere. + + Sub-systems + ----------- + atm: Atmosphere + simplified atmosphere from altitude, Mach and delta ambient temperature + tf: Turbofan + turbofan + """ + + def setup(self): + self.add_child(Atmosphere("atm")) + self.add_child(Turbofan("tf")) + + self.connect(self.atm.outwards, self.tf.fl_in, ["Pt", "Tt"]) + self.connect(self.atm.outwards, self.tf.inwards, ["pamb"]) diff --git a/tests/test_turbofan.py b/tests/test_turbofan.py index 374f63f..b9881db 100644 --- a/tests/test_turbofan.py +++ b/tests/test_turbofan.py @@ -13,10 +13,10 @@ def test_system_setup(self): # default constructor sys = self.sys - data_input = [] + data_input = ["fl_in"] data_output = [] - data_inward = ["fan_diameter", "fuel_W", "altitude", "mach", "dtamb"] - data_outward = ["thrust", "pamb", "bpr", "opr", "sfc"] + data_inward = ["fan_diameter", "fuel_W", "pamb"] + data_outward = ["thrust", "bpr", "opr", "sfc"] for data in data_input: assert data in sys.inputs @@ -30,7 +30,7 @@ def test_system_setup(self): def test_run_once(self): sys = self.sys - sys.inlet.fl_in.W = 300.0 + sys.fl_in.W = 300.0 sys.fuel_W = 1.0 sys.fan_module.splitter_fluid.fluid_fractions[0] = 0.8