From 7374d1a1a29d1630c2c71a4965d953404ca17f72 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 27 Nov 2024 17:52:01 -0800 Subject: [PATCH 01/48] glue variables in off_design_missions.ipynb --- .../docs/user_guide/off_design_missions.ipynb | 63 +++++++++++++++++-- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/aviary/docs/user_guide/off_design_missions.ipynb b/aviary/docs/user_guide/off_design_missions.ipynb index 3798fe65d..ea2fd4787 100644 --- a/aviary/docs/user_guide/off_design_missions.ipynb +++ b/aviary/docs/user_guide/off_design_missions.ipynb @@ -1,5 +1,47 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.api import Settings\n", + "import aviary.api as av\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "str_problem_type = Settings.PROBLEM_TYPE\n", + "str_sizing = av.ProblemType.SIZING.value\n", + "str_alternate = av.ProblemType.ALTERNATE.value\n", + "str_fallout = av.ProblemType.FALLOUT.value\n", + "\n", + "str_alternate_snippet = '```\\n'\n", + "str_alternate_snippet += str_problem_type + ',' + str_alternate\n", + "str_alternate_snippet +='\\n```'\n", + "glue_variable('alternate_snippet', str_alternate_snippet, md_code=False)\n", + "\n", + "fallout_snippet = '```\\n'\n", + "fallout_snippet += str_problem_type + ',' + str_fallout\n", + "fallout_snippet +='\\n```'\n", + "glue_variable('fallout_snippet', fallout_snippet, md_code=False)\n", + "\n", + "glue_variable(av.EquationsOfMotion.HEIGHT_ENERGY.value, md_code=False)\n", + "glue_variable(av.EquationsOfMotion.TWO_DEGREES_OF_FREEDOM.value, md_code=False)\n", + "\n", + "AnalysisScheme = av.AnalysisScheme\n", + "str_collocation = f'{AnalysisScheme.COLLOCATION=}'.split('=')[0]\n", + "str_collocation = str_collocation.split('.')[1].lower()\n", + "glue_variable(str_collocation, md_code=False)\n", + "str_shooting = f'{AnalysisScheme.SHOOTING=}'.split('=')[0]\n", + "str_shooting = str_shooting.split('.')[1].lower()\n", + "glue_variable(str_shooting, md_code=False)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -10,16 +52,24 @@ "\n", "Off-design missions are enabled for the following mission types:\n", "\n", - "* height_energy (collocation) (completed)\n", - "* 2DOF (collocation) (complete)\n", - "* 2DOF (shooting) (future work)\n", - "* height_energy (shooting) (future work)\n", + "* {glue:md}`height_energy` ({glue:md}`collocation`) (completed)\n", + "* {glue:md}`2DOF` ({glue:md}`collocation`) (complete)\n", + "* height_energy ({glue:md}`shooting`) (future work)\n", + "* 2DOF ({glue:md}`shooting`) (future work)\n", "\n", "An off-design mission can be created either by directly entering the parameters of the sized aircraft or by using the built-in functionality to run an off-design in the same script as the sizing mission.\n", "There are currently two types of off-design missions supported in Aviary; alternate and fallout.\n", "For an alternate mission, the target range of the mission and the payload mass are specified and the fuel mass required is solved for.\n", "Fallout missions meanwhile take the payload and fuel masses as inputs and determine the range of the aircraft.\n", - "To create a simple off-design mission, take your input deck and add the line `settings:problem_type, fallout` or `settings:problem_type, alternate`.\n", + "To create a simple off-design mission, take your input deck and add the line\n", + "\n", + "```{glue:md} fallout_snippet\n", + ":format: myst\n", + "```\n", + "or\n", + "```{glue:md} alternate_snippet\n", + ":format: myst\n", + "```\n", "\n", "```{note}\n", "You may need to revise some of the values in your input deck for the off-design mission.\n", @@ -34,7 +84,7 @@ "metadata": {}, "source": [ "You may also run multiple off-design missions in the same script used to solve the design mission.\n", - "An examples of this is shown in `run_off_design_example.py`." + "An examples of this is shown in `aviary/examples/run_off_design_example.py`." ] }, { @@ -52,6 +102,7 @@ "import aviary.api as av\n", "import os\n", "\n", + "# make sure run_off_design_example.py exists in aviary/examples folder\n", "off_design_examples = av.get_path(os.path.join('examples'))\n", "check_contains(\n", " ('run_off_design_example.py'),\n", From a57e8c28d9e08950473e517e81f58e80db64af92 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 27 Nov 2024 18:12:48 -0800 Subject: [PATCH 02/48] update how_to_contribute_docs.md --- aviary/docs/developer_guide/how_to_contribute_docs.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aviary/docs/developer_guide/how_to_contribute_docs.md b/aviary/docs/developer_guide/how_to_contribute_docs.md index b2517a24c..6a5f45a3c 100644 --- a/aviary/docs/developer_guide/how_to_contribute_docs.md +++ b/aviary/docs/developer_guide/how_to_contribute_docs.md @@ -3,7 +3,9 @@ Doc pages can be added as `.ipynb` or `.md` files within the `aviary/docs` folder. We're using [jupyter-book](https://jupyterbook.org/) for the docs, which is a well-documented and full-featured platform. To build the docs, you'll need to install jupyter-book following [these instructions](https://jupyterbook.org/en/stable/start/overview.html). -Jupyter-book allows for arbitrary Jupyter notebook usage to intersperse code and documentation and it uses [MyST markdown](https://jupyterbook.org/en/stable/content/myst.html). +Jupyter-book allows for arbitrary Jupyter notebook usage to intersperse code and documentation and it uses [MyST markdown](https://jupyterbook.org/en/stable/content/myst.html). + +Whenever a page contains code, it should be a Jupyter notebook. Otherwise, you can write it as markdown page. Note that if you run an optimiser in a Jupyter notebook, don't use `SNOPT` because it is not available in test run on Github. To modify the docs, simply add a file to the repo within the docs folder. You can then add it to the `docs/_toc.yml` file following the structure for the skeletal outline. From 202d3e4c3dc2710f4b814879ab01f597e16d5de5 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 27 Nov 2024 18:17:37 -0800 Subject: [PATCH 03/48] update how_to_contribute_docs.md --- aviary/docs/developer_guide/how_to_contribute_docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/docs/developer_guide/how_to_contribute_docs.md b/aviary/docs/developer_guide/how_to_contribute_docs.md index 6a5f45a3c..feb947dc2 100644 --- a/aviary/docs/developer_guide/how_to_contribute_docs.md +++ b/aviary/docs/developer_guide/how_to_contribute_docs.md @@ -5,7 +5,7 @@ We're using [jupyter-book](https://jupyterbook.org/) for the docs, which is a we To build the docs, you'll need to install jupyter-book following [these instructions](https://jupyterbook.org/en/stable/start/overview.html). Jupyter-book allows for arbitrary Jupyter notebook usage to intersperse code and documentation and it uses [MyST markdown](https://jupyterbook.org/en/stable/content/myst.html). -Whenever a page contains code, it should be a Jupyter notebook. Otherwise, you can write it as markdown page. Note that if you run an optimiser in a Jupyter notebook, don't use `SNOPT` because it is not available in test run on Github. +Whenever a page contains code, it should be a Jupyter notebook. Otherwise, you can write it as markdown page. Note that if you run an optimiser in a Jupyter notebook, don't use `SNOPT` because it is not available in test run on Github. Also, if you plan to push a Jupyter notebook to the Aviary repository, make sure you run `reset_notebook` on that page. To modify the docs, simply add a file to the repo within the docs folder. You can then add it to the `docs/_toc.yml` file following the structure for the skeletal outline. From 361523fde8c2de9271e00b49764df3f1cbf1f03f Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 29 Nov 2024 08:54:27 -0800 Subject: [PATCH 04/48] glue variables in docs/user_guide/mass.ipynb --- aviary/docs/user_guide/mass.ipynb | 36 +++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/aviary/docs/user_guide/mass.ipynb b/aviary/docs/user_guide/mass.ipynb index 912484e2e..614968d46 100644 --- a/aviary/docs/user_guide/mass.ipynb +++ b/aviary/docs/user_guide/mass.ipynb @@ -1,5 +1,23 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.subsystems.mass.flops_based.mass_summation import AltSystemsEquipMass\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "\n", + "AltSystemsEquipMass\n", + "glue_variable(get_variable_name(AltSystemsEquipMass), md_code=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -23,7 +41,7 @@ "- **Total Mass Summation:** Orchestrates the calculation of the total mass by summing up contributions from structural, propulsion, systems and equipment, and fuel masses.\n", "- **Structure Mass:** Calculates the mass contributions from the aircraft's structural components like wings, fuselage, landing gear, etc.\n", "- **Propulsion Mass:** Computes the mass related to the aircraft's propulsion system, including engines and associated components.\n", - "- **Systems and Equipment Mass:** Determines the mass of systems and equipment on the aircraft, with an alternative calculation option (`AltSystemsEquipMass`) available.\n", + "- **Systems and Equipment Mass:** Determines the mass of systems and equipment on the aircraft, with an alternative calculation option ({glue:md}`AltSystemsEquipMass`) available.\n", "- **Empty Mass:** Represents the total mass of the aircraft without fuel, calculated using either standard or alternative methods.\n", "- **Operating Mass:** Accounts for the mass of the crew, passengers, and service items in addition to the empty mass.\n", "- **Zero Fuel Mass:** The total mass of the aircraft without considering the fuel.\n", @@ -67,8 +85,22 @@ } ], "metadata": { + "kernelspec": { + "display_name": "av1", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.18" } }, "nbformat": 4, From d56e7aff1c898c489c491b2918946dfa63e3fd35 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 29 Nov 2024 17:41:07 -0800 Subject: [PATCH 05/48] add glue in aerodynamics.ipynb --- aviary/docs/user_guide/aerodynamics.ipynb | 85 +++++++++++++++++++---- 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/aviary/docs/user_guide/aerodynamics.ipynb b/aviary/docs/user_guide/aerodynamics.ipynb index 023e8883a..ebae50a60 100644 --- a/aviary/docs/user_guide/aerodynamics.ipynb +++ b/aviary/docs/user_guide/aerodynamics.ipynb @@ -1,5 +1,36 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import inspect\n", + "import aviary.api as av\n", + "from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "\n", + "CoreAerodynamicsBuilder\n", + "glue_variable(get_variable_name(CoreAerodynamicsBuilder), md_code=True)\n", + "\n", + "EquationsOfMotion = av.EquationsOfMotion\n", + "glue_variable(get_variable_name(EquationsOfMotion.HEIGHT_ENERGY).split('.')[1].lower().replace('_','-'), md_code=False)\n", + "glue_variable(get_variable_name(EquationsOfMotion.TWO_DEGREES_OF_FREEDOM).split('.')[1].lower().replace('_','-'), md_code=False)\n", + "\n", + "# glue all argument of function CoreAerodynamicsBuilder.__init__()\n", + "sigs = inspect.signature(CoreAerodynamicsBuilder)\n", + "parameters = sigs.parameters\n", + "for name, param in parameters.items():\n", + " glue_variable(name, md_code=True)\n", + " # print(f'Name: {name}, Default: {param.default}, Kind: {param.kind}')" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -7,7 +38,7 @@ "\n", "# Aerodynamics Subsystem\n", "\n", - "The built-in aerodynamics subsystem in Aviary offers multiple options for computing drag. Users can select from methods based on the FLOPS or GASP legacy codes. Choice of which legacy code's routines to use is determined by the `code_origin` option provided when initializing a `CoreAerodynamicsBuilder`. When using Aviary's [Level 1 interface](../getting_started/onboarding_level1), the code origin for aerodynamics is automatically set to match with the mission method (height-energy is paired with FLOPS, and 2-degree-of-freedom is paired with GASP). Future updates to Aviary will allow for the user to specify aerodynamics code origin directly in the input file." + "The built-in aerodynamics subsystem in Aviary offers multiple options for computing drag. Users can select from methods based on the FLOPS or GASP legacy codes. Choice of which legacy code's routines to use is determined by the {glue:md}`code_origin` option provided when initializing a {glue:md}`CoreAerodynamicsBuilder`. When using Aviary's [Level 1 interface](../getting_started/onboarding_level1), the code origin for aerodynamics is automatically set to match with the mission method ({glue:md}`height-energy` is paired with FLOPS, and {glue:md}`two-degrees-of-freedom` is paired with GASP). Future updates to Aviary will allow for the user to specify aerodynamics code origin directly in the input file." ] }, { @@ -21,13 +52,40 @@ "aero_builder = CoreAerodynamicsBuilder(name='aero_example', code_origin=LegacyCode.FLOPS)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.interface.methods_for_level1 import run_aviary\n", + "\n", + "# Get all functions of class CoreAerodynamicsBuilder\n", + "methods = inspect.getmembers(CoreAerodynamicsBuilder, predicate=inspect.isfunction)\n", + "for name, func in methods:\n", + " if name == 'build_pre_mission':\n", + " glue_variable('CoreAerodynamicsBuilder.' + name + '()', md_code=True)\n", + "\n", + "# glue all argument of function run_aviary()\n", + "sigs = inspect.signature(run_aviary)\n", + "parameters = sigs.parameters\n", + "for name, param in parameters.items():\n", + " if name == 'phase_info':\n", + " glue_variable(name, md_code=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Both FLOPS and GASP methods have only a single option for pre-mission components, so there are no user-configurable options when calling `CoreAerodynamicsBuilder.build_pre_mission()`.\n", + "Both FLOPS and GASP methods have only a single option for pre-mission components, so there are no user-configurable options when calling {glue:md}`CoreAerodynamicsBuilder.build_pre_mission()`.\n", "\n", - "For mission analysis, a variety of methods are available to both legacy codes, each with unique options. This can be configured per-mission segment in a `phase_info` file, with relevant aerodynamics configurations placed inside `['core_subsystems']`. The following example would instruct Aviary to send the defined options to a subsystem named 'aero_example' when building the mission, if the dictionary is properly added to `phase_info`" + "For mission analysis, a variety of methods are available to both legacy codes, each with unique options. This can be configured per-mission segment in a {glue:md}`phase_info` file, with relevant aerodynamics configurations placed inside `['core_subsystems']`. The following example would instruct Aviary to send the defined options to a subsystem named 'aero_example' when building the mission, if the dictionary is properly added to {glue:md}`phase_info`" ] }, { @@ -81,9 +139,9 @@ "\n", "\n", "The following input variables are required for the pre-mission calculations:\n", - "- `Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN` : Maximum camber at 70 percent semi-span, percent of local chord\n", - "- `Aircraft.Design.BASE_AREA` : Aircraft base area (total exit cross-section area minus inlet capture areas for internally mounted engines)\n", - "- `Aircraft.Wing.AIRFOIL_TECHNOLOGY` : Airfoil technology parameter. Limiting values are: 1.0 represents conventional technology wing (Default); 2.0 represents advanced technology wing\n", + "- {glue:md}`Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN` : Maximum camber at 70 percent semi-span, percent of local chord\n", + "- {glue:md}`Aircraft.Design.BASE_AREA` : Aircraft base area (total exit cross-section area minus inlet capture areas for internally mounted engines)\n", + "- {glue:md}`Aircraft.Wing.AIRFOIL_TECHNOLOGY` : Airfoil technology parameter. Limiting values are: 1.0 represents conventional technology wing (Default); 2.0 represents advanced technology wing\n", "" ] }, @@ -101,14 +159,17 @@ "from aviary.api import Aircraft\n", "Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN;\n", "Aircraft.Wing.AIRFOIL_TECHNOLOGY;\n", - "Aircraft.Design.BASE_AREA;" + "Aircraft.Design.BASE_AREA;\n", + "glue_variable(get_variable_name(Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Wing.AIRFOIL_TECHNOLOGY), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Design.BASE_AREA), md_code=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For mission analysis, FLOPS-based aerodynamics has several choices of method to determine the total lift and drag on the vehicle, listed below. The default is `computed`. If another method is desired, it should be specified in `phase_info` for each individual mission segment.\n", + "For mission analysis, FLOPS-based aerodynamics has several choices of method to determine the total lift and drag on the vehicle, listed below. The default is `computed`. If another method is desired, it should be specified in {glue:md}`phase_info` for each individual mission segment.\n", "- `computed`: uses regression-based techniques to estimate lift and drag\n", "- `low_speed`: for use in detailed takeoff analysis, and includes high-lift devices and considers angle-of-attack\n", "- `tabular`: allows the user to substitute the lift and drag coefficient calculations in `computed` with data tables\n", @@ -158,9 +219,9 @@ "## GASP Based\n", "### Using GASP Aerodynamics with the Height-Energy Equations of Motion (FLOPS Mission)\n", "\n", - "You can also use GASP-based aero with the height-energy mission by using the `solved_alpha` method.\n", + "You can also use GASP-based aero with the {glue:md}`height-energy` mission by using the `solved_alpha` method.\n", "\n", - "Gasp-based drag polars have 3 inputs: altitude, mach number, and angle of attack. Since the height-energy equations of motion do not incorporate angle of attack, `solved_alpha` creates an computational group with a solver that varies the angle of attack until the interpolated lift matches the weight force on the aircraft. The format for the table in the file is the same as for GASP-based aerodynamics used with the 2-DOF mission.\n", + "Gasp-based drag polars have 3 inputs: altitude, mach number, and angle of attack. Since the {glue:md}`height-energy` equations of motion do not incorporate angle of attack, `solved_alpha` creates an computational group with a solver that varies the angle of attack until the interpolated lift matches the weight force on the aircraft. The format for the table in the file is the same as for GASP-based aerodynamics used with the {glue:md}`two-degrees-of-freedom` mission.\n", "\n", "## Externally Computed Polars\n", "\n", @@ -177,7 +238,7 @@ ], "metadata": { "kernelspec": { - "display_name": "aviary", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -191,7 +252,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.1.-1" + "version": "3.9.18" } }, "nbformat": 4, From 5aead603272821bd033178b74aacf41b90ac9930 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 29 Nov 2024 17:41:28 -0800 Subject: [PATCH 06/48] add glue in aviary_commands.ipynb --- aviary/docs/user_guide/aviary_commands.ipynb | 89 +++++++++++++++++--- 1 file changed, 78 insertions(+), 11 deletions(-) diff --git a/aviary/docs/user_guide/aviary_commands.ipynb b/aviary/docs/user_guide/aviary_commands.ipynb index 853d6ec5e..89c78b245 100644 --- a/aviary/docs/user_guide/aviary_commands.ipynb +++ b/aviary/docs/user_guide/aviary_commands.ipynb @@ -1,5 +1,23 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.interface.cmd_entry_points import _command_map\n", + "from aviary.utils.doctape import glue_variable, glue_keys\n", + "\n", + "# glue all the options of 'aviary'\n", + "glue_keys(_command_map)\n" + ] + }, { "attachments": {}, "cell_type": "markdown", @@ -86,9 +104,10 @@ "(aviary-run_mission-command)=\n", "### aviary run_mission\n", "\n", - "`run_mission` is a command line interface that will run an analysis on a given csv input file.\n", + "{glue:md}`run_mission` is a command line interface that will run an analysis on a given csv input file.\n", "\n", - "To use small_single_aisle_GwGm.csv run the command `aviary run_mission models/small_single_aisle/small_single_aisle_GwGm.csv`
\n", + "To use {glue:md}`small_single_aisle_GwGm.csv` run in {glue:md}`aviary/models/small_single_aisle` the command \n", + "{glue:md}`aviary run_mission models/small_single_aisle/small_single_aisle_GwGm.csv`
\n", "\n", "SNOPT is the default optimizer, but IPOPT is available as well." ] @@ -107,7 +126,11 @@ "import subprocess\n", "command = 'aviary run_mission models/small_single_aisle/small_single_aisle_GwGm.csv'\n", "command += ' --max_iter 0 --optimizer IPOPT' # max_iter to limit build time, IPOPT to run on CI\n", - "subprocess.run(command.split()).check_returncode();\n" + "subprocess.run(command.split()).check_returncode();\n", + "\n", + "glue_variable('aviary run_mission models/small_single_aisle/small_single_aisle_GwGm.csv', md_code=True)\n", + "glue_variable('small_single_aisle_GwGm.csv', md_code=False)\n", + "glue_variable('aviary/models/small_single_aisle', md_code=True)" ] }, { @@ -133,16 +156,60 @@ "!aviary run_mission -h" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import aviary.api as av\n", + "from aviary.interface.methods_for_level1 import _setup_level1_parser, run_level_1\n", + "from aviary.utils.doctape import glue_variable\n", + "import inspect\n", + "\n", + "# glue all the options of 'aviary run_mission'\n", + "source_code = inspect.getsource(_setup_level1_parser)\n", + "new_line = ''\n", + "for ch in source_code:\n", + " if ch == '\\n':\n", + " new_line = new_line.strip()\n", + " if new_line.startswith('\\\"-') or new_line.startswith(\"'-\"):\n", + " skey = new_line.split(',')[0][1:-1]\n", + " if skey == '-o':\n", + " glue_variable('--outdir', md_code=True)\n", + " glue_variable(skey, md_code=True)\n", + " elif new_line.startswith('\\\"') or new_line.startswith(\"'\"):\n", + " skey = new_line.split(',')[0][1:-1]\n", + " glue_variable(skey, md_code=True)\n", + " new_line = ''\n", + " else:\n", + " new_line += ch\n", + "\n", + "glue_variable(av.EquationsOfMotion.HEIGHT_ENERGY.value, md_code=False, display=True)\n", + "glue_variable(av.EquationsOfMotion.TWO_DEGREES_OF_FREEDOM.value, md_code=False, display=True)\n", + "glue_variable(av.EquationsOfMotion.SOLVED_2DOF.value, md_code=False, display=True)\n", + "\n", + "# obtain the default value of maximum number of iterations from function run_level_1().\n", + "max_iter = inspect.signature(run_level_1).parameters['max_iter'].default\n", + "glue_variable('max_iter', str(max_iter), md_code=False)\n", + "\n" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "`input_deck` is the path to vehicle input deck .csv file.\n", - "`-o` or `--outdir` is the directory to write outputs. The default is current directory.\n", - "`--optimizer` is the name of the optimizer. The default is `SNOPT`.\n", - "`--shooting` indicates that the integration method is shooting method instead of collocation scheme. The default is collocation.\n", - "`--phase_info` is the path to phase info file. If it is missing, it depends on the integration method (collocation or shooting) and on the mission method (settings:equations+of_motion with value of `2DOF` or `height_energy`) which is defined in the .csv input file.\n", - "`--max_iter` is the maximum number of iterations. The default is 50.\n", + "{glue:md}`input_deck` is the path to vehicle input deck .csv file.\n", + "{glue:md}`-o` or {glue:md}`--outdir` is the directory to write outputs. The default is current directory.\n", + "{glue:md}`--optimizer` is the name of the optimizer. The default is `SNOPT`.\n", + "{glue:md}`--shooting` indicates that the integration method is shooting method instead of collocation scheme. The default is collocation.\n", + "{glue:md}`--phase_info` is the path to phase info file. If it is missing, it depends on the integration method (collocation or shooting) and on the mission method (settings:equations_of_motion with value of {glue:md}`2DOF` or {glue:md}`height_energy`) which is defined in the .csv input file.\n", + "{glue:md}`--max_iter` is the maximum number of iterations. The default is {glue:md}`max_iter`.\n", "\n", "More detailed discussions can be found in [onboarding_level1](../getting_started/onboarding_level1.ipynb)." ] @@ -558,7 +625,7 @@ "metadata": { "celltoolbar": "Tags", "kernelspec": { - "display_name": "latest_env", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -572,7 +639,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From 2f081f793701826a1ccdb58286a2b22514a8b954 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 29 Nov 2024 17:43:12 -0800 Subject: [PATCH 07/48] minor update --- aviary/docs/user_guide/off_design_missions.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/docs/user_guide/off_design_missions.ipynb b/aviary/docs/user_guide/off_design_missions.ipynb index ea2fd4787..da648f29f 100644 --- a/aviary/docs/user_guide/off_design_missions.ipynb +++ b/aviary/docs/user_guide/off_design_missions.ipynb @@ -114,7 +114,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -128,7 +128,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.9.18" } }, "nbformat": 4, From a8f9c8ba6b3a4af5aa4b70c6b224e11792026667 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 29 Nov 2024 17:52:15 -0800 Subject: [PATCH 08/48] update docstring --- aviary/utils/doctape.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aviary/utils/doctape.py b/aviary/utils/doctape.py index 13f129410..352c4d48a 100644 --- a/aviary/utils/doctape.py +++ b/aviary/utils/doctape.py @@ -27,6 +27,7 @@ get_value recursively get a value from a dict of dicts glue_variable Glue a variable for later use in markdown cells of notebooks (can auto format for code) glue_keys recursively glue all of the keys from a dict of dicts +get_previous_line returns the previous n line(s) of code as a string """ From cabf87ac79eeedb51d6d7d6dd72b6ed4800487fa Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 2 Dec 2024 17:27:51 -0800 Subject: [PATCH 09/48] format aviary command options source code --- aviary/utils/aero_table_conversion.py | 14 ++++++++------ aviary/utils/engine_deck_conversion.py | 16 ++++++++++------ aviary/utils/propeller_map_conversion.py | 17 ++++++++++------- aviary/visualization/dashboard.py | 20 +++++++++----------- 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/aviary/utils/aero_table_conversion.py b/aviary/utils/aero_table_conversion.py index 08efacb76..08a37b2ba 100644 --- a/aviary/utils/aero_table_conversion.py +++ b/aviary/utils/aero_table_conversion.py @@ -247,12 +247,14 @@ def _load_gasp_aero_table(filepath: Path): def _setup_ATC_parser(parser): - parser.add_argument('input_file', type=str, - help='path to aero data file to be converted') - parser.add_argument('output_file', type=str, nargs='?', - help='path to file where new converted data will be written') - parser.add_argument('-f', '--data_format', type=str, choices=[origin.value for origin in CodeOrigin], - help='data format used by input_file') + parser.add_argument( + 'input_file', type=str, help='path to aero data file to be converted') + parser.add_argument( + 'output_file', type=str, nargs='?', help='path to file where new converted data will be written') + parser.add_argument( + '-f', + '--data_format', type=str, choices=[origin.value for origin in CodeOrigin], + help='data format used by input_file') def _exec_ATC(args, user_args): diff --git a/aviary/utils/engine_deck_conversion.py b/aviary/utils/engine_deck_conversion.py index b6476f733..2050f04d2 100644 --- a/aviary/utils/engine_deck_conversion.py +++ b/aviary/utils/engine_deck_conversion.py @@ -715,12 +715,16 @@ def compute(self, inputs, outputs): def _setup_EDC_parser(parser): - parser.add_argument('input_file', type=str, - help='path to engine deck file to be converted') - parser.add_argument('output_file', type=str, nargs='?', - help='path to file where new converted data will be written') - parser.add_argument('-f', '--data_format', type=EngineDeckType, choices=list(EngineDeckType), - help='data format used by input_file') + parser.add_argument( + 'input_file', type=str, + help='path to engine deck file to be converted') + parser.add_argument( + 'output_file', type=str, nargs='?', + help='path to file where new converted data will be written') + parser.add_argument( + '-f', + '--data_format', type=EngineDeckType, choices=list(EngineDeckType), + help='data format used by input_file') def _exec_EDC(args, user_args): diff --git a/aviary/utils/propeller_map_conversion.py b/aviary/utils/propeller_map_conversion.py index 51183fabd..edb9cc163 100644 --- a/aviary/utils/propeller_map_conversion.py +++ b/aviary/utils/propeller_map_conversion.py @@ -146,13 +146,16 @@ def _read_pm_table(f, cmts): def _setup_PMC_parser(parser): - parser.add_argument('input_file', type=str, - help='path to propeller map file to be converted') - parser.add_argument('output_file', type=str, nargs='?', - help='path to file where new converted data will be written') - parser.add_argument('-f', '--data_format', type=PropMapType, choices=list(PropMapType), - nargs='?', default='GASP', - help='data format used by input_file') + parser.add_argument( + 'input_file', type=str, + help='path to propeller map file to be converted') + parser.add_argument( + 'output_file', type=str, nargs='?', + help='path to file where new converted data will be written') + parser.add_argument( + '-f', + '--data_format', type=PropMapType, choices=list(PropMapType), + nargs='?', default='GASP', help='data format used by input_file') def _exec_PMC(args, user_args): diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index cab3b9704..50541abe3 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -134,17 +134,15 @@ def _dashboard_setup_parser(parser): help="show debugging output", ) - parser.add_argument("--save", - nargs='?', - const=True, - default=False, - help="Name of zip file in which dashboard files are saved. If no argument given, use the script name to name the zip file", - ) - - parser.add_argument("--force", - action='store_true', - help="When displaying data from a shared zip file, if the directory in the reports directory exists, overrite if this is True", - ) + parser.add_argument( + "--save", nargs='?', const=True, default=False, + help="Name of zip file in which dashboard files are saved. If no argument given, use the script name to name the zip file", + ) + + parser.add_argument( + "--force", action='store_true', + help="When displaying data from a shared zip file, if the directory in the reports directory exists, overrite if this is True", + ) def _dashboard_cmd(options, user_args): From 61c2389043136f9b5c3e437fe640c327426bf1fb Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 2 Dec 2024 17:28:27 -0800 Subject: [PATCH 10/48] add glue to aviary_commands.ipynb --- aviary/docs/user_guide/aviary_commands.ipynb | 224 ++++++++++++++++--- 1 file changed, 192 insertions(+), 32 deletions(-) diff --git a/aviary/docs/user_guide/aviary_commands.ipynb b/aviary/docs/user_guide/aviary_commands.ipynb index 89c78b245..359f0f3ba 100644 --- a/aviary/docs/user_guide/aviary_commands.ipynb +++ b/aviary/docs/user_guide/aviary_commands.ipynb @@ -15,7 +15,9 @@ "from aviary.utils.doctape import glue_variable, glue_keys\n", "\n", "# glue all the options of 'aviary'\n", - "glue_keys(_command_map)\n" + "glue_keys(_command_map)\n", + "for key in _command_map:\n", + " glue_variable(f'aviary '+key, md_code=True)\n" ] }, { @@ -185,7 +187,8 @@ " glue_variable(skey, md_code=True)\n", " elif new_line.startswith('\\\"') or new_line.startswith(\"'\"):\n", " skey = new_line.split(',')[0][1:-1]\n", - " glue_variable(skey, md_code=True)\n", + " if len(skey) > 1:\n", + " glue_variable(skey, md_code=True)\n", " new_line = ''\n", " else:\n", " new_line += ch\n", @@ -214,6 +217,44 @@ "More detailed discussions can be found in [onboarding_level1](../getting_started/onboarding_level1.ipynb)." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import aviary.api as av\n", + "from aviary.utils.fortran_to_aviary import _setup_F2A_parser\n", + "from aviary.utils.doctape import glue_variable\n", + "import inspect\n", + "\n", + "# glue all the options of 'aviary fortran_to_aviary'\n", + "source_code = inspect.getsource(_setup_F2A_parser)\n", + "new_line = ''\n", + "for ch in source_code:\n", + " if ch == '\\n':\n", + " new_line = new_line.strip()\n", + " if new_line.startswith('\\\"-') or new_line.startswith(\"'-\"):\n", + " skey = new_line.split(',')[0][1:-1]\n", + " if skey != '-o':\n", + " glue_variable(skey, md_code=True)\n", + " new_line = ''\n", + " else:\n", + " new_line += ch\n", + "\n", + "# experimenting\n", + "# import argparse\n", + "# parser = argparse.ArgumentParser()\n", + "# _setup_F2A_parser(parser)\n", + "# options = [action.dest for action in parser._actions]\n", + "# print(\"Options:\", options)\n" + ] + }, { "attachments": {}, "cell_type": "markdown", @@ -222,14 +263,14 @@ "(aviary-fortran_to_aviary-command)=\n", "### aviary fortran_to_aviary\n", "\n", - "The `aviary fortran_to_aviary` command will convert a Fortran input deck to an Aviary csv.\n", + "The {glue:md}`aviary fortran_to_aviary` command will convert a Fortran input deck to an Aviary csv.\n", "\n", - "The only two required inputs are `-l` (for `--legacy_code` with options `FLOPS` and `GASP`) and the filepath to the input deck. \n", - "Optionally, a deck of default values can be specified via the option `-d` (for `--defaults_deck`) and a default deck file, this is useful if an input deck assumes certain values for any unspecified variables.\n", + "The only two required inputs are {glue:md}`-l` (for {glue:md}`--legacy_code` with options `FLOPS` and `GASP`) and the filepath to the input deck. \n", + "Optionally, a deck of default values can be specified via the option {glue:md}`-d` (for {glue:md}`--defaults_deck`) and a default deck file, this is useful if an input deck assumes certain values for any unspecified variables.\n", "When this command is run, a brief message is printed. To print more messages, one can set verbosity level higher. For example, `-v 3` will result in debug messages being printed. See [Controlling Display Levels](../developer_guide/coding_standards.ipynb) for more details.\n", "If an invalid filepath is given, pre-packaged resources will be checked for input decks with a matching name.\n", "If the output file name is not specified, a detault name is assumed to be the trunk of the input file name with `csv` as file extension. For example, an input file `sample.dat` will result in `sample_converted.csv`.\n", - "If the output file exists, the command will not run unless the user specifies `--force` to force the overwritten action.\n", + "If the output file exists, the command will not run unless the user specifies {glue:md}`--force` to force the overwritten action.\n", "\n", "Here, pre-packaged resources are absolute path, relative path, and Aviary based path.\n", "\n", @@ -253,7 +294,7 @@ "\n", "Example usage:\n", "```\n", - "`aviary fortran_to_aviary --legacy_code GASP --force GASP_test.dat` Convert the GASP input deck to Aviary (even if an output exists).\n", + "`aviary fortran_to_aviary --legacy_code GASP --force GASP_test.dat` converts the GASP input deck to Aviary (even if an output exists).\n", "```\n" ] }, @@ -287,7 +328,7 @@ "(aviary-hangar-command)=\n", "### aviary hangar\n", "\n", - "The `aviary hangar` command will copy files and folders from the Aviary hangar to an accessible directory.\n", + "The {glue:md}`aviary hangar` command will copy files and folders from the Aviary hangar to an accessible directory.\n", "This is useful for users that have pip installed Aviary, but want to experiment with the included examples.\n", "\n", "The only required input is the name of an input deck.\n", @@ -352,6 +393,38 @@ "!aviary hangar -h" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import aviary.api as av\n", + "from aviary.utils.engine_deck_conversion import _setup_EDC_parser\n", + "from aviary.utils.doctape import glue_variable\n", + "import inspect\n", + "\n", + "# glue all the options of 'aviary convert_engine'\n", + "source_code = inspect.getsource(_setup_EDC_parser)\n", + "new_line = ''\n", + "for ch in source_code:\n", + " if ch == '\\n':\n", + " new_line = new_line.strip()\n", + " if new_line.startswith('\\\"-') or new_line.startswith(\"'-\"):\n", + " skey = new_line.split(',')[0][1:-1]\n", + " if skey != '-o':\n", + " glue_variable(skey, md_code=True)\n", + " new_line = ''\n", + " else:\n", + " new_line += ch\n", + "\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -359,7 +432,7 @@ "(aviary-EDC-command)=\n", "### aviary convert_engine\n", "\n", - "The `aviary convert_engine` command will convert a legacy formatted (FLOPS or GASP) engine deck into an Aviary formatted engine deck.\n", + "The {glue:md}`aviary convert_engine` command will convert a legacy formatted (FLOPS or GASP) engine deck into an Aviary formatted engine deck.\n", "\n", "Users must provide the path or name of an input deck, and the engine format being converted.\n", "If an invalid filepath is given for the input file, pre-packaged resources will be checked for input decks with a matching name.\n", @@ -369,7 +442,7 @@ "\n", "If the output file exists, it will be overwritten.\n", "\n", - "The engine format is specified by `-f` or `--data_format` with one of `FLOPS`, `GASP`, and `GASP_TS` string. If multiple are specified, the last one will be used.\n", + "The engine format is specified by {glue:md}`-f` or {glue:md}`--data_format` with one of `FLOPS`, `GASP`, and `GASP_TS` string (`TS` stands for turbo shaft). If multiple are specified, the last one will be used.\n", "\n", "Notes for input decks:\n", "- Turbofan decks for both FLOPS and GASP can be converted\n", @@ -428,6 +501,44 @@ "!aviary convert_engine -h" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import aviary.api as av\n", + "from aviary.utils.aero_table_conversion import _setup_ATC_parser\n", + "from aviary.utils.doctape import check_contains\n", + "import inspect\n", + "import argparse\n", + "\n", + "# glue all the options of 'aviary fortran_to_aviary'\n", + "source_code = inspect.getsource(_setup_ATC_parser)\n", + "new_line = ''\n", + "options = []\n", + "for ch in source_code:\n", + " if ch == '\\n':\n", + " new_line = new_line.strip()\n", + " if new_line.startswith('\\\"-') or new_line.startswith(\"'-\"):\n", + " skey = new_line.split(',')[0][1:-1]\n", + " options.append(skey)\n", + " new_line = ''\n", + " else:\n", + " new_line += ch\n", + "\n", + "parser = argparse.ArgumentParser()\n", + "_setup_ATC_parser(parser)\n", + "options2 = [action.dest for action in parser._actions]\n", + "options.append(options2)\n", + "check_contains(['-f', '--data_format'], options)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -435,11 +546,11 @@ "(aviary-ATC-command)=\n", "### aviary convert_aero_table\n", "\n", - "The `aviary convert_aero_table` command will convert a legacy formatted (FLOPS or GASP) aero table into an Aviary formatted aero table.\n", + "The {glue:md}`aviary convert_aero_table` command will convert a legacy formatted (FLOPS or GASP) aero table into an Aviary formatted aero table.\n", "\n", "Users must provide the path or name of an input deck and the data format being converted.\n", "Optionally, the path to the output file can also be specified, otherwise the default output file will be in the same location and have the same name as input file, but with '_aviary' appended to the end of filename trunk while the file extension is preserved. For example, an input file `sample.txt` will result in `sample_aviary.txt` unless the user specifies the output file name.\n", - "If both `-f` and `--data_format` are specified, the later one is taken.\n", + "If both {glue:md}`-f` and {glue:md}`--data_format` are specified, the later one is taken.\n", "If an existing file has the same name as output file name, the existing file will be overwritten.\n", "If an invalid filepath is given for the input file, pre-packaged resources will be checked for input decks with a matching name.\n", "\n", @@ -452,13 +563,7 @@ "\n", "Example usage:\n", "```\n", - "`aviary convert_aero_table -f GASP subsystems/aerodynamics/gasp_based/data/GASP_aero_free.txt large_single_aisle_1_aero_flaps.txt` Convert a GASP based aero table\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ + "`aviary convert_aero_table -f GASP subsystems/aerodynamics/gasp_based/data/GASP_aero_free.txt large_single_aisle_1_aero_flaps.txt` Convert a GASP based aero table\n", "`aviary convert_aero_table -f FLOPS utils/test/flops_test_polar.txt aviary_flops_polar.txt` Convert a FLOPS based aero table\n", "```\n" ] @@ -512,7 +617,7 @@ "(aviary-PMC-command)=\n", "### aviary convert_prop_table\n", "\n", - "The `aviary convert_prop_table` command will convert a legacy formatted (GASP) propeller map into an Aviary formatted propeller map. Currently, it is the only format allowed and so it is the default format.\n", + "The {glue:md}`aviary convert_prop_table` command converts a legacy formatted (GASP) propeller map into an Aviary formatted propeller map. Currently, it is the only format allowed and so it is the default legacy format.\n", "\n", "Users must provide the path or name of an input deck, the path to the output file, and the engine format being converted.\n", "If an invalid filepath is given for the input file, pre-packaged resources will be checked for input decks with a matching name.\n", @@ -533,6 +638,26 @@ "Note that the output file name can be skipped as demonstrated in the third example. Since there is only one input data format that is supported at this time, it defaults to GASP if not provided. This is shown in the third example as well." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import run_command_no_file_error\n", + "commands = [\n", + " '-f GASP models/propellers/PropFan.map PropFan.prop',\n", + " '-f GASP models/propellers/general_aviation.map general_aviation.prop',\n", + "]\n", + "for command in commands:\n", + " run_command_no_file_error('aviary convert_prop_table ' + command)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -562,7 +687,7 @@ "(aviary-draw-command)=\n", "### aviary draw_mission\n", "\n", - "The `aviary draw_mission` command will bring up a new graphical interface for users to create a mission. This command does not have an input. More details can be found at [Drawing and running simple missions](drawing_and_running_simple_missions.ipynb)." + "The {glue:md}`aviary draw_mission` command will bring up a new graphical interface for users to create a mission. This command does not have an input. More details can be found at [Drawing and running simple missions](drawing_and_running_simple_missions.ipynb)." ] }, { @@ -572,7 +697,7 @@ "(aviary-plot-command)=\n", "### aviary plot_drag_polar\n", "\n", - "The `aviary plot_drag_polar` command will bring up a new graphical interface for users to draw drag polar. No options are needed on the command line but a file explorer window will pop-up to allow the user to select a drag polar file (a `.csv` file). It is not working at this time." + "The {glue:md}`aviary plot_drag_polar` command will bring up a new graphical interface for users to draw drag polar. No options are needed on the command line but a file explorer window will pop-up to allow the user to select a drag polar file (a `.csv` file). It is not working at this time." ] }, { @@ -584,6 +709,41 @@ "!aviary plot_drag_polar -h" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import aviary.api as av\n", + "from aviary.visualization.dashboard import _dashboard_setup_parser\n", + "from aviary.utils.doctape import glue_variable\n", + "import inspect\n", + "\n", + "# glue all the options of 'aviary run_mission'\n", + "source_code = inspect.getsource(_dashboard_setup_parser)\n", + "new_line = ''\n", + "for ch in source_code:\n", + " if ch == '\\n':\n", + " new_line = new_line.strip()\n", + " if new_line.startswith('\\\"-') or new_line.startswith(\"'-\"):\n", + " skey = new_line.split(',')[0][1:-1]\n", + " if skey != '-d' and skey != '--force':\n", + " glue_variable(skey, md_code=True)\n", + " elif new_line.startswith('\\\"') or new_line.startswith(\"'\"):\n", + " skey = new_line.split(',')[0][1:-1]\n", + " if len(skey) > 1:\n", + " glue_variable(skey, md_code=True)\n", + " new_line = ''\n", + " else:\n", + " new_line += ch\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -591,7 +751,7 @@ "(aviary-dashboard-command)=\n", "### aviary dashboard\n", "\n", - "The `aviary dashboard` command will bring up a dashboard that lets the user easily browse between the reports and files that are generated during an Aviary run." + "The {glue:md}`aviary dashboard` command will bring up a dashboard that lets the user easily browse between the reports and files that are generated during an Aviary run." ] }, { @@ -609,16 +769,16 @@ "source": [ "To use this utility, either a problem has been run or a run script is provided.\n", "\n", - "`--problem_recorder` is an input. Default is `problem_history.db`.\n", - "`--driver_recorder` is an optional input.\n", - "`--port` is the dashboard server port ID. The default is `0` meaning any free port.\n", - "`-b` or `--background` indicates to run in background. Default is `False`.\n", - "`-d` or `--debug` indicates to show debugging output. Default is `False`.\n", - "`--save` is the name of zip file in which dashboard files are saved. If no argument given, use the script name to name the zip file.\n", - "`--force` indicates to overwrite the saved zip file. The default is `False`.\n", - "`script_name` is the name of aviary script that was run (not including .py), or the csv input filename if the user runs a Level 1 script.\n", + "{glue:md}`--problem_recorder` is an input. Default is `problem_history.db`.\n", + "{glue:md}`--driver_recorder` is an optional input.\n", + "{glue:md}`--port` is the dashboard server port ID. The default is `0` meaning any free port.\n", + "{glue:md}`-b` or {glue:md}`--background` indicates to run in background. Default is `False`.\n", + "{glue:md}`-d` or {glue:md}`--debug` indicates to show debugging output. Default is `False`.\n", + "{glue:md}`--save` is the name of zip file in which dashboard files are saved. If no argument given, use the script name to name the zip file.\n", + "{glue:md}`--force` indicates to overwrite the saved zip file. The default is `False`.\n", + "{glue:md}`script_name` is the name of aviary script that was run (not including .py), or the csv input filename if the user runs a Level 1 script.\n", "\n", - "More discussion on `aviary dashboard` command can be found in [Postprocessing and Visualizing Results from Aviary](postprocessing_and_visualizing_results.ipynb)." + "More discussion on {glue:md}`aviary dashboard` command can be found in [Postprocessing and Visualizing Results from Aviary](postprocessing_and_visualizing_results.ipynb)." ] } ], From 2d16a94e824253fbc4d71eb94f485e2ca5fa898f Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 5 Dec 2024 13:48:27 -0800 Subject: [PATCH 11/48] format _setup_level1_parser in methods_for_level1.py --- aviary/interface/methods_for_level1.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/aviary/interface/methods_for_level1.py b/aviary/interface/methods_for_level1.py index b93d39c47..e6a5f8f9d 100644 --- a/aviary/interface/methods_for_level1.py +++ b/aviary/interface/methods_for_level1.py @@ -157,8 +157,10 @@ def run_level_1( def _setup_level1_parser(parser): def_outdir = os.path.join(os.getcwd(), "output") - parser.add_argument('input_deck', metavar='indeck', type=str, - nargs=1, help='Name of vehicle input deck file') + parser.add_argument( + 'input_deck', metavar='indeck', type=str, nargs=1, + help='Name of vehicle input deck file' + ) parser.add_argument( "-o", "--outdir", default=def_outdir, help="Directory to write outputs" ) @@ -179,7 +181,8 @@ def _setup_level1_parser(parser): "--max_iter", type=int, default=50, - help="maximum number of iterations") + help="maximum number of iterations" + ) parser.add_argument( "--shooting", action="store_true", From ecc22dc812125ae25090456d19294de3181bc94f Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 5 Dec 2024 13:55:31 -0800 Subject: [PATCH 12/48] autopep8 --- aviary/interface/methods_for_level1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/interface/methods_for_level1.py b/aviary/interface/methods_for_level1.py index e6a5f8f9d..86380a395 100644 --- a/aviary/interface/methods_for_level1.py +++ b/aviary/interface/methods_for_level1.py @@ -158,7 +158,7 @@ def run_level_1( def _setup_level1_parser(parser): def_outdir = os.path.join(os.getcwd(), "output") parser.add_argument( - 'input_deck', metavar='indeck', type=str, nargs=1, + 'input_deck', metavar='indeck', type=str, nargs=1, help='Name of vehicle input deck file' ) parser.add_argument( From 1829237ee6839487423be99a9f02e7a6cc817fa0 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 5 Dec 2024 15:30:09 -0800 Subject: [PATCH 13/48] minor --- aviary/interface/methods_for_level1.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aviary/interface/methods_for_level1.py b/aviary/interface/methods_for_level1.py index 86380a395..6a23e2239 100644 --- a/aviary/interface/methods_for_level1.py +++ b/aviary/interface/methods_for_level1.py @@ -158,7 +158,8 @@ def run_level_1( def _setup_level1_parser(parser): def_outdir = os.path.join(os.getcwd(), "output") parser.add_argument( - 'input_deck', metavar='indeck', type=str, nargs=1, + 'input_deck', metavar='indeck', + type=str, nargs=1, help='Name of vehicle input deck file' ) parser.add_argument( From 4167a08991af41296067062b37f24aaf29dfeaf6 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 6 Dec 2024 17:01:37 -0800 Subject: [PATCH 14/48] move aviary hangar to the end of aviary_commands.ipynb because it causes problem when I run. Remove a duplicate glue variable --verbosity. --- aviary/docs/user_guide/aviary_commands.ipynb | 153 ++++++++++--------- 1 file changed, 79 insertions(+), 74 deletions(-) diff --git a/aviary/docs/user_guide/aviary_commands.ipynb b/aviary/docs/user_guide/aviary_commands.ipynb index 359f0f3ba..2d66e87d7 100644 --- a/aviary/docs/user_guide/aviary_commands.ipynb +++ b/aviary/docs/user_guide/aviary_commands.ipynb @@ -241,7 +241,7 @@ " new_line = new_line.strip()\n", " if new_line.startswith('\\\"-') or new_line.startswith(\"'-\"):\n", " skey = new_line.split(',')[0][1:-1]\n", - " if skey != '-o':\n", + " if skey != '-o' and skey != '--verbosity':\n", " glue_variable(skey, md_code=True)\n", " new_line = ''\n", " else:\n", @@ -321,78 +321,6 @@ "!aviary fortran_to_aviary -h" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "(aviary-hangar-command)=\n", - "### aviary hangar\n", - "\n", - "The {glue:md}`aviary hangar` command will copy files and folders from the Aviary hangar to an accessible directory.\n", - "This is useful for users that have pip installed Aviary, but want to experiment with the included examples.\n", - "\n", - "The only required input is the name of an input deck.\n", - "This can be specified as the name of the file, the path from [aviary/models](https://github.com/OpenMDAO/Aviary/tree/main/aviary/models), the name of a folder in aviary/models. Multiple files and folders can be copied at once.\n", - "Optionally, the output directory can be specified; if it is not, the files will be copied into the current working directory in a folder called `aviary_models`.\n", - "If specified, the output directory will be created as needed.\n", - "\n", - "Example usage:\n", - "```\n", - "`aviary hangar engines` Copy all files in the engines folder\n", - "`aviary hangar turbofan_22k.txt` Copy the 22k turbofan deck\n", - "`aviary hangar N3CC/N3CC_data.py` Copy the N3CC data\n", - "`aviary hangar small_single_aisle_GwGm.dat small_single_aisle_GwGm.csv` Copy the Fortran and Aviary input decks for the small single aisle\n", - "`aviary hangar turbofan_22k.txt -o ~/example_files` Copy the engine model into ~/example_files\n", - "```\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "# Testing Cell\n", - "import subprocess\n", - "import tempfile\n", - "import os\n", - "commands = [\n", - " 'engines','turbofan_22k.txt','N3CC/N3CC_data.py',\n", - " 'small_single_aisle_GwGm.dat small_single_aisle_GwGm.csv',\n", - " 'turbofan_22k.txt -o ~/example_files']\n", - "with tempfile.TemporaryDirectory() as tempdir:\n", - " os.chdir(tempdir)\n", - " for command in commands:\n", - " command = 'aviary hangar ' + command\n", - " subprocess.run(command.split()).check_returncode();" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```\n", - "aviary hangar -h\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-input" - ] - }, - "outputs": [], - "source": [ - "!aviary hangar -h" - ] - }, { "cell_type": "code", "execution_count": null, @@ -776,8 +704,85 @@ "{glue:md}`-d` or {glue:md}`--debug` indicates to show debugging output. Default is `False`.\n", "{glue:md}`--save` is the name of zip file in which dashboard files are saved. If no argument given, use the script name to name the zip file.\n", "{glue:md}`--force` indicates to overwrite the saved zip file. The default is `False`.\n", - "{glue:md}`script_name` is the name of aviary script that was run (not including .py), or the csv input filename if the user runs a Level 1 script.\n", + "{glue:md}`script_name` is the name of aviary script that was run (not including .py), or the csv input filename if the user runs a Level 1 script.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(aviary-hangar-command)=\n", + "### aviary hangar\n", "\n", + "The {glue:md}`aviary hangar` command will copy files and folders from the Aviary hangar to an accessible directory.\n", + "This is useful for users that have pip installed Aviary, but want to experiment with the included examples.\n", + "\n", + "The only required input is the name of an input deck.\n", + "This can be specified as the name of the file, the path from [aviary/models](https://github.com/OpenMDAO/Aviary/tree/main/aviary/models), the name of a folder in aviary/models. Multiple files and folders can be copied at once.\n", + "Optionally, the output directory can be specified; if it is not, the files will be copied into the current working directory in a folder called `aviary_models`.\n", + "If specified, the output directory will be created as needed.\n", + "\n", + "Example usage:\n", + "```\n", + "`aviary hangar engines` Copy all files in the engines folder\n", + "`aviary hangar turbofan_22k.txt` Copy the 22k turbofan deck\n", + "`aviary hangar N3CC/N3CC_data.py` Copy the N3CC data\n", + "`aviary hangar small_single_aisle_GwGm.dat small_single_aisle_GwGm.csv` Copy the Fortran and Aviary input decks for the small single aisle\n", + "`aviary hangar turbofan_22k.txt -o ~/example_files` Copy the engine model into ~/example_files\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "aviary hangar -h\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-input" + ] + }, + "outputs": [], + "source": [ + "!aviary hangar -h" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import subprocess\n", + "import tempfile\n", + "import os\n", + "commands = [\n", + " 'engines','turbofan_22k.txt','N3CC/N3CC_data.py',\n", + " 'small_single_aisle_GwGm.dat small_single_aisle_GwGm.csv',\n", + " 'turbofan_22k.txt -o ~/example_files']\n", + "with tempfile.TemporaryDirectory() as tempdir:\n", + " os.chdir(tempdir)\n", + " for command in commands:\n", + " command = 'aviary hangar ' + command\n", + " subprocess.run(command.split()).check_returncode();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "More discussion on {glue:md}`aviary dashboard` command can be found in [Postprocessing and Visualizing Results from Aviary](postprocessing_and_visualizing_results.ipynb)." ] } From 968a62db5b5ab80c49ce96cb85ef9e00437f9647 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 6 Dec 2024 21:30:44 -0800 Subject: [PATCH 15/48] glue variables in battery_subsystem_example.ipynb --- .../battery_subsystem_example.ipynb | 96 +++++++++++++++---- 1 file changed, 75 insertions(+), 21 deletions(-) diff --git a/aviary/docs/user_guide/battery_subsystem_example.ipynb b/aviary/docs/user_guide/battery_subsystem_example.ipynb index f0491516b..db6b7d554 100644 --- a/aviary/docs/user_guide/battery_subsystem_example.ipynb +++ b/aviary/docs/user_guide/battery_subsystem_example.ipynb @@ -34,8 +34,12 @@ "outputs": [], "source": [ "# Testing Cell\n", + "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", + "from aviary.utils.doctape import glue_variable\n", "from aviary.utils.functions import get_path\n", - "get_path('examples/external_subsystems/battery/battery_builder.py');\n" + "# make sure that the path exists.\n", + "get_path('examples/external_subsystems/battery/battery_builder.py');\n", + "glue_variable(f'{SubsystemBuilderBase=}'.split('=')[0], md_code=True)" ] }, { @@ -45,7 +49,7 @@ "## Defining the builder object\n", "\n", "The first step is to define a builder object for your external subsystem.\n", - "This class extends the `SubsystemBuilderBase` class and provides implementations for all of the interface methods that Aviary requires.\n", + "This class extends the {glue:md}`SubsystemBuilderBase` class and provides implementations for all of the interface methods that Aviary requires.\n", "\n", "```{note}\n", "Throughout this doc page we add methods to the builder class in different sections.\n", @@ -87,6 +91,56 @@ "Within the subsystem builder, we will now define the states of the battery model using the `get_states` method." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import inspect\n", + "import aviary.api as av\n", + "from aviary.interface.methods_for_level2 import AviaryProblem\n", + "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", + "\n", + "# Get all functions of class CoreAerodynamicsBuilder\n", + "methods = inspect.getmembers(SubsystemBuilderBase, predicate=inspect.isfunction)\n", + "for name, func in methods:\n", + " if not name.startswith('_'):\n", + " glue_variable(name, md_code=True)\n", + "\n", + "AviaryValues = av.AviaryValues\n", + "glue_variable(f'{AviaryValues=}'.split('=')[0], md_code=True)\n", + "\n", + "sig = inspect.signature(SubsystemBuilderBase.build_pre_mission)\n", + "arguments = [param.name for param in sig.parameters.values()]\n", + "arguments.remove('self')\n", + "arguments.remove('kwargs')\n", + "for arg in arguments:\n", + " glue_variable(arg, md_code=True)\n", + "\n", + "sig = inspect.signature(SubsystemBuilderBase.build_mission)\n", + "arguments = [param.name for param in sig.parameters.values()]\n", + "arguments.remove('self')\n", + "arguments.remove('kwargs')\n", + "for arg in arguments:\n", + " if arg == \"num_nodes\":\n", + " glue_variable(arg, md_code=True)\n", + "\n", + "# Get all functions of class AviaryProblem\n", + "methods = inspect.getmembers(AviaryProblem, predicate=inspect.isfunction)\n", + "for name, func in methods:\n", + " if not name.startswith('_'):\n", + " glue_variable(name, md_code=True)\n", + "\n", + "TestSubsystemBuilderBase = av.TestSubsystemBuilderBase\n", + "glue_variable(f'{TestSubsystemBuilderBase=}'.split('=')[0], md_code=True)\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -183,7 +237,7 @@ "metadata": {}, "source": [ "If you want to add high-level design variables to your external subsystem that are not exposed at the phase level, you can do so by creating a method that describes your desired design variables.\n", - "This method is called `get_design_vars`.\n", + "This method is called {glue:md}`get_design_vars`.\n", "There might be calculations at the pre-mission level that necessitate using this method to allow the optimizer to control high-level sizing variables.\n", "In the simple battery case, we allow the optimizer to control the energy capacity of the battery, effectively sizing it." ] @@ -213,7 +267,7 @@ "source": [ "## Defining the OpenMDAO systems needed\n", "\n", - "Next up, we have the two methods for getting the mission and pre-mission models, `get_mission` and `get_pre_mission`, respectively.\n", + "Next up, we have the two methods for getting the mission and pre-mission models, {glue:md}`build_mission` and {glue:md}`build_pre_mission`, respectively.\n", "When you define these methods they should return OpenMDAO Systems ([groups](https://openmdao.org/newdocs/versions/latest/_srcdocs/packages/core/group.html) or [components](https://openmdao.org/newdocs/versions/latest/_srcdocs/packages/core/component.html)) that represent the mission and pre-mission subsystems of the external model.\n", "Please see the [OpenMDAO docs on creating a simple component](https://openmdao.org/newdocs/versions/latest/basic_user_guide/single_disciplinary_optimization/first_analysis.html) for more information on how to create OpenMDAO systems.\n", "In short, an OpenMDAO System takes in input variables, does some calculations, and returns output variables.\n", @@ -239,11 +293,11 @@ "metadata": {}, "source": [ "That's pretty straightforward.\n", - "The `build_pre_mission` method requires the `aviary_inputs` object (an instantiation of an `AviaryValues` object).\n", - "This battery example does not use any information from `aviary_inputs`.\n", - "The pre-mission builder can then use the data and options within the `aviary_inputs` object to construct the OpenMDAO System using user-specified logic.\n", + "The {glue:md}`build_pre_mission` method requires the {glue:md}`aviary_inputs` object (an instantiation of an {glue:md}`AviaryValues` object).\n", + "This battery example does not use any information from {glue:md}`aviary_inputs`.\n", + "The pre-mission builder can then use the data and options within the {glue:md}`aviary_inputs` object to construct the OpenMDAO System using user-specified logic.\n", "\n", - "Now we'll discuss arguably the most important method needed when making external subsystems (though they're all important): `build_mission`.\n", + "Now we'll discuss arguably the most important method needed when making external subsystems (though they're all important): {glue:md}`build_mission`.\n", "This method returns an OpenMDAO System that provides all computations needed during the mission.\n", "This includes computing state rates so that the mission integration code can compute the state values and obtain the corresponding performance of the aircraft.\n", "\n", @@ -265,8 +319,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that `build_mission` requires both `num_nodes` and `aviary_inputs` as arguments.\n", - "`num_nodes` is needed to correctly set up all the vectors within your mission subsystem, whereas `aviary_inputs` helps provide necessary options for the subsystem." + "Note that {glue:md}`build_mission` requires both {glue:md}`num_nodes` and {glue:md}`aviary_inputs` as arguments.\n", + "{glue:md}`num_nodes` is needed to correctly set up all the vectors within your mission subsystem, whereas {glue:md}`aviary_inputs` helps provide necessary options for the subsystem." ] }, { @@ -279,12 +333,12 @@ "\n", "Let's talk about preprocessing your inputs.\n", "You might want to have some logic that sets different values in your problem based on user-provided options.\n", - "`preprocess_inputs` allows you to do this.\n", - "It occurs between `load_inputs` and `build_pre_mission` in the Aviary stack, so after the initial data inputs are loaded but before they're used to instantiate any OpenMDAO models.\n", + "{glue:md}`preprocess_inputs` allows you to do this.\n", + "It occurs between {glue:md}`load_inputs` and {glue:md}`add_pre_mission_systems` in the Aviary stack, so after the initial data inputs are loaded but before they're used to instantiate any OpenMDAO models.\n", "This is a great place to set any values you need for variables within your subsystem.\n", "\n", "```{note}\n", - "For both users and developers: `preprocess_inputs` happens **once** per analysis or optimization run, just like loading the inputs. It does not occur as part of an OpenMDAO system, so it does not get iterated over during the optimization process.\n", + "For both users and developers: {glue:md}`preprocess_inputs` happens **once** per analysis or optimization run, just like loading the inputs. It does not occur as part of an OpenMDAO system, so it does not get iterated over during the optimization process.\n", "```\n", "\n", "You can have calculations or checks you need in this method based on user inputs.\n", @@ -292,7 +346,7 @@ "Now you may want to link some variables between phases.\n", "States, for example, are usually great candidates for linking.\n", "In the case of the battery example, if we have a climb and then a cruise phase, we'd want to connect the state-of-charge and voltage states so the end of climb is equal to the beginning of cruise.\n", - "Thus, our `get_linked_variables` method looks like this:" + "Thus, our {glue:md}`get_linked_variables` method looks like this:" ] }, { @@ -314,7 +368,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The last method we'll discuss here is `get_initial_guesses`.\n", + "The last method we'll discuss here is {glue:md}`get_initial_guesses`.\n", "This method allows you to return info for any variable you want to provide an initial guess for.\n", "Depending on the integration method you're using, initial guesses may greatly help convergence of your optimization problem.\n", "Collocation methods especially benefit from good initial guesses.\n", @@ -374,10 +428,10 @@ "Specifically, the tests can help users check that their subsystem's inputs and outputs are correct and consistent with the expected format, even before running an Aviary mission.\n", "\n", "This test works by inheriting from a base class that loops through each of the methods and tests the outputs.\n", - "All you'd have to do is provide your builder object as well as the `aviary_inputs` object needed to for the methods in the builder object.\n", + "All you'd have to do is provide your builder object as well as the {glue:md}`aviary_inputs` object needed to for the methods in the builder object.\n", "\n", "Here's an example of the full code that you would write to test the battery builder.\n", - "Although there are no unit tests explicitly shown in this file, they are contained in the `TestSubsystemBuilderBase` class, so you only need these few lines to test your subsystem." + "Although there are no unit tests explicitly shown in this file, they are contained in the {glue:md}`TestSubsystemBuilderBase` class, so you only need these few lines to test your subsystem." ] }, { @@ -488,8 +542,8 @@ "metadata": {}, "source": [ "The output is a bit verbose, but tells you which methods are incorrect and why.\n", - "For example, here the `get_states` method returned a dict that included a key (`'amps'`) with a value of 6 instead of being a dictionary as expected.\n", - "In the `get_constraints` method, a constraint was added to the dictionary but did not include a `type` key, which is required as stated by the error message.\n", + "For example, here the {glue:md}`get_states` method returned a dict that included a key (`'amps'`) with a value of 6 instead of being a dictionary as expected.\n", + "In the {glue:md}`get_constraints` method, a constraint was added to the dictionary but did not include a `type` key, which is required as stated by the error message.\n", "\n", "If you encounter an error when using your subsystem, but the test here did not find it, please let the Aviary dev team know!\n", "We'd love to hear from you on the [GitHub issues page](https://github.com/OpenMDAO/Aviary/issues) so we can help everyone write great external subsystems." @@ -498,7 +552,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -512,7 +566,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From 1c37f9280058b29a9b3920e6a621bf5b0fb399a8 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 9 Dec 2024 11:01:09 -0800 Subject: [PATCH 16/48] glue variables in drawing_and_running_simple_missions.ipynb --- .../drawing_and_running_simple_missions.ipynb | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb b/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb index 42dd8bad5..dd8140744 100644 --- a/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb +++ b/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb @@ -1,5 +1,22 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.variable_info.enums import EquationsOfMotion\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "glue_variable('height_energy', EquationsOfMotion.HEIGHT_ENERGY.value, md_code=True, display=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -62,6 +79,25 @@ "_command_map['draw_mission'];" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test Cell\n", + "import argparse\n", + "from aviary.interface.methods_for_level1 import _setup_level1_parser\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "parser = argparse.ArgumentParser()\n", + "_setup_level1_parser(parser)\n", + "for action in parser._actions:\n", + " if action.dest == 'optimizer':\n", + " for opt in action.choices:\n", + " glue_variable(opt, md_code=True)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -154,8 +190,8 @@ "aviary run_mission --phase_info outputted_phase_info.py validation_cases/benchmark_tests/test_aircraft/aircraft_for_bench_FwFm.csv\n", "```\n", "\n", - "You can also supply an optimizer, otherwise the default (SLSQP) will be used.\n", - "Here is how you'd run the mission with the IPOPT optimizer:\n", + "You can also supply an optimizer, otherwise the default ({glue:md}`SLSQP`) will be used.\n", + "Here is how you'd run the mission with the {glue:md}`IPOPT` optimizer:\n", "\n", "```bash\n", "aviary run_mission --optimizer IPOPT --phase_info outputted_phase_info.py validation_cases/benchmark_tests/test_aircraft/aircraft_for_bench_FwFm.csv\n", @@ -190,7 +226,7 @@ ], "metadata": { "kernelspec": { - "display_name": "latest_env", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -204,7 +240,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.19" + "version": "3.9.18" } }, "nbformat": 4, From 439a61dd5e2ba94aa0003982d9220eaa59d552fd Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 9 Dec 2024 13:14:44 -0800 Subject: [PATCH 17/48] glue variables in drawing_and_running_simple_missions.ipynb and examples_of_the_same_mission_at_different_UI_levels.ipynb --- .../drawing_and_running_simple_missions.ipynb | 37 +++++++++++++------ ..._same_mission_at_different_UI_levels.ipynb | 29 +++++++++++++-- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb b/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb index dd8140744..e153d54d3 100644 --- a/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb +++ b/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb @@ -11,10 +11,18 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.variable_info.enums import EquationsOfMotion\n", + "from aviary.interface.methods_for_level2 import AviaryGroup\n", "from aviary.utils.doctape import glue_variable\n", + "from aviary.variable_info.enums import EquationsOfMotion\n", "\n", - "glue_variable('height_energy', EquationsOfMotion.HEIGHT_ENERGY.value, md_code=True, display=True)" + "glue_variable('height_energy', EquationsOfMotion.HEIGHT_ENERGY.value, md_code=True, display=True)\n", + "\n", + "ag = AviaryGroup()\n", + "opts = list(ag.options)\n", + "for opt in opts:\n", + " if opt == 'phase_info':\n", + " glue_variable('phase_info', md_code=True)\n", + " glue_variable('--phase_info', md_code=True)" ] }, { @@ -28,8 +36,8 @@ "Aviary comes with a simple built-in graphical interface for defining missions.\n", "This tool can be accessed via the command line and provides an interactive way to define flight phases, including altitude, Mach number, and optimization parameters.\n", "\n", - "It is specifically made to only be used with the `\"height_energy\"` mission method.\n", - "You could use the results from the GUI to run a mission with a different method, but it would require manually changing the generated `phase_info` python dictionary.\n", + "It is specifically made to only be used with the {glue:md}`height_energy` mission method.\n", + "You could use the results from the GUI to run a mission with a different method, but it would require manually changing the generated {glue:md}`phase_info` python dictionary.\n", "\n", "![Graphical user interface for drawing missions](images/gui_main.png)" ] @@ -98,6 +106,11 @@ " glue_variable(opt, md_code=True)\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -124,13 +137,13 @@ "\n", "- **Removing Points**: Press the `X` button next to the point on the tabular section to remove that point.\n", "\n", - "- **Output Phase Info**: Press this button to create an output python file named `outputted_phase_info.py` which contains the mission information in a python dictionary called `phase_info`. This button serves the same function as using the menu `File`->`Save` command. \n", + "- **Output Phase Info**: Press this button to create an output python file named `outputted_phase_info.py` which contains the mission information in a python dictionary called {glue:md}`phase_info`. This button serves the same function as using the menu `File`->`Save` command. \n", "\n", "- **Light/Dark Mode**: Press the button on the bottom left to toggle the theme between light and dark mode. The default is light mode. If the user chooses to save settings (read `Edit Tab` below), the last used theme will be loaded the next time the program is run.\n", "\n", "### Menu Options\n", "#### File Tab\n", - "1. **Open Phase Info**: Allows user to open a previously made phase info file. This must be a python file that contains a dictionary called `phase_info`. \n", + "1. **Open Phase Info**: Allows user to open a previously made phase info file. This must be a python file that contains a dictionary called {glue:md}`phase_info`. \n", "\n", "2. **Save Phase Info**: Peforms the same function as clicking on the `Output Phase Info` button by saving the current mission as a phase info dictionary in a file named `outputted_phase_info.py`.\n", "\n", @@ -160,7 +173,7 @@ "3.2. `Solve for Distance`: If checked, calculates the total flight range based on the profile.
\n", "3.3. `Include Takeoff`: If checked, includes takeoff in the mission analysis.
\n", "3.4. `Include Landing`: If checked, includes landing in the mission analysis.
\n", - "3.5. `Polynomial Control Order`: Sets the polynomial order for control optimization, default being 1. This is for all phases. You can modify behavior on a per-phase basis by editing the outputted `phase_info` dict.
\n", + "3.5. `Polynomial Control Order`: Sets the polynomial order for control optimization, default being 1. This is for all phases. You can modify behavior on a per-phase basis by editing the outputted {glue:md}`phase_info` dict.
\n", "3.6. `Phase Transcription Order`: This setting will only show once at least 2 points are added to the plots/table. This number controls the number of points that are used to evaluate each mission phase. The minimum value is 3, and increasing this value will increase the number of points Aviary uses to analyze that phase.\n", "\n", "#### Help Tab\n", @@ -168,13 +181,13 @@ "\n", "### Output\n", "\n", - "Upon completion, the tool outputs a Python script named `outputted_phase_info.py` in the current working directory. Alternatively, if the user uses the `Save As` command, a python script with the user specified name will be saved in the user specified directory. This tool overwrites any existing python file with the same name as the output. This outputted file contains the `phase_info` dictionary, which holds the flight profile data structured for use in mission simulations.\n", + "Upon completion, the tool outputs a Python script named `outputted_phase_info.py` in the current working directory. Alternatively, if the user uses the `Save As` command, a python script with the user specified name will be saved in the user specified directory. This tool overwrites any existing python file with the same name as the output. This outputted file contains the {glue:md}`phase_info` dictionary, which holds the flight profile data structured for use in mission simulations.\n", "\n", "```{note}\n", - "When using the outputted `phase_info` dict in a mission simulation, you can modify the settings by directly changing the outputted Python file.\n", + "When using the outputted {glue:md}`phase_info` dict in a mission simulation, you can modify the settings by directly changing the outputted Python file.\n", "```\n", "\n", - "The `phase_info` dictionary makes some assumptions about different settings which you can also modify.\n", + "The {glue:md}`phase_info` dictionary makes some assumptions about different settings which you can also modify.\n", "For example, the time duration of each phase is controlled by the optimizer if `fix_duration` is False, though this can be changed to True to fix the duration of each phase.\n", "\n", "If you don't have the [black](https://pypi.org/project/black/) python autoformatter installed, your output may look slightly different - as long as you see confirmation that your phase info has been saved, your mission profile was successfully created.\n", @@ -182,8 +195,8 @@ "## Running a Mission Simulation\n", "\n", "After generating the flight profile, use the `run_mission` command to simulate the mission.\n", - "This command utilizes the `phase_info` from `outputted_phase_info.py` and simulates the mission based on the defined parameters. In the commands below, replace `outputted_phase_info.py` with your filename if you choose to save the output file with a different filename.\n", - "You can use the `--phase_info` flag to specify the path to the `outputted_phase_info.py` file.\n", + "This command utilizes the {glue:md}`phase_info` from `outputted_phase_info.py` and simulates the mission based on the defined parameters. In the commands below, replace `outputted_phase_info.py` with your filename if you choose to save the output file with a different filename.\n", + "You can use the {glue:md}`--phase_info` flag to specify the path to the `outputted_phase_info.py` file.\n", "Here we use a benchmark case as the inputted .csv file, though you can use any Aviary .csv here that defines an aircraft.\n", "\n", "```bash\n", diff --git a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb index 84634708f..2e25b2201 100644 --- a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb +++ b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb @@ -23,6 +23,29 @@ "If you want to make minor modifications to `phase_info`, you can do so here, but Level 1 largely assumes you're using the default setup." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.interface.methods_for_level2 import AviaryGroup, AviaryProblem\n", + "from aviary.utils.doctape import glue_variable\n", + "from aviary.variable_info.enums import EquationsOfMotion\n", + "\n", + "ag = AviaryGroup()\n", + "opts = list(ag.options)\n", + "for opt in opts:\n", + " if opt == 'phase_info':\n", + " glue_variable('phase_info', md_code=True)\n", + "glue_variable(f'{AviaryProblem=}'.split('=')[0], md_code=True)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -42,7 +65,7 @@ "source": [ "## Level 2\n", "\n", - "This level grants more flexibility both in defining the `phase_info` object but also in calling the individual methods of `AviaryProblem` when setting up and running your model.\n", + "This level grants more flexibility both in defining the {glue:md}`phase_info` object but also in calling the individual methods of {glue:md}`AviaryProblem` when setting up and running your model.\n", "You can modify the methods you call, what they do, and what info they're given here.\n", "This is much more verbose than Level 1.\n", "In the absence of additional arguments to the methods, much of the default behavior here is the same as Level 1." @@ -491,7 +514,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -505,7 +528,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From e291aa2c70971bb83e85a1c8df35701006fc9b9e Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 9 Dec 2024 14:46:32 -0800 Subject: [PATCH 18/48] glue variables in external_aero.ipynb --- aviary/docs/user_guide/external_aero.ipynb | 25 +++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/aviary/docs/user_guide/external_aero.ipynb b/aviary/docs/user_guide/external_aero.ipynb index 40936bd6e..05c246db2 100644 --- a/aviary/docs/user_guide/external_aero.ipynb +++ b/aviary/docs/user_guide/external_aero.ipynb @@ -106,11 +106,11 @@ "id": "elder-kinase", "metadata": {}, "source": [ - "In a structured grid, interpolation data must be present for every combination of inputs. In other words, our `ExternalAero` component must run a full factorial of points spanning those 3 variables. The Aviary variable hierarchy includes two variables for the polars: `Aircraft.Design.LIFT_POLAR`, and `Aircraft.Design.DRAG_POLAR`. The data in each of these polars should be a `n` x `m` x `k` numpy array, where `n` is the number of altitudes, `m` is the number of mach numbers, and `k` is the number of angles of attack. The `ExternalAero` will need to compute these values and place them into an array of this shape.\n", + "In a structured grid, interpolation data must be present for every combination of inputs. In other words, our `ExternalAero` component must run a full factorial of points spanning those 3 variables. The Aviary variable hierarchy includes two variables for the polars: {glue:md}`Aircraft.Design.LIFT_POLAR`, and {glue:md}`Aircraft.Design.DRAG_POLAR`. The data in each of these polars should be a `n` x `m` x `k` numpy array, where `n` is the number of altitudes, `m` is the number of mach numbers, and `k` is the number of angles of attack. The `ExternalAero` will need to compute these values and place them into an array of this shape.\n", "\n", "If use of a structured grid is not desirable, then the data does not need to meet these formatting requirements. In that case, the data table does not have to be regularly spaced, and each variable (`Altitude`, `Mach`, `angle_of_attack`, `LIFT_POLAR`, and `DRAG_POLAR`) must be 1-dimensional numpy arrays of equal length.\n", "\n", - "Using the level-2 interface, we create a builder for our external `ExternalAero` subsystem. In this example, the component produces outputs `drag_table` and `lift_table`, but we can specify an alias to `Aircraft.Design.DRAG_POLAR` and `Aircraft.Design.LIFT_POLAR` respectively. It is important that we inherit from the `AerodynamicsBuilderBase` to let Aviary know this is builder produces aerodynamics components. Some mission analysis methods require special handling of aerodynamics components that will not occur if we skip this step." + "Using the level-2 interface, we create a builder for our external `ExternalAero` subsystem. In this example, the component produces outputs `drag_table` and `lift_table`, but we can specify an alias to {glue:md}`Aircraft.Design.DRAG_POLAR` and {glue:md}`Aircraft.Design.LIFT_POLAR` respectively. It is important that we inherit from the {glue:md}`AerodynamicsBuilderBase` to let Aviary know this is builder produces aerodynamics components. Some mission analysis methods require special handling of aerodynamics components that will not occur if we skip this step." ] }, { @@ -126,8 +126,17 @@ "source": [ "# Testing Cell\n", "from aviary.api import Aircraft\n", + "from aviary.interface.methods_for_level2 import AviaryProblem\n", + "from aviary.subsystems.aerodynamics.aerodynamics_builder import AerodynamicsBuilderBase\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "\n", + "AerodynamicsBuilderBase\n", "Aircraft.Design.LIFT_POLAR;\n", - "Aircraft.Design.DRAG_POLAR;" + "Aircraft.Design.DRAG_POLAR;\n", + "glue_variable(f'{AerodynamicsBuilderBase=}'.split('=')[0], md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Design.LIFT_POLAR), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Design.DRAG_POLAR), md_code=True)\n", + "glue_variable(f'{AviaryProblem=}'.split('=')[0], md_code=False)" ] }, { @@ -209,7 +218,7 @@ "id": "technological-compatibility", "metadata": {}, "source": [ - "Next, the existing mission phases need to be given the information they need to set up our aerodynamics analysis using `phase_info`. We use the `solved_alpha` method of Aviary's included aerodynamics for this, which can accept the input passed from our external subsystem. Since we are using Aviary's built-in aerodynamics methods, we use the default name \"core_aerodynamics\". Don't forget to update the `subsystem_options` for each phase. We must specify the `method`, the `aero_data` that contains our altitude, Mach, and angle of attack data, as well as the `connect_training_data` flag to denote we are passing our drag polars via openMDAO connections." + "Next, the existing mission phases need to be given the information they need to set up our aerodynamics analysis using _glue:md}`phase_info`. We use the `solved_alpha` method of Aviary's included aerodynamics for this, which can accept the input passed from our external subsystem. Since we are using Aviary's built-in aerodynamics methods, we use the default name \"core_aerodynamics\". Don't forget to update the `subsystem_options` for each phase. We must specify the `method`, the `aero_data` that contains our altitude, Mach, and angle of attack data, as well as the `connect_training_data` flag to denote we are passing our drag polars via openMDAO connections." ] }, { @@ -233,7 +242,7 @@ "id": "equivalent-lawsuit", "metadata": {}, "source": [ - "Finally, we can instantiate the AviaryProblem like normal. However, we need to tell Aviary the size of our lift and drag polars so that it can allocate the right shape for the connection." + "Finally, we can instantiate the {glue:md}`AviaryProblem` like normal. However, we need to tell Aviary the size of our lift and drag polars so that it can allocate the right shape for the connection." ] }, { @@ -296,7 +305,7 @@ }, "outputs": [], "source": [ - "\n", + "# Testing Cell\n", "# Make sure we succesfully passed the polar\n", "from openmdao.utils.assert_utils import assert_near_equal\n", "om_CD = prob.get_val(Aircraft.Design.DRAG_POLAR)[0, 0, 0]\n", @@ -307,7 +316,7 @@ "metadata": { "celltoolbar": "Tags", "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -321,7 +330,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.9.18" }, "orphan": true }, From af117c7936b95285361c4fbcc7aa9e258ad0acb9 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 9 Dec 2024 16:21:39 -0800 Subject: [PATCH 19/48] add glue variables to features_and_functionalities.ipynb --- .../features_and_functionalities.ipynb | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/aviary/docs/user_guide/features_and_functionalities.ipynb b/aviary/docs/user_guide/features_and_functionalities.ipynb index 27a2ef86e..6b140f13c 100644 --- a/aviary/docs/user_guide/features_and_functionalities.ipynb +++ b/aviary/docs/user_guide/features_and_functionalities.ipynb @@ -1,5 +1,25 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.api import LegacyCode\n", + "from aviary.interface.methods_for_level2 import AviaryGroup\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "ag = AviaryGroup()\n", + "opts = list(ag.options)\n", + "for opt in opts:\n", + " if opt == 'phase_info':\n", + " glue_variable('phase_info', md_code=True)\n", + "glue_variable(LegacyCode.FLOPS.name, md_code=False)\n", + "glue_variable(LegacyCode.GASP.name, md_code=False)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -45,11 +65,11 @@ "\n", "Throughout Aviary we use a series of terms when discussing mission optimization.\n", "\n", - "A \"trajectory\" is the full mission that the aircraft flies.\n", + "A [\"trajectory\"](https://openmdao.github.io/dymos/features/phases/phases.html) is the full mission that the aircraft flies.\n", "Usually this is from takeoff to landing, inclusive.\n", "Sometimes you might want to model just a portion of the full aircraft trajectory; for example only the cruise portion.\n", "\n", - "A \"phase\" is a part of the trajectory that is defined by a single set of differential equations.\n", + "A []\"phase\"](https://openmdao.github.io/dymos/features/phases/phases.html) is a part of the trajectory that is defined by a single set of differential equations.\n", "For example, a simple way of defining a full trajectory is to have climb, cruise, and descent phases.\n", "Each of these phases can have different physics, subsystems, controls, and constraints.\n", "For example, the climb phase for a hybrid-electric aircraft might be have electric motor assistance whereas that might not be needed for the cruise phase.\n", @@ -59,19 +79,19 @@ "\n", "### Defining a mission\n", "\n", - "A mission is defined by a series of phases that the user chooses by specifying options in the `phase_info` dictionary.\n", - "The `phase_info` dictionary is a dictionary of dictionaries, where each key is the name of a phase and the value is a dictionary of options for that phase.\n", + "A mission is defined by a series of phases that the user chooses by specifying options in the {glue:md}`phase_info` dictionary.\n", + "The {glue:md}`phase_info` dictionary is a dictionary of dictionaries, where each key is the name of a phase and the value is a dictionary of options for that phase.\n", "\n", "How you choose to define your phases is dependent on the aircraft you're modeling, the mission you're trying to evaluate, and the flexibility you want to give the optimizer.\n", "For example, if you have a relatively conventional aircraft that is flying a straightforward mission, you might just need three phases: climb, cruise, and descent.\n", "However, if you have a more complex aircraft or mission, you might need to define more phases.\n", "For instance, if you're modeling a hybrid-electric aircraft with non-conventional propulsion systems that are controlled in different ways, you might want to define additional phases and prescribe different options based on which physics you want included at different stages in the flight.\n", "\n", - "In general, if you're familiar with the legacy tools FLOPS or GASP, you can use the corresponding default `phase_info` objects to start defining your mission.\n", + "In general, if you're familiar with the legacy tools {glue:md}`FLOPS` or {glue:md}`GASP`, you can use the corresponding default {glue:md}`phase_info` objects to start defining your mission.\n", "FLOPS-based missions have three integrated phases: climb, cruise, and descent, as well as analytic takeoff and landing systems.\n", - "GASP-based missions have at least nine integrated phases: groundroll, rotation, ascent, accel, climb1, climb2, cruise, desc1, and desc2, as well landing systems.\n", - "GASP-based missions that are solved using SGM have additional phases.\n", - "The difference in the number of phases is due to the fact that GASP had more detailed requirements on the flight profile, especially in the early phases of a mission." + "GASP-based missions have at least nine integrated phases: {glue:md}`groundroll`, {glue:md}`rotation`, {glue:md}`ascent`, {glue:md}`accel`, {glue:md}`climb1`, {glue:md}`climb2`, {glue:md}`cruise`, {glue:md}`desc1`, and {glue:md}`desc2`, as well landing systems.\n", + "{glue:md}`GASP`-based missions that are solved using SGM have additional phases.\n", + "The difference in the number of phases is due to the fact that {glue:md}`GASP` had more detailed requirements on the flight profile, especially in the early phases of a mission." ] }, { @@ -86,16 +106,22 @@ "source": [ "# Testing Cell\n", "from aviary.interface.utils.check_phase_info import phase_keys_gasp\n", - "from aviary.utils.doctape import check_value\n", + "from aviary.utils.doctape import check_value, glue_variable\n", + "from aviary.variable_info.enums import AnalysisScheme\n", "expected_keys = ['groundroll', 'rotation', 'ascent', 'accel', 'climb1', 'climb2', 'cruise', 'desc1', 'desc2']\n", - "check_value(list(phase_keys_gasp.keys()), expected_keys)" + "check_value(list(phase_keys_gasp.keys()), expected_keys)\n", + "for key in expected_keys:\n", + " glue_variable(key, md_code=False)\n", + "glue_variable(f'{AnalysisScheme=}'.split('=')[0], md_code=True)\n", + "glue_variable('COLLOCATION', AnalysisScheme.COLLOCATION.name, md_code=True)\n", + "glue_variable('SHOOTING', AnalysisScheme.SHOOTING.name, md_code=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "You can import a copy of the default `phase_info` dicts and then modify them as you need to for your own mission definition.\n", + "You can import a copy of the default {glue:md}`phase_info` dicts and then modify them as you need to for your own mission definition.\n", "\n", "### Defining mission controls and constraints\n", "\n", @@ -109,7 +135,7 @@ "\n", "## Collocation and Shooting\n", "\n", - "Both [collocation](https://openmdao.org/dymos/docs/latest/getting_started/collocation.html) and shooting methods are included in Aviary for mission analysis as they each have something to offer.\n", + "Both [collocation](https://openmdao.org/dymos/docs/latest/getting_started/collocation.html) and [shooting](https://link.springer.com/article/10.1007/s10957-023-02303-3) methods are included in Aviary for mission analysis as they each have something to offer.\n", "Collocation methods are easily parallelizable and call the model ODE relatively few times.\n", "This leads to significantly faster optimization times for large problems.\n", "\n", @@ -126,7 +152,7 @@ "Collocation results are presented as part of a fixed step-size timeseries. To improve performance, the shooting method uses an adaptive step size; this means that the resulting trajectories will not always have a consistent number of points. There are plans to add a post processing interpolation to the trajectory results to produce a consistent timeseries, but that has not been implemented yet.\n", "\n", "```{note}\n", - "When using Aviary, the `AnalysisScheme` option is used to select the integration method. The default is `COLLOCATION`, but this can be changed to `SHOOTING` to use the shooting method.\n", + "When using Aviary, the {glue:md}`AnalysisScheme` option is used to select the integration method. The default is {glue:md}`COLLOCATION`, but this can be changed to {glue:md}`SHOOTING` to use the shooting method.\n", "```\n", "\n", "```{note}\n", @@ -154,7 +180,7 @@ ], "metadata": { "kernelspec": { - "display_name": "latest_env", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -168,7 +194,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From 028f229775a9ea5b15d15c0f70a8da1f18e0212d Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 9 Dec 2024 16:22:46 -0800 Subject: [PATCH 20/48] minor update --- .../examples_of_the_same_mission_at_different_UI_levels.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb index 2e25b2201..15ed05c20 100644 --- a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb +++ b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb @@ -20,7 +20,7 @@ "\n", "This is the most basic level of the UI.\n", "There's a command-line interface (CLI) for Level 1, or you can use the Python API shown below.\n", - "If you want to make minor modifications to `phase_info`, you can do so here, but Level 1 largely assumes you're using the default setup." + "If you want to make minor modifications to {glue:md}`phase_info`, you can do so here, but Level 1 largely assumes you're using the default setup." ] }, { From f794777d44eece08499e46878cfd41c458ecbd3f Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 10 Dec 2024 09:23:55 -0800 Subject: [PATCH 21/48] glue variables in FLOPS_based_detailed_takeoff_and_landing.ipynb --- ...S_based_detailed_takeoff_and_landing.ipynb | 250 +++++++++++++----- 1 file changed, 180 insertions(+), 70 deletions(-) diff --git a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb index 80456bf57..258dfed78 100644 --- a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb +++ b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb @@ -1,5 +1,25 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "262c6ac0", + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.aviary_values import AviaryValues\n", + "from aviary.utils.doctape import glue_variable\n", + "from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder\n", + "\n", + "glue_variable(f'{AviaryValues=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{CoreAerodynamicsBuilder=}'.split('=')[0], md_code=True)" + ] + }, { "cell_type": "markdown", "id": "01c83833", @@ -12,7 +32,7 @@ "```\n", "\n", "Aviary support of FLOPS based detailed takeoff and landing is implemented in terms of\n", - "user options, initial guesses, and different types of builders. User options and initial guesses are often collected in `AviaryValues` objects, which are then used to setup different builders. Builders are used to create analysis components. The builders for takeoff and landing can be separated into three general categories: aerodynamics, phases, and trajectories. The following sections describe which builders are associated with takeoff and landing and how to generally use them.\n", + "user options, initial guesses, and different types of builders. User options and initial guesses are often collected in {glue:md}`AviaryValues` objects, which are then used to setup different builders. Builders are used to create analysis components. The builders for takeoff and landing can be separated into three general categories: aerodynamics, phases, and trajectories. The following sections describe which builders are associated with takeoff and landing and how to generally use them.\n", "\n", "The following code excerpts were copied from Aviary validation data and benchmarks. For a\n", "more complete working example, with appropriate support for drivers, see the following\n", @@ -25,11 +45,11 @@ "## Takeoff\n", "\n", "### Aerodynamics Builder\n", - "Both takeoff and landing are designed to use the FLOPS-derived `low_speed` aerodynamics method defined in the `CoreAerodynamicsBuilder`. The builder supports several options specified in a `subsystem_options` dictionary provided to the phase builder. The most important subsystem options are the three required sequences: `angles_of_attack`, `lift_coefficients`, and `drag_coefficients`. At least two values must be specified in `angles_of_attack`. For each value in `angles_of_attack`, there must be one dependent value at the corresponding index in each of `lift_coefficients` and `drag_coefficients`.\n", + "Both takeoff and landing are designed to use the FLOPS-derived `low_speed` aerodynamics method defined in the {glue:md}`CoreAerodynamicsBuilder`. The builder supports several options specified in a `subsystem_options` dictionary provided to the phase builder. The most important subsystem options are the three required sequences: `angles_of_attack`, `lift_coefficients`, and `drag_coefficients`. At least two values must be specified in `angles_of_attack`. For each value in `angles_of_attack`, there must be one dependent value at the corresponding index in each of `lift_coefficients` and `drag_coefficients`.\n", "\n", - "Once a `CoreAerodynamicsBuilder` object is created, it can be used to create a phase builder.\n", + "Once a {glue:md}`CoreAerodynamicsBuilder` object is created, it can be used to create a phase builder.\n", "The phase builder will pass the aerodynamics builder down to where it is needed to\n", - "create appropriate aerodynamics analysis components. A single `CoreAerodynamicsBuilder` object\n", + "create appropriate aerodynamics analysis components. A single {glue:md}`CoreAerodynamicsBuilder` object\n", "can be shared with different phase builders. Subsystem options can also often be shared by different phase builders. In most cases, values like `angles_of_attack`, `lift_coefficients`, `drag_coefficients`, and a few others are identical across all phases of takeoff/landing trajectory, even if other option values vary by phase." ] }, @@ -87,6 +107,74 @@ "prop_builder = av.CorePropulsionBuilder(engine_models=engine)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "2597f97e", + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import ast\n", + "import inspect\n", + "import aviary.api as av\n", + "from aviary.mission.flops_based.phases.detailed_takeoff_phases import TakeoffTrajectory\n", + "\n", + "def get_class_names(file_path):\n", + " # Read the content of the file\n", + " with open(file_path, 'r') as file:\n", + " file_content = file.read()\n", + " \n", + " # Parse the file content into an AST\n", + " tree = ast.parse(file_content)\n", + " \n", + " # Extract class names\n", + " class_names = [\n", + " node.name for node in ast.walk(tree)\n", + " if isinstance(node, ast.ClassDef)\n", + " ]\n", + " \n", + " return class_names\n", + "\n", + "def get_Function_names(file_path):\n", + " # Read the content of the file\n", + " with open(file_path, 'r') as file:\n", + " file_content = file.read()\n", + " \n", + " # Parse the file content into an AST\n", + " tree = ast.parse(file_content)\n", + " \n", + " # Extract function names\n", + " function_names = [\n", + " node.name for node in ast.walk(tree)\n", + " if isinstance(node, ast.FunctionDef)\n", + " ]\n", + " \n", + " return function_names\n", + "\n", + "file_path = av.get_path('mission/flops_based/phases/detailed_takeoff_phases.py')\n", + "takeoff_class_names = get_class_names(file_path)\n", + "for class_name in takeoff_class_names:\n", + " glue_variable(class_name, md_code=True)\n", + "takeoff_function_names = get_Function_names(file_path)\n", + "\n", + "# for function_name in takeoff_function_names:\n", + "# if not function_name.startswith('_'):\n", + "# glue_variable(function_name+'()', md_code=True)\n", + "\n", + "# Get all functions of class TakeoffTrajectory\n", + "functs = inspect.getmembers(TakeoffTrajectory, predicate=inspect.isfunction)\n", + "takeoff_functs = []\n", + "for name, func in functs:\n", + " if not name.startswith('_'):\n", + " takeoff_functs.append(name)\n", + " glue_variable(name + '()', md_code=True)\n" + ] + }, { "cell_type": "markdown", "id": "294cdced", @@ -95,40 +183,40 @@ "### Phase Builders\n", "There are eleven types of phase builders for takeoff. In general, the following phase\n", "builders are always required:\n", - "- `TakeoffBrakeReleaseToDecisionSpeed` : a phase builder for the first phase of takeoff,\n", + "- {glue:md}`TakeoffBrakeReleaseToDecisionSpeed` : a phase builder for the first phase of takeoff,\n", " from brake release to decision speed, the maximum speed at which takeoff can be safely\n", " brought to full stop using zero thrust while braking;\n", - "- `TakeoffDecisionSpeedToRotate` : a phase builder for the second phase of takeoff, from\n", + "- {glue:md}`TakeoffDecisionSpeedToRotate` : a phase builder for the second phase of takeoff, from\n", " decision speed to rotation;\n", - "- `TakeoffRotateToLiftoff` : a phase builder for the third phase of takeoff, from\n", + "- {glue:md}`TakeoffRotateToLiftoff` : a phase builder for the third phase of takeoff, from\n", " rotation to liftoff;\n", - "- `TakeoffLiftoffToObstacle` : a phase builder for the fourth phase of takeoff, from\n", + "- {glue:md}`TakeoffLiftoffToObstacle` : a phase builder for the fourth phase of takeoff, from\n", " liftoff to clearing the required obstacle.\n", "\n", "The following phase builders are only required if acoustic calculations are required:\n", - "- `TakeoffObstacleToMicP2` : a phase builder for the fifth phase of takeoff, from\n", + "- {glue:md}`TakeoffObstacleToMicP2` : a phase builder for the fifth phase of takeoff, from\n", " clearing the required obstacle to the P2 mic location;\n", - "- `TakeoffMicP2ToEngineCutback` : a phase builder for the sixth phase of takeoff, from\n", + "- {glue:md}`TakeoffMicP2ToEngineCutback` : a phase builder for the sixth phase of takeoff, from\n", " the P2 mic location to engine cutback;\n", - "- `TakeoffEngineCutback` : a phase builder for the seventh phase of takeoff, from start\n", + "- {glue:md}`TakeoffEngineCutback` : a phase builder for the seventh phase of takeoff, from start\n", " to finish of engine cutback;\n", - "- `TakeoffEngineCutbackToMicP1` : a phase builder for the eighth phase of takeoff, from\n", + "- {glue:md}`TakeoffEngineCutbackToMicP1` : a phase builder for the eighth phase of takeoff, from\n", " engine cutback to the P1 mic location;\n", - "- `TakeoffMicP1ToClimb` : a phase builder for the ninth phase of takeoff, from P1 mic\n", + "- {glue:md}`TakeoffMicP1ToClimb` : a phase builder for the ninth phase of takeoff, from P1 mic\n", " location to climb.\n", "\n", "The following phase builders are only required if balanced field length calculations are\n", "required:\n", - "- `TakeoffDecisionSpeedBrakeDelay` : a phase builder for the second phase of aborted\n", + "- {glue:md}`TakeoffDecisionSpeedBrakeDelay` : a phase builder for the second phase of aborted\n", " takeoff, from decision speed to brake application;\n", - "- `TakeoffBrakeToAbort` : a phase builder for the last phase of aborted takeoff, from\n", + "- {glue:md}`TakeoffBrakeToAbort` : a phase builder for the last phase of aborted takeoff, from\n", " brake application to full stop.\n", "\n", "When creating any of these phase builders, the following data should first be collected\n", "and passed to the builder during creation: subsystem builders, subsystem options, user options, and initial guesses. The subsystem builders and options are created as described in the previous\n", - "section. User options are collected in an `AviaryValues` object. Each type of phase\n", + "section. User options are collected in an {glue:md}`AviaryValues` object. Each type of phase\n", "builder supports its own set of user options, with associated default values. Initial\n", - "guesses are collected in an `AviaryValues` object separate from the user options. Each\n", + "guesses are collected in an {glue:md}`AviaryValues` object separate from the user options. Each\n", "type of phase builder supports its own set of initial guesses; initial guesses have no\n", "default values and are required.\n", "\n", @@ -204,64 +292,64 @@ "metadata": {}, "source": [ "### Trajectory Builder\n", - "Objects of the trajectory builder type `TakeoffTrajectory` can be used to collect the\n", + "Objects of the trajectory builder type {glue:md}`TakeoffTrajectory` can be used to collect the\n", "required phases for either general takeoff analysis or balanced field length analysis.\n", "The builder has setters for each of the following generally required phase builders:\n", - "- `set_brake_release_to_decision_speed()` : assign a phase builder, typically of type\n", - " `TakeoffBrakeReleaseToDecisionSpeed`, for the beginning of takeoff to the time when the\n", + "- {glue:md}`set_brake_release_to_decision_speed()` : assign a phase builder, typically of type\n", + " {glue:md}`TakeoffBrakeReleaseToDecisionSpeed`, for the beginning of takeoff to the time when the\n", " pilot must choose either to liftoff or halt the aircraft;\n", - "- `set_decision_speed_to_rotate()` : assign a phase builder, typically of type\n", - " `TakeoffDecisionSpeedToRotate`, for the short distance between achieving decision speed\n", + "- {glue:md}`set_decision_speed_to_rotate()` : assign a phase builder, typically of type\n", + " {glue:md}`TakeoffDecisionSpeedToRotate`, for the short distance between achieving decision speed\n", " and beginning the rotation phase;\n", - "- `set_rotate_to_liftoff()` : assign a phase builder, typically of type\n", - " `TakeoffRotateToLiftoff`, for the short distance required to rotate the aircraft to\n", + "- {glue:md}`set_rotate_to_liftoff()` : assign a phase builder, typically of type\n", + " {glue:md}`TakeoffRotateToLiftoff`, for the short distance required to rotate the aircraft to\n", " achieve liftoff;\n", - "- `set_liftoff_to_obstacle()` : assign a phase builder, typically of type\n", - " `TakeoffLiftoffToObstacle`, for the short period between liftoff and clearing the\n", + "- {glue:md}`set_liftoff_to_obstacle()` : assign a phase builder, typically of type\n", + " {glue:md}`TakeoffLiftoffToObstacle`, for the short period between liftoff and clearing the\n", " required obstacle.\n", "\n", "The builder has setters for the following phase builders, which are only required if\n", "acoustic calculations are required:\n", - "- `set_obstacle_to_mic_p2()` : assign a phase builder, typically of type\n", - " `TakeoffObstacleToMicP2`, for the fifth phase of takeoff, from clearing the required\n", + "- {glue:md}`set_obstacle_to_mic_p2()` : assign a phase builder, typically of type\n", + " {glue:md}`TakeoffObstacleToMicP2`, for the fifth phase of takeoff, from clearing the required\n", " obstacle to the p2 mic loation;\n", - "- `set_mic_p2_to_engine_cutback()` : a phase builder, typically of type\n", - " `TakeoffMicP2ToEngineCutback`, for the sixth phase of takeoff, from the p2 mic location\n", + "- {glue:md}`set_mic_p2_to_engine_cutback()` : a phase builder, typically of type\n", + " {glue:md}`TakeoffMicP2ToEngineCutback`, for the sixth phase of takeoff, from the p2 mic location\n", " to engine cutback;\n", - "- `set_engine_cutback()` : a phase builder, typically of type `TakeoffEngineCutback`, for\n", + "- {glue:md}`set_engine_cutback()` : a phase builder, typically of type {glue:md}`TakeoffEngineCutback`, for\n", " the seventh phase of takeoff, from start to finish of engine cutback;\n", - "- `set_engine_cutback_to_mic_p1()` : a phase builder, typically of type\n", - " `TakeoffEngineCutbackToMicP1`, for the eighth phase of takeoff, engine cutback to the\n", + "- {glue:md}`set_engine_cutback_to_mic_p1()` : a phase builder, typically of type\n", + " {glue:md}`TakeoffEngineCutbackToMicP1`, for the eighth phase of takeoff, engine cutback to the\n", " P1 mic location;\n", - "- `set_mic_p1_to_climb()` : a phase builder, typically of type `TakeoffMicP1ToClimb`, for\n", + "- `{glue:md}set_mic_p1_to_climb()` : a phase builder, typically of type {glue:md}`TakeoffMicP1ToClimb`, for\n", " the ninth phase of takeoff, from P1 mic location to climb.\n", "\n", "The builder also has setters for the following phase builders, which are only required if\n", "balanced field length calculations are required:\n", - "- `set_decision_speed_to_brake()` : assign a phase builder, typically of type\n", - " `TakeoffDecisionSpeedBrakeDelay`, for delayed braking when the engine fails;\n", - "- `set_brake_to_abort()` : assign a phase builder, typically of type\n", - " `TakeoffBrakeToAbort`, for braking to fullstop after engine failure.\n", + "- {glue:md}`set_decision_speed_to_brake()` : assign a phase builder, typically of type\n", + " {glue:md}`TakeoffDecisionSpeedBrakeDelay`, for delayed braking when the engine fails;\n", + "- {glue:md}`set_brake_to_abort()` : assign a phase builder, typically of type\n", + " {glue:md}`TakeoffBrakeToAbort`, for braking to fullstop after engine failure.\n", "\n", - "After all required phase builders have been assigned, the `build_trajectory()` method can\n", - "be called on the builder, which requires an `AviaryValues` object for Aviary level\n", + "After all required phase builders have been assigned, the {glue:md}`build_trajectory()` method can\n", + "be called on the builder, which requires an {glue:md}`AviaryValues` object for Aviary level\n", "analysis options, and which optionally accepts a model (an OpenMDAO `Group`) and a\n", "trajectory. If specified, the model is used in handling trajectory parameter setup;\n", "otherwise, trajectory parameter setup must be handled by client code. If specified, the\n", "trajectory is updated with phase analysis components created from the phase builders;\n", "otherwise, a new trajectory is created, updated with these components, and returned.\n", - "Calling `build_trajectory()` adds phase analysis components to the trajectory, and then\n", + "Calling {glue:md}`build_trajectory()` adds phase analysis components to the trajectory, and then\n", "links those phases appropriately. Note, externally created trajectories can be added to\n", - "the problem model either before or after the call to `build_trajectory()`.\n", + "the problem model either before or after the call to {glue:md}`build_trajectory()`.\n", "\n", - "Once `build_trajectory()` is called on the builder, client code can optionally retrieve\n", - "named phase analysis components from the builder with the `get_phase()` method. Client\n", + "Once {glue:md}`build_trajectory()` is called on the builder, client code can optionally retrieve\n", + "named phase analysis components from the builder with the {glue:md}`get_phase()` method. Client\n", "code can then add objectives and constraints to these components to satisfy application\n", "specific requirements.\n", "\n", - "Before running the problem, the `apply_initial_guesses()` method should be called on the\n", + "Before running the problem, the {glue:md}`apply_initial_guesses()` method should be called on the\n", "trajectory builder with the problem and the name of the trajectory. For each created\n", - "phase, this method calls the `apply_initial_guesses()` method on the associated phase\n", + "phase, this method calls the {glue:md}`apply_initial_guesses()` method on the associated phase\n", "builder. Any initial guesses not applied are returned in a dictionary, where the name of\n", "the phase maps to the list of initial guesses not applied. Once the problem is built up\n", "and set up, the problem can be run for trajectory analysis." @@ -364,8 +452,7 @@ "\n", "av.set_aviary_initial_values(takeoff, aviary_options)\n", "\n", - "takeoff_trajectory_builder.apply_initial_guesses(takeoff, 'traj')\n", - "\n" + "takeoff_trajectory_builder.apply_initial_guesses(takeoff, 'traj')\n" ] }, { @@ -413,6 +500,29 @@ " 'spoiler_drag_coefficient': 0.085}}" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "084a0348", + "metadata": {}, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import aviary.api as av\n", + "from aviary.mission.flops_based.phases.detailed_landing_phases import LandingTrajectory\n", + "\n", + "file_path = av.get_path('mission/flops_based/phases/detailed_landing_phases.py')\n", + "landing_class_names = get_class_names(file_path)\n", + "for class_name in landing_class_names:\n", + " glue_variable(class_name, md_code=True)\n", + "\n", + "# Get all functions of class LandingTrajectory\n", + "functs = inspect.getmembers(LandingTrajectory, predicate=inspect.isfunction)\n", + "for name, func in functs:\n", + " if (not name.startswith('_')) and (not name in takeoff_functs):\n", + " glue_variable(name + '()', md_code=True)\n" + ] + }, { "cell_type": "markdown", "id": "ead2ef44", @@ -421,20 +531,20 @@ "### Phase Builders\n", "There are six types of phase builders for landing. In general, the following phase\n", "builders are always required:\n", - "- `LandingObstacleToFlare` : a phase builder for moving from the start of the runway,\n", + "- {glue:md}`LandingObstacleToFlare` : a phase builder for moving from the start of the runway,\n", " just above the required clearance height, to the start of a maneuver to help soften the\n", " impact of touchdown;\n", - "- `LandingFlareToTouchdown` : a phase builder for moving through a maneuver to help\n", + "- {glue:md}`LandingFlareToTouchdown` : a phase builder for moving through a maneuver to help\n", " soften the impact of touchdown;\n", - "- `LandingTouchdownToNoseDown` : a phase builder for rotating the nose down after\n", + "- {glue:md}`LandingTouchdownToNoseDown` : a phase builder for rotating the nose down after\n", " touchdown;\n", - "- `LandingNoseDownToStop` : a phase builder for the final phase of landing, from nose\n", + "- {glue:md}`LandingNoseDownToStop` : a phase builder for the final phase of landing, from nose\n", " down to full stop.\n", "\n", "The following phase builders are only required if acoustic calculations are required:\n", - "- `LandingApproachToMicP3` : a phase builder for moving from descent to the mic location\n", + "- {glue:md}`LandingApproachToMicP3` : a phase builder for moving from descent to the mic location\n", " P3;\n", - "- `LandingMicP3ToObstacle` : a phase builder for moving from the mic location P3 to the\n", + "- {glue:md}`LandingMicP3ToObstacle` : a phase builder for moving from the mic location P3 to the\n", " start of the runway, just above the required clearance height.\n", "\n", "The general procedure for creating and using phase builders for landing is the same as\n", @@ -533,31 +643,31 @@ "metadata": {}, "source": [ "### Trajectory Builder\n", - "Objects of the trajectory builder type `LandingTrajectory` can be used to collect the\n", + "Objects of the trajectory builder type {glue:md}`LandingTrajectory` can be used to collect the\n", "required phases for general landing analysis. The builder has setters for each of the\n", "following generally required phase builders:\n", - "- `set_obstacle_to_flare()` : assign a phase builder, typically of type\n", - " `LandingObstacleToFlare`, for moving from the start of the runway, just above the\n", + "- {glue:md}`set_obstacle_to_flare()` : assign a phase builder, typically of type\n", + " {glue:md}`LandingObstacleToFlare`, for moving from the start of the runway, just above the\n", " required clearance height, to the start of a maneuver to help soften the impact of\n", " touchdown;\n", - "- `set_flare_to_touchdown()` : assign a phase builder, typically of type\n", - " `LandingFlareToTouchdown`, for moving through a maneuver to help soften the impact of\n", + "- {glue:md}`set_flare_to_touchdown()` : assign a phase builder, typically of type\n", + " {glue:md}`LandingFlareToTouchdown`, for moving through a maneuver to help soften the impact of\n", " touchdown;\n", - "- `set_touchdown_to_nose_down()` : assign a phase builder, typically of type\n", - " `LandingTouchdownToNoseDown`, for rotating the nose down after touchdown;\n", - "- `set_nose_down_to_stop()` : assign a phase builder, typically of type\n", - " `LandingNoseDownToStop`, for the final phase of landing, from nose down to full stop.\n", + "- {glue:md}`set_touchdown_to_nose_down()` : assign a phase builder, typically of type\n", + " {glue:md}`LandingTouchdownToNoseDown`, for rotating the nose down after touchdown;\n", + "- {glue:md}`set_nose_down_to_stop()` : assign a phase builder, typically of type\n", + " {glue:md}`LandingNoseDownToStop`, for the final phase of landing, from nose down to full stop.\n", "\n", "The builder also has setters for each of the following phase builders, which are only\n", "required if acoustic calculations are required:\n", - "- `set_approach_to_mic_p3()` : assign a phase builder, typically of type\n", - " `LandingApproachToMicP3`, for moving from the end of descent to the mic location P3;\n", - "- `set_mic_p3_to_obstacle()` : assign a phase builder, typically of type\n", - " `LandingMicP3ToObstacle`, for moving from the mic location P3 to the start of the\n", + "- {glue:md}`set_approach_to_mic_p3()` : assign a phase builder, typically of type\n", + " {glue:md}`LandingApproachToMicP3`, for moving from the end of descent to the mic location P3;\n", + "- {glue:md}`set_mic_p3_to_obstacle()` : assign a phase builder, typically of type\n", + " {glue:md}`LandingMicP3ToObstacle`, for moving from the mic location P3 to the start of the\n", " runway, just above the required clearance height.\n", "\n", "After all required phase builders have been assigned, the general procedure for using the\n", - "`build_trajectory()`, `get_phase()`, and `apply_initial_guesses()` methods of the\n", + "{glue:md}`build_trajectory()`, {glue:md}`get_phase()`, and {glue:md}`apply_initial_guesses()` methods of the\n", "trajectory builder is the same for landing as that for takeoff. See the \"Trajectory\n", "Builder\" subsection in the \"Takeoff\" section above for a description." ] @@ -635,7 +745,7 @@ ], "metadata": { "kernelspec": { - "display_name": "base", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -649,7 +759,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.5" + "version": "3.9.18" } }, "nbformat": 4, From e779ba0d58b10c35602d87a8967cae362278fafa Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 10 Dec 2024 13:47:34 -0800 Subject: [PATCH 22/48] glue variables in hamilton_standard.ipynb --- .../docs/user_guide/hamilton_standard.ipynb | 105 ++++++++++++++---- 1 file changed, 85 insertions(+), 20 deletions(-) diff --git a/aviary/docs/user_guide/hamilton_standard.ipynb b/aviary/docs/user_guide/hamilton_standard.ipynb index b6fa18475..f9985e4be 100644 --- a/aviary/docs/user_guide/hamilton_standard.ipynb +++ b/aviary/docs/user_guide/hamilton_standard.ipynb @@ -1,5 +1,33 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "\n", + "from aviary.api import Aircraft\n", + "from aviary.subsystems.propulsion.propeller.hamilton_standard import (\n", + " PreHamiltonStandard, HamiltonStandard, PostHamiltonStandard)\n", + "from aviary.subsystems.propulsion.propeller.propeller_performance import InstallLoss\n", + "from aviary.utils.doctape import check_value, get_variable_name, glue_variable\n", + "from aviary.subsystems.atmosphere.atmosphere import Atmosphere\n", + "\n", + "check_value(Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS,'aircraft:engine:compute_propeller_installation_loss')\n", + "glue_variable(get_variable_name(Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS), md_code=True)\n", + "glue_variable(f'{Atmosphere=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{InstallLoss=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{PreHamiltonStandard=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{HamiltonStandard=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{PostHamiltonStandard=}'.split('=')[0], md_code=True)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -12,7 +40,7 @@ "You can find the definitions, methodology, and Fortran code in the document.\n", "In Aviary, we implement only one of the computation options: the code computes the corresponding thrust for a given horsepower.\n", "\n", - "Below is an XDSM diagram of Hamilton Standard model (assuming `Dynamic.Mission.INSTALLATION_LOSS_FACTOR` is computed):\n", + "Below is an XDSM diagram of Hamilton Standard model (assuming {glue:md}`Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS` is `True`):\n", "\n", "![Hamilton Standard Diagram](images/hamilton_standard.png)\n", "\n", @@ -63,13 +91,13 @@ "\n", "When shaft power is zero, propeller efficiencies are undefined. We set them as 0.0.\n", "\n", - "As shown in the above XDSM diagram, the model is an OpenMDAO group that is composed of four components and one subgroup:\n", + "As shown in the above XDSM diagram, the model is an OpenMDAO group that is composed of three components and two groups:\n", "\n", - "- `USatmos`\n", - "- `PreHamiltonStandard`\n", - "- `HamiltonStandard`\n", - "- `InstallLoss`\n", - "- `PostHamiltonStandard`" + "- {glue:md}`Atmosphere` (group)\n", + "- {glue:md}`PreHamiltonStandard`\n", + "- {glue:md}`HamiltonStandard`\n", + "- {glue:md}`InstallLoss` (group)\n", + "- {glue:md}`PostHamiltonStandard`" ] }, { @@ -147,11 +175,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The `atmosphere` component provides the flight conditions.\n", - "The flight conditions are passed to the `PreHamiltonStandard` component which computes the propeller tip Mach number, advance ratio, and power coefficient.\n", - "These values are then fed into the `HamiltonStandard` component.\n", + "The {glue:md}`Atmosphere` component provides the flight conditions.\n", + "The flight conditions are passed to the {glue:md}`PreHamiltonStandard` component which computes the propeller tip Mach number, advance ratio, and power coefficient.\n", + "These values are then fed into the {glue:md}`HamiltonStandard` component.\n", "\n", - "`HamiltonStandard` is the core of the model.\n", + "{glue:md}`HamiltonStandard` is the core of the model.\n", "Given the power coefficient (CP) and advance ratio (J), it finds the blade angle (BL) by a CP-BL chart by tracing the advance ratio.\n", "Then with the blade angle, it finds the thrust coefficient (CT) using its CT-BL chart by tracing advance ratio again.\n", "This algorithm is shown in the below pair of charts.\n", @@ -162,7 +190,7 @@ "\n", "![CP and CT matching](images/CPE_CTE_matching.png)\n", "\n", - "Finally, the thrust is computed in the `PostHamiltonStandard` component based on thrust coefficient and tip compressibility loss factor.\n", + "Finally, the thrust is computed in the {glue:md}`PostHamiltonStandard` component based on thrust coefficient and tip compressibility loss factor.\n", "\n", "The Hamilton Standard model uses wind tunnel test data from uninstalled propellers.\n", "When a nacelle is mounted behind the propeller, an installation loss factor is introduced.\n", @@ -171,7 +199,7 @@ "\n", "![Installation Loss Factor](images/installation_loss_factor.png)\n", "\n", - "This diagram is represented by `InstallLoss` group in the first diagram.\n", + "This diagram is represented by {glue:md}`InstallLoss` group in the first diagram.\n", "Nacelle diameter is needed when installation loss factor is computed.\n", "We use the average nacelle diameter.\n", "\n", @@ -190,7 +218,8 @@ "source": [ "# Testing Cell\n", "from aviary.api import Aircraft, Dynamic\n", - "from aviary.subsystems.propulsion.turboprop_model import TurbopropModel" + "from aviary.subsystems.propulsion.turboprop_model import TurbopropModel\n", + "glue_variable(f'{TurbopropModel=}'.split('=')[0], md_code=True)" ] }, { @@ -216,7 +245,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To build a turboprop engine that uses the Hamilton Standard propeller model we use a `TurboPropModel` object with `propeller_model` set to `True` and `shaft_power_model` set to `False` (the default):" + "To build a turboprop engine that uses the Hamilton Standard propeller model we use a {glue:md}`TurbopropModel` object with `propeller_model` set to `None` and `shaft_power_model` set to `None` (the default):" ] }, { @@ -229,7 +258,7 @@ }, "outputs": [], "source": [ - "engine = TurbopropModel(options=options, shaft_power_model=None, propeller_model=True)" + "engine = TurbopropModel(options=options, shaft_power_model=None, propeller_model=None)" ] }, { @@ -276,15 +305,51 @@ "prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT}', 0.5, units='unitless')" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import aviary.api as av\n", + "from aviary.variable_info.enums import OutMachType\n", + "from aviary.subsystems.propulsion.propeller.propeller_performance import OutMachs\n", + "file_path = av.get_path('models/propellers/general_aviation.prop')\n", + "file_path = av.get_path('models/propellers/PropFan.prop')\n", + "glue_variable('models/propellers', md_code=True)\n", + "glue_variable('general_aviation.prop', md_code=True)\n", + "glue_variable('PropFan.prop', md_code=True)\n", + "file_path = av.get_path('models/propellers/general_aviation.map')\n", + "file_path = av.get_path('models/propellers/PropFan.map')\n", + "glue_variable('general_aviation.map', md_code=True)\n", + "glue_variable('PropFan.map', md_code=True)\n", + "\n", + "glue_variable(OutMachType.HELICAL_MACH.name.title(), md_code=True)\n", + "glue_variable(OutMachType.MACH.name.title(), md_code=True)\n", + "\n", + "check_value(Aircraft.Engine.USE_PROPELLER_MAP,'aircraft:engine:use_propeller_map')\n", + "glue_variable(get_variable_name(Aircraft.Engine.USE_PROPELLER_MAP), md_code=True)\n", + "check_value(Aircraft.Engine.PROPELLER_DATA_FILE,'aircraft:engine:propeller_data_file')\n", + "glue_variable(get_variable_name(Aircraft.Engine.PROPELLER_DATA_FILE), md_code=True)\n", + "check_value(Dynamic.Mission.MACH,'mach')\n", + "glue_variable(get_variable_name(Dynamic.Mission.MACH), md_code=True)\n", + "glue_variable(f'{OutMachs=}'.split('=')[0], md_code=True)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Propeller Map Alternative\n", "\n", - "The Hamilton Standard model has limitations where it can be applied; for model aircraft design, it is possible that users may want to provide their own data tables. Two sample data sets are provided in `models/propellers` folder: `general_aviation.prop` and `PropFan.prop`. In both cases, they are in `.csv` format and are converted from `GASP` maps: `general_aviation.map` and `PropFan.map` (see [Command Line Tools](aviary_commands.ipynb) for details). The difference between these two samples is that the generatl aviation sample uses helical Mach numbers as input while the propfan sample uses the free stream Mach numbers. Helical Mach numbers appear higher, due to the inclusion of the rotational component of the tip velocity. In our example, they range from 0.7 to 0.95. To determine which mach type in a GASP map is used, please look at the first integer of the first line. If it is 1, it uses helical mach; if it is 2, it uses free stream mach. To determin which mach type is an Aviary propeller file is used, please look at the second item in the header. It is either `Helical_Mach` or `Mach`.\n", + "The Hamilton Standard model has limitations where it can be applied; for model aircraft design, it is possible that users may want to provide their own data tables. Two sample data sets are provided in {glue:md}`models/propellers` folder: {glue:md}`general_aviation.prop` and {glue:md}`PropFan.prop`. In both cases, they are in `.csv` format and are converted from `GASP` maps: {glue:md}`general_aviation.map` and {glue:md}`PropFan.map` (see [Command Line Tools](aviary_commands.ipynb) for details). The difference between these two samples is that the generatl aviation sample uses helical Mach numbers as input while the propfan sample uses the free stream Mach numbers. Helical Mach numbers appear higher, due to the inclusion of the rotational component of the tip velocity. In our example, they range from 0.7 to 0.95. To determine which mach type in a GASP map is used, please look at the first integer of the first line. If it is 1, it uses helical mach; if it is 2, it uses free stream mach. To determin which mach type is an Aviary propeller file is used, please look at the second column in the header. It is either {glue:md}`Helical_Mach` or {glue:md}`Mach`.\n", "\n", - "To use a propeller map, users can set `Aircraft.Engine.USE_PROPELLER_MAP` to `True` and provide the propeller map file path to `Aircraft.Engine.PROPELLER_DATA_FILE`. If helical Mach numbers are in the propeller map file, then an `OutMachs` component is added to convert helical Mach numbers to flight Mach numbers (`Dynamic.Mission.MACH`).\n", + "To use a propeller map, users can set {glue:md}`Aircraft.Engine.USE_PROPELLER_MAP` to `True` and provide the propeller map file path to {glue:md}`Aircraft.Engine.PROPELLER_DATA_FILE`. If helical Mach numbers are in the propeller map file, then an {glue:md}`OutMachs` component is added to convert helical Mach numbers to flight Mach numbers ({glue:md}`Dynamic.Mission.MACH`).\n", "\n", "In the Hamilton Standard models, the thrust coefficients do not take compressibility into account. Therefore, propeller tip compressibility loss factor has to be computed and will be used to compute thrust. If a propeller map is used, the compressibility effects should be included in the data provided. Therefore, this factor is assumed to be 1.0 and is supplied to post Hamilton Standard component. Other outputs are computed using the same formulas." ] @@ -292,7 +357,7 @@ ], "metadata": { "kernelspec": { - "display_name": "latest_env", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -306,7 +371,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From 01cf911319b220b48db1f8bfbc4444bb0367fd84 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 10 Dec 2024 15:22:24 -0800 Subject: [PATCH 23/48] glue variables in input_files.ipynb --- aviary/docs/user_guide/input_files.ipynb | 57 ++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/aviary/docs/user_guide/input_files.ipynb b/aviary/docs/user_guide/input_files.ipynb index 40465df57..91ea4157a 100644 --- a/aviary/docs/user_guide/input_files.ipynb +++ b/aviary/docs/user_guide/input_files.ipynb @@ -65,12 +65,51 @@ "The data in an external data file must be in column format, delimited by commas. Only numerical data that can be cast to type `float` is compatible with Aviary data tables at this time. An error will be raised if non-numerical data is present in the data file that is not a comment or a correctly formatted header." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import ast\n", + "from aviary.utils.csv_data_file import read_data_file, write_data_file\n", + "from aviary.utils.doctape import check_value, get_variable_name, glue_variable\n", + "\n", + "def get_Function_names(file_path):\n", + " # Read the content of the file\n", + " with open(file_path, 'r') as file:\n", + " file_content = file.read()\n", + " \n", + " # Parse the file content into an AST\n", + " tree = ast.parse(file_content)\n", + " \n", + " # Extract function names\n", + " function_names = [\n", + " node.name for node in ast.walk(tree)\n", + " if isinstance(node, ast.FunctionDef)\n", + " ]\n", + " \n", + " return function_names\n", + "\n", + "file_path = av.get_path('utils/csv_data_file.py')\n", + "takeoff_function_names = get_Function_names(file_path)\n", + "\n", + "for function_name in takeoff_function_names:\n", + " if not function_name.startswith('_'):\n", + " glue_variable(function_name+'()', md_code=True)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reading and writing Aviary data files\n", - "Aviary includes a pair of utility functions, `read_data_file` and `write_data_file`, to assist reading and writing files in Aviary data format. Here we will demonstrate writing data to a csv file, then reading it back to retrieve the data." + "Aviary includes a pair of utility functions, {glue:md}`read_data_file()` and {glue:md}`write_data_file()`, to assist reading and writing files in Aviary data format. Here we will demonstrate writing data to a csv file, then reading it back to retrieve the data." ] }, { @@ -143,11 +182,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Running this code shows our comments were correctly retrieved (stripped of leading `#`). We also have both our variables with their correct units and values. The `write_data_file` function has added back in units of 'unitless' for Mach Number. `Scale Factor` was also modified to `Scale_Factor`. This is because it is assumed these names will feed into openMDAO variables, and spaces are not allowed.\n", + "Running this code shows our comments were correctly retrieved (stripped of leading `#`). We also have both our variables with their correct units and values. The {glue:md}`write_data_file()` function has added back in units of 'unitless' for Mach Number. `Scale Factor` was also modified to `Scale_Factor`. This is because it is assumed these names will feed into openMDAO variables, and spaces are not allowed.\n", "\n", - "Now let's explore some optional arguments for `csv_reader`.\n", + "Now let's explore some optional arguments for {glue:md}`read_data_file()`.\n", "\n", - "The first optional argument for `csv_reader` is variable metadata. When provided, `read_data_file` checks variable names in the header against the metadata and skips reading any variables not found. In addition, units specified in the data file are checked for compatibility with the default units for that variable. If units are not provided for a variable, default units are applied instead of always applying 'unitless'. Let's re-run the same code as before, but this time provide Aviary's core metadata to the reader. The expected behavior is for `Scale Factor` to be skipped, since it isn't in the variable hierarchy." + "The first optional argument for {glue:md}`read_data_file()` is variable metadata. When provided, {glue:md}`read_data_file()` checks variable names in the header against the metadata and skips reading any variables not found. In addition, units specified in the data file are checked for compatibility with the default units for that variable. If units are not provided for a variable, default units are applied instead of always applying 'unitless'. Let's re-run the same code as before, but this time provide Aviary's core metadata to the reader. The expected behavior is for `Scale Factor` to be skipped, since it isn't in the variable hierarchy." ] }, { @@ -173,7 +212,7 @@ "source": [ "We can see that only `aircraft:wing:span` was read from file this time, and is the only variable present in the data loaded to memory. Additionally, a warning was created informing us that `Scale Factor` was skipped.\n", "\n", - "A second optional argument is `aliases`. This argument is used to map multiple possible header names to the same openMDAO variable. This is useful if your data files do not use Aviary variable names, or could contain multiple variants of names that all mean the same thing (such as 'height', 'alt', and 'altitude'). In this example, our data file has a header labeled `Scale Factor`, but we would like to map it to the more precise `aircraft:wing:mass_scaler`. The allowable header name matching is not case-sensitive and Aviary will treat spaces and underscores as identical, so `scale_factor` will match with `Scale Factor`. This improves ease-of-use. However, the variable name you want headers mapped to are case-sensitive, in case you are connecting to an external component that doesn't follow Aviary's [variable naming standards](../developer_guide/coding_standards). So if your alias dict contains `Final_Name: example_var`, any case combination of `example_var` will always return `Final_Name` capitalized as specified." + "A second optional argument is `aliases`. This argument is used to map multiple possible header names to the same openMDAO variable. This is useful if your data files do not use Aviary variable names, or could contain multiple variants of names that all mean the same thing (such as 'height', 'alt', and 'altitude'). In this example, our data file has a header labeled `Scale Factor`, but we would like to map it to the more precise `aircraft:wing:mass_scaler`. The allowable header name matching is not case-sensitive and Aviary will treat spaces and underscores as identical, so `scale_factor` will match with `Scale Factor`. This improves ease-of-use. However, the variable name you want headers mapped to are case-sensitive, in case you are connecting to an external component that doesn't follow Aviary's [variable naming standards](../developer_guide/coding_standards). So if your alias dict contains `Final_Name:example_var`, any case combination of `example_var` will always return `Final_Name` capitalized as specified." ] }, { @@ -190,7 +229,9 @@ "from aviary.api import Aircraft\n", "from aviary.utils.doctape import check_value\n", "check_value(Aircraft.Wing.SPAN,'aircraft:wing:span')\n", - "check_value(Aircraft.Wing.MASS_SCALER,'aircraft:wing:mass_scaler')" + "glue_variable(get_variable_name(Aircraft.Wing.SPAN), md_code=True)\n", + "check_value(Aircraft.Wing.MASS_SCALER,'aircraft:wing:mass_scaler')\n", + "glue_variable(get_variable_name(Aircraft.Wing.MASS_SCALER), md_code=True)\n" ] }, { @@ -224,7 +265,7 @@ ], "metadata": { "kernelspec": { - "display_name": "aviary", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -238,7 +279,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.9.18" } }, "nbformat": 4, From 0e93159d7ea3cbd89b92bb2a078e0a4bab26ea74 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 11 Dec 2024 13:40:36 -0800 Subject: [PATCH 24/48] glue variables in postprocessing_and_visualizing_results.ipynb --- ...stprocessing_and_visualizing_results.ipynb | 88 ++++++++++++++++--- 1 file changed, 77 insertions(+), 11 deletions(-) diff --git a/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb b/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb index a24c03ef1..669bf8a84 100644 --- a/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb +++ b/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb @@ -1,5 +1,44 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import inspect\n", + "from aviary.utils.functions import get_path\n", + "from aviary.utils.doctape import glue_variable\n", + "from aviary.interface.methods_for_level2 import AviaryProblem\n", + "\n", + "# make sure that the path exists.\n", + "str_run_aviary_example = 'run_aviary_example'\n", + "print('examples/' + str_run_aviary_example + '.py')\n", + "get_path('examples/' + str_run_aviary_example + '.py')\n", + "glue_variable('aviary/examples', md_code=True)\n", + "glue_variable(str_run_aviary_example + '.py', md_code=True)\n", + "glue_variable(str_run_aviary_example + '.zip', md_code=True)\n", + "\n", + "# Get all functions of class AviaryProblem\n", + "functs = inspect.getmembers(AviaryProblem, predicate=inspect.isfunction)\n", + "takeoff_functs = []\n", + "for name, func in functs:\n", + " if not name.startswith('_') and name == 'run_aviary_problem':\n", + " takeoff_functs.append(name)\n", + " glue_variable(name + '()', md_code=True)\n", + "\n", + "sig = inspect.signature(AviaryProblem.run_aviary_problem)\n", + "arguments = [param.name for param in sig.parameters.values()]\n", + "for arg in arguments:\n", + " if arg == 'optimization_history_filename':\n", + " glue_variable(arg, md_code=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -31,7 +70,7 @@ "| Results | Mission Results | ./reports/subsystems/mission_summary.md |\n", "| Results | Problem final case recording | Case Recorder file specified by `problem_recorder` command option, default is `problem_history.db` |\n", "\n", - "As an example of the workflow for the dashboard, assume that the user has run an Aviary script, `run_aviary_example`, which records both the `Problem` final case and also all the cases of the optimization done by the `Driver`. (To record both the Problem final case and also the Driver optimization iterations, the user must make use of the `optimization_history_filename` option in the call to `run_aviary_problem`.)\n", + "As an example of the workflow for the dashboard, assume that the user has run an Aviary script, {glue:md}`run_aviary_example.py`, which records both the `Problem` final case and also all the cases of the optimization done by the [`Driver`](https://openmdao.org/newdocs/versions/latest/features/building_blocks/drivers/). The sample code can be found in {glue:md}`aviary/examples` folder. (To record both the Problem final case and also the Driver optimization iterations, the user must make use of the {glue:md}`optimization_history_filename` option in the call to {glue:md}`run_aviary_problem()`.)\n", "\n", "```bash\n", "python run_aviary_example.py\n", @@ -49,6 +88,32 @@ "```" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import argparse\n", + "from aviary.visualization.dashboard import _dashboard_setup_parser\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "parser = argparse.ArgumentParser()\n", + "_dashboard_setup_parser(parser)\n", + "glueing_arguments = ['problem_recorder', 'driver_recorder', 'save', 'force']\n", + "for action in parser._actions:\n", + " if action.dest in glueing_arguments:\n", + " #print(action.dest, action.default)\n", + " glue_variable('--' + action.dest, md_code=True)\n", + " if action.default is not None and not type(action.default) is bool:\n", + " glue_variable(str(action.default), md_code=True)\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -94,19 +159,19 @@ "The Problem recorder file is required for the Aircraft 3d model tab to be displayed in the dashboard.\n", "```\n", "\n", - "The `problem_recorder` and `driver_recorder` options to the dashboard command are used to indicate the file names for those recorder files, if they are not the standard values of `problem_history.db` and `driver_history.db`, respectively. If `driver_recorder` is set to the string `\"None\"`, then the driver case recorder file is ignored. This is useful if the user is not interested in seeing dashboard tabs related to driver history. If that file is large, it could unnecessarily be read and slow down the generation of the dashboard significantly.\n", + "The {glue:md}`--problem_recorder` and {glue:md}`--driver_recorder` options to the dashboard command are used to indicate the file names for those recorder files, if they are not the standard values of {glue:md}`problem_history.db` and {glue:md}`driver_history.db`, respectively. If {glue:md}`--driver_recorder` is set to the string `\"None\"`, then the driver case recorder file is ignored. This is useful if the user is not interested in seeing dashboard tabs related to driver history. If that file is large, it could unnecessarily be read and slow down the generation of the dashboard significantly.\n", "\n", "### Saving and Sharing Dashboards\n", "\n", - "The user can also save a dashboard and share it with other users to view. The dashboard is saved as a zip file. To save a dashboard to a file, use the `--save` option. For example, \n", + "The user can also save a dashboard and share it with other users to view. The dashboard is saved as a zip file. To save a dashboard to a file, use the {glue:md}`--save` option. For example, \n", "\n", "```bash\n", "aviary dashboard --save run_aviary_example --problem_recorder=problem_final_case.db --driver_recorder=driver_cases.db\n", "```\n", "\n", - "By default, the zip file is named based on the name of the problem. So in this example, the saved zip file will be named `run_aviary_example.zip`. \n", + "By default, the zip file is named based on the name of the problem. So in this example, the saved zip file will be named {glue:md}`run_aviary_example.zip`.\n", "\n", - "If the user wants to save to a different file, they can provide that file name as an argument to the `save` option as in this example:\n", + "If the user wants to save to a different file, they can provide that file name as an argument to the {glue:md}`--save` option as in this example:\n", "\n", "```bash\n", "aviary dashboard --save saved_dashboard.zip run_aviary_example --problem_recorder=problem_final_case.db --driver_recorder=driver_cases.db\n", @@ -121,7 +186,7 @@ "```\n", "\n", "Running this form of the dashboard command will result in a new directory being created in the `reports` directory. For the example, this\n", - "directory is named `reports/saved_dashboard`. If that directory existed previously, the command will fail to prevent the existing directory from being overwritten. The user can force that overwriting to happen by using the `--force` option, as shown in this example:\n", + "directory is named `reports/saved_dashboard`. If that directory existed previously, the command will fail to prevent the existing directory from being overwritten. The user can force that overwriting to happen by using the {glue:md}`--force` option, as shown in this example:\n", "\n", "```bash\n", "aviary dashboard --force saved_dashboard.zip\n", @@ -147,7 +212,7 @@ " - It contains the following columns: absolute name, source name, source is IVC, source is DV, units, shape, tags, val, min val, and max val. Here, `IVC` is the abbreviation of `IndepVarComp` and `DV` is the abbreviation of \"design variable\".\n", "- `n2.html`\n", " - This is an OpenMDAO model hierarchy and an N-squared diagram in the shape of a matrix, representing functional or physical interfaces between system elements. It can be used to systematically identify, define, tabulate, design, and analyze functional and physical interfaces.\n", - " - More information can be found at OpenMDAO's [N2 Basics](https://openmdao.org/newdocs/versions/latest/features/model_visualization/n2_basics/n2_basics.html) and [N2 Details](https://openmdao.org/newdocs/versions/latest/features/model_visualization/n2_details/n2_details.html). There is a tutorial on [YouTub e](https://www.youtube.com/watch?v=42VtbX6CX3A).\n", + " - More information can be found at OpenMDAO's [N2 Basics](https://openmdao.org/newdocs/versions/latest/features/model_visualization/n2_basics/n2_basics.html) and [N2 Details](https://openmdao.org/newdocs/versions/latest/features/model_visualization/n2_details/n2_details.html). There is a tutorial on [YouTube](https://www.youtube.com/watch?v=42VtbX6CX3A).\n", "- `opt_report.html`\n", " - This is the OpenMDAO Optimization Report. It writes a summary of results of an optimization run.\n", " - OpenMDAO reference is at [Optimization Report](https://openmdao.org/newdocs/versions/latest/features/reports/optimization_report.html).\n", @@ -271,7 +336,8 @@ "except ImportError:\n", " pass # SNOPT might not be available\n", "run_and_check(av.Verbosity.DEBUG,optimizer='IPOPT')\n", - "run_and_check(av.Verbosity.DEBUG,optimizer='SLSQP')\n" + "run_and_check(av.Verbosity.DEBUG,optimizer='SLSQP')\n", + "\n" ] }, { @@ -282,7 +348,7 @@ "\n", "There is an optimizer output. If {glue:md}`SNOPT` is the optimizer, {glue:md}`SNOPT_print.out` is generated. The SNOPT output is a detailed output of the optimizer performance. New users likely will want to exercise caution when viewing this output, as it includes some advanced information.\n", "\n", - "If {glue:md}`IPOPT` is the optimizer, {glue:md}`IPOPT.out` is generated. If {glue:md}`SLSQP` is the optimizer and `pyOptSparseDriver` is the driver, {glue:md}`SLSQP.out` is generated.\n", + "If {glue:md}`IPOPT` is the optimizer, {glue:md}`IPOPT.out` is generated. If {glue:md}`SLSQP` is the optimizer and [`pyOptSparseDriver`](https://openmdao.org/newdocs/versions/latest/features/building_blocks/drivers/pyoptsparse_driver.html) is the driver, {glue:md}`SLSQP.out` is generated.\n", "\n", "{glue:md}`verbosity_files`\n", "\n", @@ -332,7 +398,7 @@ ], "metadata": { "kernelspec": { - "display_name": "latest_env", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -346,7 +412,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From 30c6d3b414facea41e5824c63f86cebd45fcb215 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 11 Dec 2024 15:22:34 -0800 Subject: [PATCH 25/48] work in progress --- .../user_guide/pre_mission_and_mission.ipynb | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/aviary/docs/user_guide/pre_mission_and_mission.ipynb b/aviary/docs/user_guide/pre_mission_and_mission.ipynb index e82566fc6..03e944115 100644 --- a/aviary/docs/user_guide/pre_mission_and_mission.ipynb +++ b/aviary/docs/user_guide/pre_mission_and_mission.ipynb @@ -36,7 +36,7 @@ "\n", "Systems within the mission group are often vectorized.\n", "This is possible because the systems are evaluated at each analysis point independently of the other analysis points when using {term}`collocation integration methods`.\n", - "Within Aviary, the number of mission analysis points is called `num_nodes`." + "Within Aviary, the number of mission analysis points is called {glue:md}`num_nodes`." ] }, { @@ -50,9 +50,19 @@ "outputs": [], "source": [ "# Testing Cell\n", + "import inspect\n", "from aviary.mission.phase_builder_base import PhaseBuilderBase\n", - "from aviary.utils.doctape import check_args\n", - "check_args(PhaseBuilderBase.__init__,'num_nodes')" + "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", + "from aviary.utils.doctape import check_args, glue_variable\n", + "check_args(PhaseBuilderBase.__init__,'num_nodes')\n", + "glue_variable('num_nodes', md_code=True)\n", + "glue_variable(f'{SubsystemBuilderBase=}'.split('=')[0], md_code=True)\n", + "\n", + "# Get all functions of class AviaryProblem\n", + "functs = inspect.getmembers(SubsystemBuilderBase, predicate=inspect.isfunction)\n", + "for name, func in functs:\n", + " if not name.startswith('_') and name == 'get_parameters':\n", + " glue_variable(name + '()', md_code=True)" ] }, { @@ -69,7 +79,7 @@ "## The Bus System in Aviary\n", "\n", "Within Aviary, you might want to connect a pre-mission system to a mission system.\n", - "Variables that include a `':'` (which includes all variables that start with `aircraft:` and `mission:`) are connected when you use the `get_parameters()` method within `SubsystemBuilderBase`.\n", + "Variables that include a `':'` (which includes all variables that start with `aircraft:` and `mission:`) are connected when you use the {glue:md}`get_parameters()` method within {glue:md}`SubsystemBuilderBase`.\n", "However, you might want to connect a variable from a pre-mission system to a mission system that does not begin with `'aircraft:'`.\n", "For example, you might have a subsystem that has some computations in the pre-mission system that you want to connect to the mission system, but you don't necessarily want to expose those variables to the rest of Aviary.\n", "The bus system is also useful if you have variables that begin with `'aircraft:'` but you don't want them exposed to the rest of Aviary.\n", @@ -77,7 +87,7 @@ "To do this, you can use the \"bus\" system.\n", "The bus system allows you to connect variables from the pre-mission system to the mission system based on what you specify.\n", "This is especially relevant when you're using external subsystems as core Aviary does not use the bus system internally.\n", - "The notion of the bus system is detailed more within the `SubsystemBuilderBase` docstrings.\n" + "The notion of the bus system is detailed more within the {glue:md}`SubsystemBuilderBase` docstrings.\n" ] }, { @@ -110,7 +120,7 @@ ], "metadata": { "kernelspec": { - "display_name": "latest_env", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -124,7 +134,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From b30e5560d6200691ee59eb9820131299b688684b Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 11 Dec 2024 19:17:02 -0800 Subject: [PATCH 26/48] glue variables in propulsion.ipynb --- aviary/docs/user_guide/propulsion.ipynb | 321 ++++++++++++++++++++++-- 1 file changed, 297 insertions(+), 24 deletions(-) diff --git a/aviary/docs/user_guide/propulsion.ipynb b/aviary/docs/user_guide/propulsion.ipynb index 83489c562..faf0817b9 100644 --- a/aviary/docs/user_guide/propulsion.ipynb +++ b/aviary/docs/user_guide/propulsion.ipynb @@ -51,37 +51,282 @@ "\n", "| Variable | Default Units | Required? |\n", "| :--- | :--- | :---: |\n", - "| `Mach Number` | unitless | ✔ |\n", - "| `Altitude` | ft | ✔ |\n", - "| `Throttle` | unitless | ✔ |\n", - "| `Hybrid Throttle` | unitless | ✘ |\n", - "| `Net Thrust` | lbf | ✔* |\n", - "| `Gross Thrust` | lbf | ✘ |\n", - "| `Ram Drag` | lbf | ✘ |\n", - "| `Fuel Flow Rate` | lbm/h | ✘ |\n", - "| `Electric Power` | kW | ✘ |\n", - "| `NOx Rate` | lbm/h | ✘ |\n", - "| `T4 Temperature` | degR | ✘ |\n", + "| {glue:md}`Mach Number` | unitless | ✔ |\n", + "| {glue:md}`Altitude` | ft | ✔ |\n", + "| {glue:md}`Throttle` | unitless | ✔ |\n", + "| {glue:md}`Hybrid Throttle` | unitless | ✘ |\n", + "| {glue:md}`Net Thrust` | lbf | ✔* |\n", + "| {glue:md}`Gross Thrust` | lbf | ✘ |\n", + "| {glue:md}`Ram Drag` | lbf | ✘ |\n", + "| {glue:md}`Fuel Flow Rate` | lbm/h | ✘ |\n", + "| {glue:md}`Electric Power` | kW | ✘ |\n", + "| {glue:md}`NOx Rate` | lbm/h | ✘ |\n", + "| {glue:md}`T4 Temperature` | degR | ✘ |\n", "\n", - "**`Net Thrust` (defined as `Gross Thrust` - `Ram Drag`) is not required if both of those variables are provided for calculation*\n", + "**{glue:md}`Net Thrust` (defined as {glue:md}`Gross Thrust` - {glue:md}`Ram Drag`) is not required if both of those variables are provided for calculation*\n", "\n", - "`Mach Number`, `Altitude`, and the two throttle parameters are independent variables required to describe the operating conditions of the engine. `Hybrid Throttle` is optional, and is intended for use as a second degree of control for engines using independently controllable fuel- and electric-based power. The remaining variables are dependent on the operating conditions and are therefore typically optional.\n", + "{glue:md}`Mach Number`, {glue:md}`Altitude`, and the two throttle parameters are independent variables required to describe the operating conditions of the engine. {glue:md}`Hybrid Throttle` is optional, and is intended for use as a second degree of control for engines using independently controllable fuel- and electric-based power. The remaining variables are dependent on the operating conditions and are therefore typically optional.\n", "\n", - "Engine decks without headers are assumed to contain only the required variable set, in the order specified by the table (`Mach`, `Altitude`, `Throttle`, and `Net Thrust`), and with default units.\n", + "Engine decks without headers are assumed to contain only the required variable set, in the order specified by the table ({glue:md}`Mach`, {glue:md}`Altitude`, {glue:md}`Throttle`, and {glue:md}`Net Thrust`), and with default units.\n", "\n", "Comments may be added to an engine deck data file by using a '`#`' symbol preceding the comment. Anything after this symbol on that line is ignored by Aviary, allowing the user to temporarily remove data points or add in-line comments with context for the data. It is good practice to include comments at the start of the file to explain what kind of engine the data represents, and where it came from." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "e0344b4f", "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/markdown": [ + "`Mach Number`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Mach Number" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Altitude`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Altitude" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Throttle`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Throttle" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Hybrid Throttle`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Hybrid Throttle" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Net Thrust`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Net Thrust" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Gross Thrust`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Gross Thrust" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Ram Drag`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Ram Drag" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Fuel Flow Rate`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Fuel Flow Rate" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Electric Power`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Electric Power" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`NOx Rate`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "NOx Rate" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`T4 Temperature`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "T4 Temperature" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Mach`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Mach" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "* `Aircraft.Engine.SCALE_PERFORMANCE`\n", + "* `Aircraft.Engine.IGNORE_NEGATIVE_THRUST`\n", + "* `Aircraft.Engine.GEOPOTENTIAL_ALT`\n", + "* `Aircraft.Engine.GENERATE_FLIGHT_IDLE`\n", + "* `Aircraft.Engine.NUM_WING_ENGINES` and/or `Aircraft.Engine.NUM_FUSELAGE_ENGINES`\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "required_options" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "* `Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION`\n", + "* `Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION`\n", + "* `Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION`\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "flight_idle_options" + } + }, + "output_type": "display_data" + } + ], "source": [ "# Testing Cell\n", "from aviary.api import Aircraft\n", @@ -95,6 +340,12 @@ " 'T4 Temperature']\n", "required = ['Mach', 'Altitude', 'Throttle', 'Net Thrust']\n", "\n", + "for var in vars:\n", + " glue_variable(var, md_code=True)\n", + "for var in required:\n", + " if not var in vars:\n", + " glue_variable(var, md_code=True)\n", + "\n", "def str_to_enum(list_of_vars):\n", " for ii, var in enumerate(list_of_vars):\n", " for enum, alias in aliases.items():\n", @@ -179,7 +430,25 @@ "remove-cell" ] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/markdown": [ + "`EngineModel`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "EngineModel" + } + }, + "output_type": "display_data" + } + ], "source": [ "# Testing Cell\n", "from aviary.api import Aircraft\n", @@ -188,7 +457,7 @@ "ae = Aircraft.Engine\n", "\n", "required = (ae.FLIGHT_IDLE_THRUST_FRACTION, ae.FLIGHT_IDLE_MIN_FRACTION, ae.FLIGHT_IDLE_MAX_FRACTION)\n", - "check_value(required,dependent_options[ae.GENERATE_FLIGHT_IDLE])" + "check_value(required,dependent_options[ae.GENERATE_FLIGHT_IDLE])\n" ] }, { @@ -198,9 +467,9 @@ "source": [ "### Intermediate Guide\n", "\n", - "Engine models are defined in Aviary using an `EngineModel` object. An `EngineModel` is responsible for handling many tasks required to prepare an engine for use in Aviary, such as reading engine data from a file in the case of an `EngineDeck` (which is a child class of `EngineModel`). \n", + "Engine models are defined in Aviary using an {glue:md}`EngineModel` object. An {glue:md}`EngineModel` is responsible for handling many tasks required to prepare an engine for use in Aviary, such as reading engine data from a file in the case of an {glue:md}`EngineDeck` (which is a child class of {glue:md}`EngineModel`). \n", "\n", - "An `EngineModel` (and classes inheriting it) can be manually created and added to the Aviary problem. This is extremely useful when setting up an aircraft with multiple heterogenous types, each with unique properties, or using a custom engine model. An `EngineModel` requires an `AviaryValues` object containing the variables required for that engine (such as those outlined in the Beginner Guide example for `EngineDecks`)." + "An {glue:md}`EngineModel` (and classes inheriting it) can be manually created and added to the Aviary problem. This is extremely useful when setting up an aircraft with multiple heterogenous types, each with unique properties, or using a custom engine model. An {glue:md}`EngineModel` requires an {glue:md}`AviaryValues` object containing the variables required for that engine (such as those outlined in the Beginner Guide example for {glue:md}`EngineDeck`)." ] }, { @@ -223,7 +492,11 @@ "\n", "check_value(EngineDeck.__base__, EngineModel)\n", "type_hint = inspect.signature(EngineModel).parameters['options'].annotation\n", - "check_value(type_hint, AviaryValues)" + "check_value(type_hint, AviaryValues)\n", + "\n", + "glue_variable(f'{EngineModel=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{EngineDeck=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{AviaryValues=}'.split('=')[0], md_code=True)" ] }, { @@ -257,7 +530,7 @@ "id": "19e31c3b", "metadata": {}, "source": [ - "Once an `EngineModel` has been created, it must be added to the Aviary analysis you want to perform. The simplest way to do this is to take advantage of the propulsion preprocessor utility. This preprocessor handles all of the details of getting data related to `EngineModels`, which may change during initialization, correctly set up in the `AviaryValues` object which is used to define the vehicle at the Aviary problem level." + "Once an {glue:md}`EngineModel` has been created, it must be added to the Aviary analysis you want to perform. The simplest way to do this is to take advantage of the propulsion preprocessor utility. This preprocessor handles all of the details of getting data related to {glue:md}`EngineModel`, which may change during initialization, correctly set up in the {glue:md}`AviaryValues` object which is used to define the vehicle at the Aviary problem level." ] }, { @@ -332,7 +605,7 @@ ], "metadata": { "kernelspec": { - "display_name": "latest_env", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -346,7 +619,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From 46191d274264db526e3f9e7eb936c128a52ec60e Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 12 Dec 2024 11:16:13 -0800 Subject: [PATCH 27/48] remove a print statement --- .../docs/user_guide/postprocessing_and_visualizing_results.ipynb | 1 - 1 file changed, 1 deletion(-) diff --git a/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb b/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb index 669bf8a84..7970a7382 100644 --- a/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb +++ b/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb @@ -18,7 +18,6 @@ "\n", "# make sure that the path exists.\n", "str_run_aviary_example = 'run_aviary_example'\n", - "print('examples/' + str_run_aviary_example + '.py')\n", "get_path('examples/' + str_run_aviary_example + '.py')\n", "glue_variable('aviary/examples', md_code=True)\n", "glue_variable(str_run_aviary_example + '.py', md_code=True)\n", From d0491749de46fe4c6bd161b729ca52c82ed9fc38 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 12 Dec 2024 11:24:02 -0800 Subject: [PATCH 28/48] glue variables in reserve_missions.ipynb --- aviary/docs/user_guide/reserve_missions.ipynb | 434 ++++++++++++++++-- 1 file changed, 407 insertions(+), 27 deletions(-) diff --git a/aviary/docs/user_guide/reserve_missions.ipynb b/aviary/docs/user_guide/reserve_missions.ipynb index 42a13eb58..6f5cb358d 100644 --- a/aviary/docs/user_guide/reserve_missions.ipynb +++ b/aviary/docs/user_guide/reserve_missions.ipynb @@ -1,5 +1,239 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "height_energy" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "height_energy" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "2DOF" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "2DOF" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "collocation" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "collocation" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "shooting" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "shooting" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`phase_info`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "phase_info" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`run_reserve_mission_multiphase.py`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "run_reserve_mission_multiphase.py" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`run_2dof_reserve_mission_multiphase.py`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "run_2dof_reserve_mission_multiphase.py" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`check_and_preprocess_inputs()`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "check_and_preprocess_inputs()" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`prob.check_and_preprocess_inputs()`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "prob.check_and_preprocess_inputs()" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`load_inputs()`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "load_inputs()" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`prob.load_inputs()`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "prob.load_inputs()" + } + }, + "output_type": "display_data" + } + ], + "source": [ + "# Testing Cell\n", + "import inspect\n", + "import aviary.api as av\n", + "from aviary.interface.methods_for_level2 import AviaryGroup, AviaryProblem\n", + "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.functions import get_path\n", + "\n", + "glue_variable(av.EquationsOfMotion.HEIGHT_ENERGY.value, md_code=False)\n", + "glue_variable(av.EquationsOfMotion.TWO_DEGREES_OF_FREEDOM.value, md_code=False)\n", + "\n", + "AnalysisScheme = av.AnalysisScheme\n", + "str_collocation = f'{AnalysisScheme.COLLOCATION=}'.split('=')[0]\n", + "str_collocation = str_collocation.split('.')[1].lower()\n", + "glue_variable(str_collocation, md_code=False)\n", + "str_shooting = f'{AnalysisScheme.SHOOTING=}'.split('=')[0]\n", + "str_shooting = str_shooting.split('.')[1].lower()\n", + "glue_variable(str_shooting, md_code=False)\n", + "\n", + "ag = AviaryGroup()\n", + "opts = list(ag.options)\n", + "for opt in opts:\n", + " if opt == 'phase_info':\n", + " glue_variable('phase_info', md_code=True)\n", + "\n", + "str_run_aviary_example = 'run_reserve_mission_multiphase'\n", + "get_path('examples/reserve_missions/' + str_run_aviary_example + '.py')\n", + "glue_variable(str_run_aviary_example + '.py', md_code=True)\n", + "\n", + "str_run_aviary_example = 'run_2dof_reserve_mission_multiphase'\n", + "get_path('examples/reserve_missions/' + str_run_aviary_example + '.py')\n", + "glue_variable(str_run_aviary_example + '.py', md_code=True)\n", + "\n", + "# Get all functions of class AviaryProblem\n", + "methods = inspect.getmembers(AviaryProblem, predicate=inspect.isfunction)\n", + "for name, func in methods:\n", + " if not name.startswith('_') and name in ['check_and_preprocess_inputs', 'load_inputs']:\n", + " glue_variable(name + '()', md_code=True)\n", + " glue_variable('prob.' + name + '()', md_code=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -10,19 +244,19 @@ "\n", "Reserve missions are enabled for the following mission types:\n", "\n", - "* height_energy (completed)\n", - "* 2DOF (collocation) (complete)\n", - "* 2DOF (shooting) (in-progress)\n", - "* height_energy (shooting) (future work)\n", + "* {glue:md}`height_energy` ({glue:md}`collocation`) (completed)\n", + "* {glue:md}`2DOF` ({glue:md}`collocation`) (complete)\n", + "* {glue:md}`2DOF` ({glue:md}`shooting`) (in-progress)\n", + "* {glue:md}`height_energy` ({glue:md}`shooting`) (future work)\n", "\n", - "A reserve mission can be created by appending one or more reserve phases to `phase_info` after the last phase of the regular mission.\n", - "To create a simple reserve mission, copy your current cruise phase which is located in `phase_info`.\n", + "A reserve mission can be created by appending one or more reserve phases to {glue:md}`phase_info` after the last phase of the regular mission.\n", + "To create a simple reserve mission, copy your current cruise phase which is located in {glue:md}`phase_info`.\n", "\n", "```{note}\n", "You may need to revise some of your assumptions for the copied phase if you are making a reserve phase that is radically different than the original (i.e. original phase was to travel 3000km but reserve phase is 100km).\n", "```\n", "\n", - "Append that phase to the end of `phase_info`, name it `reserve_cruise` and add `\"reserve\": True,` to `user_options` for this phase.\n", + "Append that phase to the end of {glue:md}`phase_info`, name it `reserve_cruise` and add `\"reserve\": True,` to `user_options` for this phase.\n", "There are two optional flags that can now be added to `user_options`.\n", "The `\"target_duration\"` option creates a phase requiring the aircraft to fly for a specific amount of time.\n", "The `\"target_distance\"` option creates a phase requiring the aircraft to fly for a specific distance.\n", @@ -73,7 +307,7 @@ "metadata": {}, "source": [ "You can chain together multiple reserve phases to make a complete reserve mission (i.e. climb to altitude, cruise for range, cruise for time, then descend).\n", - "Examples of this are shown in `run_reserve_mission_multiphase.py` and `run_2dof_reserve_mission_multiphase.py`." + "Examples of this are shown in {glue:md}`run_reserve_mission_multiphase.py` and {glue:md}`run_2dof_reserve_mission_multiphase.py`." ] }, { @@ -114,10 +348,10 @@ "\n", "### Caveats when using 2DOF\n", "\n", - "If you are using 2DOF equations of motion (EOM) in your problem (i.e. `settings:equations_of_motion,2DOF`) there are some additional things you need to be aware of.\n", - "The name of the reserve phase should include one of the keywords to indicate which EOM from 2DOF will be selected and the prefix `reserve_`.\n", + "If you are using {glue:md}`2DOF` equations of motion (EOM) in your problem (i.e. `settings:equations_of_motion,2DOF`) there are some additional things you need to be aware of.\n", + "The name of the reserve phase should include one of the keywords to indicate which EOM from {glue:md}`2DOF` will be selected and the prefix `reserve_`.\n", "Valid keywords include: `rotation`, `accel`, `ascent`, `climb1`, `climb2`, `cruise`, `desc1`, `desc2`.\n", - "This is because 2DOF uses different EOMs for different phases and we need to let `methods_for_level2.py` know which method to select.\n", + "This is because {glue:md}`2DOF` uses different EOMs for different phases and we need to let `methods_for_level2.py` know which method to select.\n", "This is why in the example in the first paragraph above, the phase was named `reserve_cruise`.\n", "Cruise phases can have additional information in suffixes, but this isn't necessary.\n", "Do not worry about phase naming if you are using Height-Energy EOM as all those EOMs are the same for every phase." @@ -151,21 +385,21 @@ "source": [ "## Theory\n", "\n", - "When adding a reserve phase, `check_and_preprocess_inputs()` divides all the phases into two dictionaries: `regular_phases` which contain your nominal phases and `reserve_phases` which contains any phases with the `reserve` flag set to `True`.\n", - "Additionally, `check_and_preprocess_inputs()` will add the `\"analytic\"` flag to each phase.\n", + "When adding a reserve phase, {glue:md}`check_and_preprocess_inputs()` divides all the phases into two dictionaries: `regular_phases` which contain your nominal phases and `reserve_phases` which contains any phases with the `reserve` flag set to `True`.\n", + "Additionally, {glue:md}`check_and_preprocess_inputs()` will add the `\"analytic\"` flag to each phase.\n", "This is used to indicate if a phase is an analytic phase (i.e. Breguet range) or a ordinary differential equation (ODE).\n", "\n", "Only the final mission mass and range from `regular_phases` are automatically connected to the first point of the `reserve_phases`.\n", "All other state variables (i.e. altitude, mach) are not automatically connected, allowing you to start the reserve mission at whatever altitude you want.\n", "\n", - "The `\"analytic\"` flag helps to properly connect phases for 2DOF missions.\n", - "2DOF `cruise` missions are analytic because they use a Breguet range calculation instead of integrating an EOM. \n", + "The `\"analytic\"` flag helps to properly connect phases for {glue:md}`2DOF` missions.\n", + "{glue:md}`2DOF` `cruise` missions are analytic because they use a Breguet range calculation instead of integrating an EOM. \n", "Analytic phases have a slightly different naming convention in order to access state/timeseries variables like distance, mass, and range compared with their non-analytic counterparts.\n", "\n", "You cannot create a reserve mission that enforces time or range constraints over multiple phases (i.e specify the total range covered by a climb + cruise + descent).\n", "This is because each constraint `\"target_distance\"` or `\"target_time\"` is only enforced on a single phase.\n", "\n", - "It is essential that you run `prob.check_and_preprocess_inputs()` after `prob.load_inputs()` to make sure that regular and reserve phases are separated via `phase_separator()`." + "It is essential that you run {glue:md}`prob.check_and_preprocess_inputs()` after {glue:md}`prob.load_inputs()` to make sure that regular and reserve phases are separated via `phase_separator()`." ] }, { @@ -212,7 +446,7 @@ "### Advanced Users and Target Duration Phases\n", "\n", "For advanced users, instead of just copying a phase you used before, you might completely specify a new phase from scratch. \n", - "When creating a `\"target_duration\"` reserve phase there are a number of values inside of `phase_info['user_options']` that are overwritten in `check_and_preprocess_inputs()`. \n", + "When creating a `\"target_duration\"` reserve phase there are a number of values inside of `phase_info['user_options']` that are overwritten in {glue:md}`check_and_preprocess_inputs()`. \n", "Specifically, `duration_bounds`, `fixed_duration`, and `\"initial_guesses\": {\"time\"}` will be over-written. \n", "That is because if `\"target_duration\"` is specified, Aviary already knows what these other three values need to be: `target_duration = duration_bounds = \"initial_guesses\": {\"time\"}`, and `fix_duration = True`." ] @@ -266,38 +500,184 @@ "source": [ "### Fuel Burn Calculations\n", "\n", - "Fuel burn during the regular mission (`Mission.Summary.FUEL_BURNED`) is calculated only based on `regular_phases`.\n", + "Fuel burn during the regular mission ({glue:md}`Mission.Summary.FUEL_BURNED`) is calculated only based on `regular_phases`.\n", "\n", - "Reserve fuel (`Mission.Design.RESERVE_FUEL`) is the sum of `Aircraft.Design.RESERVE_FUEL_ADDITIONAL`, `Aircraft.Design.RESERVE_FUEL_FRACTION`, and `Mission.Summary.RESERVE_FUEL_BURNED`.\n", + "Reserve fuel ({glue:md}`Mission.Design.RESERVE_FUEL`) is the sum of {glue:md}`Aircraft.Design.RESERVE_FUEL_ADDITIONAL`, {glue:md}`Aircraft.Design.RESERVE_FUEL_FRACTION`, and {glue:md}`Mission.Summary.RESERVE_FUEL_BURNED`.\n", "\n", - "* `RESERVE_FUEL_ADDITIONAL` is a fixed value (i.e. 300kg)\n", - "* `RESERVE_FUEL_FRACTION` is based on a fraction of `Mission.Summary.FUEL_BURNED`\n", - "* `RESERVE_FUEL_BURNED` is sum of fuel burn in all `reserve_phases`\n" + "* {glue:md}`RESERVE_FUEL_ADDITIONAL` is a fixed value (i.e. 300kg)\n", + "* {glue:md}`RESERVE_FUEL_FRACTION` is based on a fraction of {glue:md}`Mission.Summary.FUEL_BURNED`\n", + "* {glue:md}`RESERVE_FUEL_BURNED` is sum of fuel burn in all `reserve_phases`\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/markdown": [ + "`Mission.Summary.FUEL_BURNED`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Mission.Summary.FUEL_BURNED" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Mission.Design.RESERVE_FUEL`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Mission.Design.RESERVE_FUEL" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Aircraft.Design.RESERVE_FUEL_ADDITIONAL`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Aircraft.Design.RESERVE_FUEL_ADDITIONAL" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Aircraft.Design.RESERVE_FUEL_FRACTION`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Aircraft.Design.RESERVE_FUEL_FRACTION" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`Mission.Summary.RESERVE_FUEL_BURNED`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "Mission.Summary.RESERVE_FUEL_BURNED" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`RESERVE_FUEL_ADDITIONAL`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "RESERVE_FUEL_ADDITIONAL" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`RESERVE_FUEL_FRACTION`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "RESERVE_FUEL_FRACTION" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`RESERVE_FUEL_BURNED`" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "scrapbook": { + "mime_prefix": "", + "name": "RESERVE_FUEL_BURNED" + } + }, + "output_type": "display_data" + } + ], "source": [ "# Testing Cell\n", "from aviary.api import Aircraft, Mission\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "Mission.Summary.FUEL_BURNED;\n", "Mission.Design.RESERVE_FUEL;\n", "Aircraft.Design.RESERVE_FUEL_ADDITIONAL;\n", "Aircraft.Design.RESERVE_FUEL_FRACTION;\n", - "Mission.Summary.RESERVE_FUEL_BURNED;" + "Mission.Summary.RESERVE_FUEL_BURNED;\n", + "glue_variable(get_variable_name(Mission.Summary.FUEL_BURNED), md_code=True)\n", + "glue_variable(get_variable_name(Mission.Design.RESERVE_FUEL), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Design.RESERVE_FUEL_ADDITIONAL), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Design.RESERVE_FUEL_FRACTION), md_code=True)\n", + "glue_variable(get_variable_name(Mission.Summary.RESERVE_FUEL_BURNED), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Design.RESERVE_FUEL_ADDITIONAL).split('.')[2], md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Design.RESERVE_FUEL_FRACTION).split('.')[2], md_code=True)\n", + "glue_variable(get_variable_name(Mission.Summary.RESERVE_FUEL_BURNED).split('.')[2], md_code=True)" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -311,7 +691,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.9.18" } }, "nbformat": 4, From 7c8a7d731115c6cc8d1be854b64579762250acb4 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 12 Dec 2024 15:49:26 -0800 Subject: [PATCH 29/48] glue variables in SGM_capabilities.ipynb --- aviary/docs/user_guide/SGM_capabilities.ipynb | 111 +++++++++++++++--- 1 file changed, 96 insertions(+), 15 deletions(-) diff --git a/aviary/docs/user_guide/SGM_capabilities.ipynb b/aviary/docs/user_guide/SGM_capabilities.ipynb index b8e008215..84ae3deb6 100644 --- a/aviary/docs/user_guide/SGM_capabilities.ipynb +++ b/aviary/docs/user_guide/SGM_capabilities.ipynb @@ -1,5 +1,26 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.interface.methods_for_level2 import AviaryGroup\n", + "from aviary.utils.doctape import glue_variable\n", + "#from aviary.interface.default_phase_info.two_dof_fiti import\n", + "ag = AviaryGroup()\n", + "opts = list(ag.options)\n", + "for opt in opts:\n", + " if opt == 'phase_info':\n", + " glue_variable('phase_info', md_code=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -27,6 +48,7 @@ }, "outputs": [], "source": [ + "# Testing Cell\n", "from aviary.mission.gasp_based.ode.base_ode import BaseODE\n", "from aviary.variable_info.variables import Dynamic, Mission, Aircraft\n", "from aviary.variable_info.enums import AnalysisScheme, LegacyCode\n", @@ -81,11 +103,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "these functions allow the user to leave the EOMs unmodified for collocation vs shooting, and provide an easy way to set the units, default values, and any other keyword args for the OpenMDAO functions [add_input and add_output](https://openmdao.org/newdocs/versions/latest/features/core_features/working_with_components/continuous_variables.html) for any variables that only used by SGM.\n", + "These functions allow the user to leave the EOMs unmodified for collocation vs shooting, and provide an easy way to set the units, default values, and any other keyword args for the OpenMDAO functions [add_input and add_output](https://openmdao.org/newdocs/versions/latest/features/core_features/working_with_components/continuous_variables.html) for any variables that only used by SGM.\n", "\n", "## Setting up Phases\n", "\n", - "Each SGM phase should inherit from SimuPyProblem and requires an instantiated ODE. If no states are provided Aviary will attempt to determine the states in the current phase by finding the state rates (any output that ends in `'_rate'`). States and their rates are expected to have the same name (other than the addition of the `'_rate'` suffix for the state rate), if the state rate associated with a state doesn't follow this pattern, it can be specified through `alternate_state_rate_names`, a dictionary with state names as the keys and the desired state rate as the value." + "Each SGM phase should inherit from SimuPyProblem and requires an instantiated ODE. If no states are provided Aviary will attempt to determine the states in the current phase by finding the state rates (any output that ends in `'_rate'`). States and their rates are expected to have the same name (other than the addition of the `'_rate'` suffix for the state rate), if the state rate associated with a state doesn't follow this pattern, it can be specified through {glue:md}`alternate_state_rate_names`, a dictionary with state names as the keys and the desired state rate as the value." ] }, { @@ -100,12 +122,13 @@ "source": [ "# Testing Cell\n", "from aviary.mission.gasp_based.ode.time_integration_base_classes import SimuPyProblem\n", - "from aviary.utils.doctape import check_args, check_value\n", + "from aviary.utils.doctape import check_args, check_value, glue_variable\n", "import inspect\n", "\n", "rate_suffix = inspect.signature(SimuPyProblem).parameters['rate_suffix'].default\n", "check_value(rate_suffix, '_rate')\n", - "check_args(SimuPyProblem,'alternate_state_rate_names')" + "check_args(SimuPyProblem,'alternate_state_rate_names')\n", + "glue_variable('alternate_state_rate_names', md_code=True)" ] }, { @@ -151,7 +174,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "One of the main benefits of SGM is the ability to add arbitrarily ordered phases using triggers. Aviary uses an `event_trigger` class to store the information necessary for SGM phases. Instantiated event_triggers can be passed directly to the problem, or the helper function self.add_trigger can be used to generate the triggers. Triggers are generally used to check when the value of a state reaches a certain value, but can be used with any output from the ODE, such as `normal_force` in SGMRotation. Multiple triggers can be added to one phase, but the event will be triggered by whichever condition is met first." + "One of the main benefits of SGM is the ability to add arbitrarily ordered phases using triggers. Aviary uses an {glue:md}`event_trigger` class to store the information necessary for SGM phases. Instantiated {glue:md}`event_triggers` can be passed directly to the problem, or the helper function self.add_trigger can be used to generate the triggers. Triggers are generally used to check when the value of a state reaches a certain value, but can be used with any output from the ODE, such as `normal_force` in {glue:md}`SGMRotation`. Multiple triggers can be added to one phase, but the event will be triggered by whichever condition is met first." ] }, { @@ -165,12 +188,27 @@ "outputs": [], "source": [ "# Testing Cell\n", + "import inspect\n", "from aviary.mission.gasp_based.ode.time_integration_base_classes import event_trigger\n", "from aviary.mission.gasp_based.phases.time_integration_phases import SGMRotation\n", - "from aviary.utils.doctape import check_value\n", + "from aviary.mission.gasp_based.phases.time_integration_traj import FlexibleTraj\n", + "from aviary.utils.doctape import check_value, glue_variable\n", + "#from aviary.interface.default_phase_info.two_dof_fiti import add_default_sgm_args\n", "\n", "rotation_trigger: event_trigger = SGMRotation(ode_args=ode_args).triggers[0]\n", - "check_value(rotation_trigger.state,'normal_force')\n" + "check_value(rotation_trigger.state,'normal_force')\n", + "glue_variable(f'{event_trigger=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{event_trigger=}'.split('=')[0]+'s', md_code=False)\n", + "glue_variable(f'{SGMRotation=}'.split('=')[0], md_code=False)\n", + "glue_variable(f'{FlexibleTraj=}'.split('=')[0], md_code=False)\n", + "\n", + "signature = inspect.signature(SGMRotation.__init__)\n", + "# Print argument details\n", + "for param_name, param in signature.parameters.items():\n", + " if param_name != \"self\":\n", + " glue_variable(param_name, md_code=True)\n", + "\n", + "glue_variable('two_dof_fiti', md_code=True)" ] }, { @@ -179,7 +217,7 @@ "source": [ "## Setting up Trajectories\n", "\n", - "Aviary problems using the shooting method use `FlexibleTraj` to define their trajectories, instead of `dm.Trajectory()`. Similar to collocation problems, SGM will loop through the phases specified in the `phase_info` to build up the trajectory. When creating an SGM trajectory, the variables that will be used as inputs and outputs for states, triggers, and variables, including phase specific ones, are specified." + "Aviary problems using the shooting method use {glue:md}`FlexibleTraj` to define their trajectories, instead of `dm.Trajectory()`. Similar to collocation problems, SGM will loop through the phases specified in the {glue:md}`phase_info` to build up the trajectory. When creating an SGM trajectory, the variables that will be used as inputs and outputs for states, triggers, and variables, including phase specific ones, are specified." ] }, { @@ -223,12 +261,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Because all phases require `ode_args` and `simupy_args` which are usually the same for all phases, `add_default_sgm_args` has been provided to add these to the phase info automatically.\n", + "Because all phases require {glue:md}`ode_args` and {glue:md}`simupy_args` which are usually the same for all phases, {glue:md}`add_default_sgm_args` has been provided to add these to the phase info automatically.\n", "\n", "### Setting up Phase Info\n", "\n", - "By default, SGM uses the `two_dof_fiti` (two degree of freedom, forward in time integration) phase_info, which contains the information required to build the default trajectory used by GASP. This phase info can be imported all at once or in a few pre-defined groups:\n", - "phase_info contains all the phases from ascent_phases (which is composed of takeoff_phases and climb_phases), cruise_phases, and descent_phases." + "By default, SGM uses the {glue:md}`two_dof_fiti` (two degree of freedom, forward in time integration) phase_info, which contains the information required to build the default trajectory used by GASP. This phase info can be imported all at once or in a few pre-defined groups:\n", + "phase_info contains all the phases from {glue:md}`ascent_phases` (which is composed of {glue:md}`takeoff_phases` and {glue:md}`climb_phases`), {glue:md}`cruise_phase`, and {glue:md}`descent_phases`." ] }, { @@ -238,14 +276,15 @@ "outputs": [], "source": [ "from aviary.interface.default_phase_info.two_dof_fiti import phase_info\n", - "from aviary.interface.default_phase_info.two_dof_fiti import takeoff_phases, climb_phases, descent_phases" + "from aviary.interface.default_phase_info.two_dof_fiti import (\n", + " ascent_phases, takeoff_phases, climb_phases, cruise_phase, descent_phases)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "`phase_info_parameterization` can be used to update the values of certain variables, like speed_trigger or cruise_alt using values from the input deck.\n", + "{glue:md}`phase_info_parameterization` can be used to update the values of certain variables, like speed_trigger or cruise_alt using values from the input deck.\n", "\n", "## Descent Fuel Estimation\n", "\n", @@ -280,11 +319,53 @@ "for phase_name, phase in descent_phases.items():\n", " check_value(phase['user_options'][Dynamic.Mission.THROTTLE],(0, 'unitless'))" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import ast\n", + "import aviary.api as av\n", + "\n", + "def get_Function_names(file_path):\n", + " # Read the content of the file\n", + " with open(file_path, 'r') as file:\n", + " file_content = file.read()\n", + " \n", + " # Parse the file content into an AST\n", + " tree = ast.parse(file_content)\n", + " \n", + " # Extract function names\n", + " function_names = [\n", + " node.name for node in ast.walk(tree)\n", + " if isinstance(node, ast.FunctionDef)\n", + " ]\n", + " \n", + " return function_names\n", + "\n", + "file_path = av.get_path('interface/default_phase_info/two_dof_fiti.py')\n", + "takeoff_function_names = get_Function_names(file_path)\n", + "for func_name in takeoff_function_names:\n", + " glue_variable(func_name, md_code=True)\n", + "\n", + "glue_variable(f'{ascent_phases=}'.split('=')[0], md_code=False)\n", + "glue_variable(f'{takeoff_phases=}'.split('=')[0], md_code=False)\n", + "glue_variable(f'{climb_phases=}'.split('=')[0], md_code=False)\n", + "glue_variable(f'{cruise_phase=}'.split('=')[0], md_code=False)\n", + "glue_variable(f'{descent_phases=}'.split('=')[0], md_code=False)" + ] } ], "metadata": { "kernelspec": { - "display_name": "latest_env", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -298,7 +379,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From 5e0567422b400d501cdb9b47c0fe705a3ce727c9 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 12 Dec 2024 16:48:33 -0800 Subject: [PATCH 30/48] glue variables in step_by_step_external_guide.ipynb --- .../step_by_step_external_guide.ipynb | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/aviary/docs/user_guide/step_by_step_external_guide.ipynb b/aviary/docs/user_guide/step_by_step_external_guide.ipynb index b1c70a128..e9567ac9f 100644 --- a/aviary/docs/user_guide/step_by_step_external_guide.ipynb +++ b/aviary/docs/user_guide/step_by_step_external_guide.ipynb @@ -55,7 +55,7 @@ "\n", "Now we'll create your subsystem builder. This is arguably the most important step since it exposes your model to Aviary using a consistent interface. The main idea surrounding the subsystem builder is that subject matter experts (you!) will create a specialized Python class that defines specific methods needed by Aviary to integrate your subsystem. I'll walk you through this process now, but don't worry -- we also have some tests to help ensure your subsystem builder is set up correctly.\n", "\n", - "1. First, let's work out some ground rules of the subsystem builder. You'll inherit from `SubsystemBuilderBase` when you create your builder. This base class features *all* methods used by Aviary, even if your specific subsystem doesn't need them (this varies on a subsystem to subsystem basis).\n", + "1. First, let's work out some ground rules of the subsystem builder. You'll inherit from {glue:md}`SubsystemBuilderBase` when you create your builder. This base class features *all* methods used by Aviary, even if your specific subsystem doesn't need them (this varies on a subsystem to subsystem basis).\n", "2. Most all of these methods are documented in-line, as well as on the doc page. I hope that you can follow those and understand what to do with your model, but if you can't, please let us know your questions and we'll rework these docs.\n", "3. These methods can be roughly divided into three broad categories (shown in the graphic below):\n", "\n", @@ -67,7 +67,7 @@ "\n", "![subsystem methods](images/external_subsystem_methods.png)\n", "\n", - "To integrate external subsystems into Aviary, you need to use the [`SubsystemBuilderBase` class](../user_guide/subsystems) as a template for creating your builder object.\n", + "To integrate external subsystems into Aviary, you need to use the [{glue:md}`SubsystemBuilderBase` class](../user_guide/subsystems) as a template for creating your builder object.\n", "This class provides you with skeletal methods that you replace to specify the behavior of your subsystem.\n", "The methods you should implement depend on what type of subsystem you're building." ] @@ -83,7 +83,11 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase" + "from aviary.examples.external_subsystems.battery.battery_builder import BatteryBuilder\n", + "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", + "from aviary.utils.doctape import glue_variable\n", + "glue_variable(f'{SubsystemBuilderBase=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{BatteryBuilder=}'.split('=')[0]+'()', md_code=True)" ] }, { @@ -153,7 +157,7 @@ "\n", "2. **Add any `external_subsystems` to your pre- and post-mission phases too.** If you have pre- or post-mission analyses in your subsystem, make sure to add the `external_subsystems` list to the `pre_mission` and `post_mission` sub-dicts within the `phase_info` dict. This means that Aviary will build and use those systems before or after the mission; otherwise Aviary won't know to put the systems there.\n", "\n", - "3. **Start with a simple mission in Aviary.** To begin, try adapting the [`run_cruise.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/external_subsystems/battery/run_cruise.py) script to use your subsystem. Replace the `BatteryBuilder()` instance with your subsystem, for example. You might need other setup or inputs based on the complexity of your model. But in general, it helps to start with the simplest mission you can. In this case, that's probably a steady level cruise flight.\n", + "3. **Start with a simple mission in Aviary.** To begin, try adapting the [`run_cruise.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/external_subsystems/battery/run_cruise.py) script to use your subsystem. Replace the {glue:md}`BatteryBuilder()` instance with your subsystem, for example. You might need other setup or inputs based on the complexity of your model. But in general, it helps to start with the simplest mission you can. In this case, that's probably a steady level cruise flight.\n", "\n", " Even though this is a \"simple\" mission, there's still a lot that can go wrong. It turns out that designing an aircraft is challenging sometimes. I don't expect your mission optimization to converge well your first try; it often takes some debugging and digging to get your subsystem integrated well. It's really challenging to write docs to help you do this without knowing more about your system, what it's trying to do while the aircraft is flying, and what you've already checked. That being said, make sure to reach out if you're encountering problems here.\n", "\n", @@ -162,8 +166,22 @@ } ], "metadata": { + "kernelspec": { + "display_name": "av1", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.18" } }, "nbformat": 4, From fb5d88a8878ea9647e831e8d7c87a21c8f21b86c Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 12 Dec 2024 18:23:51 -0800 Subject: [PATCH 31/48] minor update to step_by_step_external_guide.ipynb --- .../user_guide/step_by_step_external_guide.ipynb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/aviary/docs/user_guide/step_by_step_external_guide.ipynb b/aviary/docs/user_guide/step_by_step_external_guide.ipynb index e9567ac9f..1daee2c14 100644 --- a/aviary/docs/user_guide/step_by_step_external_guide.ipynb +++ b/aviary/docs/user_guide/step_by_step_external_guide.ipynb @@ -117,7 +117,20 @@ }, "outputs": [], "source": [ - "from aviary.examples.external_subsystems.battery.battery_builder import BatteryBuilder" + "import inspect\n", + "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", + "from aviary.utils.doctape import check_contains\n", + "\n", + "# Get all functions of class SubsystemBuilderBase\n", + "functs = inspect.getmembers(SubsystemBuilderBase, predicate=inspect.isfunction)\n", + "all_function_names = []\n", + "for name, func in functs:\n", + " if (not name.startswith('_')):\n", + " all_function_names.append(name)\n", + "# make sure all the functions in images/external_subsystem_methods.png exist\n", + "expected_function_names = ['get_states', 'get_constraints', 'get_design_vars', 'get_parameters',\n", + " 'preprocess_inputs', 'get_initial_guesses', 'get_mass_names', 'get_outputs']\n", + "check_contains(expected_function_names, all_function_names)\n" ] }, { From a0e151f9da8c13ce807913f64cc1b3eecc97c388 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 12 Dec 2024 18:49:32 -0800 Subject: [PATCH 32/48] remove outputs --- aviary/docs/user_guide/propulsion.ipynb | 269 +------------- aviary/docs/user_guide/reserve_missions.ipynb | 333 +----------------- 2 files changed, 7 insertions(+), 595 deletions(-) diff --git a/aviary/docs/user_guide/propulsion.ipynb b/aviary/docs/user_guide/propulsion.ipynb index faf0817b9..ca6c7632e 100644 --- a/aviary/docs/user_guide/propulsion.ipynb +++ b/aviary/docs/user_guide/propulsion.ipynb @@ -74,259 +74,14 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "e0344b4f", "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [ - { - "data": { - "text/markdown": [ - "`Mach Number`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Mach Number" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Altitude`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Altitude" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Throttle`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Throttle" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Hybrid Throttle`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Hybrid Throttle" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Net Thrust`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Net Thrust" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Gross Thrust`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Gross Thrust" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Ram Drag`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Ram Drag" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Fuel Flow Rate`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Fuel Flow Rate" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Electric Power`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Electric Power" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`NOx Rate`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "NOx Rate" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`T4 Temperature`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "T4 Temperature" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Mach`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Mach" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "* `Aircraft.Engine.SCALE_PERFORMANCE`\n", - "* `Aircraft.Engine.IGNORE_NEGATIVE_THRUST`\n", - "* `Aircraft.Engine.GEOPOTENTIAL_ALT`\n", - "* `Aircraft.Engine.GENERATE_FLIGHT_IDLE`\n", - "* `Aircraft.Engine.NUM_WING_ENGINES` and/or `Aircraft.Engine.NUM_FUSELAGE_ENGINES`\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "required_options" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "* `Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION`\n", - "* `Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION`\n", - "* `Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION`\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "flight_idle_options" - } - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Testing Cell\n", "from aviary.api import Aircraft\n", @@ -430,25 +185,7 @@ "remove-cell" ] }, - "outputs": [ - { - "data": { - "text/markdown": [ - "`EngineModel`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "EngineModel" - } - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Testing Cell\n", "from aviary.api import Aircraft\n", diff --git a/aviary/docs/user_guide/reserve_missions.ipynb b/aviary/docs/user_guide/reserve_missions.ipynb index 6f5cb358d..93b4cb9c2 100644 --- a/aviary/docs/user_guide/reserve_missions.ipynb +++ b/aviary/docs/user_guide/reserve_missions.ipynb @@ -2,197 +2,9 @@ "cells": [ { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "height_energy" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "height_energy" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "2DOF" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "2DOF" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "collocation" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "collocation" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "shooting" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "shooting" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`phase_info`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "phase_info" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`run_reserve_mission_multiphase.py`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "run_reserve_mission_multiphase.py" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`run_2dof_reserve_mission_multiphase.py`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "run_2dof_reserve_mission_multiphase.py" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`check_and_preprocess_inputs()`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "check_and_preprocess_inputs()" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`prob.check_and_preprocess_inputs()`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "prob.check_and_preprocess_inputs()" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`load_inputs()`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "load_inputs()" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`prob.load_inputs()`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "prob.load_inputs()" - } - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Testing Cell\n", "import inspect\n", @@ -511,150 +323,13 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [ - { - "data": { - "text/markdown": [ - "`Mission.Summary.FUEL_BURNED`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Mission.Summary.FUEL_BURNED" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Mission.Design.RESERVE_FUEL`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Mission.Design.RESERVE_FUEL" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Aircraft.Design.RESERVE_FUEL_ADDITIONAL`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Aircraft.Design.RESERVE_FUEL_ADDITIONAL" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Aircraft.Design.RESERVE_FUEL_FRACTION`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Aircraft.Design.RESERVE_FUEL_FRACTION" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`Mission.Summary.RESERVE_FUEL_BURNED`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "Mission.Summary.RESERVE_FUEL_BURNED" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`RESERVE_FUEL_ADDITIONAL`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "RESERVE_FUEL_ADDITIONAL" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`RESERVE_FUEL_FRACTION`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "RESERVE_FUEL_FRACTION" - } - }, - "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "`RESERVE_FUEL_BURNED`" - ], - "text/plain": [ - "" - ] - }, - "metadata": { - "scrapbook": { - "mime_prefix": "", - "name": "RESERVE_FUEL_BURNED" - } - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Testing Cell\n", "from aviary.api import Aircraft, Mission\n", From 677f206ad1b3a30bf20eb7af344516287e976f37 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 13 Dec 2024 11:42:22 -0800 Subject: [PATCH 33/48] minor updates --- ...S_based_detailed_takeoff_and_landing.ipynb | 5 +- aviary/docs/user_guide/reserve_missions.ipynb | 6 +- .../docs/user_guide/variable_metadata.ipynb | 189 +++++++++++++++--- 3 files changed, 169 insertions(+), 31 deletions(-) diff --git a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb index 258dfed78..e4e6f626d 100644 --- a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb +++ b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb @@ -141,6 +141,9 @@ " return class_names\n", "\n", "def get_Function_names(file_path):\n", + " \"\"\"\n", + " Get all function names in a file using ast.\n", + " \"\"\"\n", " # Read the content of the file\n", " with open(file_path, 'r') as file:\n", " file_content = file.read()\n", @@ -160,8 +163,8 @@ "takeoff_class_names = get_class_names(file_path)\n", "for class_name in takeoff_class_names:\n", " glue_variable(class_name, md_code=True)\n", - "takeoff_function_names = get_Function_names(file_path)\n", "\n", + "#takeoff_function_names = get_Function_names(file_path)\n", "# for function_name in takeoff_function_names:\n", "# if not function_name.startswith('_'):\n", "# glue_variable(function_name+'()', md_code=True)\n", diff --git a/aviary/docs/user_guide/reserve_missions.ipynb b/aviary/docs/user_guide/reserve_missions.ipynb index 93b4cb9c2..794ee6549 100644 --- a/aviary/docs/user_guide/reserve_missions.ipynb +++ b/aviary/docs/user_guide/reserve_missions.ipynb @@ -3,7 +3,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [ + "remove-cell" + ] + }, "outputs": [], "source": [ "# Testing Cell\n", diff --git a/aviary/docs/user_guide/variable_metadata.ipynb b/aviary/docs/user_guide/variable_metadata.ipynb index 15fea1c3b..533604b64 100644 --- a/aviary/docs/user_guide/variable_metadata.ipynb +++ b/aviary/docs/user_guide/variable_metadata.ipynb @@ -1,5 +1,62 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "\n", + "import ast\n", + "import inspect\n", + "import aviary.api as av\n", + "from aviary.api import Aircraft\n", + "from aviary.utils.develop_metadata import add_meta_data\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "\n", + "# Retrieve all arguments from a function\n", + "sig = inspect.signature(add_meta_data)\n", + "arguments = [param.name for param in sig.parameters.values()]\n", + "for arg in arguments:\n", + " if not arg.startswith('_'):\n", + " glue_variable(arg, md_code=False)\n", + "\n", + "glue_variable(get_variable_name(Aircraft.Wing.MASS_SCALER), md_code=True)\n", + "glue_variable('Aircraft', get_variable_name(Aircraft.Wing.MASS_SCALER).split('.')[0], md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Wing.SPAN), md_code=False)\n", + "glue_variable('utils/develop_metadata.py', md_code=False)\n", + "\n", + "def get_Function_names(file_path):\n", + " \"\"\"\n", + " Get all function names in a file using ast.\n", + " \"\"\"\n", + " # Read the content of the file\n", + " with open(file_path, 'r') as file:\n", + " file_content = file.read()\n", + " \n", + " # Parse the file content into an AST\n", + " tree = ast.parse(file_content)\n", + " \n", + " # Extract function names\n", + " function_names = [\n", + " node.name for node in ast.walk(tree)\n", + " if isinstance(node, ast.FunctionDef)\n", + " ]\n", + " \n", + " return function_names\n", + "\n", + "file_path = av.get_path('utils/develop_metadata.py')\n", + "function_names = get_Function_names(file_path)\n", + "for function_name in function_names:\n", + " if not function_name.startswith('_'):\n", + " glue_variable(function_name+'()', md_code=True)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -9,16 +66,16 @@ "\n", "Every variable in an Aviary variable hierarchy must have metadata associated with it. This metadata is used for setting initial values, setting Aviary inputs and outputs, and various other functionalities throughout the code. It is also helpful information for the user to have regarding each variable and the metadata dictionary allows all that information to live in one organized location. Unlike variable hierarchies, which are broken up into different categories based on the type of information they contain, the variable metadata all lives in the same dictionary, regardless of which variable hierarchy its variables come from.\n", "\n", - "The variable metadata dictionary is exactly what it sounds like: a Python dictionary, or more explicitly a Python dictionary of dictionaries. The entire metadata is one dictionary, and within that metadata dictionary each variable has its own sub-dictionary including all the information relevant to that variable. The information included in each sub-dictionary is:\n", + "The variable metadata dictionary is exactly what it sounds like: a Python dictionary, or more explicitly a Python dictionary of dictionaries. The entire metadata is one dictionary, and within that metadata dictionary each variable (the {glue:md}`key`) has its own sub-dictionary including all the information relevant to that variable. The information included in each sub-dictionary is:\n", "\n", - "| Information | Default Value | Key Name in Metadata |\n", - "| --------------------------- | ------------- | -------------------- |\n", - "| Units | `unitless` | units |\n", - "| Description | `None` | desc |\n", - "| Default Value | `0.0` | default_value |\n", - "| Is Option? | `False` | option |\n", - "| Type Restrictions | `None` | types |\n", - "| Historical Variable Name(s) | `None` | historical_name |" + "| Information | Default Value | Key Name in Metadata |\n", + "| --------------------------- | ------------- | -------------------------- |\n", + "| Units | `unitless` | {glue:md}`units` |\n", + "| Description | `None` | {glue:md}`desc` |\n", + "| Default Value | `0.0` | {glue:md}`default_value` |\n", + "| Is Option? | `False` | {glue:md}`option` |\n", + "| Type Restrictions | `None` | {glue:md}`types` |\n", + "| Historical Variable Name(s) | `None` | {glue:md}`historical_name` |" ] }, { @@ -46,15 +103,14 @@ "\n", "meta_data = {}\n", "add_meta_data('testing',meta_data)\n", - "check_value(meta_data['testing'], expected_meta_data)\n", - "\n" + "check_value(meta_data['testing'], expected_meta_data)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The information in the metadata dictionary is accessed just like information in any other Python dictionary. For example, if you wanted to know the units of the `Aircraft.Wing.SPAN` variable from the Aviary-core `Aircraft` variable hierarchy along with whether or not the variable was an option, you would access those units using the following code:" + "The information in the metadata dictionary is accessed just like information in any other Python dictionary. For example, if you wanted to know the units of the {glue:md}`Aircraft.Wing.SPAN` variable from the Aviary-core {glue:md}`Aircraft` variable hierarchy along with whether or not the variable was an option, you would access those units using the following code:" ] }, { @@ -82,7 +138,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In this example we use the variable hierarchy to provide the name of the variable we are seeking to Aviary's `CoreMetaData`, and we use the keys from the metadata dictionary to provide the specific information that we would like to know. This would return" + "In this example we use the variable hierarchy to provide the name of the variable we are seeking to Aviary's {glue:md}`CoreMetaData`, and we use the keys from the metadata dictionary to provide the specific information that we would like to know. This would return" ] }, { @@ -112,12 +168,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "which tells you that the units of the variable Aircraft.Wing.SPAN from the Aviary-core `Aircraft` variable hierarchy are feet, and that Aircraft.Wing.SPAN is not an option.\n", + "which tells you that the units of the variable {glue:md}`Aircraft.Wing.SPAN` from the Aviary-core {glue:md}`Aircraft` variable hierarchy are feet, and that {glue:md}`Aircraft.Wing.SPAN` is not an option.\n", "\n", "```{note}\n", "Many of the weight and aerodynamic estimating relationships in Aviary originated from historical codes called GASP and FLOPS. For engineers who are familiar with GASP and FLOPS it is helpful to know what an Aviary variable was called in those historical codes.\n", "\n", - "The historical variable name portion of the metadata allows us to associate any names that an Aviary variable may have had in a previous code. This piece of the metadata is actually a dictionary within each subdictionary belonging to each variable. This dictionary is used by adding an entry for each historical code, where the key is the name of the historical code, and the value for that key is a string or list of strings illustrating the name(s) that variable held in the historic code. This is an optional feature, but can be helpful for users who are porting old codes into new formats. If a tilde (~) is attached to a historical variable, it is a local variable or parameter in GASP or FLOPS. More details about the naming convention is described in `utils/develop_metadata.py`.\n", + "The historical variable name portion of the metadata allows us to associate any names that an Aviary variable may have had in a previous code. This piece of the metadata is actually a dictionary within each subdictionary belonging to each variable. This dictionary is used by adding an entry for each historical code, where the key is the name of the historical code, and the value for that key is a string or list of strings illustrating the name(s) that variable held in the historic code. This is an optional feature, but can be helpful for users who are porting old codes into new formats. If a tilde (~) is attached to a historical variable, it is a local variable or parameter in GASP or FLOPS. More details about the naming convention is described in {glue:md}`utils/develop_metadata.py`.\n", "```\n", "\n", "## The Aviary-core Metadata\n", @@ -149,11 +205,11 @@ "## Building Your Own Metadata\n", "Unlike the variable hierarchies, which are separated out into different hierarchies for different types of data, there is only one metadata dictionary for all variables in every variable hierarchy. Technically the user may build a metadata dictionary from scratch instead of extending the Aviary-core metadata, however, there is no real value to this as you will eventually have to merge back in the Aviary-core metadata anyway, so there are no normal circumstances under which this is the recommended practice. However, just like with variable hierarchies, you can have several different metadata dictionaries which will eventually be merged together. This may be necessary when there are multiple people developing different external subsystems in different locations.\n", "\n", - "There are two different ways to change the metadata in a metadata dictionary. The first is to add a new variable to the dictionary, and add that variable's metadata along with it. This makes use of the `add_meta_data()` function. This function takes in the variable name of the variable to be added to the metadata dictionary be provided, as well as the dictionary itself that the variable should be added to. It also optionally takes in all of the metadata information listed at the beginning of this page. The function returns nothing, but it internally updates the provided metadata dictionary so that dictionary will contain the new variable and its metadata.\n", + "There are two different ways to change the metadata in a metadata dictionary. The first is to add a new variable to the dictionary, and add that variable's metadata along with it. This makes use of the {glue:md}`add_meta_data()` function. This function takes in the variable name of the variable to be added to the metadata dictionary be provided, as well as the dictionary itself that the variable should be added to. It also optionally takes in all of the metadata information listed at the beginning of this page. The function returns nothing, but it internally updates the provided metadata dictionary so that dictionary will contain the new variable and its metadata.\n", "\n", - "The second way to change the metadata in a metadata dictionary is by updating the metadata associated with a variable that is already in the dictionary. This is accomplished using the `update_meta_data()` function. This function behaves almost identically to the `add_meta_data()` function, the only difference being that instead of adding a new variable to the dictionary, it will take the input of metadata information that you provide and overwrite the old metadata of the given variable with the new metadata.\n", + "The second way to change the metadata in a metadata dictionary is by updating the metadata associated with a variable that is already in the dictionary. This is accomplished using the {glue:md}`update_meta_data()` function. This function behaves almost identically to the {glue:md}`add_meta_data()` function, the only difference being that instead of adding a new variable to the dictionary, it will take the input of metadata information that you provide and overwrite the old metadata of the given variable with the new metadata.\n", "\n", - "There are two pitfalls that may occur when using these functions. The first pitfall is attempting to call the `add_meta_data()` function for a variable that already exists in the metadata. This will throw an error, because the `add_meta_data()` function is only for new variables to the metadata. Conversely, attempting to update the metadata of a variable that is not in the metadata dictionary via `update_meta_data()` will throw an error because that function is only for variables that already exist in the metadata.\n", + "There are two pitfalls that may occur when using these functions. The first pitfall is attempting to call the {glue:md}`add_meta_data()` function for a variable that already exists in the metadata. This will throw an error, because the {glue:md}`add_meta_data()` function is only for new variables to the metadata. Conversely, attempting to update the metadata of a variable that is not in the metadata dictionary via {glue:md}`update_meta_data()` will throw an error because that function is only for variables that already exist in the metadata.\n", "\n", "The methods outlined above for updating and adding to the variable metadata are the crux of how the variable metadata can be extended for new variables. The user will simply import the existing Aviary-core metadata and add to it as they see fit.\n", "\n", @@ -161,7 +217,7 @@ "The variable metadata dictionary that is imported from the Aviary API is actually a copy of the original Aviary metadata dictionary to avoid mutating the original dictionary. That being said, it functions just as a metadata dictionary that you would input to an Aviary model and you can extend it or input it to a model as-is depending on your needs.\n", "```\n", "\n", - "Lets examine how we would extend the variable metadata dictionary in practice. Say we have just extended the Aviary-core `Aircraft` variable hierarchy to add some center of gravity, flap, and jury strut information using the extension below:" + "Lets examine how we would extend the variable metadata dictionary in practice. Say we have just extended the Aviary-core {glue:md}`Aircraft` variable hierarchy to add some center of gravity, flap, and jury strut information using the extension below:" ] }, { @@ -271,16 +327,64 @@ ")" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.variable_info.variable_meta_data import CoreMetaData\n", + "glue_variable(f'{CoreMetaData=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{ExtendedAircraft=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{ExtendedMetaData=}'.split('=')[0], md_code=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "\n", + "import aviary.api as av\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "glue_variable('utils/merge_hierarchies.py', md_code=False)\n", + "glue_variable('utils/merge_variable_metadata.py', md_code=False)\n", + "\n", + "file_path = av.get_path('utils/merge_hierarchies.py')\n", + "function_names = get_Function_names(file_path)\n", + "for function_name in function_names:\n", + " if not function_name.startswith('_'):\n", + " glue_variable(function_name+'()', md_code=True)\n", + "\n", + "file_path = av.get_path('utils/merge_variable_metadata.py')\n", + "function_names = get_Function_names(file_path)\n", + "for function_name in function_names:\n", + " if not function_name.startswith('_'):\n", + " glue_variable(function_name+'()', md_code=True)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "`ExtendedMetaData` now contains the metadata of all the Aviary-core variables along with the metadata information that we just added.\n", + "{glue:md}`ExtendedMetaData` now contains the metadata of all the Aviary-core variables along with the metadata information that we just added.\n", "\n", "## Merging Independent Metadata\n", - "Extending the metadata is great, but sometimes users will end up with multiple metadata dictionaries because different subsystem developers extended the metadata (and created associated variable hierarchies) to suit their own needs. Aviary needs to be given one single metadata dictionary which contains metadata of all the variables it has been given, so we need to be able to merge together multiple metadata dictionaries into one. The `merge_meta_data()` function has been provided to combine all the different metadata into one. The `merge_meta_data()` function behaves quite similarly to the `merge_hierarchies()` function. It takes in a string of metadata dictionaries that need to be merged together, and it returns a single metadata dictionary containing the metadata from all the individual dictionaries.\n", + "Extending the metadata is great, but sometimes users will end up with multiple metadata dictionaries because different subsystem developers extended the metadata (and created associated variable hierarchies) to suit their own needs. Aviary needs to be given one single metadata dictionary which contains metadata of all the variables it has been given, so we need to be able to merge together multiple metadata dictionaries into one. The {glue:md}`merge_meta_data()` function has been provided to combine all the different metadata into one. The `merge_meta_data()` function behaves quite similarly to the{glue:md} `merge_hierarchies()` function. It takes in a string of metadata dictionaries that need to be merged together, and it returns a single metadata dictionary containing the metadata from all the individual dictionaries.\n", "\n", - "Let's say that we have created our `ExtendedAircraft` and `ExtendedMetaData` from above, and that elsewhere we have a subsystem that requires information about engine cooling system mass as well as whether the aircraft has winglets. Below is the buildup of the `Aircraft` type hierarchy and the metadata for our new subsystem:" + "Let's say that we have created our `ExtendedAircraft` and `ExtendedMetaData` from above, and that elsewhere we have a subsystem that requires information about engine cooling system mass as well as whether the aircraft has winglets. Below is the buildup of the {glue:md}`Aircraft` type hierarchy and the metadata for our new subsystem:" ] }, { @@ -343,11 +447,26 @@ ")" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-output" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "glue_variable(f'{ExtendedAircraft2=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{ExtendedMetaData2=}'.split('=')[0], md_code=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We can see from the above code that we have an `Aircraft` type variable hierarchy named `ExtendedAircraft2` and that we have created our own metadata dictionary `ExtendedMetaData2` which is an extension of the `CoreMetaData` dictionary in Aviary-core. Now we have two different `Aircraft` type variable hierarchy extensions, `ExtendedAircraft` and `ExtendedAircraft2`. We also have two different metadata extensions, `ExtendedMetaData` and `ExtendedMetaData2`. We need a single `Aircraft` type variable hierarchy, and single metadata dictionary. Thus, we will use the merging functions built into Aviary:" + "We can see from the above code that we have an {glue:md}`Aircraft` type variable hierarchy named {glue:md}`ExtendedAircraft2` and that we have created our own metadata dictionary {glue:md}`ExtendedMetaData2` which is an extension of the {glue:md}`CoreMetaData` dictionary in Aviary-core. Now we have two different {glue:md}`Aircraft` type variable hierarchy extensions, {glue:md}`ExtendedAircraft` and {glue:md}`ExtendedAircraft2`. We also have two different metadata extensions, {glue:md}`ExtendedMetaData` and {glue:md}`ExtendedMetaData2`. We need a single {glue:md}`Aircraft` type variable hierarchy, and single metadata dictionary. Thus, we will use the merging functions built into Aviary:" ] }, { @@ -364,11 +483,26 @@ "FinalMetaData = av.merge_meta_data([ExtendedMetaData, ExtendedMetaData2])" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "glue_variable(f'{FinalAircraft=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{FinalMetaData=}'.split('=')[0], md_code=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Above we merged together our hierarchy and metadata extensions, and now we have one single `Aircraft` type hierarchy `FinalAircraft` and one single metadata dictionary `FinalMetaData` which we can provide to the Aviary model.\n", + "Above we merged together our hierarchy and metadata extensions, and now we have one single {glue:md}`Aircraft` type hierarchy {glue:md}`FinalAircraft` and one single metadata dictionary {glue:md}`FinalMetaData` which we can provide to the Aviary model.\n", "\n", "There is one situation when an attempt to merge together multiple metadata dictionaries will cause errors, and that situation is if more than one metadata dictionary contains the same variable with different metadata. If multiple dictionaries contain the same variable with identical metadata the merge will proceed, but if the metadata differs at all the merge will halt and force the user to rectify the discrepancy.\n", "\n", @@ -443,11 +577,8 @@ ], "metadata": { "celltoolbar": "Tags", - "interpreter": { - "hash": "e6c7471802ed76737b16357fb02af5587f3a4cbee5ea7658f3f9a6981469039b" - }, "kernelspec": { - "display_name": "Python 3", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -461,7 +592,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" }, "orphan": true }, From 7e8d414de895708d889ca2ae73b9fdd2c8f75791 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 13 Dec 2024 16:26:40 -0800 Subject: [PATCH 34/48] glue variables in variable_hierarchy.ipynb and variable_metadata.ipynb --- .../docs/user_guide/variable_hierarchy.ipynb | 90 +++++++++++++++---- .../docs/user_guide/variable_metadata.ipynb | 25 +++--- 2 files changed, 84 insertions(+), 31 deletions(-) diff --git a/aviary/docs/user_guide/variable_hierarchy.ipynb b/aviary/docs/user_guide/variable_hierarchy.ipynb index 8f213a134..2f94bb674 100644 --- a/aviary/docs/user_guide/variable_hierarchy.ipynb +++ b/aviary/docs/user_guide/variable_hierarchy.ipynb @@ -1,5 +1,64 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "import ast\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "import aviary.api as av\n", + "from aviary.api import Aircraft, Mission\n", + "from aviary.variable_info.variables import Aircraft\n", + "\n", + "glue_variable(get_variable_name(Aircraft.Wing.SPAN), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Fuselage.LENGTH), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.HorizontalTail.ROOT_CHORD), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.VerticalTail.ROOT_CHORD), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.VerticalTail.SPAN), md_code=True)\n", + "glue_variable(get_variable_name(Mission.Design.CRUISE_ALTITUDE), md_code=True)\n", + "glue_variable(get_variable_name(Mission.Design.RANGE), md_code=True)\n", + "glue_variable(f'{Aircraft=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{Mission=}'.split('=')[0], md_code=True)\n", + "glue_variable(f'{Aircraft.Wing=}'.split('=')[0].split('.')[1], md_code=True)\n", + "\n", + "def get_function_names(file_path):\n", + " \"\"\"\n", + " Get all function names in a file using ast.\n", + " \"\"\"\n", + " # Read the content of the file\n", + " with open(file_path, 'r') as file:\n", + " file_content = file.read()\n", + " \n", + " # Parse the file content into an AST\n", + " tree = ast.parse(file_content)\n", + " \n", + " # Extract function names\n", + " function_names = [\n", + " node.name for node in ast.walk(tree)\n", + " if isinstance(node, ast.FunctionDef)\n", + " ]\n", + " \n", + " return set(function_names)\n", + "\n", + "file_path = av.get_path('variable_info/functions.py')\n", + "var_function_names = get_function_names(file_path)\n", + "for function_name in var_function_names:\n", + " if not function_name.startswith('_'):\n", + " glue_variable(function_name+'()', md_code=True)\n", + "\n", + "file_path = av.get_path('utils/functions.py')\n", + "util_function_names = get_function_names(file_path)\n", + "for function_name in util_function_names:\n", + " if not function_name.startswith('_') and not function_name in var_function_names:\n", + " glue_variable(function_name+'()', md_code=True)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -10,7 +69,7 @@ "\n", "The variable hierarchy itself is rather simple. The variables are broken up into separate high level categories and each category becomes its own top-level class. Within that class we create \"inner classes\" (classes which are an attribute of a higher level class) that encompass a more specific category. If needed, secondary inner classes within an inner class may be created, and so on until the desired detail depth is achieved. However, too many layers down and the tedium will outweigh any value gained through specificity. \n", "\n", - "These classes and inner classes are not used for any sort of complex coding functionality. Instead they simply serve to house model variables themselves. Each class and inner class can have variables assigned to it (in object-oriented speak, the variables become an attribute of the class or inner class), and each variable assigned to a class or inner class corresponds 1-to-1 with a variable needed for the model. The variables in each class are really just identifiers that point to the actual variable name in the model. The value assigned to each variable in the classes is a string that is the name of that variable in the actual model. That string is the variable name that OpenMDAO will see, despite the fact that the user will rarely call the variable by that name. Instead the user will refer to a variable name by its hierarchy variable (eg. referring to `'aircraft:wing:span'` as `Aircraft.Wing.SPAN`) to make it easier to autofill the variable and also to allow more uniform and controlled access to the variable names themselves.\n", + "These classes and inner classes are not used for any sort of complex coding functionality. Instead they simply serve to house model variables themselves. Each class and inner class can have variables assigned to it (in object-oriented speak, the variables become an attribute of the class or inner class), and each variable assigned to a class or inner class corresponds 1-to-1 with a variable needed for the model. The variables in each class are really just identifiers that point to the actual variable name in the model. The value assigned to each variable in the classes is a string that is the name of that variable in the actual model. That string is the variable name that OpenMDAO will see, despite the fact that the user will rarely call the variable by that name. Instead the user will refer to a variable name by its hierarchy variable (eg. referring to `'aircraft:wing:span'` as {glue:md}`Aircraft.Wing.SPAN`) to make it easier to autofill the variable and also to allow more uniform and controlled access to the variable names themselves.\n", "\n", "Below is an example of a simple variable hierarchy that includes basic information for an aircraft:" ] @@ -69,7 +128,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This code snippet is a notional example of how an overly simple hierarchy looks. In this example the variables all have a depth of three, meaning that all the variables are referred to in three tiers: `Aircraft.Fuselage.LENGTH`, `Aircraft.HorizontalTail.ROOT_CHORD`, `Aircraft.Wing.SPAN`, etc. The variable names in this hierarchy can actually be used to access the values of those variables in an Aviary model, assuming that the hierarchy has been properly provided to the Aviary model. Below is an example of using a variable hierarchy variable in the `add_aviary_input()` and `add_aviary_output()` functions to add inputs and outputs to an OpenMDAO component for use in Aviary." + "This code snippet is a notional example of how an overly simple hierarchy looks. In this example the variables all have a depth of three, meaning that all the variables are referred to in three tiers: {glue:md}`Aircraft.Fuselage.LENGTH`, {glue:md`Aircraft.HorizontalTail.ROOT_CHORD`, {glue:md`Aircraft.Wing.SPAN`, etc. The variable names in this hierarchy can actually be used to access the values of those variables in an Aviary model, assuming that the hierarchy has been properly provided to the Aviary model. Below is an example of using a variable hierarchy variable in the {glue:md}`add_aviary_input()` and {glue:md}`add_aviary_output()` functions to add inputs and outputs to an OpenMDAO component for use in Aviary." ] }, { @@ -116,10 +175,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In this code snippet the variables `Aircraft.VerticalTail.ROOT_CHORD` and `Aircraft.VerticalTail.SPAN` from the variable hierarchy are used in the `add_aviary_input` and `add_aviary_output` functions to represent the actual variable names, which are `aircraft:vertical_tail:root_chord` and `aircraft:vertical_tail:span` respectively. The point being illustrated here is that you can use the variables from these variable hierarchies just as you would use their string-valued variable names, and in fact you *must* use the variable hierarchy variable and *not* the string-valued variable name. This way, if a change is made to the string-valued variable name in the hierarchy, that change is automatically reflected throughout all your code.\n", + "In this code snippet the variables {glue:md}`Aircraft.VerticalTail.ROOT_CHORD` and {glue:md}`Aircraft.VerticalTail.SPAN` from the variable hierarchy are used in the {glue:md}`add_aviary_input()` and {glue:md}`add_aviary_output()` functions to represent the actual variable names, which are `aircraft:vertical_tail:root_chord` and `aircraft:vertical_tail:span` respectively. The point being illustrated here is that you can use the variables from these variable hierarchies just as you would use their string-valued variable names, and in fact you *must* use the variable hierarchy variable and *not* the string-valued variable name. This way, if a change is made to the string-valued variable name in the hierarchy, that change is automatically reflected throughout all your code.\n", "\n", "## The Aviary-core Variable Hierarchies\n", - "While the idea of a variable hierarchy can be created and used on its own, Aviary-core provides two specific variable hierarchies that are necessary for Aviary-core systems and which follow both the rules of convention and the rules of programmatic necessity laid out above. The two hierarchies provided by Aviary-core are `Aircraft` and `Mission`. `Aircraft` houses all variables that have to do with physical aspects of the aircraft, as well as all variables that do not affect the mission or change in time. This includes several variables that are options in the model instead of inputs or outputs. `Mission` on the other hand houses all variables that reference the mission or change in time. This includes things such as `Mission.Design.CRUISE_ALTITUDE` and `Mission.Design.RANGE` as well as things such as objectives for the optimization, parameters at various phases of flight, etc. The `Aircraft` and `Mission` hierarchies are the only hierarchies provided by Aviary-core, and they are both necessary for the successful running of various Aviary subsystems. Whatever additional or extended variable hierarchies have been created by the user, the end hierarchy *must* include the variables from the `Aircraft` and `Mission` hierarchies in the Aviary core, and these variables must not be altered. We offer more information below on extending and merging together variable hierarchies.\n", + "While the idea of a variable hierarchy can be created and used on its own, Aviary-core provides two specific variable hierarchies that are necessary for Aviary-core systems and which follow both the rules of convention and the rules of programmatic necessity laid out above. The two hierarchies provided by Aviary-core are {glue:md}`Aircraft` and {glue:md}`Mission`. {glue:md}`Aircraft` houses all variables that have to do with physical aspects of the aircraft, as well as all variables that do not affect the mission or change in time. This includes several variables that are options in the model instead of inputs or outputs. {glue:md}`Mission` on the other hand houses all variables that reference the mission or change in time. This includes things such as {glue:md}`Mission.Design.CRUISE_ALTITUDE` and {glue:md}`Mission.Design.RANGE` as well as things such as objectives for the optimization, parameters at various phases of flight, etc. The {glue:md}`Aircraft` and {glue:md}`Mission` hierarchies are the only hierarchies provided by Aviary-core, and they are both necessary for the successful running of various Aviary subsystems. Whatever additional or extended variable hierarchies have been created by the user, the end hierarchy *must* include the variables from the {glue:md}`Aircraft` and {glue:md}`Mission` hierarchies in the Aviary core, and these variables must not be altered. We offer more information below on extending and merging together variable hierarchies.\n", "\n", "For a complete list of the variables included in the Aviary-core hierarchy visit the [Variable Metadata doc page](../user_guide/variable_metadata). The hierarchies themselves are located [here](https://github.com/OpenMDAO/Aviary/blob/main/aviary/variable_info/variables.py) in the repository and can be accessed in this way:" ] @@ -171,14 +230,14 @@ "- All variables in the hierarchy have a depth of 3. This is optional, but again we follow this convention within the Aviary-core variable hierarchy to preserve cleanliness and uniformity of code.\n", "- Including colons after all words in the string-valued variable name is optional. As stated above, it is a must after the first word for use in promotion statements, but after that it is purely a choice of convention to preserve clarity.\n", "\n", - "It is prudent at this point to pause and explain what is meant by *hierarchy type*. This is not a technical coding in term, instead *type* is an explanatory term that we use to describe the classification of a hierarchy. A hierarchy's type is its high level category. For example, a hierarchy of the `Aircraft` type would be a hierarchy that houses the variables that have to do with the physical aspects of an aircraft, and a hierarchy of the `Mission` type would be a hierarchy that houses the variables which reference the mission or change in time. These are the only two types of hierarchies that are provided in Aviary-core, however, other types are possible, such as a `Fleet` type hierarchy describing the variables that affect an entire fleet of aircraft, an `AirTrafficControl` type hierarchy describing all the variables having to do with air traffic control, etc. The concept of the `Aircraft` and `Mission` type hierarchies will be used throughout the rest of this article.\n", + "It is prudent at this point to pause and explain what is meant by *hierarchy type*. This is not a technical coding in term, instead *type* is an explanatory term that we use to describe the classification of a hierarchy. A hierarchy's type is its high level category. For example, a hierarchy of the {glue:md}`Aircraft` type would be a hierarchy that houses the variables that have to do with the physical aspects of an aircraft, and a hierarchy of the {glue:md}`Mission` type would be a hierarchy that houses the variables which reference the mission or change in time. These are the only two types of hierarchies that are provided in Aviary-core, however, other types are possible, such as a `Fleet` type hierarchy describing the variables that affect an entire fleet of aircraft, an `AirTrafficControl` type hierarchy describing all the variables having to do with air traffic control, etc. The concept of the {glue:md}`Aircraft` and {glue:md}`Mission` type hierarchies will be used throughout the rest of this article.\n", "\n", "\n", "## Building Your Own Hierarchy\n", - "The Aviary-core provides the pre-built variable hierarchies listed above. However, for the user that would like to add external subsystems to Aviary, the variables in the Aviary-core hierarchies may not be sufficient. In this case, there are three options: 1) extend the existing variable hierarchies from Aviary-core, 2) create your own variable hierarchies and merge them with the existing hierarchies from Aviary-core, 3) do a combination of #1 and #2. Extending a creating your own variable hierarchies are addressed below.\n", + "The Aviary-core provides the pre-built variable hierarchies listed above. However, for the user that would like to add external subsystems to Aviary, the variables in the Aviary-core hierarchies may not be sufficient. In this case, there are three options: 1) extend the existing variable hierarchies from Aviary-core, 2) create your own variable hierarchies and merge them with the existing hierarchies from Aviary-core, 3) do a combination of #1 and #2. Extending and creating your own variable hierarchies are addressed below.\n", "\n", "### Extend the Existing Aviary-core Hierarchies\n", - "If you are just adding one external subsystem to an Aviary-core model, or if you are adding multiple subsystems all being developed in the same location by the same person, our suggested path is to create one extension of the Aviary-core hierarchies. The method to extend the Aviary-core variable hierarchies is to subclass those hierarchies (which preserves all the data from the original hierarchies) and add your own additional variables as necessary. To take a simple example, let's say we wanted to add a little bit of detail to the existing `Aircraft` variable hierarchy for our external subsystem. The detail we would like to add is some information about the flaps on the wing as well as a jury strut and a center of gravity location. We would extend the existing variable hierarchy using the following code:" + "If you are just adding one external subsystem to an Aviary-core model, or if you are adding multiple subsystems all being developed in the same location by the same person, our suggested path is to create one extension of the Aviary-core hierarchies. The method to extend the Aviary-core variable hierarchies is to subclass those hierarchies (which preserves all the data from the original hierarchies) and add your own additional variables as necessary. To take a simple example, let's say we wanted to add a little bit of detail to the existing {glue:md}`Aircraft` variable hierarchy for our external subsystem. The detail we would like to add is some information about the flaps on the wing as well as a jury strut and a center of gravity location. We would extend the existing variable hierarchy using the following code:" ] }, { @@ -209,12 +268,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "There are a few things to notice about this code. The first is that, unlike the Aviary-core `Aircraft` variable hierarchy, this hierarchy has variables with a depth of two and a depth of four. When we extend the Aviary-core variable hierarchies we are not restricted to the depth of three that the core hierarchies have. The second thing to notice is that when we extend an inner class that already exists in the Aviary-core hierarchy (`Wing`) we subclass the inner class from the Aviary-core so that we can preserve all the information from that Aviary-core inner class. However, in the case of the inner class `Jury` which does not already exist in the Aviary-core hierarchy, there is nothing to subclass, and thus that inner class stands on its own.\n", + "There are a few things to notice about this code. The first is that, unlike the Aviary-core {glue:md}`Aircraft` variable hierarchy, this hierarchy has variables with a depth of two and a depth of four. When we extend the Aviary-core variable hierarchies we are not restricted to the depth of three that the core hierarchies have. The second thing to notice is that when we extend an inner class that already exists in the Aviary-core hierarchy ({glue:md}`Wing`) we subclass the inner class from the Aviary-core so that we can preserve all the information from that Aviary-core inner class. However, in the case of the inner class `Jury` which does not already exist in the Aviary-core hierarchy, there is nothing to subclass, and thus that inner class stands on its own.\n", "\n", "When extending the Aviary-core variable hierarchies, you can create one extension of each type of hierarchy, or you can create multiple extensions of each type which will eventually be merged together. If you are developing only one external subsystem or all your subsystems are being developed in the same place by the same person, one extension of each Aviary-core hierarchy should suffice. However, if you have multiple developers working on different subsystems in different locations, each developer may want to create their own extension. To aid in this case, Aviary provides the capability to merge together multiple hierarchies of the same type into one hierarchy of that type. More information on this capability is shown at the bottom of this page.\n", "\n", "### Creating Your Own Variable Hierarchy\n", - "It is possible to create your own variable hierarchy that is not an extension of the Aviary-core variable hierarchies, but there are specific things to know. The use case for this is mostly when you would like to create a third hierarchy that does not fall under either the `Aircraft` or the `Mission` categories. An example of this might be if you are doing fleet-level analyses and would like a `Fleet` variable hierarchy.\n", + "It is possible to create your own variable hierarchy that is not an extension of the Aviary-core variable hierarchies, but there are specific things to know. The use case for this is mostly when you would like to create a third hierarchy that does not fall under either the {glue:md}`Aircraft` or the {glue:md}`Mission` categories. An example of this might be if you are doing fleet-level analyses and would like a `Fleet` variable hierarchy.\n", "\n", "A new variable hierarchy can be created in exactly the same manner that Aviary-core creates its own variable hierarchies, illustrated above. For the case of creating a new `Fleet` variable hierarchy, it might look something like this:" ] @@ -245,17 +304,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Usually if you are creating your own variable hierarchy that is not an extension of the Aviary-core hierarchies it will be because you want a hierarchy that is not of the type `Aircraft` or `Mission`. In this case, your new hierarchy is relatively straightforward, you can create it and simply provide it to Aviary along with the core hierarchies or extensions thereof. However, if you are creating your own variable hierarchy that is of the type `Aircraft` or `Mission` but is not an extension of the Aviary-core hierarchies (which we do not recommend doing), there are a few things to keep in mind:\n", + "Usually if you are creating your own variable hierarchy that is not an extension of the Aviary-core hierarchies it will be because you want a hierarchy that is not of the type {glue:md}`Aircraft` or {glue:md}`Mission`. In this case, your new hierarchy is relatively straightforward, you can create it and simply provide it to Aviary along with the core hierarchies or extensions thereof. However, if you are creating your own variable hierarchy that is of the type {glue:md}`Aircraft` or {glue:md}`Mission` but is not an extension of the Aviary-core hierarchies (which we do not recommend doing), there are a few things to keep in mind:\n", "- The newly created variable hierarchy does not have any of the information from the Aviary-core hierarchy. You *must* still provide Aviary with the input values and information from the Aviary-core hierarchy, or all the inputs will be set to their default values which are unlikely to suit your needs.\n", " + You can merge together all variable hierarchies that are of the same type (see below).\n", "- You should avoid adding variables to your created hierarchy that already exist in the Aviary-core hierarchy, as this may cause conflicts when merging hierarchies together.\n", "\n", - "In general, we recommend extending the Aviary-core variable hierarchies whenever possible, and only creating a new hierarchy from scratch when the categories of `Aircraft` and `Mission` do not fit your needs.\n", + "In general, we recommend extending the Aviary-core variable hierarchies whenever possible, and only creating a new hierarchy from scratch when the categories of {glue:md}`Aircraft` and {glue:md}`Mission` do not fit your needs.\n", "\n", "## Merging Extended Hierarchies\n", "As briefly mentioned above, when there are multiple variable hierarchies of the same type we need the ability to merge them together into one hierarchy of that type which includes all the information from the different hierarchies. Aviary provides this capability through the `merge_hierarchies()` method. The goal of this method is to clean up all the user hierarchies so that Aviary can be provided with only one hierarchy of each type, and also to resolve any discrepancies between different hierarchies of the same type.\n", "\n", - "Using the [`merge_hierarchies()` function](../theory_guide/merging_syntax) is quite simple. It takes a list of all the hierarchies you would like to merge together and returns one hierarchy that has the merged information from all the input hierarchies, as in this snippet of code where we are merging together three notional `Aircraft` type hierarchies:" + "Using the [`merge_hierarchies()` function](../theory_guide/merging_syntax) is quite simple. It takes a list of all the hierarchies you would like to merge together and returns one hierarchy that has the merged information from all the input hierarchies, as in this snippet of code where we are merging together three notional {glue:md}`Aircraft` type hierarchies:" ] }, { @@ -309,11 +368,8 @@ ], "metadata": { "celltoolbar": "Tags", - "interpreter": { - "hash": "e6c7471802ed76737b16357fb02af5587f3a4cbee5ea7658f3f9a6981469039b" - }, "kernelspec": { - "display_name": "Python 3", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -327,7 +383,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" }, "orphan": true }, diff --git a/aviary/docs/user_guide/variable_metadata.ipynb b/aviary/docs/user_guide/variable_metadata.ipynb index 533604b64..dd808fdb4 100644 --- a/aviary/docs/user_guide/variable_metadata.ipynb +++ b/aviary/docs/user_guide/variable_metadata.ipynb @@ -27,11 +27,11 @@ " glue_variable(arg, md_code=False)\n", "\n", "glue_variable(get_variable_name(Aircraft.Wing.MASS_SCALER), md_code=True)\n", - "glue_variable('Aircraft', get_variable_name(Aircraft.Wing.MASS_SCALER).split('.')[0], md_code=True)\n", + "glue_variable(f'{Aircraft=}'.split('=')[0], md_code=True)\n", "glue_variable(get_variable_name(Aircraft.Wing.SPAN), md_code=False)\n", "glue_variable('utils/develop_metadata.py', md_code=False)\n", "\n", - "def get_Function_names(file_path):\n", + "def get_function_names(file_path):\n", " \"\"\"\n", " Get all function names in a file using ast.\n", " \"\"\"\n", @@ -48,13 +48,8 @@ " if isinstance(node, ast.FunctionDef)\n", " ]\n", " \n", - " return function_names\n", - "\n", - "file_path = av.get_path('utils/develop_metadata.py')\n", - "function_names = get_Function_names(file_path)\n", - "for function_name in function_names:\n", - " if not function_name.startswith('_'):\n", - " glue_variable(function_name+'()', md_code=True)\n" + " return set(function_names)\n", + "\n" ] }, { @@ -231,7 +226,9 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.utils.develop_metadata import add_meta_data, update_meta_data" + "from aviary.utils.develop_metadata import add_meta_data, update_meta_data\n", + "glue_variable(f'{add_meta_data=}'.split('=')[0]+'()', md_code=True)\n", + "glue_variable(f'{update_meta_data=}'.split('=')[0]+'()', md_code=True)" ] }, { @@ -363,13 +360,13 @@ "glue_variable('utils/merge_variable_metadata.py', md_code=False)\n", "\n", "file_path = av.get_path('utils/merge_hierarchies.py')\n", - "function_names = get_Function_names(file_path)\n", + "function_names = get_function_names(file_path)\n", "for function_name in function_names:\n", " if not function_name.startswith('_'):\n", " glue_variable(function_name+'()', md_code=True)\n", "\n", "file_path = av.get_path('utils/merge_variable_metadata.py')\n", - "function_names = get_Function_names(file_path)\n", + "function_names = get_function_names(file_path)\n", "for function_name in function_names:\n", " if not function_name.startswith('_'):\n", " glue_variable(function_name+'()', md_code=True)\n" @@ -382,9 +379,9 @@ "{glue:md}`ExtendedMetaData` now contains the metadata of all the Aviary-core variables along with the metadata information that we just added.\n", "\n", "## Merging Independent Metadata\n", - "Extending the metadata is great, but sometimes users will end up with multiple metadata dictionaries because different subsystem developers extended the metadata (and created associated variable hierarchies) to suit their own needs. Aviary needs to be given one single metadata dictionary which contains metadata of all the variables it has been given, so we need to be able to merge together multiple metadata dictionaries into one. The {glue:md}`merge_meta_data()` function has been provided to combine all the different metadata into one. The `merge_meta_data()` function behaves quite similarly to the{glue:md} `merge_hierarchies()` function. It takes in a string of metadata dictionaries that need to be merged together, and it returns a single metadata dictionary containing the metadata from all the individual dictionaries.\n", + "Extending the metadata is great, but sometimes users will end up with multiple metadata dictionaries because different subsystem developers extended the metadata (and created associated variable hierarchies) to suit their own needs. Aviary needs to be given one single metadata dictionary which contains metadata of all the variables it has been given, so we need to be able to merge together multiple metadata dictionaries into one. The {glue:md}`merge_meta_data()` function has been provided to combine all the different metadata into one. The {glue:md}`merge_meta_data()` function behaves quite similarly to the {glue:md}`merge_hierarchies()` function. It takes in a string of metadata dictionaries that need to be merged together, and it returns a single metadata dictionary containing the metadata from all the individual dictionaries.\n", "\n", - "Let's say that we have created our `ExtendedAircraft` and `ExtendedMetaData` from above, and that elsewhere we have a subsystem that requires information about engine cooling system mass as well as whether the aircraft has winglets. Below is the buildup of the {glue:md}`Aircraft` type hierarchy and the metadata for our new subsystem:" + "Let's say that we have created our {glue:md}`ExtendedAircraft` and {glue:md}`ExtendedMetaData` from above, and that elsewhere we have a subsystem that requires information about engine cooling system mass as well as whether the aircraft has winglets. Below is the buildup of the {glue:md}`Aircraft` type hierarchy and the metadata for our new subsystem:" ] }, { From 8842366427ffb73b9ee0d7112dee3d81abe5b37a Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 13 Dec 2024 17:24:42 -0800 Subject: [PATCH 35/48] glue variables in overriding.ipynb --- .../docs/user_guide/features/overriding.ipynb | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/aviary/docs/user_guide/features/overriding.ipynb b/aviary/docs/user_guide/features/overriding.ipynb index 2948c2b1e..405ee8ab5 100644 --- a/aviary/docs/user_guide/features/overriding.ipynb +++ b/aviary/docs/user_guide/features/overriding.ipynb @@ -53,6 +53,23 @@ "aviary_inputs.set_val(Aircraft.HorizontalTail.MASS, 2200.0, units='lbm')" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c32c524", + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.api import Aircraft\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "glue_variable(get_variable_name(Aircraft.HorizontalTail.MASS), md_code=False)" + ] + }, { "cell_type": "markdown", "id": "encouraging-picnic", @@ -60,7 +77,7 @@ "source": [ "## Replacing Computed Value with the Output of Another Component\n", "\n", - "Consider a case where we have added one component that computes the mass of the horizontal tail. We want to override the internally computed value of the mass with a new value that comes from an external component. We can do this in the level 2 interface when we define our builder, by simply providing an output that uses Aviary's name in the variable hierarchy. (i.e., Aircraft.HorizontalTail.MASS for this case) When we do this, aviary will automatically detect that an external subsystem is providing this variable, and will override the internal calculation." + "Consider a case where we have added one component that computes the mass of the horizontal tail. We want to override the internally computed value of the mass with a new value that comes from an external component. We can do this in the level 2 interface when we define our builder, by simply providing an output that uses Aviary's name in the variable hierarchy. (i.e., {glue:md}`Aircraft.HorizontalTail.MASS` for this case) When we do this, aviary will automatically detect that an external subsystem is providing this variable, and will override the internal calculation." ] }, { @@ -152,7 +169,7 @@ "metadata": { "celltoolbar": "Tags", "kernelspec": { - "display_name": "Python 3", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -166,7 +183,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.17" + "version": "3.9.18" }, "orphan": true }, From 75a5453fbd514bbae241dcb060610dbf3f4c2315 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 13 Dec 2024 18:53:25 -0800 Subject: [PATCH 36/48] glue variables in externally_supported_subsystems.ipynb and modeling_exercise.ipynb --- .../externally_supported_subsystems.ipynb | 6 ++- .../misc_resources/modeling_exercise.ipynb | 44 +++++++++++++++---- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/aviary/docs/misc_resources/externally_supported_subsystems.ipynb b/aviary/docs/misc_resources/externally_supported_subsystems.ipynb index 76cb510d2..504c0c427 100644 --- a/aviary/docs/misc_resources/externally_supported_subsystems.ipynb +++ b/aviary/docs/misc_resources/externally_supported_subsystems.ipynb @@ -7,7 +7,7 @@ "# Externally Supported Subsystems\n", "\n", "Aviary supports any generic subsystem that a user adds.\n", - "We include some examples within the Aviary repo within the `aviary/examples/external_subsystems` folder." + "We include some examples within the Aviary repo within the {glue:md}`aviary/examples/external_subsystems` folder." ] }, { @@ -22,7 +22,9 @@ "source": [ "# Testing Cell\n", "import aviary.api as av\n", - "av.get_path('examples/external_subsystems')" + "from aviary.utils.doctape import glue_variable\n", + "av.get_path('examples/external_subsystems')\n", + "glue_variable('aviary/examples/external_subsystems', md_code=True)" ] } ], diff --git a/aviary/docs/misc_resources/modeling_exercise.ipynb b/aviary/docs/misc_resources/modeling_exercise.ipynb index 526690215..c905067b8 100644 --- a/aviary/docs/misc_resources/modeling_exercise.ipynb +++ b/aviary/docs/misc_resources/modeling_exercise.ipynb @@ -20,8 +20,8 @@ "\n", "## Task 1: Run a basic Aviary script\n", "\n", - "Aviary ships with multiple examples in the `aviary/examples` directory.\n", - "The most basic, `run_basic_aviary_example.py`, [(available here)](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/run_basic_aviary_example.py) is our first starting point.\n", + "Aviary ships with multiple examples in the {glue:md}`aviary/examples` directory.\n", + "The most basic, {glue:md}`run_basic_aviary_example.py`, [(available here)](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/run_basic_aviary_example.py) is our first starting point.\n", "Run this script in your terminal." ] }, @@ -37,7 +37,10 @@ "source": [ "# Testing Cell\n", "import aviary.api as av\n", - "av.get_path('examples/run_basic_aviary_example.py')" + "from aviary.utils.doctape import glue_variable\n", + "av.get_path('examples/run_basic_aviary_example.py')\n", + "glue_variable('aviary/examples', md_code=True)\n", + "glue_variable('run_basic_aviary_example.py', md_code=True)" ] }, { @@ -76,6 +79,27 @@ "_command_map['dashboard'];" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.interface.methods_for_level2 import AviaryGroup\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "ag = AviaryGroup()\n", + "opts = list(ag.options)\n", + "for opt in opts:\n", + " if opt == 'phase_info':\n", + " glue_variable('phase_info', md_code=True)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -88,10 +112,10 @@ "The next step is to run an Aviary case with a mission profile that you define.\n", "Please follow the [instructions in this example doc](../examples/simple_mission_example) to create a custom mission profile.\n", "Once you have created your custom mission profile, run the Aviary case following the instructions in the example doc.\n", - "If you are not able to successfully create a custom `phase_info` object to define the mission, please use the default one defined in the example.\n", + "If you are not able to successfully create a custom {glue:md}`phase_info` object to define the mission, please use the default one defined in the example.\n", "\n", "```{note}\n", - "The survey will ask you to provide a copy of the `phase_info` object you create, so please save this information for later.\n", + "The survey will ask you to provide a copy of the {glue:md}`phase_info` object you create, so please save this information for later.\n", "```\n", "\n", "Again open the Aviary dashboard and visually examine the results by running the following command in your terminal:\n", @@ -103,7 +127,7 @@ "## Task 3: Run a mission with a reserve phase\n", "\n", "Aviary has the capability to run a mission with a reserve phase as [detailed in the docs here](https://openmdao.github.io/Aviary/examples/reserve_missions.html).\n", - "The included example, `run_reserve_mission_fixedrange.py`, [(available here)](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/reserve_missions/run_reserve_mission_fixedrange.py) demonstrates how to run a mission with a reserve phase.\n", + "The included example, {glue:md}`run_reserve_mission_fixedrange.py`, [(available here)](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/reserve_missions/run_reserve_mission_fixedrange.py) demonstrates how to run a mission with a reserve phase.\n", "Please copy the contents of this file into a new Python script." ] }, @@ -119,7 +143,9 @@ "source": [ "# Testing Cell\n", "import aviary.api as av\n", - "av.get_path('examples/reserve_missions/run_reserve_mission_fixedrange.py');" + "from aviary.utils.doctape import glue_variable\n", + "av.get_path('examples/reserve_missions/run_reserve_mission_fixedrange.py');\n", + "glue_variable('run_reserve_mission_fixedrange.py', md_code=True)" ] }, { @@ -141,7 +167,7 @@ ], "metadata": { "kernelspec": { - "display_name": "latest_env", + "display_name": "av1", "language": "python", "name": "python3" }, @@ -155,7 +181,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.18" } }, "nbformat": 4, From 570f05afbd06ab3a9aec00f4889fd39fd31c2b04 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 16 Dec 2024 09:04:59 -0800 Subject: [PATCH 37/48] move get_class_names() and get_function_names() to doctape.py --- ...S_based_detailed_takeoff_and_landing.ipynb | 42 +-------------- aviary/docs/user_guide/SGM_capabilities.ipynb | 20 +------- aviary/docs/user_guide/input_files.ipynb | 19 +------ .../docs/user_guide/variable_metadata.ipynb | 22 +------- aviary/utils/doctape.py | 51 +++++++++++++++++++ 5 files changed, 56 insertions(+), 98 deletions(-) diff --git a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb index e4e6f626d..814663f2a 100644 --- a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb +++ b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb @@ -119,56 +119,16 @@ "outputs": [], "source": [ "# Testing Cell\n", - "import ast\n", "import inspect\n", "import aviary.api as av\n", + "from aviary.utils.doctape import get_class_names\n", "from aviary.mission.flops_based.phases.detailed_takeoff_phases import TakeoffTrajectory\n", "\n", - "def get_class_names(file_path):\n", - " # Read the content of the file\n", - " with open(file_path, 'r') as file:\n", - " file_content = file.read()\n", - " \n", - " # Parse the file content into an AST\n", - " tree = ast.parse(file_content)\n", - " \n", - " # Extract class names\n", - " class_names = [\n", - " node.name for node in ast.walk(tree)\n", - " if isinstance(node, ast.ClassDef)\n", - " ]\n", - " \n", - " return class_names\n", - "\n", - "def get_Function_names(file_path):\n", - " \"\"\"\n", - " Get all function names in a file using ast.\n", - " \"\"\"\n", - " # Read the content of the file\n", - " with open(file_path, 'r') as file:\n", - " file_content = file.read()\n", - " \n", - " # Parse the file content into an AST\n", - " tree = ast.parse(file_content)\n", - " \n", - " # Extract function names\n", - " function_names = [\n", - " node.name for node in ast.walk(tree)\n", - " if isinstance(node, ast.FunctionDef)\n", - " ]\n", - " \n", - " return function_names\n", - "\n", "file_path = av.get_path('mission/flops_based/phases/detailed_takeoff_phases.py')\n", "takeoff_class_names = get_class_names(file_path)\n", "for class_name in takeoff_class_names:\n", " glue_variable(class_name, md_code=True)\n", "\n", - "#takeoff_function_names = get_Function_names(file_path)\n", - "# for function_name in takeoff_function_names:\n", - "# if not function_name.startswith('_'):\n", - "# glue_variable(function_name+'()', md_code=True)\n", - "\n", "# Get all functions of class TakeoffTrajectory\n", "functs = inspect.getmembers(TakeoffTrajectory, predicate=inspect.isfunction)\n", "takeoff_functs = []\n", diff --git a/aviary/docs/user_guide/SGM_capabilities.ipynb b/aviary/docs/user_guide/SGM_capabilities.ipynb index 84ae3deb6..c5513feb3 100644 --- a/aviary/docs/user_guide/SGM_capabilities.ipynb +++ b/aviary/docs/user_guide/SGM_capabilities.ipynb @@ -331,27 +331,11 @@ "outputs": [], "source": [ "# Testing Cell\n", - "import ast\n", "import aviary.api as av\n", - "\n", - "def get_Function_names(file_path):\n", - " # Read the content of the file\n", - " with open(file_path, 'r') as file:\n", - " file_content = file.read()\n", - " \n", - " # Parse the file content into an AST\n", - " tree = ast.parse(file_content)\n", - " \n", - " # Extract function names\n", - " function_names = [\n", - " node.name for node in ast.walk(tree)\n", - " if isinstance(node, ast.FunctionDef)\n", - " ]\n", - " \n", - " return function_names\n", + "from aviary.utils.doctape import get_function_names\n", "\n", "file_path = av.get_path('interface/default_phase_info/two_dof_fiti.py')\n", - "takeoff_function_names = get_Function_names(file_path)\n", + "takeoff_function_names = get_function_names(file_path)\n", "for func_name in takeoff_function_names:\n", " glue_variable(func_name, md_code=True)\n", "\n", diff --git a/aviary/docs/user_guide/input_files.ipynb b/aviary/docs/user_guide/input_files.ipynb index 91ea4157a..02536db01 100644 --- a/aviary/docs/user_guide/input_files.ipynb +++ b/aviary/docs/user_guide/input_files.ipynb @@ -76,25 +76,8 @@ "outputs": [], "source": [ "# Testing Cell\n", - "import ast\n", "from aviary.utils.csv_data_file import read_data_file, write_data_file\n", - "from aviary.utils.doctape import check_value, get_variable_name, glue_variable\n", - "\n", - "def get_Function_names(file_path):\n", - " # Read the content of the file\n", - " with open(file_path, 'r') as file:\n", - " file_content = file.read()\n", - " \n", - " # Parse the file content into an AST\n", - " tree = ast.parse(file_content)\n", - " \n", - " # Extract function names\n", - " function_names = [\n", - " node.name for node in ast.walk(tree)\n", - " if isinstance(node, ast.FunctionDef)\n", - " ]\n", - " \n", - " return function_names\n", + "from aviary.utils.doctape import check_value, get_Function_names, get_variable_name, glue_variable\n", "\n", "file_path = av.get_path('utils/csv_data_file.py')\n", "takeoff_function_names = get_Function_names(file_path)\n", diff --git a/aviary/docs/user_guide/variable_metadata.ipynb b/aviary/docs/user_guide/variable_metadata.ipynb index dd808fdb4..8e276bf51 100644 --- a/aviary/docs/user_guide/variable_metadata.ipynb +++ b/aviary/docs/user_guide/variable_metadata.ipynb @@ -12,7 +12,6 @@ "source": [ "# Testing Cell\n", "\n", - "import ast\n", "import inspect\n", "import aviary.api as av\n", "from aviary.api import Aircraft\n", @@ -30,25 +29,6 @@ "glue_variable(f'{Aircraft=}'.split('=')[0], md_code=True)\n", "glue_variable(get_variable_name(Aircraft.Wing.SPAN), md_code=False)\n", "glue_variable('utils/develop_metadata.py', md_code=False)\n", - "\n", - "def get_function_names(file_path):\n", - " \"\"\"\n", - " Get all function names in a file using ast.\n", - " \"\"\"\n", - " # Read the content of the file\n", - " with open(file_path, 'r') as file:\n", - " file_content = file.read()\n", - " \n", - " # Parse the file content into an AST\n", - " tree = ast.parse(file_content)\n", - " \n", - " # Extract function names\n", - " function_names = [\n", - " node.name for node in ast.walk(tree)\n", - " if isinstance(node, ast.FunctionDef)\n", - " ]\n", - " \n", - " return set(function_names)\n", "\n" ] }, @@ -354,7 +334,7 @@ "# Testing Cell\n", "\n", "import aviary.api as av\n", - "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.doctape import get_function_names, glue_variable\n", "\n", "glue_variable('utils/merge_hierarchies.py', md_code=False)\n", "glue_variable('utils/merge_variable_metadata.py', md_code=False)\n", diff --git a/aviary/utils/doctape.py b/aviary/utils/doctape.py index db3806226..b6fff936d 100644 --- a/aviary/utils/doctape.py +++ b/aviary/utils/doctape.py @@ -1,3 +1,4 @@ +import ast import inspect import subprocess import tempfile @@ -405,3 +406,53 @@ def glue_keys(dict_of_dicts: dict, display=True) -> list: for key in all_keys: glue_variable(key, md_code=True, display=display) return all_keys + + +def get_class_names(file_path): + """ + Retrieve all class names from a given file and return as a set + + Parameters + ---------- + file_path: str or Path + file path + """ + # Read the content of the file + with open(file_path, 'r') as file: + file_content = file.read() + + # Parse the file content into an AST + tree = ast.parse(file_content) + + # Extract class names + class_names = [ + node.name for node in ast.walk(tree) + if isinstance(node, ast.ClassDef) + ] + + return set(class_names) + + +def get_function_names(file_path): + """ + Get all function names in a given file and return as a set. + + Parameters + ---------- + file_path: str or Path + file path + """ + # Read the content of the file + with open(file_path, 'r') as file: + file_content = file.read() + + # Parse the file content into an AST + tree = ast.parse(file_content) + + # Extract function names + function_names = [ + node.name for node in ast.walk(tree) + if isinstance(node, ast.FunctionDef) + ] + + return set(function_names) From 1ce5e768717964b6c6ee2a1b3134ee7b293df47a Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 16 Dec 2024 09:05:28 -0800 Subject: [PATCH 38/48] move get_class_names() and get_function_names() to doctape.py --- .../docs/user_guide/variable_hierarchy.ipynb | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/aviary/docs/user_guide/variable_hierarchy.ipynb b/aviary/docs/user_guide/variable_hierarchy.ipynb index 2f94bb674..679832646 100644 --- a/aviary/docs/user_guide/variable_hierarchy.ipynb +++ b/aviary/docs/user_guide/variable_hierarchy.ipynb @@ -11,7 +11,7 @@ "outputs": [], "source": [ "import ast\n", - "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "from aviary.utils.doctape import get_function_names, get_variable_name, glue_variable\n", "import aviary.api as av\n", "from aviary.api import Aircraft, Mission\n", "from aviary.variable_info.variables import Aircraft\n", @@ -27,25 +27,6 @@ "glue_variable(f'{Mission=}'.split('=')[0], md_code=True)\n", "glue_variable(f'{Aircraft.Wing=}'.split('=')[0].split('.')[1], md_code=True)\n", "\n", - "def get_function_names(file_path):\n", - " \"\"\"\n", - " Get all function names in a file using ast.\n", - " \"\"\"\n", - " # Read the content of the file\n", - " with open(file_path, 'r') as file:\n", - " file_content = file.read()\n", - " \n", - " # Parse the file content into an AST\n", - " tree = ast.parse(file_content)\n", - " \n", - " # Extract function names\n", - " function_names = [\n", - " node.name for node in ast.walk(tree)\n", - " if isinstance(node, ast.FunctionDef)\n", - " ]\n", - " \n", - " return set(function_names)\n", - "\n", "file_path = av.get_path('variable_info/functions.py')\n", "var_function_names = get_function_names(file_path)\n", "for function_name in var_function_names:\n", From ba1f04e4398d8395665222b2a93aaf92af372fa6 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 16 Dec 2024 19:58:55 -0800 Subject: [PATCH 39/48] polish glue task --- ...S_based_detailed_takeoff_and_landing.ipynb | 17 +++- aviary/docs/user_guide/SGM_capabilities.ipynb | 24 +++--- aviary/docs/user_guide/aerodynamics.ipynb | 6 +- aviary/docs/user_guide/aviary_commands.ipynb | 12 ++- .../battery_subsystem_example.ipynb | 35 ++++---- .../drawing_and_running_simple_missions.ipynb | 67 ++++++---------- ..._same_mission_at_different_UI_levels.ipynb | 50 ++++++------ aviary/docs/user_guide/external_aero.ipynb | 21 ++++- .../features_and_functionalities.ipynb | 12 ++- .../docs/user_guide/hamilton_standard.ipynb | 26 ++++-- aviary/docs/user_guide/input_files.ipynb | 4 +- aviary/docs/user_guide/mass.ipynb | 79 +++++++++++++++---- aviary/docs/user_guide/multi_mission.ipynb | 2 +- .../docs/user_guide/off_design_missions.ipynb | 22 +++++- .../user_guide/pre_mission_and_mission.ipynb | 4 +- aviary/docs/user_guide/propulsion.ipynb | 29 ++++--- aviary/docs/user_guide/reserve_missions.ipynb | 17 ++-- .../step_by_step_external_guide.ipynb | 19 ++++- .../docs/user_guide/variable_hierarchy.ipynb | 6 +- .../docs/user_guide/variable_metadata.ipynb | 23 +++--- 20 files changed, 294 insertions(+), 181 deletions(-) diff --git a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb index 814663f2a..3237c7fae 100644 --- a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb +++ b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb @@ -12,12 +12,21 @@ "outputs": [], "source": [ "# Testing Cell\n", + "import inspect\n", + "from aviary.mission.phase_builder_base import PhaseBuilderBase\n", "from aviary.utils.aviary_values import AviaryValues\n", - "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder\n", "\n", - "glue_variable(f'{AviaryValues=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{CoreAerodynamicsBuilder=}'.split('=')[0], md_code=True)" + "glue_variable(get_variable_name(AviaryValues), md_code=True)\n", + "glue_variable(get_variable_name(CoreAerodynamicsBuilder), md_code=True)\n", + "\n", + "# glue all arguments of function PhaseBuilderBase.__init__(self, name=None, meta_data=None, code_origin=None)\n", + "sigs = inspect.signature(PhaseBuilderBase)\n", + "parameters = sigs.parameters\n", + "for name, param in parameters.items():\n", + " glue_variable(name, md_code=True)\n", + " # print(f'Name: {name}, Default: {param.default}, Kind: {param.kind}')" ] }, { @@ -45,7 +54,7 @@ "## Takeoff\n", "\n", "### Aerodynamics Builder\n", - "Both takeoff and landing are designed to use the FLOPS-derived `low_speed` aerodynamics method defined in the {glue:md}`CoreAerodynamicsBuilder`. The builder supports several options specified in a `subsystem_options` dictionary provided to the phase builder. The most important subsystem options are the three required sequences: `angles_of_attack`, `lift_coefficients`, and `drag_coefficients`. At least two values must be specified in `angles_of_attack`. For each value in `angles_of_attack`, there must be one dependent value at the corresponding index in each of `lift_coefficients` and `drag_coefficients`.\n", + "Both takeoff and landing are designed to use the FLOPS-derived `low_speed` aerodynamics method defined in the {glue:md}`CoreAerodynamicsBuilder`. The builder supports several options specified in a {glue:md}`subsystem_options` dictionary provided to the phase builder. The most important subsystem options are the three required sequences: `angles_of_attack`, `lift_coefficients`, and `drag_coefficients`. At least two values must be specified in `angles_of_attack`. For each value in `angles_of_attack`, there must be one dependent value at the corresponding index in each of `lift_coefficients` and `drag_coefficients`.\n", "\n", "Once a {glue:md}`CoreAerodynamicsBuilder` object is created, it can be used to create a phase builder.\n", "The phase builder will pass the aerodynamics builder down to where it is needed to\n", diff --git a/aviary/docs/user_guide/SGM_capabilities.ipynb b/aviary/docs/user_guide/SGM_capabilities.ipynb index c5513feb3..e68c3d0cb 100644 --- a/aviary/docs/user_guide/SGM_capabilities.ipynb +++ b/aviary/docs/user_guide/SGM_capabilities.ipynb @@ -17,7 +17,7 @@ "ag = AviaryGroup()\n", "opts = list(ag.options)\n", "for opt in opts:\n", - " if opt == 'phase_info':\n", + " if opt == 'phase_info': # only need this option to glue\n", " glue_variable('phase_info', md_code=True)" ] }, @@ -192,15 +192,15 @@ "from aviary.mission.gasp_based.ode.time_integration_base_classes import event_trigger\n", "from aviary.mission.gasp_based.phases.time_integration_phases import SGMRotation\n", "from aviary.mission.gasp_based.phases.time_integration_traj import FlexibleTraj\n", - "from aviary.utils.doctape import check_value, glue_variable\n", + "from aviary.utils.doctape import check_value, get_variable_name, glue_variable\n", "#from aviary.interface.default_phase_info.two_dof_fiti import add_default_sgm_args\n", "\n", "rotation_trigger: event_trigger = SGMRotation(ode_args=ode_args).triggers[0]\n", "check_value(rotation_trigger.state,'normal_force')\n", - "glue_variable(f'{event_trigger=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{event_trigger=}'.split('=')[0]+'s', md_code=False)\n", - "glue_variable(f'{SGMRotation=}'.split('=')[0], md_code=False)\n", - "glue_variable(f'{FlexibleTraj=}'.split('=')[0], md_code=False)\n", + "glue_variable(get_variable_name(event_trigger), md_code=True)\n", + "glue_variable(get_variable_name(event_trigger)+'s', md_code=False)\n", + "glue_variable(get_variable_name(SGMRotation), md_code=False)\n", + "glue_variable(get_variable_name(FlexibleTraj), md_code=False)\n", "\n", "signature = inspect.signature(SGMRotation.__init__)\n", "# Print argument details\n", @@ -332,18 +332,18 @@ "source": [ "# Testing Cell\n", "import aviary.api as av\n", - "from aviary.utils.doctape import get_function_names\n", + "from aviary.utils.doctape import get_variable_name, get_function_names\n", "\n", "file_path = av.get_path('interface/default_phase_info/two_dof_fiti.py')\n", "takeoff_function_names = get_function_names(file_path)\n", "for func_name in takeoff_function_names:\n", " glue_variable(func_name, md_code=True)\n", "\n", - "glue_variable(f'{ascent_phases=}'.split('=')[0], md_code=False)\n", - "glue_variable(f'{takeoff_phases=}'.split('=')[0], md_code=False)\n", - "glue_variable(f'{climb_phases=}'.split('=')[0], md_code=False)\n", - "glue_variable(f'{cruise_phase=}'.split('=')[0], md_code=False)\n", - "glue_variable(f'{descent_phases=}'.split('=')[0], md_code=False)" + "glue_variable(get_variable_name(ascent_phases), md_code=False)\n", + "glue_variable(get_variable_name(takeoff_phases), md_code=False)\n", + "glue_variable(get_variable_name(climb_phases), md_code=False)\n", + "glue_variable(get_variable_name(cruise_phase), md_code=False)\n", + "glue_variable(get_variable_name(descent_phases), md_code=False)" ] } ], diff --git a/aviary/docs/user_guide/aerodynamics.ipynb b/aviary/docs/user_guide/aerodynamics.ipynb index ebae50a60..2fdc9fd19 100644 --- a/aviary/docs/user_guide/aerodynamics.ipynb +++ b/aviary/docs/user_guide/aerodynamics.ipynb @@ -20,10 +20,10 @@ "glue_variable(get_variable_name(CoreAerodynamicsBuilder), md_code=True)\n", "\n", "EquationsOfMotion = av.EquationsOfMotion\n", - "glue_variable(get_variable_name(EquationsOfMotion.HEIGHT_ENERGY).split('.')[1].lower().replace('_','-'), md_code=False)\n", + "glue_variable('height-energy', get_variable_name(EquationsOfMotion.HEIGHT_ENERGY).split('.')[1].lower().replace('_','-'), md_code=False)\n", "glue_variable(get_variable_name(EquationsOfMotion.TWO_DEGREES_OF_FREEDOM).split('.')[1].lower().replace('_','-'), md_code=False)\n", "\n", - "# glue all argument of function CoreAerodynamicsBuilder.__init__()\n", + "# glue all arguments of function CoreAerodynamicsBuilder.__init__()\n", "sigs = inspect.signature(CoreAerodynamicsBuilder)\n", "parameters = sigs.parameters\n", "for name, param in parameters.items():\n", @@ -75,7 +75,7 @@ "sigs = inspect.signature(run_aviary)\n", "parameters = sigs.parameters\n", "for name, param in parameters.items():\n", - " if name == 'phase_info':\n", + " if name == 'phase_info': # for this file, we need one argument 'phase_info'\n", " glue_variable(name, md_code=True)" ] }, diff --git a/aviary/docs/user_guide/aviary_commands.ipynb b/aviary/docs/user_guide/aviary_commands.ipynb index 2d66e87d7..2a37c73ff 100644 --- a/aviary/docs/user_guide/aviary_commands.ipynb +++ b/aviary/docs/user_guide/aviary_commands.ipynb @@ -126,13 +126,17 @@ "source": [ "# Testing Cell\n", "import subprocess\n", - "command = 'aviary run_mission models/small_single_aisle/small_single_aisle_GwGm.csv'\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "str_model = 'small_single_aisle_GwGm'\n", + "str_folder = 'models/small_single_aisle'\n", + "command = 'aviary run_mission ' + str_folder + '/' + str_model + '.csv'\n", "command += ' --max_iter 0 --optimizer IPOPT' # max_iter to limit build time, IPOPT to run on CI\n", "subprocess.run(command.split()).check_returncode();\n", "\n", - "glue_variable('aviary run_mission models/small_single_aisle/small_single_aisle_GwGm.csv', md_code=True)\n", - "glue_variable('small_single_aisle_GwGm.csv', md_code=False)\n", - "glue_variable('aviary/models/small_single_aisle', md_code=True)" + "glue_variable('aviary run_mission models/small_single_aisle/' + str_model + '.csv', md_code=True)\n", + "glue_variable(str_model + '.csv', md_code=False)\n", + "glue_variable('aviary/' + str_folder, md_code=True)" ] }, { diff --git a/aviary/docs/user_guide/battery_subsystem_example.ipynb b/aviary/docs/user_guide/battery_subsystem_example.ipynb index db6b7d554..001265882 100644 --- a/aviary/docs/user_guide/battery_subsystem_example.ipynb +++ b/aviary/docs/user_guide/battery_subsystem_example.ipynb @@ -88,7 +88,7 @@ "You can use any arguments that the `add_state` command accepts here, including `ref`s, `bound`s, `solve_segments`, and more.\n", "Please see the [Dymos docs for states](https://openmdao.github.io/dymos/features/phases/variables.html#states) for a table of all the available input args.\n", "\n", - "Within the subsystem builder, we will now define the states of the battery model using the `get_states` method." + "Within the subsystem builder, we will now define the states of the battery model using the {glue:md}`get_states()` method." ] }, { @@ -106,16 +106,18 @@ "import aviary.api as av\n", "from aviary.interface.methods_for_level2 import AviaryProblem\n", "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", + "from aviary.utils.doctape import glue_variable\n", "\n", "# Get all functions of class CoreAerodynamicsBuilder\n", "methods = inspect.getmembers(SubsystemBuilderBase, predicate=inspect.isfunction)\n", "for name, func in methods:\n", " if not name.startswith('_'):\n", - " glue_variable(name, md_code=True)\n", + " glue_variable(name + '()', md_code=True)\n", "\n", "AviaryValues = av.AviaryValues\n", "glue_variable(f'{AviaryValues=}'.split('=')[0], md_code=True)\n", "\n", + "# retrieve all argument of build_pre_mission(self, aviary_inputs, **kwargs)\n", "sig = inspect.signature(SubsystemBuilderBase.build_pre_mission)\n", "arguments = [param.name for param in sig.parameters.values()]\n", "arguments.remove('self')\n", @@ -123,6 +125,7 @@ "for arg in arguments:\n", " glue_variable(arg, md_code=True)\n", "\n", + "# retrieve all argument of build_mission(self, num_nodes, aviary_inputs, **kwargs)\n", "sig = inspect.signature(SubsystemBuilderBase.build_mission)\n", "arguments = [param.name for param in sig.parameters.values()]\n", "arguments.remove('self')\n", @@ -134,8 +137,8 @@ "# Get all functions of class AviaryProblem\n", "methods = inspect.getmembers(AviaryProblem, predicate=inspect.isfunction)\n", "for name, func in methods:\n", - " if not name.startswith('_'):\n", - " glue_variable(name, md_code=True)\n", + " if not name.startswith('_'): # exclude private functions\n", + " glue_variable(name + '()', md_code=True)\n", "\n", "TestSubsystemBuilderBase = av.TestSubsystemBuilderBase\n", "glue_variable(f'{TestSubsystemBuilderBase=}'.split('=')[0], md_code=True)\n" @@ -237,7 +240,7 @@ "metadata": {}, "source": [ "If you want to add high-level design variables to your external subsystem that are not exposed at the phase level, you can do so by creating a method that describes your desired design variables.\n", - "This method is called {glue:md}`get_design_vars`.\n", + "This method is called {glue:md}`get_design_vars()`.\n", "There might be calculations at the pre-mission level that necessitate using this method to allow the optimizer to control high-level sizing variables.\n", "In the simple battery case, we allow the optimizer to control the energy capacity of the battery, effectively sizing it." ] @@ -267,7 +270,7 @@ "source": [ "## Defining the OpenMDAO systems needed\n", "\n", - "Next up, we have the two methods for getting the mission and pre-mission models, {glue:md}`build_mission` and {glue:md}`build_pre_mission`, respectively.\n", + "Next up, we have the two methods for getting the mission and pre-mission models, {glue:md}`build_mission()` and {glue:md}`build_pre_mission()`, respectively.\n", "When you define these methods they should return OpenMDAO Systems ([groups](https://openmdao.org/newdocs/versions/latest/_srcdocs/packages/core/group.html) or [components](https://openmdao.org/newdocs/versions/latest/_srcdocs/packages/core/component.html)) that represent the mission and pre-mission subsystems of the external model.\n", "Please see the [OpenMDAO docs on creating a simple component](https://openmdao.org/newdocs/versions/latest/basic_user_guide/single_disciplinary_optimization/first_analysis.html) for more information on how to create OpenMDAO systems.\n", "In short, an OpenMDAO System takes in input variables, does some calculations, and returns output variables.\n", @@ -293,11 +296,11 @@ "metadata": {}, "source": [ "That's pretty straightforward.\n", - "The {glue:md}`build_pre_mission` method requires the {glue:md}`aviary_inputs` object (an instantiation of an {glue:md}`AviaryValues` object).\n", + "The {glue:md}`build_pre_mission()` method requires the {glue:md}`aviary_inputs` object (an instantiation of an {glue:md}`AviaryValues` object).\n", "This battery example does not use any information from {glue:md}`aviary_inputs`.\n", "The pre-mission builder can then use the data and options within the {glue:md}`aviary_inputs` object to construct the OpenMDAO System using user-specified logic.\n", "\n", - "Now we'll discuss arguably the most important method needed when making external subsystems (though they're all important): {glue:md}`build_mission`.\n", + "Now we'll discuss arguably the most important method needed when making external subsystems (though they're all important): {glue:md}`build_mission()`.\n", "This method returns an OpenMDAO System that provides all computations needed during the mission.\n", "This includes computing state rates so that the mission integration code can compute the state values and obtain the corresponding performance of the aircraft.\n", "\n", @@ -319,7 +322,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that {glue:md}`build_mission` requires both {glue:md}`num_nodes` and {glue:md}`aviary_inputs` as arguments.\n", + "Note that {glue:md}`build_mission()` requires both {glue:md}`num_nodes` and {glue:md}`aviary_inputs` as arguments.\n", "{glue:md}`num_nodes` is needed to correctly set up all the vectors within your mission subsystem, whereas {glue:md}`aviary_inputs` helps provide necessary options for the subsystem." ] }, @@ -333,12 +336,12 @@ "\n", "Let's talk about preprocessing your inputs.\n", "You might want to have some logic that sets different values in your problem based on user-provided options.\n", - "{glue:md}`preprocess_inputs` allows you to do this.\n", - "It occurs between {glue:md}`load_inputs` and {glue:md}`add_pre_mission_systems` in the Aviary stack, so after the initial data inputs are loaded but before they're used to instantiate any OpenMDAO models.\n", + "{glue:md}`preprocess_inputs()` allows you to do this.\n", + "It occurs between {glue:md}`load_inputs()` and {glue:md}`add_pre_mission_systems()` in the Aviary stack, so after the initial data inputs are loaded but before they're used to instantiate any OpenMDAO models.\n", "This is a great place to set any values you need for variables within your subsystem.\n", "\n", "```{note}\n", - "For both users and developers: {glue:md}`preprocess_inputs` happens **once** per analysis or optimization run, just like loading the inputs. It does not occur as part of an OpenMDAO system, so it does not get iterated over during the optimization process.\n", + "For both users and developers: {glue:md}`preprocess_inputs()` happens **once** per analysis or optimization run, just like loading the inputs. It does not occur as part of an OpenMDAO system, so it does not get iterated over during the optimization process.\n", "```\n", "\n", "You can have calculations or checks you need in this method based on user inputs.\n", @@ -346,7 +349,7 @@ "Now you may want to link some variables between phases.\n", "States, for example, are usually great candidates for linking.\n", "In the case of the battery example, if we have a climb and then a cruise phase, we'd want to connect the state-of-charge and voltage states so the end of climb is equal to the beginning of cruise.\n", - "Thus, our {glue:md}`get_linked_variables` method looks like this:" + "Thus, our {glue:md}`get_linked_variables()` method looks like this:" ] }, { @@ -368,7 +371,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The last method we'll discuss here is {glue:md}`get_initial_guesses`.\n", + "The last method we'll discuss here is {glue:md}`get_initial_guesses()`.\n", "This method allows you to return info for any variable you want to provide an initial guess for.\n", "Depending on the integration method you're using, initial guesses may greatly help convergence of your optimization problem.\n", "Collocation methods especially benefit from good initial guesses.\n", @@ -542,8 +545,8 @@ "metadata": {}, "source": [ "The output is a bit verbose, but tells you which methods are incorrect and why.\n", - "For example, here the {glue:md}`get_states` method returned a dict that included a key (`'amps'`) with a value of 6 instead of being a dictionary as expected.\n", - "In the {glue:md}`get_constraints` method, a constraint was added to the dictionary but did not include a `type` key, which is required as stated by the error message.\n", + "For example, here the {glue:md}`get_states()` method returned a dict that included a key (`'amps'`) with a value of 6 instead of being a dictionary as expected.\n", + "In the {glue:md}`get_constraints()` method, a constraint was added to the dictionary but did not include a `type` key, which is required as stated by the error message.\n", "\n", "If you encounter an error when using your subsystem, but the test here did not find it, please let the Aviary dev team know!\n", "We'd love to hear from you on the [GitHub issues page](https://github.com/OpenMDAO/Aviary/issues) so we can help everyone write great external subsystems." diff --git a/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb b/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb index e153d54d3..a7ca88678 100644 --- a/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb +++ b/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb @@ -11,18 +11,17 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.interface.methods_for_level2 import AviaryGroup\n", + "import inspect\n", + "from aviary.interface.methods_for_level1 import run_aviary\n", "from aviary.utils.doctape import glue_variable\n", - "from aviary.variable_info.enums import EquationsOfMotion\n", "\n", - "glue_variable('height_energy', EquationsOfMotion.HEIGHT_ENERGY.value, md_code=True, display=True)\n", - "\n", - "ag = AviaryGroup()\n", - "opts = list(ag.options)\n", - "for opt in opts:\n", - " if opt == 'phase_info':\n", - " glue_variable('phase_info', md_code=True)\n", - " glue_variable('--phase_info', md_code=True)" + "# glue all argument of function run_aviary()\n", + "sigs = inspect.signature(run_aviary)\n", + "parameters = sigs.parameters\n", + "for name, param in parameters.items():\n", + " if name == 'phase_info': # for this file, we need one argument 'phase_info'\n", + " glue_variable(name, md_code=True)\n", + " glue_variable('--' + name, md_code=True)" ] }, { @@ -54,7 +53,9 @@ "source": [ "# Testing Cell\n", "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", - "check_phase_info({}, HEIGHT_ENERGY)" + "from aviary.utils.doctape import glue_variable\n", + "check_phase_info({}, HEIGHT_ENERGY)\n", + "glue_variable('height_energy', f'{HEIGHT_ENERGY=}'.split('=')[0].lower(), md_code=False)\n" ] }, { @@ -84,33 +85,13 @@ "source": [ "# Test Cell\n", "from aviary.interface.cmd_entry_points import _command_map\n", - "_command_map['draw_mission'];" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Test Cell\n", - "import argparse\n", - "from aviary.interface.methods_for_level1 import _setup_level1_parser\n", - "from aviary.utils.doctape import glue_variable\n", + "_command_map['draw_mission'];\n", "\n", - "parser = argparse.ArgumentParser()\n", - "_setup_level1_parser(parser)\n", - "for action in parser._actions:\n", - " if action.dest == 'optimizer':\n", - " for opt in action.choices:\n", - " glue_variable(opt, md_code=True)\n" + "str_run_mission = 'run_mission'\n", + "_command_map[str_run_mission];\n", + "glue_variable(str_run_mission, md_code=True)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, { "cell_type": "markdown", "metadata": {}, @@ -143,7 +124,7 @@ "\n", "### Menu Options\n", "#### File Tab\n", - "1. **Open Phase Info**: Allows user to open a previously made phase info file. This must be a python file that contains a dictionary called {glue:md}`phase_info`. \n", + "1. **Open Phase Info**: Allows user to open a previously made phase info file. This must be a python file that contains a dictionary called `phase_info`. \n", "\n", "2. **Save Phase Info**: Peforms the same function as clicking on the `Output Phase Info` button by saving the current mission as a phase info dictionary in a file named `outputted_phase_info.py`.\n", "\n", @@ -173,7 +154,7 @@ "3.2. `Solve for Distance`: If checked, calculates the total flight range based on the profile.
\n", "3.3. `Include Takeoff`: If checked, includes takeoff in the mission analysis.
\n", "3.4. `Include Landing`: If checked, includes landing in the mission analysis.
\n", - "3.5. `Polynomial Control Order`: Sets the polynomial order for control optimization, default being 1. This is for all phases. You can modify behavior on a per-phase basis by editing the outputted {glue:md}`phase_info` dict.
\n", + "3.5. `Polynomial Control Order`: Sets the polynomial order for control optimization, default being 1. This is for all phases. You can modify behavior on a per-phase basis by editing the outputted `phase_info` dict.
\n", "3.6. `Phase Transcription Order`: This setting will only show once at least 2 points are added to the plots/table. This number controls the number of points that are used to evaluate each mission phase. The minimum value is 3, and increasing this value will increase the number of points Aviary uses to analyze that phase.\n", "\n", "#### Help Tab\n", @@ -181,20 +162,20 @@ "\n", "### Output\n", "\n", - "Upon completion, the tool outputs a Python script named `outputted_phase_info.py` in the current working directory. Alternatively, if the user uses the `Save As` command, a python script with the user specified name will be saved in the user specified directory. This tool overwrites any existing python file with the same name as the output. This outputted file contains the {glue:md}`phase_info` dictionary, which holds the flight profile data structured for use in mission simulations.\n", + "Upon completion, the tool outputs a Python script named `outputted_phase_info.py` in the current working directory. Alternatively, if the user uses the `Save As` command, a python script with the user specified name will be saved in the user specified directory. This tool overwrites any existing python file with the same name as the output. This outputted file contains the `phase_info` dictionary, which holds the flight profile data structured for use in mission simulations.\n", "\n", "```{note}\n", - "When using the outputted {glue:md}`phase_info` dict in a mission simulation, you can modify the settings by directly changing the outputted Python file.\n", + "When using the outputted `phase_info` dict in a mission simulation, you can modify the settings by directly changing the outputted Python file.\n", "```\n", "\n", - "The {glue:md}`phase_info` dictionary makes some assumptions about different settings which you can also modify.\n", + "The `phase_info` dictionary makes some assumptions about different settings which you can also modify.\n", "For example, the time duration of each phase is controlled by the optimizer if `fix_duration` is False, though this can be changed to True to fix the duration of each phase.\n", "\n", "If you don't have the [black](https://pypi.org/project/black/) python autoformatter installed, your output may look slightly different - as long as you see confirmation that your phase info has been saved, your mission profile was successfully created.\n", "\n", "## Running a Mission Simulation\n", "\n", - "After generating the flight profile, use the `run_mission` command to simulate the mission.\n", + "After generating the flight profile, use the {glue:md}`run_mission` command to simulate the mission.\n", "This command utilizes the {glue:md}`phase_info` from `outputted_phase_info.py` and simulates the mission based on the defined parameters. In the commands below, replace `outputted_phase_info.py` with your filename if you choose to save the output file with a different filename.\n", "You can use the {glue:md}`--phase_info` flag to specify the path to the `outputted_phase_info.py` file.\n", "Here we use a benchmark case as the inputted .csv file, though you can use any Aviary .csv here that defines an aircraft.\n", @@ -203,8 +184,8 @@ "aviary run_mission --phase_info outputted_phase_info.py validation_cases/benchmark_tests/test_aircraft/aircraft_for_bench_FwFm.csv\n", "```\n", "\n", - "You can also supply an optimizer, otherwise the default ({glue:md}`SLSQP`) will be used.\n", - "Here is how you'd run the mission with the {glue:md}`IPOPT` optimizer:\n", + "You can also supply an optimizer, otherwise the default (SLSQP) will be used.\n", + "Here is how you'd run the mission with the IPOPT optimizer:\n", "\n", "```bash\n", "aviary run_mission --optimizer IPOPT --phase_info outputted_phase_info.py validation_cases/benchmark_tests/test_aircraft/aircraft_for_bench_FwFm.csv\n", diff --git a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb index 15ed05c20..876aa8b56 100644 --- a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb +++ b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb @@ -1,5 +1,30 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import inspect\n", + "from aviary.interface.methods_for_level1 import run_aviary\n", + "from aviary.interface.methods_for_level2 import AviaryProblem\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "# glue all argument of function run_aviary()\n", + "sigs = inspect.signature(run_aviary)\n", + "parameters = sigs.parameters\n", + "for name, param in parameters.items():\n", + " if name == 'phase_info': # for this file, we need one argument 'phase_info'\n", + " glue_variable(name, md_code=True)\n", + "glue_variable(f'{AviaryProblem=}'.split('=')[0], md_code=False)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -20,30 +45,7 @@ "\n", "This is the most basic level of the UI.\n", "There's a command-line interface (CLI) for Level 1, or you can use the Python API shown below.\n", - "If you want to make minor modifications to {glue:md}`phase_info`, you can do so here, but Level 1 largely assumes you're using the default setup." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "# Testing Cell\n", - "from aviary.interface.methods_for_level2 import AviaryGroup, AviaryProblem\n", - "from aviary.utils.doctape import glue_variable\n", - "from aviary.variable_info.enums import EquationsOfMotion\n", - "\n", - "ag = AviaryGroup()\n", - "opts = list(ag.options)\n", - "for opt in opts:\n", - " if opt == 'phase_info':\n", - " glue_variable('phase_info', md_code=True)\n", - "glue_variable(f'{AviaryProblem=}'.split('=')[0], md_code=True)" + "If you want to make minor modifications to {glue:md}`phase_info`, you can do so here, but Level 1 largely assumes you're using the default setup." ] }, { diff --git a/aviary/docs/user_guide/external_aero.ipynb b/aviary/docs/user_guide/external_aero.ipynb index 05c246db2..cd6647a9c 100644 --- a/aviary/docs/user_guide/external_aero.ipynb +++ b/aviary/docs/user_guide/external_aero.ipynb @@ -9,7 +9,7 @@ "\n", "This example shows how to build, using the level-2 interface, an aviary model that includes an external susbsystem that computes a lift and drag polar and passes them into the mission aerodynamics for a 3-phase mission (climb, cruise, descent). During the mission, Aviary will interpolate on the computed polars to compute actual lift and drag for a given flight condition.\n", "\n", - "We start with the assumption that we have an external component called `ExternalAero` that can compute the lift and drag at any given altitude, mach number, and angle of attack. The details of such a component may be highly complicated and not important for the purposes of this example. We will be using a structured grid, which assumes the data table is regularly spaced in all dimensions. We want to compute lift and drag over a grid of altitudes (in 'ft'), mach numbers, and angles of attack given by:" + "We start with the assumption that we have an external component called {glue:md}`ExternalAero` that can compute the lift and drag at any given altitude, mach number, and angle of attack. The details of such a component may be highly complicated and not important for the purposes of this example. We will be using a structured grid, which assumes the data table is regularly spaced in all dimensions. We want to compute lift and drag over a grid of altitudes (in 'ft'), mach numbers, and angles of attack given by:" ] }, { @@ -101,12 +101,29 @@ "print('Angle of Attack (deg)', angle_of_attack)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "c21e45ca", + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_variable\n", + "# class ExternalAero is defined with this file\n", + "glue_variable(f'{ExternalAero=}'.split('=')[0], md_code=True)" + ] + }, { "cell_type": "markdown", "id": "elder-kinase", "metadata": {}, "source": [ - "In a structured grid, interpolation data must be present for every combination of inputs. In other words, our `ExternalAero` component must run a full factorial of points spanning those 3 variables. The Aviary variable hierarchy includes two variables for the polars: {glue:md}`Aircraft.Design.LIFT_POLAR`, and {glue:md}`Aircraft.Design.DRAG_POLAR`. The data in each of these polars should be a `n` x `m` x `k` numpy array, where `n` is the number of altitudes, `m` is the number of mach numbers, and `k` is the number of angles of attack. The `ExternalAero` will need to compute these values and place them into an array of this shape.\n", + "In a structured grid, interpolation data must be present for every combination of inputs. In other words, our {glue:md}`ExternalAero` component must run a full factorial of points spanning those 3 variables. The Aviary variable hierarchy includes two variables for the polars: {glue:md}`Aircraft.Design.LIFT_POLAR`, and {glue:md}`Aircraft.Design.DRAG_POLAR`. The data in each of these polars should be a `n` x `m` x `k` numpy array, where `n` is the number of altitudes, `m` is the number of mach numbers, and `k` is the number of angles of attack. The `ExternalAero` will need to compute these values and place them into an array of this shape.\n", "\n", "If use of a structured grid is not desirable, then the data does not need to meet these formatting requirements. In that case, the data table does not have to be regularly spaced, and each variable (`Altitude`, `Mach`, `angle_of_attack`, `LIFT_POLAR`, and `DRAG_POLAR`) must be 1-dimensional numpy arrays of equal length.\n", "\n", diff --git a/aviary/docs/user_guide/features_and_functionalities.ipynb b/aviary/docs/user_guide/features_and_functionalities.ipynb index 6b140f13c..21b181202 100644 --- a/aviary/docs/user_guide/features_and_functionalities.ipynb +++ b/aviary/docs/user_guide/features_and_functionalities.ipynb @@ -3,7 +3,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [ + "remove-cell" + ] + }, "outputs": [], "source": [ "# Testing Cell\n", @@ -69,7 +73,7 @@ "Usually this is from takeoff to landing, inclusive.\n", "Sometimes you might want to model just a portion of the full aircraft trajectory; for example only the cruise portion.\n", "\n", - "A []\"phase\"](https://openmdao.github.io/dymos/features/phases/phases.html) is a part of the trajectory that is defined by a single set of differential equations.\n", + "A [\"phase\"](https://openmdao.github.io/dymos/features/phases/phases.html) is a part of the trajectory that is defined by a single set of differential equations.\n", "For example, a simple way of defining a full trajectory is to have climb, cruise, and descent phases.\n", "Each of these phases can have different physics, subsystems, controls, and constraints.\n", "For example, the climb phase for a hybrid-electric aircraft might be have electric motor assistance whereas that might not be needed for the cruise phase.\n", @@ -106,13 +110,13 @@ "source": [ "# Testing Cell\n", "from aviary.interface.utils.check_phase_info import phase_keys_gasp\n", - "from aviary.utils.doctape import check_value, glue_variable\n", + "from aviary.utils.doctape import check_value, get_variable_name, glue_variable\n", "from aviary.variable_info.enums import AnalysisScheme\n", "expected_keys = ['groundroll', 'rotation', 'ascent', 'accel', 'climb1', 'climb2', 'cruise', 'desc1', 'desc2']\n", "check_value(list(phase_keys_gasp.keys()), expected_keys)\n", "for key in expected_keys:\n", " glue_variable(key, md_code=False)\n", - "glue_variable(f'{AnalysisScheme=}'.split('=')[0], md_code=True)\n", + "glue_variable(get_variable_name(AnalysisScheme), md_code=True)\n", "glue_variable('COLLOCATION', AnalysisScheme.COLLOCATION.name, md_code=True)\n", "glue_variable('SHOOTING', AnalysisScheme.SHOOTING.name, md_code=True)" ] diff --git a/aviary/docs/user_guide/hamilton_standard.ipynb b/aviary/docs/user_guide/hamilton_standard.ipynb index f9985e4be..30e6cea9b 100644 --- a/aviary/docs/user_guide/hamilton_standard.ipynb +++ b/aviary/docs/user_guide/hamilton_standard.ipynb @@ -21,11 +21,11 @@ "\n", "check_value(Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS,'aircraft:engine:compute_propeller_installation_loss')\n", "glue_variable(get_variable_name(Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS), md_code=True)\n", - "glue_variable(f'{Atmosphere=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{InstallLoss=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{PreHamiltonStandard=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{HamiltonStandard=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{PostHamiltonStandard=}'.split('=')[0], md_code=True)\n" + "glue_variable(get_variable_name(Atmosphere), md_code=True)\n", + "glue_variable(get_variable_name(InstallLoss), md_code=True)\n", + "glue_variable(get_variable_name(PreHamiltonStandard), md_code=True)\n", + "glue_variable(get_variable_name(HamiltonStandard), md_code=True)\n", + "glue_variable(get_variable_name(PostHamiltonStandard), md_code=True)\n" ] }, { @@ -217,9 +217,19 @@ "outputs": [], "source": [ "# Testing Cell\n", + "import inspect\n", "from aviary.api import Aircraft, Dynamic\n", "from aviary.subsystems.propulsion.turboprop_model import TurbopropModel\n", - "glue_variable(f'{TurbopropModel=}'.split('=')[0], md_code=True)" + "from aviary.utils.doctape import glue_variable\n", + "\n", + "glue_variable(get_variable_name(TurbopropModel), md_code=True)\n", + "\n", + "# glue all arguments of function TurbopropModel.__init__()\n", + "sigs = inspect.signature(TurbopropModel)\n", + "parameters = sigs.parameters\n", + "for name, param in parameters.items():\n", + " glue_variable(name, md_code=True)\n", + " # print(f'Name: {name}, Default: {param.default}, Kind: {param.kind}')" ] }, { @@ -245,7 +255,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To build a turboprop engine that uses the Hamilton Standard propeller model we use a {glue:md}`TurbopropModel` object with `propeller_model` set to `None` and `shaft_power_model` set to `None` (the default):" + "To build a turboprop engine that uses the Hamilton Standard propeller model we use a {glue:md}`TurbopropModel` object with {glue:md}`propeller_model` set to `None` and {glue:md}`shaft_power_model` set to `None` (the default):" ] }, { @@ -338,7 +348,7 @@ "glue_variable(get_variable_name(Aircraft.Engine.PROPELLER_DATA_FILE), md_code=True)\n", "check_value(Dynamic.Mission.MACH,'mach')\n", "glue_variable(get_variable_name(Dynamic.Mission.MACH), md_code=True)\n", - "glue_variable(f'{OutMachs=}'.split('=')[0], md_code=True)\n" + "glue_variable(get_variable_name(OutMachs), md_code=True)\n" ] }, { diff --git a/aviary/docs/user_guide/input_files.ipynb b/aviary/docs/user_guide/input_files.ipynb index 02536db01..e2dec6b50 100644 --- a/aviary/docs/user_guide/input_files.ipynb +++ b/aviary/docs/user_guide/input_files.ipynb @@ -77,10 +77,10 @@ "source": [ "# Testing Cell\n", "from aviary.utils.csv_data_file import read_data_file, write_data_file\n", - "from aviary.utils.doctape import check_value, get_Function_names, get_variable_name, glue_variable\n", + "from aviary.utils.doctape import check_value, get_function_names, get_variable_name, glue_variable\n", "\n", "file_path = av.get_path('utils/csv_data_file.py')\n", - "takeoff_function_names = get_Function_names(file_path)\n", + "takeoff_function_names = get_function_names(file_path)\n", "\n", "for function_name in takeoff_function_names:\n", " if not function_name.startswith('_'):\n", diff --git a/aviary/docs/user_guide/mass.ipynb b/aviary/docs/user_guide/mass.ipynb index 614968d46..e717a1f81 100644 --- a/aviary/docs/user_guide/mass.ipynb +++ b/aviary/docs/user_guide/mass.ipynb @@ -11,11 +11,60 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.subsystems.mass.flops_based.mass_summation import AltSystemsEquipMass\n", + "import re\n", + "from aviary.subsystems.mass.flops_based.mass_summation import (\n", + " AltSystemsEquipMass, MassSummation, StructureMass, PropulsionMass, SystemsEquipMass,\n", + " EmptyMass, OperatingMass, ZeroFuelMass, FuelMass)\n", + "from aviary.subsystems.mass.gasp_based.design_load import DesignLoadGroup\n", + "from aviary.subsystems.mass.gasp_based.fixed import FixedMassGroup\n", + "from aviary.subsystems.mass.gasp_based.equipment_and_useful_load import EquipAndUsefulLoadMass\n", + "from aviary.subsystems.mass.gasp_based.wing import WingMassGroup\n", + "from aviary.subsystems.mass.gasp_based.fuel import FuelMassGroup\n", "from aviary.utils.doctape import get_variable_name, glue_variable\n", "\n", + "def split_by_capitals_and_underscores(text):\n", + " # Use a regex to split the string at capital letters and underscores\n", + " # Make sure it handles consecutive capital letters\n", + " phrases = re.findall(r'[A-Z]+(?:[a-z]*)', text)\n", + " phrases = [phrase for phrase in phrases if phrase != '_'] # Remove standalone underscores\n", + " str_phrase = ''\n", + " for item in phrases:\n", + " str_phrase += item + ' '\n", + " str_phrase = str_phrase[:-1]\n", + " return str_phrase\n", + "\n", "AltSystemsEquipMass\n", - "glue_variable(get_variable_name(AltSystemsEquipMass), md_code=True)" + "glue_variable(get_variable_name(AltSystemsEquipMass), md_code=True)\n", + "\n", + "st = split_by_capitals_and_underscores(get_variable_name(MassSummation))\n", + "glue_variable('Total ' + st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(StructureMass))\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(PropulsionMass))\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(SystemsEquipMass))\n", + "st = st.replace('Equip','and Equipment')\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(EmptyMass))\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(OperatingMass))\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(ZeroFuelMass))\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(FuelMass))\n", + "glue_variable(st, md_code=False)\n", + "\n", + "st = split_by_capitals_and_underscores(get_variable_name(DesignLoadGroup))\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(FixedMassGroup))\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(EquipAndUsefulLoadMass))\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(WingMassGroup))\n", + "glue_variable(st, md_code=False)\n", + "st = split_by_capitals_and_underscores(get_variable_name(FuelMassGroup))\n", + "glue_variable(st, md_code=False)\n", + "\n" ] }, { @@ -38,22 +87,22 @@ "\n", "### FLOPS-Based Components\n", "\n", - "- **Total Mass Summation:** Orchestrates the calculation of the total mass by summing up contributions from structural, propulsion, systems and equipment, and fuel masses.\n", - "- **Structure Mass:** Calculates the mass contributions from the aircraft's structural components like wings, fuselage, landing gear, etc.\n", - "- **Propulsion Mass:** Computes the mass related to the aircraft's propulsion system, including engines and associated components.\n", - "- **Systems and Equipment Mass:** Determines the mass of systems and equipment on the aircraft, with an alternative calculation option ({glue:md}`AltSystemsEquipMass`) available.\n", - "- **Empty Mass:** Represents the total mass of the aircraft without fuel, calculated using either standard or alternative methods.\n", - "- **Operating Mass:** Accounts for the mass of the crew, passengers, and service items in addition to the empty mass.\n", - "- **Zero Fuel Mass:** The total mass of the aircraft without considering the fuel.\n", - "- **Fuel Mass:** Calculates the mass of the fuel required for the mission.\n", + "- **{glue:md}`Total Mass Summation`:** Orchestrates the calculation of the total mass by summing up contributions from structural, propulsion, systems and equipment, and fuel masses.\n", + "- **{glue:md}`Structure Mass`:** Calculates the mass contributions from the aircraft's structural components like wings, fuselage, landing gear, etc.\n", + "- **{glue:md}`Propulsion Mass`:** Computes the mass related to the aircraft's propulsion system, including engines and associated components.\n", + "- **{glue:md}`Systems and Equipment Mass`:** Determines the mass of systems and equipment on the aircraft, with an alternative calculation option ({glue:md}`AltSystemsEquipMass`) available.\n", + "- **{glue:md}`Empty Mass`:** Represents the total mass of the aircraft without fuel, calculated using either standard or alternative methods.\n", + "- **{glue:md}`Operating Mass`:** Accounts for the mass of the crew, passengers, and service items in addition to the empty mass.\n", + "- **{glue:md}`Zero Fuel Mass`:** The total mass of the aircraft without considering the fuel.\n", + "- **{glue:md}`Fuel Mass`:** Calculates the mass of the fuel required for the mission.\n", "\n", "### GASP-Based Components\n", "\n", - "- **Design Load Group:** Establishes design load parameters that influence other mass calculations.\n", - "- **Fixed Mass Group:** Deals with fixed masses, like payload and engine mass, that are essential in determining the wing and fuel mass.\n", - "- **Equip and Useful Load Mass:** Calculates the equipment and useful load mass, vital for determining the aircraft's operability.\n", - "- **Wing Mass Group:** Computes the mass of the wing, influenced by fixed mass group outputs.\n", - "- **Fuel Mass Group:** Determines the fuel mass, taking into account design load and fixed mass group parameters.\n", + "- **{glue:md}`Design Load Group`:** Establishes design load parameters that influence other mass calculations.\n", + "- **{glue:md}`Fixed Mass Group`:** Deals with fixed masses, like payload and engine mass, that are essential in determining the wing and fuel mass.\n", + "- **{glue:md}`Equip And Useful Load Mass`:** Calculates the equipment and useful load mass, vital for determining the aircraft's operability.\n", + "- **{glue:md}`Wing Mass Group`:** Computes the mass of the wing, influenced by fixed mass group outputs.\n", + "- **{glue:md}`Fuel Mass Group`:** Determines the fuel mass, taking into account design load and fixed mass group parameters.\n", "\n", "## Using the Mass Subsystem\n", "\n", diff --git a/aviary/docs/user_guide/multi_mission.ipynb b/aviary/docs/user_guide/multi_mission.ipynb index 6c18ad0e8..e9c47b268 100644 --- a/aviary/docs/user_guide/multi_mission.ipynb +++ b/aviary/docs/user_guide/multi_mission.ipynb @@ -38,7 +38,7 @@ "The objective function is based on combining the fuel-burn values from both missions and the optimizers objective is to minimize the weighted fuel-burn. Other objectives, like max range, have not been tested yet.\n", "\n", "## Design vs. As-Flown\n", - "To support the need to design an aircraft with a certain number of seats, but then possibly fly missions with less passengers, a distinction in the metadata was introduced between {glue:md}Aircraft.CrewPayload.Design.NUM_PASSENGERS and {glue:md}Aircraft.CrewPayload.NUM_PASSENGERS. The individual passenger classes ({glue:md}Aircraft.CrewPayload.NUM_FIRST_CLASS, {glue:md}Aircraft.CrewPayload.NUM_BUSINESS_CLASS, {glue:md}Aircraft.CrewPayload.NUM_TOURIST_CLASS) also have these distinctions. The Design values represent how many seats are available in the aircraft. Whereas the non-design values represent an as-flow value of how many passengers are on a particular flight. \n", + "To support the need to design an aircraft with a certain number of seats, but then possibly fly missions with less passengers, a distinction in the metadata was introduced between {glue:md}`Aircraft.CrewPayload.Design.NUM_PASSENGERS` and {glue:md}`Aircraft.CrewPayload.NUM_PASSENGERS`. The individual passenger classes ({glue:md}`Aircraft.CrewPayload.NUM_FIRST_CLASS`, {glue:md}`Aircraft.CrewPayload.NUM_BUSINESS_CLASS`, {glue:md}`Aircraft.CrewPayload.NUM_TOURIST_CLASS`) also have these distinctions. The Design values represent how many seats are available in the aircraft. Whereas the non-design values represent an as-flow value of how many passengers are on a particular flight. \n", "\n", "A number of checks exist in {glue:md}`capi` to help the user in the case that incomplete as-flow or design passenger information is provided. Please review the [Multi-Mission Theory](../examples/multi_mission) for further details.\n", "\n", diff --git a/aviary/docs/user_guide/off_design_missions.ipynb b/aviary/docs/user_guide/off_design_missions.ipynb index da648f29f..5b5818987 100644 --- a/aviary/docs/user_guide/off_design_missions.ipynb +++ b/aviary/docs/user_guide/off_design_missions.ipynb @@ -13,7 +13,7 @@ "# Testing Cell\n", "from aviary.api import Settings\n", "import aviary.api as av\n", - "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "\n", "str_problem_type = Settings.PROBLEM_TYPE\n", "str_sizing = av.ProblemType.SIZING.value\n", @@ -34,10 +34,10 @@ "glue_variable(av.EquationsOfMotion.TWO_DEGREES_OF_FREEDOM.value, md_code=False)\n", "\n", "AnalysisScheme = av.AnalysisScheme\n", - "str_collocation = f'{AnalysisScheme.COLLOCATION=}'.split('=')[0]\n", + "str_collocation = get_variable_name(AnalysisScheme.COLLOCATION)\n", "str_collocation = str_collocation.split('.')[1].lower()\n", "glue_variable(str_collocation, md_code=False)\n", - "str_shooting = f'{AnalysisScheme.SHOOTING=}'.split('=')[0]\n", + "str_shooting = get_variable_name(AnalysisScheme.SHOOTING)\n", "str_shooting = str_shooting.split('.')[1].lower()\n", "glue_variable(str_shooting, md_code=False)\n" ] @@ -79,12 +79,26 @@ "From there, the mission may be run as before." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import aviary.api as av\n", + "from aviary.utils.doctape import glue_variable\n", + "str_file_path = 'examples/run_off_design_example.py'\n", + "file_path = av.get_path(str_file_path)\n", + "glue_variable('aviary/' + str_file_path, md_code=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "You may also run multiple off-design missions in the same script used to solve the design mission.\n", - "An examples of this is shown in `aviary/examples/run_off_design_example.py`." + "An examples of this is shown in {glue:md}`aviary/examples/run_off_design_example.py`." ] }, { diff --git a/aviary/docs/user_guide/pre_mission_and_mission.ipynb b/aviary/docs/user_guide/pre_mission_and_mission.ipynb index 03e944115..addbf1a18 100644 --- a/aviary/docs/user_guide/pre_mission_and_mission.ipynb +++ b/aviary/docs/user_guide/pre_mission_and_mission.ipynb @@ -53,10 +53,10 @@ "import inspect\n", "from aviary.mission.phase_builder_base import PhaseBuilderBase\n", "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", - "from aviary.utils.doctape import check_args, glue_variable\n", + "from aviary.utils.doctape import check_args, get_variable_name, glue_variable\n", "check_args(PhaseBuilderBase.__init__,'num_nodes')\n", "glue_variable('num_nodes', md_code=True)\n", - "glue_variable(f'{SubsystemBuilderBase=}'.split('=')[0], md_code=True)\n", + "glue_variable(get_variable_name(SubsystemBuilderBase), md_code=True)\n", "\n", "# Get all functions of class AviaryProblem\n", "functs = inspect.getmembers(SubsystemBuilderBase, predicate=inspect.isfunction)\n", diff --git a/aviary/docs/user_guide/propulsion.ipynb b/aviary/docs/user_guide/propulsion.ipynb index ca6c7632e..6f4171d1c 100644 --- a/aviary/docs/user_guide/propulsion.ipynb +++ b/aviary/docs/user_guide/propulsion.ipynb @@ -87,7 +87,7 @@ "from aviary.api import Aircraft\n", "from aviary.subsystems.propulsion.engine_deck import aliases, default_required_variables, required_options, dependent_options\n", "from aviary.subsystems.propulsion.utils import EngineModelVariables\n", - "from aviary.utils.doctape import check_value, check_contains, glue_variable\n", + "from aviary.utils.doctape import check_value, check_contains, get_variable_name, glue_variable\n", "from aviary.variable_info.variable_meta_data import CoreMetaData\n", "\n", "vars = ['Mach Number', 'Altitude', 'Throttle', 'Hybrid Throttle', 'Net Thrust',\n", @@ -119,10 +119,10 @@ "Aircraft.Engine = Aircraft.Engine\n", "check_contains(required_options, CoreMetaData)\n", "required = (#f'{Aircraft.Engine.DATA_FILE=}'.split('=')[0],\n", - " f'{Aircraft.Engine.SCALE_PERFORMANCE=}'.split('=')[0],\n", - " f'{Aircraft.Engine.IGNORE_NEGATIVE_THRUST=}'.split('=')[0],\n", - " f'{Aircraft.Engine.GEOPOTENTIAL_ALT=}'.split('=')[0],\n", - " f'{Aircraft.Engine.GENERATE_FLIGHT_IDLE=}'.split('=')[0])\n", + " get_variable_name(Aircraft.Engine.SCALE_PERFORMANCE),\n", + " get_variable_name(Aircraft.Engine.IGNORE_NEGATIVE_THRUST),\n", + " get_variable_name(Aircraft.Engine.GEOPOTENTIAL_ALT),\n", + " get_variable_name(Aircraft.Engine.GENERATE_FLIGHT_IDLE))\n", "required_options_list = ''\n", "for var in required:\n", " required_options_list += f'* `{var}`\\n'\n", @@ -223,7 +223,7 @@ "# Testing Cell\n", "from aviary.subsystems.propulsion.engine_model import EngineModel\n", "from aviary.subsystems.propulsion.engine_deck import EngineDeck\n", - "from aviary.utils.doctape import check_value\n", + "from aviary.utils.doctape import check_value, get_variable_name, glue_variable\n", "from aviary.utils.aviary_values import AviaryValues\n", "import inspect\n", "\n", @@ -231,9 +231,9 @@ "type_hint = inspect.signature(EngineModel).parameters['options'].annotation\n", "check_value(type_hint, AviaryValues)\n", "\n", - "glue_variable(f'{EngineModel=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{EngineDeck=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{AviaryValues=}'.split('=')[0], md_code=True)" + "glue_variable(get_variable_name(EngineModel), md_code=True)\n", + "glue_variable(get_variable_name(EngineDeck), md_code=True)\n", + "glue_variable(get_variable_name(AviaryValues), md_code=True)" ] }, { @@ -286,7 +286,7 @@ "id": "bbabdf30", "metadata": {}, "source": [ - "In this example, *aviary_options* is modified in-place with updated values from *engine_model*, as well as properly configuring engine-related variables into vectors. When working with multiple heterogenous engines, simply provide `preprocess_propulsion()` with a list of all `EngineModels`, like so:" + "In this example, *{glue:md}aviary_options* is modified in-place with updated values from *{glue:md}engine_model*, as well as properly configuring engine-related variables into vectors. When working with multiple heterogenous engines, simply provide {glue:md}`preprocess_propulsion()` with a list of all `EngineModels`, like so:" ] }, { @@ -302,6 +302,7 @@ "source": [ "# Testing Cell\n", "import aviary.api as av\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "\n", "filename = 'models/engines/turbofan_28k.deck'\n", "options = av.AviaryValues()\n", @@ -310,7 +311,13 @@ "\n", "engine_model_1 = av.EngineDeck(options=options)\n", "engine_model_2 = av.EngineModel(options=options)\n", - "aviary_options = options" + "aviary_options = options\n", + "\n", + "glue_variable(get_variable_name(aviary_options))\n", + "\n", + "preprocess_propulsion = av.preprocess_propulsion\n", + "glue_variable(get_variable_name(preprocess_propulsion) + '()', md_code=True)\n", + "glue_variable(get_variable_name(engine_model))" ] }, { diff --git a/aviary/docs/user_guide/reserve_missions.ipynb b/aviary/docs/user_guide/reserve_missions.ipynb index 794ee6549..58c2fc4eb 100644 --- a/aviary/docs/user_guide/reserve_missions.ipynb +++ b/aviary/docs/user_guide/reserve_missions.ipynb @@ -14,17 +14,17 @@ "import inspect\n", "import aviary.api as av\n", "from aviary.interface.methods_for_level2 import AviaryGroup, AviaryProblem\n", - "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "from aviary.utils.functions import get_path\n", "\n", "glue_variable(av.EquationsOfMotion.HEIGHT_ENERGY.value, md_code=False)\n", "glue_variable(av.EquationsOfMotion.TWO_DEGREES_OF_FREEDOM.value, md_code=False)\n", "\n", "AnalysisScheme = av.AnalysisScheme\n", - "str_collocation = f'{AnalysisScheme.COLLOCATION=}'.split('=')[0]\n", + "str_collocation = get_variable_name(AnalysisScheme.COLLOCATION)\n", "str_collocation = str_collocation.split('.')[1].lower()\n", "glue_variable(str_collocation, md_code=False)\n", - "str_shooting = f'{AnalysisScheme.SHOOTING=}'.split('=')[0]\n", + "str_shooting = get_variable_name(AnalysisScheme.SHOOTING)\n", "str_shooting = str_shooting.split('.')[1].lower()\n", "glue_variable(str_shooting, md_code=False)\n", "\n", @@ -166,7 +166,7 @@ "\n", "If you are using {glue:md}`2DOF` equations of motion (EOM) in your problem (i.e. `settings:equations_of_motion,2DOF`) there are some additional things you need to be aware of.\n", "The name of the reserve phase should include one of the keywords to indicate which EOM from {glue:md}`2DOF` will be selected and the prefix `reserve_`.\n", - "Valid keywords include: `rotation`, `accel`, `ascent`, `climb1`, `climb2`, `cruise`, `desc1`, `desc2`.\n", + "Valid keywords include: {glue:md}`rotation`, {glue:md}`accel`, {glue:md}`ascent`, {glue:md}`climb1`, {glue:md}`climb2`, {glue:md}`cruise`, {glue:md}`desc1`, {glue:md}`desc2`.\n", "This is because {glue:md}`2DOF` uses different EOMs for different phases and we need to let `methods_for_level2.py` know which method to select.\n", "This is why in the example in the first paragraph above, the phase was named `reserve_cruise`.\n", "Cruise phases can have additional information in suffixes, but this isn't necessary.\n", @@ -185,14 +185,17 @@ "source": [ "# Testing Cell\n", "from aviary.interface.utils.check_phase_info import phase_keys_gasp\n", - "from aviary.utils.doctape import check_contains\n", + "from aviary.utils.doctape import check_contains, glue_variable\n", "\n", + "two_DOF_phases = ['rotation','accel','ascent','climb1','climb2','cruise','desc1','desc2']\n", "expected_phases = [phase for phase in phase_keys_gasp if phase!='groundroll'] # no reserve groundroll\n", "check_contains(\n", - " ['rotation','accel','ascent','climb1','climb2','cruise','desc1','desc2'],\n", + " two_DOF_phases,\n", " expected_phases,\n", " error_string=\"{var} is not a valid name for a 2DOF reserve phase, choose from \"+f\"{expected_phases}\"\n", - " )\n" + " )\n", + "for ph in two_DOF_phases:\n", + " glue_variable(ph, md_code=True)" ] }, { diff --git a/aviary/docs/user_guide/step_by_step_external_guide.ipynb b/aviary/docs/user_guide/step_by_step_external_guide.ipynb index 1daee2c14..7b9134b52 100644 --- a/aviary/docs/user_guide/step_by_step_external_guide.ipynb +++ b/aviary/docs/user_guide/step_by_step_external_guide.ipynb @@ -85,9 +85,9 @@ "# Testing Cell\n", "from aviary.examples.external_subsystems.battery.battery_builder import BatteryBuilder\n", "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", - "from aviary.utils.doctape import glue_variable\n", - "glue_variable(f'{SubsystemBuilderBase=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{BatteryBuilder=}'.split('=')[0]+'()', md_code=True)" + "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "glue_variable(get_variable_name(SubsystemBuilderBase), md_code=True)\n", + "glue_variable(get_variable_name(BatteryBuilder)+'()', md_code=True)" ] }, { @@ -104,7 +104,7 @@ "\n", "## Using your builder within Aviary\n", "\n", - "Awesome. Let's keep going and start to discuss using these subsystems within Aviary. The overarching idea is that now that you have a subsystem builder, you can pass an instantiation of this builder object to Aviary via the `phase_info` dictionary. Take a look at [`run_cruise.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/external_subsystems/battery/run_cruise.py) and [`run_multiphase_mission.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/external_subsystems/battery/run_multiphase_mission.py) to see how we do this for the battery model. Specifically, here are the relevant lines of code from the `run_cruise.py` file:" + "Awesome. Let's keep going and start to discuss using these subsystems within Aviary. The overarching idea is that now that you have a subsystem builder, you can pass an instantiation of this builder object to Aviary via the {glue:md}`phase_info` dictionary. Take a look at [`run_cruise.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/external_subsystems/battery/run_cruise.py) and [`run_multiphase_mission.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/external_subsystems/battery/run_multiphase_mission.py) to see how we do this for the battery model. Specifically, here are the relevant lines of code from the `run_cruise.py` file:" ] }, { @@ -160,6 +160,17 @@ " # ... #" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "glue_variable(get_variable_name(phase_info), md_code=True)" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/aviary/docs/user_guide/variable_hierarchy.ipynb b/aviary/docs/user_guide/variable_hierarchy.ipynb index 679832646..336d931a8 100644 --- a/aviary/docs/user_guide/variable_hierarchy.ipynb +++ b/aviary/docs/user_guide/variable_hierarchy.ipynb @@ -23,9 +23,9 @@ "glue_variable(get_variable_name(Aircraft.VerticalTail.SPAN), md_code=True)\n", "glue_variable(get_variable_name(Mission.Design.CRUISE_ALTITUDE), md_code=True)\n", "glue_variable(get_variable_name(Mission.Design.RANGE), md_code=True)\n", - "glue_variable(f'{Aircraft=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{Mission=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{Aircraft.Wing=}'.split('=')[0].split('.')[1], md_code=True)\n", + "glue_variable(get_variable_name(Aircraft), md_code=True)\n", + "glue_variable(get_variable_name(Mission), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Wing).split('.')[1], md_code=True)\n", "\n", "file_path = av.get_path('variable_info/functions.py')\n", "var_function_names = get_function_names(file_path)\n", diff --git a/aviary/docs/user_guide/variable_metadata.ipynb b/aviary/docs/user_guide/variable_metadata.ipynb index 8e276bf51..ed2a91606 100644 --- a/aviary/docs/user_guide/variable_metadata.ipynb +++ b/aviary/docs/user_guide/variable_metadata.ipynb @@ -26,10 +26,9 @@ " glue_variable(arg, md_code=False)\n", "\n", "glue_variable(get_variable_name(Aircraft.Wing.MASS_SCALER), md_code=True)\n", - "glue_variable(f'{Aircraft=}'.split('=')[0], md_code=True)\n", + "glue_variable(get_variable_name(Aircraft), md_code=True)\n", "glue_variable(get_variable_name(Aircraft.Wing.SPAN), md_code=False)\n", - "glue_variable('utils/develop_metadata.py', md_code=False)\n", - "\n" + "glue_variable('utils/develop_metadata.py', md_code=False)\n" ] }, { @@ -207,8 +206,8 @@ "source": [ "# Testing Cell\n", "from aviary.utils.develop_metadata import add_meta_data, update_meta_data\n", - "glue_variable(f'{add_meta_data=}'.split('=')[0]+'()', md_code=True)\n", - "glue_variable(f'{update_meta_data=}'.split('=')[0]+'()', md_code=True)" + "glue_variable(get_variable_name(add_meta_data)+'()', md_code=True)\n", + "glue_variable(get_variable_name(update_meta_data)+'()', md_code=True)" ] }, { @@ -316,9 +315,9 @@ "source": [ "# Testing Cell\n", "from aviary.variable_info.variable_meta_data import CoreMetaData\n", - "glue_variable(f'{CoreMetaData=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{ExtendedAircraft=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{ExtendedMetaData=}'.split('=')[0], md_code=True)" + "glue_variable(get_variable_name(CoreMetaData), md_code=True)\n", + "glue_variable(get_variable_name(ExtendedAircraft), md_code=True)\n", + "glue_variable(get_variable_name(ExtendedMetaData), md_code=True)" ] }, { @@ -435,8 +434,8 @@ "outputs": [], "source": [ "# Testing Cell\n", - "glue_variable(f'{ExtendedAircraft2=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{ExtendedMetaData2=}'.split('=')[0], md_code=True)" + "glue_variable(get_variable_name(ExtendedAircraft2), md_code=True)\n", + "glue_variable(get_variable_name(ExtendedMetaData2), md_code=True)" ] }, { @@ -471,8 +470,8 @@ "outputs": [], "source": [ "# Testing Cell\n", - "glue_variable(f'{FinalAircraft=}'.split('=')[0], md_code=True)\n", - "glue_variable(f'{FinalMetaData=}'.split('=')[0], md_code=True)" + "glue_variable(get_variable_name(FinalAircraft), md_code=True)\n", + "glue_variable(get_variable_name(FinalMetaData), md_code=True)" ] }, { From ca176ddccd98feb39069c866e77849d9231bf31e Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 16 Dec 2024 20:40:09 -0800 Subject: [PATCH 40/48] further polish --- aviary/docs/user_guide/battery_subsystem_example.ipynb | 10 +++++----- .../drawing_and_running_simple_missions.ipynb | 4 ++-- ...es_of_the_same_mission_at_different_UI_levels.ipynb | 4 ++-- aviary/docs/user_guide/external_aero.ipynb | 8 ++++---- aviary/docs/user_guide/propulsion.ipynb | 10 +++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/aviary/docs/user_guide/battery_subsystem_example.ipynb b/aviary/docs/user_guide/battery_subsystem_example.ipynb index 001265882..761a7dfae 100644 --- a/aviary/docs/user_guide/battery_subsystem_example.ipynb +++ b/aviary/docs/user_guide/battery_subsystem_example.ipynb @@ -35,11 +35,11 @@ "source": [ "# Testing Cell\n", "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", - "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "from aviary.utils.functions import get_path\n", "# make sure that the path exists.\n", "get_path('examples/external_subsystems/battery/battery_builder.py');\n", - "glue_variable(f'{SubsystemBuilderBase=}'.split('=')[0], md_code=True)" + "glue_variable(get_variable_name(SubsystemBuilderBase), md_code=True)" ] }, { @@ -106,7 +106,7 @@ "import aviary.api as av\n", "from aviary.interface.methods_for_level2 import AviaryProblem\n", "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", - "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "\n", "# Get all functions of class CoreAerodynamicsBuilder\n", "methods = inspect.getmembers(SubsystemBuilderBase, predicate=inspect.isfunction)\n", @@ -115,7 +115,7 @@ " glue_variable(name + '()', md_code=True)\n", "\n", "AviaryValues = av.AviaryValues\n", - "glue_variable(f'{AviaryValues=}'.split('=')[0], md_code=True)\n", + "glue_variable(get_variable_name(AviaryValues), md_code=True)\n", "\n", "# retrieve all argument of build_pre_mission(self, aviary_inputs, **kwargs)\n", "sig = inspect.signature(SubsystemBuilderBase.build_pre_mission)\n", @@ -141,7 +141,7 @@ " glue_variable(name + '()', md_code=True)\n", "\n", "TestSubsystemBuilderBase = av.TestSubsystemBuilderBase\n", - "glue_variable(f'{TestSubsystemBuilderBase=}'.split('=')[0], md_code=True)\n" + "glue_variable(get_variable_name(TestSubsystemBuilderBase), md_code=True)\n" ] }, { diff --git a/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb b/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb index a7ca88678..43420bf94 100644 --- a/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb +++ b/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb @@ -53,9 +53,9 @@ "source": [ "# Testing Cell\n", "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", - "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "check_phase_info({}, HEIGHT_ENERGY)\n", - "glue_variable('height_energy', f'{HEIGHT_ENERGY=}'.split('=')[0].lower(), md_code=False)\n" + "glue_variable('height_energy', get_variable_name(HEIGHT_ENERGY).lower(), md_code=False)\n" ] }, { diff --git a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb index 876aa8b56..2e3756ccf 100644 --- a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb +++ b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb @@ -14,7 +14,7 @@ "import inspect\n", "from aviary.interface.methods_for_level1 import run_aviary\n", "from aviary.interface.methods_for_level2 import AviaryProblem\n", - "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "\n", "# glue all argument of function run_aviary()\n", "sigs = inspect.signature(run_aviary)\n", @@ -22,7 +22,7 @@ "for name, param in parameters.items():\n", " if name == 'phase_info': # for this file, we need one argument 'phase_info'\n", " glue_variable(name, md_code=True)\n", - "glue_variable(f'{AviaryProblem=}'.split('=')[0], md_code=False)" + "glue_variable(get_variable_name(AviaryProblem), md_code=False)" ] }, { diff --git a/aviary/docs/user_guide/external_aero.ipynb b/aviary/docs/user_guide/external_aero.ipynb index cd6647a9c..0c6ec327d 100644 --- a/aviary/docs/user_guide/external_aero.ipynb +++ b/aviary/docs/user_guide/external_aero.ipynb @@ -113,9 +113,9 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.utils.doctape import glue_variable\n", + "from aviary.utils.doctape import get_variable_name, glue_variable\n", "# class ExternalAero is defined with this file\n", - "glue_variable(f'{ExternalAero=}'.split('=')[0], md_code=True)" + "glue_variable(get_variable_name(ExternalAero), md_code=True)" ] }, { @@ -150,10 +150,10 @@ "AerodynamicsBuilderBase\n", "Aircraft.Design.LIFT_POLAR;\n", "Aircraft.Design.DRAG_POLAR;\n", - "glue_variable(f'{AerodynamicsBuilderBase=}'.split('=')[0], md_code=True)\n", + "glue_variable(get_variable_name(AerodynamicsBuilderBase), md_code=True)\n", "glue_variable(get_variable_name(Aircraft.Design.LIFT_POLAR), md_code=True)\n", "glue_variable(get_variable_name(Aircraft.Design.DRAG_POLAR), md_code=True)\n", - "glue_variable(f'{AviaryProblem=}'.split('=')[0], md_code=False)" + "glue_variable(get_variable_name(AviaryProblem), md_code=False)" ] }, { diff --git a/aviary/docs/user_guide/propulsion.ipynb b/aviary/docs/user_guide/propulsion.ipynb index 6f4171d1c..c9da5c839 100644 --- a/aviary/docs/user_guide/propulsion.ipynb +++ b/aviary/docs/user_guide/propulsion.ipynb @@ -126,17 +126,17 @@ "required_options_list = ''\n", "for var in required:\n", " required_options_list += f'* `{var}`\\n'\n", - "required_options_list += f'* `{f\"{Aircraft.Engine.NUM_WING_ENGINES=}\".split(\"=\")[0]}` and/or '+\\\n", - " f'`{f\"{Aircraft.Engine.NUM_FUSELAGE_ENGINES=}\".split(\"=\")[0]}`\\n'\n", + "required_options_list += f'* `{get_variable_name(Aircraft.Engine.NUM_WING_ENGINES)}` and/or '+\\\n", + " f'`{get_variable_name(Aircraft.Engine.NUM_FUSELAGE_ENGINES)}`\\n'\n", "glue_variable('required_options', required_options_list, display=True)\n", "\n", "GENERATE_FLIGHT_IDLE = (Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION,\n", " Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION,\n", " Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION,)\n", "check_value(dependent_options[Aircraft.Engine.GENERATE_FLIGHT_IDLE], GENERATE_FLIGHT_IDLE)\n", - "flight_idle_options = f'* `{f\"{Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION=}\".split(\"=\")[0]}`\\n' +\\\n", - " f'* `{f\"{Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION=}\".split(\"=\")[0]}`\\n' +\\\n", - " f'* `{f\"{Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION=}\".split(\"=\")[0]}`\\n'\n", + "flight_idle_options = f'* `{get_variable_name(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION)}`\\n' +\\\n", + " f'* `{get_variable_name(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION)}`\\n' +\\\n", + " f'* `{get_variable_name(Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION)}`\\n'\n", "glue_variable('flight_idle_options', flight_idle_options, display=True)\n", "\n" ] From b7278ac78ae4b96e7b609d1e393d7eee5cc05498 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 17 Dec 2024 08:58:27 -0800 Subject: [PATCH 41/48] autopep8 --- aviary/utils/doctape.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aviary/utils/doctape.py b/aviary/utils/doctape.py index b6fff936d..bb32e1300 100644 --- a/aviary/utils/doctape.py +++ b/aviary/utils/doctape.py @@ -408,7 +408,7 @@ def glue_keys(dict_of_dicts: dict, display=True) -> list: return all_keys -def get_class_names(file_path): +def get_class_names(file_path) -> set: """ Retrieve all class names from a given file and return as a set @@ -420,20 +420,20 @@ def get_class_names(file_path): # Read the content of the file with open(file_path, 'r') as file: file_content = file.read() - + # Parse the file content into an AST tree = ast.parse(file_content) - + # Extract class names class_names = [ node.name for node in ast.walk(tree) if isinstance(node, ast.ClassDef) ] - + return set(class_names) -def get_function_names(file_path): +def get_function_names(file_path) -> set: """ Get all function names in a given file and return as a set. @@ -445,14 +445,14 @@ def get_function_names(file_path): # Read the content of the file with open(file_path, 'r') as file: file_content = file.read() - + # Parse the file content into an AST tree = ast.parse(file_content) - + # Extract function names function_names = [ node.name for node in ast.walk(tree) if isinstance(node, ast.FunctionDef) ] - + return set(function_names) From ce353c87f9890c61e3afcafc7bc24c5371b8c6d3 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 17 Dec 2024 09:40:04 -0800 Subject: [PATCH 42/48] docpage update --- aviary/utils/doctape.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aviary/utils/doctape.py b/aviary/utils/doctape.py index bb32e1300..ba190c5b2 100644 --- a/aviary/utils/doctape.py +++ b/aviary/utils/doctape.py @@ -29,6 +29,8 @@ glue_variable Glue a variable for later use in markdown cells of notebooks (can auto format for code) glue_keys recursively glue all of the keys from a dict of dicts get_previous_line returns the previous n line(s) of code as a string +get_class_names return the class names in a file as a set +get_function_names returns the function names in a file as a set """ From cc1eb0f77b3e62218655edd47eda62fd0582580c Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 17 Dec 2024 10:17:55 -0800 Subject: [PATCH 43/48] add two utility functions: get_class_names and get_function_names --- aviary/docs/developer_guide/doctape.ipynb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aviary/docs/developer_guide/doctape.ipynb b/aviary/docs/developer_guide/doctape.ipynb index b4db14ae8..9346a839b 100644 --- a/aviary/docs/developer_guide/doctape.ipynb +++ b/aviary/docs/developer_guide/doctape.ipynb @@ -71,6 +71,8 @@ " \"get_attribute_name\": \"gets the name of an object's attribute based on it's value\",\n", " \"get_all_keys\": \"recursively get all of the keys from a dict of dicts\",\n", " \"get_value\": \"recursively get a value from a dict of dicts\",\n", + " \"get_class_names\": \"gets all class names from a given file and return as a set\",\n", + " \"get_function_names\": \"gets all function names in a given file and return as a set\",\n", "}\n", "\n", "doctape.check_value(imported_classes.keys(),custom_classes.keys())\n", From b97f574edbb235ff4c775b9dc35a27b7a3a9c223 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 17 Dec 2024 18:38:18 -0800 Subject: [PATCH 44/48] rename Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS to Aircraft.Engine.Propeller.COMPUTE_PROPELLER_INSTALLATION_LOSS --- aviary/docs/user_guide/hamilton_standard.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aviary/docs/user_guide/hamilton_standard.ipynb b/aviary/docs/user_guide/hamilton_standard.ipynb index 0a0e1b46b..4a4ebc653 100644 --- a/aviary/docs/user_guide/hamilton_standard.ipynb +++ b/aviary/docs/user_guide/hamilton_standard.ipynb @@ -19,8 +19,8 @@ "from aviary.utils.doctape import check_value, get_variable_name, glue_variable\n", "from aviary.subsystems.atmosphere.atmosphere import Atmosphere\n", "\n", - "check_value(Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS,'aircraft:engine:compute_propeller_installation_loss')\n", - "glue_variable(get_variable_name(Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS), md_code=True)\n", + "check_value(Aircraft.Engine.Propeller.COMPUTE_PROPELLER_INSTALLATION_LOSS,'aircraft:engine:propeller:compute_propeller_installation_loss')\n", + "glue_variable(get_variable_name(Aircraft.Engine.Propeller.COMPUTE_PROPELLER_INSTALLATION_LOSS), md_code=True)\n", "glue_variable(get_variable_name(Atmosphere), md_code=True)\n", "glue_variable(get_variable_name(InstallLoss), md_code=True)\n", "glue_variable(get_variable_name(PreHamiltonStandard), md_code=True)\n", @@ -40,7 +40,7 @@ "You can find the definitions, methodology, and Fortran code in the document.\n", "In Aviary, we implement only one of the computation options: the code computes the corresponding thrust for a given horsepower.\n", "\n", - "Below is an XDSM diagram of Hamilton Standard model (assuming {glue:md}`Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS` is `True`):\n", + "Below is an XDSM diagram of Hamilton Standard model (assuming {glue:md}`Aircraft.Engine.Propeller.COMPUTE_PROPELLER_INSTALLATION_LOSS` is `True`):\n", "\n", "![Hamilton Standard Diagram](images/hamilton_standard.png)\n", "\n", From 735435789d422744a2d9c2177fe43be170bb2aaf Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 17 Dec 2024 19:00:56 -0800 Subject: [PATCH 45/48] rename Aircraft.Engine.COMPUTE_INSTALLATION_LOSS to Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS --- aviary/docs/user_guide/hamilton_standard.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aviary/docs/user_guide/hamilton_standard.ipynb b/aviary/docs/user_guide/hamilton_standard.ipynb index 4a4ebc653..b2a867ebd 100644 --- a/aviary/docs/user_guide/hamilton_standard.ipynb +++ b/aviary/docs/user_guide/hamilton_standard.ipynb @@ -19,8 +19,8 @@ "from aviary.utils.doctape import check_value, get_variable_name, glue_variable\n", "from aviary.subsystems.atmosphere.atmosphere import Atmosphere\n", "\n", - "check_value(Aircraft.Engine.Propeller.COMPUTE_PROPELLER_INSTALLATION_LOSS,'aircraft:engine:propeller:compute_propeller_installation_loss')\n", - "glue_variable(get_variable_name(Aircraft.Engine.Propeller.COMPUTE_PROPELLER_INSTALLATION_LOSS), md_code=True)\n", + "check_value(Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS,'aircraft:engine:propeller:compute_installation_loss')\n", + "glue_variable(get_variable_name(Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS), md_code=True)\n", "glue_variable(get_variable_name(Atmosphere), md_code=True)\n", "glue_variable(get_variable_name(InstallLoss), md_code=True)\n", "glue_variable(get_variable_name(PreHamiltonStandard), md_code=True)\n", @@ -40,7 +40,7 @@ "You can find the definitions, methodology, and Fortran code in the document.\n", "In Aviary, we implement only one of the computation options: the code computes the corresponding thrust for a given horsepower.\n", "\n", - "Below is an XDSM diagram of Hamilton Standard model (assuming {glue:md}`Aircraft.Engine.Propeller.COMPUTE_PROPELLER_INSTALLATION_LOSS` is `True`):\n", + "Below is an XDSM diagram of Hamilton Standard model (assuming {glue:md}`Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS` is `True`):\n", "\n", "![Hamilton Standard Diagram](images/hamilton_standard.png)\n", "\n", From 641371a132afbaacb2d0a73b725d62161f425e36 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 18 Dec 2024 09:34:53 -0800 Subject: [PATCH 46/48] Update hamilton_standard.ipynb Replace "Aircraft.Engine.PROPELLER_DATA_FILE" by "Aircraft.Engine.Propeller.DATA_FILE". --- aviary/docs/user_guide/hamilton_standard.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/docs/user_guide/hamilton_standard.ipynb b/aviary/docs/user_guide/hamilton_standard.ipynb index b2a867ebd..fc8a63786 100644 --- a/aviary/docs/user_guide/hamilton_standard.ipynb +++ b/aviary/docs/user_guide/hamilton_standard.ipynb @@ -343,8 +343,8 @@ "\n", "check_value(Aircraft.Engine.USE_PROPELLER_MAP,'aircraft:engine:use_propeller_map')\n", "glue_variable(get_variable_name(Aircraft.Engine.USE_PROPELLER_MAP), md_code=True)\n", - "check_value(Aircraft.Engine.PROPELLER_DATA_FILE,'aircraft:engine:propeller_data_file')\n", - "glue_variable(get_variable_name(Aircraft.Engine.PROPELLER_DATA_FILE), md_code=True)\n", + "check_value(Aircraft.Engine.Propeller.DATA_FILE,'aircraft:engine:propeller:data_file')\n", + "glue_variable(get_variable_name(Aircraft.Engine.Propeller.DATA_FILE), md_code=True)\n", "check_value(Dynamic.Mission.MACH,'mach')\n", "glue_variable(get_variable_name(Dynamic.Mission.MACH), md_code=True)\n", "glue_variable(get_variable_name(OutMachs), md_code=True)\n" From a029c94e912de923026b4658360eacd4562abf6a Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 18 Dec 2024 10:30:01 -0800 Subject: [PATCH 47/48] Update hamilton_standard.ipynb Replace Dynamic.Mission.MACH by Dynamic.Atmosphere.MACH. --- aviary/docs/user_guide/hamilton_standard.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/docs/user_guide/hamilton_standard.ipynb b/aviary/docs/user_guide/hamilton_standard.ipynb index fc8a63786..fdec0a730 100644 --- a/aviary/docs/user_guide/hamilton_standard.ipynb +++ b/aviary/docs/user_guide/hamilton_standard.ipynb @@ -345,8 +345,8 @@ "glue_variable(get_variable_name(Aircraft.Engine.USE_PROPELLER_MAP), md_code=True)\n", "check_value(Aircraft.Engine.Propeller.DATA_FILE,'aircraft:engine:propeller:data_file')\n", "glue_variable(get_variable_name(Aircraft.Engine.Propeller.DATA_FILE), md_code=True)\n", - "check_value(Dynamic.Mission.MACH,'mach')\n", - "glue_variable(get_variable_name(Dynamic.Mission.MACH), md_code=True)\n", + "check_value(Dynamic.Atmosphere.MACH,'mach')\n", + "glue_variable(get_variable_name(Dynamic.Atmosphere.MACH), md_code=True)\n", "glue_variable(get_variable_name(OutMachs), md_code=True)\n" ] }, From 37a44a7823654b635412115d231b69c0e23a33ce Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 18 Dec 2024 10:51:12 -0800 Subject: [PATCH 48/48] Update hamilton_standard.ipynb Remove Aircraft.Engine.USE_PROPELLER_MAP. --- aviary/docs/user_guide/hamilton_standard.ipynb | 2 -- 1 file changed, 2 deletions(-) diff --git a/aviary/docs/user_guide/hamilton_standard.ipynb b/aviary/docs/user_guide/hamilton_standard.ipynb index fdec0a730..d94d26e5c 100644 --- a/aviary/docs/user_guide/hamilton_standard.ipynb +++ b/aviary/docs/user_guide/hamilton_standard.ipynb @@ -341,8 +341,6 @@ "glue_variable(OutMachType.HELICAL_MACH.name.title(), md_code=True)\n", "glue_variable(OutMachType.MACH.name.title(), md_code=True)\n", "\n", - "check_value(Aircraft.Engine.USE_PROPELLER_MAP,'aircraft:engine:use_propeller_map')\n", - "glue_variable(get_variable_name(Aircraft.Engine.USE_PROPELLER_MAP), md_code=True)\n", "check_value(Aircraft.Engine.Propeller.DATA_FILE,'aircraft:engine:propeller:data_file')\n", "glue_variable(get_variable_name(Aircraft.Engine.Propeller.DATA_FILE), md_code=True)\n", "check_value(Dynamic.Atmosphere.MACH,'mach')\n",