diff --git a/.github/workflows/test_benchmarks.yml b/.github/workflows/test_benchmarks.yml index ef06bf6a6..5b18b2c2c 100644 --- a/.github/workflows/test_benchmarks.yml +++ b/.github/workflows/test_benchmarks.yml @@ -18,7 +18,7 @@ on: jobs: latest_benchmarks: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 timeout-minutes: 90 steps: @@ -38,8 +38,7 @@ jobs: SCIPY: 1 PYOPTSPARSE: 'v2.9.1' SNOPT: '7.7' - #OPENMDAO: 'latest' - OPENMDAO: '3.34.2' + OPENMDAO: 'latest' DYMOS: 'latest' SSH_PRIVATE_KEY: ${{secrets.SSH_PRIVATE_KEY}} SSH_KNOWN_HOSTS: ${{secrets.SSH_KNOWN_HOSTS}} diff --git a/.github/workflows/test_docs.yml b/.github/workflows/test_docs.yml index adb4cd351..287fc9510 100644 --- a/.github/workflows/test_docs.yml +++ b/.github/workflows/test_docs.yml @@ -18,7 +18,7 @@ on: jobs: latest_docs: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 timeout-minutes: 90 steps: @@ -38,8 +38,7 @@ jobs: SCIPY: 1 PYOPTSPARSE: 'v2.9.1' SNOPT: '7.7' - #OPENMDAO: 'latest' - OPENMDAO: '3.34.2' + OPENMDAO: 'latest' DYMOS: 'latest' SSH_PRIVATE_KEY: ${{secrets.SSH_PRIVATE_KEY}} SSH_KNOWN_HOSTS: ${{secrets.SSH_KNOWN_HOSTS}} diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 36242e636..ce705719b 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -18,7 +18,7 @@ jobs: pre_commit: # run pre-commit checks - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -28,19 +28,20 @@ jobs: - uses: pre-commit/action@v3.0.1 test_ubuntu: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: include: # oldest versions of openmdao/dymos + # Note: bugfixes sometimes require incrementing the minimal version of openmdao or dymos. - NAME: oldest PY: '3.9' NUMPY: '1.20' SCIPY: '1.6' PYOPTSPARSE: 'v2.9.1' SNOPT: '7.7' - OPENMDAO: '3.33.0' + OPENMDAO: '3.35.0' DYMOS: '1.8.0' # latest versions of openmdao/dymos @@ -50,8 +51,7 @@ jobs: SCIPY: 1 PYOPTSPARSE: 'v2.9.1' SNOPT: '7.7' - #OPENMDAO: 'latest' - OPENMDAO: '3.34.2' + OPENMDAO: 'latest' DYMOS: 'latest' steps: diff --git a/.github/workflows/test_workflow_dev_deps.yml b/.github/workflows/test_workflow_dev_deps.yml index a3fd58944..fed5ad912 100644 --- a/.github/workflows/test_workflow_dev_deps.yml +++ b/.github/workflows/test_workflow_dev_deps.yml @@ -14,7 +14,7 @@ on: jobs: test_ubuntu: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: @@ -27,8 +27,7 @@ jobs: SCIPY: 1 PYOPTSPARSE: 'latest' SNOPT: '7.7' - #OPENMDAO: 'dev' - OPENMDAO: '3.34.2' + OPENMDAO: 'dev' DYMOS: 'dev' steps: diff --git a/.github/workflows/test_workflow_no_dev_install.yml b/.github/workflows/test_workflow_no_dev_install.yml index b4c9d1672..d58ffea15 100644 --- a/.github/workflows/test_workflow_no_dev_install.yml +++ b/.github/workflows/test_workflow_no_dev_install.yml @@ -17,7 +17,7 @@ on: jobs: test_ubuntu_no_dev_install: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 timeout-minutes: 90 @@ -70,7 +70,6 @@ jobs: echo "" echo "Temporarily install specific versions for now." pip install "numpy<2" - pip install "openmdao==3.34.2" pip install packaging pip install .[all] diff --git a/.gitignore b/.gitignore index 824371144..dd8663cd2 100644 --- a/.gitignore +++ b/.gitignore @@ -152,5 +152,9 @@ coloring_files/ # OpenMDAO N2 diagrams n2.html +# Input and output lists +input_list.txt +output_list.txt + # Windows downloads *:Zone.Identifier diff --git a/aviary/api.py b/aviary/api.py index c0b6b026a..4136c3aa8 100644 --- a/aviary/api.py +++ b/aviary/api.py @@ -23,7 +23,7 @@ from aviary.variable_info.options import get_option_defaults, is_option from aviary.utils.develop_metadata import add_meta_data, update_meta_data from aviary.variable_info.variable_meta_data import CoreMetaData -from aviary.variable_info.functions import add_aviary_input, add_aviary_output, get_units, override_aviary_vars, setup_trajectory_params +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, get_units, override_aviary_vars, setup_trajectory_params, setup_model_options from aviary.utils.merge_hierarchies import merge_hierarchies from aviary.utils.merge_variable_metadata import merge_meta_data from aviary.utils.named_values import NamedValues, get_keys, get_items, get_values diff --git a/aviary/constants.py b/aviary/constants.py index c7770d804..23b694d60 100644 --- a/aviary/constants.py +++ b/aviary/constants.py @@ -7,6 +7,8 @@ GRAV_METRIC_FLOPS = 9.80665 # m/s^2 GRAV_ENGLISH_FLOPS = 32.17399 # ft/s^2 GRAV_ENGLISH_LBM = 1.0 # lbf/lbm +# TODO this does not match what dymos atmosphere comp predicts, which leads to subtle +# problems such as density ratio not being 1 at sea level RHO_SEA_LEVEL_ENGLISH = 0.0023769 # slug/ft^3 RHO_SEA_LEVEL_METRIC = 1.225 # kg/m^3 MU_TAKEOFF = 0.02 # TODO: fill in coefficient of friction for takeoff diff --git a/aviary/docs/_toc.yml b/aviary/docs/_toc.yml index 4c53a7e9c..bc76d351b 100644 --- a/aviary/docs/_toc.yml +++ b/aviary/docs/_toc.yml @@ -45,6 +45,7 @@ parts: - file: user_guide/features/overriding - file: user_guide/FLOPS_based_detailed_takeoff_and_landing - file: user_guide/reserve_missions + - file: user_guide/multi_mission - file: user_guide/off_design_missions - file: user_guide/SGM_capabilities - file: user_guide/troubleshooting @@ -57,6 +58,7 @@ parts: - file: examples/coupled_aircraft_mission_optimization - file: examples/additional_flight_phases - file: examples/reserve_missions + - file: examples/multi_mission - file: examples/off_design_example - file: examples/OAS_subsystem - file: examples/level_2_detailed_takeoff_and_landing @@ -82,6 +84,9 @@ parts: - file: developer_guide/unit_tests - file: developer_guide/contributing_guidelines - file: developer_guide/how_to_contribute_docs + sections: + - file: developer_guide/doctape.ipynb + - file: developer_guide/doctape_examples.ipynb - file: developer_guide/debugging_env_from_github - caption: Miscellaneous Resources diff --git a/aviary/docs/developer_guide/codebase_overview.ipynb b/aviary/docs/developer_guide/codebase_overview.ipynb index 92dae0ab3..23cc6bc89 100644 --- a/aviary/docs/developer_guide/codebase_overview.ipynb +++ b/aviary/docs/developer_guide/codebase_overview.ipynb @@ -10,7 +10,7 @@ }, "outputs": [], "source": [ - "from aviary.docs.tests.utils import Markdown, glue_variable\n", + "from aviary.utils.doctape import glue_variable\n", "\n", "structure = {\n", " 'docs':'contains the doc files for Aviary',\n", @@ -18,7 +18,7 @@ " 'interface':'is where most code that users interact with is located',\n", " 'mission':'contains OpenMDAO components and groups for modeling the aircraft mission',\n", " 'models':'contains aircraft and propulsion models for use in Aviary examples and tests',\n", - " 'subsystems':'is where the aerodynamic, propulsion, mass, and geometry core subsystems are located',\n", + " 'subsystems':'is where the aerodynamic, atmosphere, energy, propulsion, mass, and geometry core subsystems are located',\n", " 'utils':'contains utility functions for use in Aviary code, examples, and tests',\n", " 'validation_cases':'contains validation cases for testing and benchmarking Aviary',\n", " 'variable_info':'contains the variable meta data as well as several variable classes that are used in Aviary',\n", @@ -31,7 +31,7 @@ "\n", "# change display to False to prevent displaying the results when running cells directly\n", "# (Does not change the generated book)\n", - "glue_variable('folder_structure', Markdown(bulleted_list), display=True)\n" + "glue_variable('folder_structure', bulleted_list, display=True)\n" ] }, { @@ -62,7 +62,7 @@ "# Testing Cell\n", "import os\n", "from aviary.utils.functions import get_path\n", - "from aviary.docs.tests.utils import check_contains\n", + "from aviary.utils.doctape import check_contains\n", "\n", "folder = get_path('docs').parent\n", "subfolders = [ f.name for f in os.scandir(folder) ]\n", diff --git a/aviary/docs/developer_guide/coding_standards.ipynb b/aviary/docs/developer_guide/coding_standards.ipynb index 680236a1e..e77c5fb60 100644 --- a/aviary/docs/developer_guide/coding_standards.ipynb +++ b/aviary/docs/developer_guide/coding_standards.ipynb @@ -12,15 +12,15 @@ "source": [ "# Testing Cell\n", "import aviary.api as av\n", - "from aviary.docs.tests.utils import get_attribute_name, glue_variable\n", + "from aviary.utils.doctape import get_attribute_name, get_variable_name, glue_variable\n", "Verbosity = av.Verbosity;\n", "\n", "verbosity = get_attribute_name(av.Settings,av.Settings.VERBOSITY)\n", "glue_variable('VERBOSITY',verbosity, md_code=True)\n", - "glue_variable(f'{Verbosity=}'.split('=')[0], md_code=True)\n", + "glue_variable(get_variable_name(Verbosity), md_code=True)\n", "glue_variable('QUIET',av.Verbosity.QUIET.name, md_code=True)\n", "glue_variable('BRIEF',av.Verbosity.BRIEF.name, md_code=True)\n", - "glue_variable(f'{Verbosity.BRIEF=}'.split('=')[0], md_code=True)\n", + "glue_variable(get_variable_name(Verbosity.BRIEF), md_code=True)\n", "glue_variable('VERBOSE',av.Verbosity.VERBOSE.name, md_code=True)\n", "glue_variable('DEBUG',av.Verbosity.DEBUG.name, md_code=True)" ] diff --git a/aviary/docs/developer_guide/doctape.ipynb b/aviary/docs/developer_guide/doctape.ipynb new file mode 100644 index 000000000..b4db14ae8 --- /dev/null +++ b/aviary/docs/developer_guide/doctape.ipynb @@ -0,0 +1,212 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# DocTAPE\n", + "\n", + "DocTAPE (Documentation Testing and Automated Placement of Expressions) is a collection of utility functions (and wrappers for [Glue](https://myst-nb.readthedocs.io/en/latest/render/glue.html)) that are useful\n", + "for automating the process of building and testing documentation to ensure that documentation doesn't get stale.\n", + "\n", + "Our standard practice it to include a comment (`# Testing Cell`) at the begining of code cells as well as make use of the `remove-cell` tag.\n", + "\n", + "> \"metadata\": { \"tags\": [ \"remove-cell\" ] },\n", + "\n", + "
More info about adding cell tags\n", + "\n", + "- [Jupyter Book](https://jupyterbook.org/en/stable/content/metadata.html)\n", + "- [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.vscode-jupyter-cell-tags)\n", + "
\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "\n", + "from aviary.utils import doctape\n", + "import inspect\n", + "\n", + "imported_functions = {k:v for k,v in inspect.getmembers(doctape, inspect.isfunction) if v.__module__ == doctape.__name__}\n", + "imported_classes = {k:v for k,v in inspect.getmembers(doctape, inspect.isclass) if v.__module__ == doctape.__name__}\n", + "\n", + "custom_classes = {\n", + " \"expected_error\": \"is an execption that can be used in try/except blocks to allow desired errors to pass while still raising unexpected errors.\",\n", + "}\n", + "testing_functions = {\n", + " \"check_value\": \"is a simple function for comparing two values\",\n", + " \"check_contains\": \"confirms that all the elements of one iterable are contained in the other\",\n", + " \"check_args\": \"gets the signature of a function and compares it to the arguments you are expecting\",\n", + " \"run_command_no_file_error\": \"executes a CLI command but won't fail if a FileNotFoundError is raised\",\n", + "}\n", + "glue_functions = {\n", + " \"glue_variable\": \"Glue a variable for later use in markdown cells of notebooks (can auto format for code)\",\n", + " \"glue_keys\": \"recursively glue all of the keys from a dict of dicts\",\n", + "}\n", + "utility_functions = {\n", + " \"gramatical_list\": \"combines the elements of a list into a string with proper punctuation\",\n", + " \"get_variable_name\": \"returns the name of the variable passed to the function as a string\",\n", + " \"get_previous_line\": \"returns the previous line of code as a string\",\n", + " \"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", + "}\n", + "\n", + "doctape.check_value(imported_classes.keys(),custom_classes.keys())\n", + "doctape.check_value(imported_functions.keys(), {\n", + " **testing_functions, **glue_functions, **utility_functions}.keys())\n", + "\n", + "class_list = ''\n", + "for key,val in custom_classes.items():\n", + " doctape.glue_variable(key, md_code=True)\n", + " class_list += f'- `{key}` {val}\\n'\n", + "\n", + "# testing_list = ''\n", + "# for key,val in testing_functions.items():\n", + "# testing_list += f'- `{key}` {val}\\n'\n", + "\n", + "utility_list = '```{eval-rst}\\n'\n", + "for key in utility_functions:\n", + " doctape.glue_variable(key, md_code=True)\n", + " utility_list += ' '*4+f'.. autofunction:: aviary.utils.doctape.{key}\\n{\" \"*8}:noindex:\\n\\n'\n", + "utility_list += '```'\n", + "\n", + "# testing_list = '```{eval-rst}\\n'\n", + "# for key in testing_functions:\n", + "# utils.glue_variable(key, md_code=True)\n", + "# testing_list += ' '*4+f'.. autofunction:: aviary.utils.doctape.{key}\\n{\" \"*8}:noindex:\\n\\n'\n", + "# testing_list += '```'\n", + "\n", + "# testing_list = '
\\n\\nFunction Docs\\n\\n'\n", + "testing_list = '```{eval-rst}\\n'\n", + "for key in testing_functions:\n", + " doctape.glue_variable(key, md_code=True)\n", + " testing_list += ' '*4+f'.. autofunction:: aviary.utils.doctape.{key}\\n{\" \"*8}:noindex:\\n\\n'\n", + "testing_list += '```'\n", + "# testing_list += '\\n\\n
'\n", + "\n", + "# glue_list = ''\n", + "# for key,val in glue_functions.items():\n", + "# glue_list += f'- `{key}` {key}\\n'\n", + "\n", + "# glue_list = ''\n", + "# for key in glue_functions:\n", + "# # doc_str = inspect.getdoc(imported_functions[key])\n", + "# doc_str = imported_functions[key].__doc__.split('\\n')[1]\n", + "# # doc_str = '\\n'.join([s+' ' for s in imported_functions[key].__doc__.split('\\n')])\n", + "# print(doc_str)\n", + "# glue_list += f'- `{key}`: {doc_str}\\n'\n", + "\n", + "glue_list = '```{eval-rst}\\n'\n", + "for key in glue_functions:\n", + " doctape.glue_variable(key, md_code=True)\n", + " glue_list += ' '*4+f'.. autofunction:: aviary.utils.doctape.{key}\\n{\" \"*8}:noindex:\\n\\n'\n", + "glue_list += '```'\n", + "\n", + "doctape.glue_variable('class_list', class_list)\n", + "doctape.glue_variable('utility_list', utility_list)\n", + "doctape.glue_variable('testing_list', testing_list)\n", + "doctape.glue_variable('glue_list', glue_list)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Classes\n", + "```{glue:md} class_list\n", + ":format: myst\n", + "```\n", + "\n", + "## Testing Functions\n", + "\n", + "Functions that raise an error provide the option to specify an error type to use instead of the default. This allows users to change the error type that is raised which can be useful in try/except blocks, especially when combined with the {glue:md}`expected_error` class.\n", + "\n", + "```{glue:md} testing_list\n", + ":format: myst\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import myst_nb\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "glue_variable(myst_nb.__name__)\n", + "glue_variable(myst_nb.glue.__name__, md_code=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Glue Functions\n", + "\n", + "The glue functions provide a wrapper for the {glue:md}`myst_nb` {glue:md}`glue` function that provides a simplified interface.\n", + "\n", + "```{glue:md} glue_list\n", + ":format: myst\n", + "```\n", + "\n", + "## Utility Functions\n", + "\n", + "Utility functions are provided that the user may find useful for generating or testing their documentation.\n", + "\n", + "```{glue:md} utility_list\n", + ":format: myst\n", + "```" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "latest_env", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/aviary/docs/developer_guide/doctape_examples.ipynb b/aviary/docs/developer_guide/doctape_examples.ipynb new file mode 100644 index 000000000..378bfe52e --- /dev/null +++ b/aviary/docs/developer_guide/doctape_examples.ipynb @@ -0,0 +1,508 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# DocTAPE Examples\n", + "\n", + "DocTAPE (Documentation Testing and Automated Placement of Expressions) is a collection of utility functions (and wrappers for [Glue](https://myst-nb.readthedocs.io/en/latest/render/glue.html)) that are useful\n", + "for automating the process of building and testing documentation to ensure that documentation doesn't get stale.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils import doctape\n", + "import inspect\n", + "\n", + "imported_functions = {k for k,v in inspect.getmembers(doctape, inspect.isfunction) if v.__module__ == doctape.__name__}\n", + "for func in imported_functions:\n", + " doctape.glue_variable(func, md_code=True)\n", + "doctape.glue_variable(doctape.expected_error.__name__, md_code=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Custom Classes\n", + "\n", + "### {glue:md}`expected_error` \n", + "Functions that raise an error provide the option to specify an error type to use instead of the default. This allows users to change the error type that is raised which can be useful in try/except blocks, especially when combined with the {glue:md}`expected_error` class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from aviary.utils.doctape import expected_error, check_value\n", + "try:\n", + " check_value(int('1'), 2, error_type=expected_error)\n", + "except expected_error:\n", + " print('we expected that to fail (1 is not equal to 2),')\n", + "print('but this will still run')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we just used `ValueError` in the `except` branch, we might miss errors that we actually do want to catch." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "raises-exception" + ] + }, + "outputs": [], + "source": [ + "from aviary.utils.doctape import expected_error, check_value\n", + "\n", + "try:\n", + " check_value(int('1)'), 2)\n", + "except ValueError:\n", + " print('1 is not equal to 2')\n", + "print(\"we mistyped '1', so we should have failed\")\n", + "\n", + "try:\n", + " check_value(int('1)'), 2, error_type=expected_error)\n", + "except expected_error:\n", + " print('1 is not equal to 2')\n", + "print(\"something unnexpected happened (we mistyped '1'), and we won't reach this\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Testing Functions\n", + "\n", + "The testing functions provide code that will raise errors when the documentation is built if the results don't match what is expected.\n", + "These can be used in places where it would be too difficult to glue portions of the documentation, or it is preferable to have a more uninterupted flow in the markdown cells.\n", + "\n", + "However, it is important to note that it is possible to notice an error when the documentation builds and fix the code in the testing cell without updating the text in the markdown cell. For this reason, it is recommended to use a combination of testing and glueing functions in documentation.\n", + "\n", + "### {glue:md}`check_value`\n", + "is a simple function for comparing two values.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from aviary.utils.doctape import check_value\n", + "from aviary.examples.reserve_missions.run_reserve_mission_fixedrange import phase_info\n", + "\n", + "user_opts = phase_info['reserve_cruise']['user_options']\n", + "check_value(user_opts['target_distance'],(200, 'km'))\n", + "check_value(user_opts['reserve'],True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### {glue:md}`check_contains`\n", + "confirms that all the elements of one iterable are contained in the other" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "raises-exception" + ] + }, + "outputs": [], + "source": [ + "from aviary.utils.doctape import check_contains\n", + "import aviary.api as av\n", + "import os\n", + "\n", + "off_design_examples = av.get_path(os.path.join('examples'))\n", + "check_contains(\n", + " ('run_off_design_example.py'),\n", + " os.listdir(off_design_examples),\n", + " error_string=\"{var} not in \"+str(off_design_examples),\n", + " error_type=FileNotFoundError)\n", + "print('This file exists and does not raise any errors')\n", + "check_contains(\n", + " ('made_up_file.py'),\n", + " os.listdir(off_design_examples),\n", + " error_string=\"{var} not in \"+str(off_design_examples),\n", + " error_type=FileNotFoundError)\n", + "print('This file does not exist, so we will not reach this point')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we are checking that a certain file exists in a folder and specify a more useful error type than the default {glue:md}`default_error`\n", + "\n", + "### {glue:md}`check_args`\n", + "gets the signature of a function and compares it to the arguments you are expecting.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-output" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import check_args, check_contains, glue_variable\n", + "\n", + "default_error = RuntimeError\n", + "check_args(check_contains, {'error_type':default_error}, exact=False)\n", + "glue_variable('default_error', default_error.__name__)\n", + "\n", + "exact_arg = 'exact'\n", + "check_args(check_args, exact_arg)\n", + "glue_variable(exact_arg, md_code=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting the {glue:md}`exact` argument to `False` means that we don't need to exactly match the signature of the function and instead just want to make sure that all of the arguments are valid and possibly that their default values are correct.\n", + "\n", + "### {glue:md}`run_command_no_file_error`\n", + "executes a CLI command but won't fail if a FileNotFoundError is raised." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-output" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import run_command_no_file_error\n", + "command = \"\"\"\n", + " aviary run_mission --optimizer IPOPT --phase_info outputted_phase_info.py \n", + " validation_cases/benchmark_tests/test_aircraft/aircraft_for_bench_FwFm.csv\n", + " --max_iter 0\n", + "\"\"\"\n", + "run_command_no_file_error(command)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This allows the command syntax and setup to be tested without requiring all of the files that command will use." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import myst_nb\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "glue_variable(myst_nb.__name__)\n", + "glue_variable(myst_nb.glue.__name__, md_code=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Glue Functions\n", + "\n", + "The glue functions provide a wrapper for the {glue:md}`myst_nb` {glue:md}`glue` function that simplifies the interface.\n", + "\n", + "After a variable has been glued in a Python cell, it can be accessed from a markdown cell with the \\{glue:md\\}\\`variable name\\` notation. Note that glue won't access the value of the glued variable until the documentation is built." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### {glue:md}`glue_variable`\n", + "allows users to specify a value that is {glue:}`something different than` what is displayed, but defaults to using the name of the variable if nothing is specified. This makes adapting old documentation easier, because users can just wrap {glue:}`the entire phrase they want to replace`.\n", + "\n", + "Glued text can either be {glue:md}`plain text` or can be formatted as {glue:md}`inline code`\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-output" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "glue_variable('plain text')\n", + "glue_variable('inline code', md_code=True)\n", + "glue_variable('something different than','not the same as')\n", + "glue_variable('the entire phrase they want to replace')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### {glue:md}`glue_keys` \n", + "combines {glue:md}`get_all_keys` and {glue:md}`glue_variable` to glue all of the unique keys from a dict of dicts for later use." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-output" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_keys\n", + "\n", + "simplified_dict = {\n", + " 'phase1':{'altitude':{'val':30,'units':'kft'},'mach':.4},\n", + " 'phase2':{'altitude':{'val':10,'units':'km'},'mach':.5}\n", + " }\n", + "glue_keys(simplified_dict)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This allows us to ensure that {glue:md}`altitude` and {glue:md}`mach` do exist in the dictionary." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Utility Functions\n", + "\n", + "Utility functions are provided that the user may find useful for generating or testing their documentation.\n", + "\n", + "### {glue:md}`gramatical_list`\n", + "is a simple function that forms a string that can be used in a sentence using a list of items." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from aviary.utils.doctape import gramatical_list\n", + "\n", + "single_element = gramatical_list([1])\n", + "two_elements = gramatical_list(['apples','bananas'])\n", + "three_elements_with_or = gramatical_list(['apples','bananas', 'strawberries'],'or')\n", + "\n", + "print(f\"I would like to order {single_element} smoothie.\")\n", + "print(f\"Do you want {three_elements_with_or} in your smoothie?\")\n", + "print(f\"I only want {two_elements}.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### {glue:md}`get_variable_name`\n", + "is a function that just returns the name of the variable passed to it as a string.\n", + "\n", + "The contents of the variable can be of any type, as the variable isn't used in the function, but rather the [inspect](https://docs.python.org/3/library/inspect.html) functionality is used to retrieve the line of code itself.\n", + "\n", + "{glue:md}`get_variable_name` can even accept multiple arguments, in which case a list of the names will be returned." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "hide-output" + ] + }, + "outputs": [], + "source": [ + "from aviary.utils.doctape import get_variable_name, glue_variable\n", + "from aviary.api import AviaryProblem\n", + "\n", + "glue_variable('function_name', get_variable_name(get_variable_name))\n", + "glue_variable(get_variable_name(print))\n", + "\n", + "some_string = 'that contains important information'\n", + "simple_variable_name = get_variable_name(some_string)\n", + "phrase = simple_variable_name + ' is a variable ' + some_string\n", + "print(phrase)\n", + "\n", + "complex_object_name = get_variable_name(AviaryProblem)\n", + "print(complex_object_name)\n", + "\n", + "multiple = 2\n", + "arguments = str\n", + "print(get_variable_name(multiple, arguments))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "{glue:md}`function_name` can be called directly in functions like {glue:md}`print` or {glue:md}`glue_variable` or the results can be saved.\n", + "\n", + "### {glue:md}`get_previous_line`\n", + "returns the previous line of code as a string, which allows users to grab individual lines of code from Python cells to use as inline code in markdown cells." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-output" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.api import Mission\n", + "from aviary.utils.doctape import glue_variable, get_previous_line, get_variable_name\n", + "\n", + "glue_variable('value', Mission.Design.MACH, md_code=True)\n", + "glue_variable('var_value_code', get_previous_line(), md_code=True)\n", + "glue_variable(get_variable_name(Mission.Design.MACH), md_code=True)\n", + "glue_variable('var_name_code', get_previous_line(), md_code=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you want to glue the name of a variable, instead of the value that variable holds, you can use the {glue:md}`get_variable_name` to extract it.\n", + "\n", + "For example:\n", + "Using {glue:md}`var_value_code` will result in {glue:md}`value`, whereas using {glue:md}`var_name_code` will result in {glue:md}`Mission.Design.MACH`\n", + "\n", + "### {glue:md}`get_attribute_name`\n", + "allows users to get the name of object attributes in order to glue them into documentation. This works well for Enums or Class Variables that have unique values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "hide-output" + ] + }, + "outputs": [], + "source": [ + "from aviary.api import LegacyCode\n", + "from aviary.utils.doctape import get_attribute_name, glue_variable\n", + "import aviary.api as av\n", + "\n", + "some_custom_alias = av.LegacyCode\n", + "\n", + "gasp_name = get_attribute_name(some_custom_alias, LegacyCode.GASP)\n", + "glue_variable(gasp_name)\n", + "brief_name = get_attribute_name(av.Verbosity, 1)\n", + "glue_variable(brief_name)\n", + "verbosity = get_attribute_name(av.Settings, av.Settings.VERBOSITY)\n", + "glue_variable(verbosity)\n", + "glue_variable(av.Settings.VERBOSITY)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### {glue:md}`get_all_keys` and {glue:md}`get_value`\n", + "are intended to be used together for getting keys from nested dictionaries and then getting values back from those nested dictionaries, respectively. They were originally added for complex dictionaries, like the phase_info." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from aviary.utils.doctape import get_all_keys, get_value\n", + "\n", + "simplified_dict = {\n", + " 'phase1':{'altitude':{'val':30,'units':'kft'},'mach':.4},\n", + " 'phase2':{'altitude':{'val':10,'units':'km'},'mach':.5}\n", + " }\n", + "unique_keys_only = get_all_keys(simplified_dict)\n", + "all_keys = get_all_keys(simplified_dict, track_layers=True)\n", + "print(unique_keys_only)\n", + "print(all_keys)\n", + "\n", + "p1_alt = get_value(simplified_dict, 'phase1.altitude.val')\n", + "print(p1_alt)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "latest_env", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/aviary/docs/developer_guide/how_to_contribute_docs.md b/aviary/docs/developer_guide/how_to_contribute_docs.md index 73432ac76..b2517a24c 100644 --- a/aviary/docs/developer_guide/how_to_contribute_docs.md +++ b/aviary/docs/developer_guide/how_to_contribute_docs.md @@ -9,7 +9,6 @@ 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. You can then run the `build_book.sh` bash script using the `sh build_book.sh` command to build the docs. -Currently, they are not hosted publicly online. To view the docs you must build them locally. The built docs live at `..Aviary/aviary/docs/_build/html/intro.html`. Navigate to this file in your file manager once you have built the docs, and you can open it from there to your favorite internet browser. @@ -57,3 +56,7 @@ When writing docs, please - write each sentence on a new line (this helps make diffs more clear) - use the active voice - consider the audience of the particular section you're writing + +## Doc Testing + +To ensure that doc pages don't get out of date when changes are made to the code, we have added [several utilities](./doctape) to allow developers to add tests into their documentation pages. diff --git a/aviary/docs/examples/OAS_subsystem.ipynb b/aviary/docs/examples/OAS_subsystem.ipynb index 1aef50ad0..712eb63d1 100644 --- a/aviary/docs/examples/OAS_subsystem.ipynb +++ b/aviary/docs/examples/OAS_subsystem.ipynb @@ -12,7 +12,7 @@ "source": [ "# Testing Cell\n", "import openmdao.api as om\n", - "from aviary.docs.tests.utils import check_args, glue_variable\n", + "from aviary.utils.doctape import check_args, glue_variable\n", "group = om.Group()\n", "promotes_inputs='promotes_inputs'\n", "check_args(group.add_subsystem,promotes_inputs)\n", @@ -123,7 +123,7 @@ "from aviary.api import Aircraft\n", "from aviary.examples.external_subsystems.OAS_weight.run_simple_OAS_mission import use_OAS\n", "from aviary.examples.external_subsystems.OAS_weight.OAS_wing_weight_analysis import OAStructures\n", - "from aviary.docs.tests.utils import glue_variable, glue_keys, Markdown\n", + "from aviary.utils.doctape import glue_variable, glue_keys, get_variable_name\n", "\n", "glue_variable(OAStructures.__qualname__, md_code=True)\n", "o = OAStructures()\n", @@ -134,20 +134,20 @@ "options_list = ''\n", "for key in o.options._dict:\n", " options_list += f'- {key}\\n'\n", - "glue_variable('options_list', Markdown(options_list), display=False)\n", + "glue_variable('options_list', options_list, display=False)\n", "glue_keys(o.options._dict, display=False)\n", "\n", "inputs_list = ''\n", "for key in o._static_var_rel_names['input']:\n", " inputs_list += f'- {key}\\n'\n", - "glue_variable('inputs_list', Markdown(inputs_list), display=False)\n", + "glue_variable('inputs_list', inputs_list, display=False)\n", "\n", "outputs_list = ''\n", "for key in o._static_var_rel_names['output']:\n", " outputs_list += f'- {key}\\n'\n", - "glue_variable('outputs_list', Markdown(outputs_list), display=False)\n", + "glue_variable('outputs_list', outputs_list, display=False)\n", "\n", - "glue_variable(f'{Aircraft.Wing.MASS=}'.split('=')[0], md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Wing.MASS), md_code=True)\n", "oas = f'{use_OAS=}'.split('=')[0]\n", "glue_variable(oas, md_code=True)\n", "glue_variable(oas+'=False', md_code=True)\n", @@ -438,7 +438,7 @@ ], "metadata": { "kernelspec": { - "display_name": "base", + "display_name": "latest_env", "language": "python", "name": "python3" }, diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb index 0684ed7b2..2c026f3d0 100644 --- a/aviary/docs/examples/additional_flight_phases.ipynb +++ b/aviary/docs/examples/additional_flight_phases.ipynb @@ -11,7 +11,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import glue_variable\n", + "from aviary.utils.doctape import glue_variable\n", "from aviary.interface.cmd_entry_points import _command_map\n", "\n", "draw_mission = 'draw_mission'\n", @@ -236,7 +236,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import glue_keys\n", + "from aviary.utils.doctape import glue_keys\n", "glue_keys(phase_info, display=False)\n" ] }, diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb index d5ac63919..1546e6ae6 100644 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb @@ -137,7 +137,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import check_value, glue_variable\n", + "from aviary.utils.doctape import check_value, glue_variable\n", "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", "\n", "# checking that the phase info example is valid\n", @@ -197,7 +197,7 @@ "aircraft_filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", "optimizer = \"IPOPT\"\n", "make_plots = True\n", - "max_iter = 200\n", + "max_iter = 100\n", "\n", "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", " make_plots=make_plots, max_iter=max_iter)" @@ -234,7 +234,7 @@ "source": [ "# Testing Cell\n", "from aviary.interface.methods_for_level1 import run_aviary\n", - "from aviary.docs.tests.utils import glue_variable\n", + "from aviary.utils.doctape import glue_variable\n", "\n", "glue_variable(run_aviary.__name__,md_code=True)\n" ] diff --git a/aviary/docs/examples/images/multi_mission.png b/aviary/docs/examples/images/multi_mission.png new file mode 100644 index 000000000..ef605db51 Binary files /dev/null and b/aviary/docs/examples/images/multi_mission.png differ diff --git a/aviary/docs/examples/intro.ipynb b/aviary/docs/examples/intro.ipynb index c1dc74117..4c24a1ad7 100644 --- a/aviary/docs/examples/intro.ipynb +++ b/aviary/docs/examples/intro.ipynb @@ -14,7 +14,7 @@ "from aviary.utils.functions import get_path\n", "from pathlib import Path\n", "import pkg_resources\n", - "from aviary.docs.tests.utils import glue_variable\n", + "from aviary.utils.doctape import glue_variable\n", "\n", "aviary_base_path = Path(pkg_resources.resource_filename('aviary', '.')).parent\n", "path=get_path('examples/external_subsystems').relative_to(aviary_base_path)\n", diff --git a/aviary/docs/examples/level_2_detailed_takeoff_and_landing.ipynb b/aviary/docs/examples/level_2_detailed_takeoff_and_landing.ipynb index 029c83c57..1107acb8f 100644 --- a/aviary/docs/examples/level_2_detailed_takeoff_and_landing.ipynb +++ b/aviary/docs/examples/level_2_detailed_takeoff_and_landing.ipynb @@ -13,7 +13,7 @@ "# Testing Cell\n", "import aviary.api as av\n", "from aviary.interface.graphical_input import create_phase_info\n", - "from aviary.docs.tests.utils import check_value, glue_keys\n", + "from aviary.utils.doctape import check_value, glue_keys\n", "from aviary.examples.run_detailed_takeoff_in_level2 import phase_info as takeoff_phase_info\n", "from aviary.examples.run_detailed_landing_in_level2 import phase_info as landing_phase_info\n", "\n", diff --git a/aviary/docs/examples/modified_aircraft.csv b/aviary/docs/examples/modified_aircraft.csv new file mode 100644 index 000000000..445c8e328 --- /dev/null +++ b/aviary/docs/examples/modified_aircraft.csv @@ -0,0 +1,156 @@ +aircraft:air_conditioning:mass_scaler,1.0,unitless +aircraft:anti_icing:mass_scaler,1.0,unitless +aircraft:apu:mass_scaler,1.1,unitless +aircraft:avionics:mass_scaler,1.2,unitless +aircraft:canard:area,0.0,ft**2 +aircraft:canard:aspect_ratio,0.0,unitless +aircraft:canard:thickness_to_chord,0.0,unitless +aircraft:crew_and_payload:baggage_mass_per_passenger,45.0,lbm +aircraft:crew_and_payload:cargo_container_mass_scaler,1.0,unitless +aircraft:crew_and_payload:design:num_business_class,0,unitless +aircraft:crew_and_payload:design:num_first_class,11,unitless +aircraft:crew_and_payload:design:num_passengers,169,unitless +aircraft:crew_and_payload:design:num_tourist_class,158,unitless +aircraft:crew_and_payload:flight_crew_mass_scaler,1.0,unitless +aircraft:crew_and_payload:mass_per_passenger,180.0,lbm +aircraft:crew_and_payload:misc_cargo,0.0,lbm +aircraft:crew_and_payload:non_flight_crew_mass_scaler,1.0,unitless +aircraft:crew_and_payload:num_flight_attendants,3,unitless +aircraft:crew_and_payload:num_flight_crew,2,unitless +aircraft:crew_and_payload:num_galley_crew,0,unitless +aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless +aircraft:crew_and_payload:wing_cargo,0.0,lbm +aircraft:design:base_area,0.0,ft**2 +aircraft:design:empty_mass_margin_scaler,0.0,unitless +aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless +aircraft:design:touchdown_mass,152800.0,lbm +aircraft:design:reserve_fuel_additional,3000.,lbm +aircraft:design:subsonic_drag_coeff_factor,1.0,unitless +aircraft:design:supersonic_drag_coeff_factor,1.0,unitless +aircraft:design:use_alt_mass,False,unitless +aircraft:design:zero_lift_drag_coeff_factor,0.930890028006548,unitless +aircraft:electrical:mass_scaler,1.25,unitless +aircraft:engine:additional_mass_fraction,0.,unitless +aircraft:engine:constant_fuel_consumption,0.,lbm/h +aircraft:engine:data_file,models/engines/turbofan_28k.deck,unitless +aircraft:engine:flight_idle_thrust_fraction,0.0,unitless +aircraft:engine:flight_idle_max_fraction,1.0,unitless +aircraft:engine:flight_idle_min_fraction,0.08,unitless +aircraft:engine:fuel_flow_scaler_constant_term,0.,unitless +aircraft:engine:fuel_flow_scaler_linear_term,0.,unitless +aircraft:engine:generate_flight_idle,True,unitless +aircraft:engine:geopotential_alt,False,unitless +aircraft:engine:ignore_negative_thrust,False,unitless +aircraft:engine:interpolation_method,slinear,unitless +aircraft:engine:mass_scaler,1.15,unitless +aircraft:engine:mass,7400,lbm +aircraft:engine:num_engines,2,unitless +aircraft:engine:num_fuselage_engines,0,unitless +aircraft:engine:num_wing_engines,2,unitless +aircraft:engine:reference_mass,7400,lbm +aircraft:engine:reference_sls_thrust,28928.1,lbf +aircraft:engine:scale_mass,True,unitless +aircraft:engine:scale_performance,True,unitless +aircraft:engine:scaled_sls_thrust,28928.1,lbf +aircraft:engine:subsonic_fuel_flow_scaler,1.,unitless +aircraft:engine:supersonic_fuel_flow_scaler,1.,unitless +aircraft:engine:thrust_reversers_mass_scaler,0.0,unitless +aircraft:engine:wing_locations,[0.26869218],unitless +aircraft:fins:area,0.0,ft**2 +aircraft:fins:mass_scaler,1.0,unitless +aircraft:fins:mass,0.0,lbm +aircraft:fins:num_fins,0,unitless +aircraft:fins:taper_ratio,10.0,unitless +aircraft:fuel:auxiliary_fuel_capacity,0.0,lbm +aircraft:fuel:density_ratio,1.0,unitless +aircraft:fuel:fuel_system_mass_scaler,1.0,unitless +aircraft:fuel:fuselage_fuel_capacity,0.0,lbm +aircraft:fuel:num_tanks,7,unitless +aircraft:fuel:total_capacity,45694.0,lbm +aircraft:fuel:unusable_fuel_mass_scaler,1.0,unitless +aircraft:furnishings:mass_scaler,1.1,unitless +aircraft:fuselage:length,128.0,ft +aircraft:fuselage:mass_scaler,1.05,unitless +aircraft:fuselage:max_height,13.17,ft +aircraft:fuselage:max_width,12.33,ft +aircraft:fuselage:military_cargo_floor,False,unitless +aircraft:fuselage:num_fuselages,1,unitless +aircraft:fuselage:passenger_compartment_length,85.5,ft +aircraft:fuselage:planform_area,1578.24,ft**2 +aircraft:fuselage:wetted_area_scaler,1.0,unitless +aircraft:fuselage:wetted_area,4158.62,ft**2 +aircraft:horizontal_tail:area,355.0,ft**2 +aircraft:horizontal_tail:aspect_ratio,6.0,unitless +aircraft:horizontal_tail:mass_scaler,1.2,unitless +aircraft:horizontal_tail:taper_ratio,0.22,unitless +aircraft:horizontal_tail:thickness_to_chord,0.125,unitless +aircraft:horizontal_tail:vertical_tail_fraction,0.0,unitless +aircraft:horizontal_tail:wetted_area_scaler,1.0,unitless +aircraft:horizontal_tail:wetted_area,592.65,ft**2 +aircraft:hydraulics:mass_scaler,1.0,unitless +aircraft:hydraulics:system_pressure,3000,psi +aircraft:instruments:mass_scaler,1.25,unitless +aircraft:landing_gear:carrier_based,False,unitless +aircraft:landing_gear:main_gear_mass_scaler,1.1,unitless +aircraft:landing_gear:main_gear_oleo_length,102.0,inch +aircraft:landing_gear:nose_gear_mass_scaler,1.0,unitless +aircraft:landing_gear:nose_gear_oleo_length,67.0,inch +aircraft:nacelle:avg_diameter,7.94,ft +aircraft:nacelle:avg_length,12.3,ft +aircraft:nacelle:mass_scaler,1.0,unitless +aircraft:nacelle:wetted_area_scaler,1.0,unitless +aircraft:paint:mass_per_unit_area,0.037,lbm/ft**2 +aircraft:propulsion:engine_oil_mass_scaler,1.0,unitless +aircraft:propulsion:misc_mass_scaler,1.0,unitless +aircraft:vertical_tail:area,284.0,ft**2 +aircraft:vertical_tail:aspect_ratio,1.75,unitless +aircraft:vertical_tail:mass_scaler,1.0,unitless +aircraft:vertical_tail:num_tails,1,unitless +aircraft:vertical_tail:taper_ratio,0.33,unitless +aircraft:vertical_tail:thickness_to_chord,0.1195,unitless +aircraft:vertical_tail:wetted_area_scaler,1.0,unitless +aircraft:vertical_tail:wetted_area,581.13,ft**2 +aircraft:wing:aeroelastic_tailoring_factor,0.0,unitless +aircraft:wing:airfoil_technology,1.92669766647637,unitless +aircraft:wing:area,1370.0,ft**2 +aircraft:wing:aspect_ratio,11.02091,unitless +aircraft:wing:BENDING_MATERIAL_MASS_SCALER,1.0,unitless +aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless +aircraft:wing:composite_fraction,0.2,unitless +aircraft:wing:control_surface_area,137,ft**2 +aircraft:wing:control_surface_area_ratio,0.1,unitless +aircraft:wing:glove_and_bat,134.0,ft**2 +aircraft:wing:input_station_dist,0.,0.2759,0.9367,unitless +aircraft:wing:load_distribution_control,2.0,unitless +aircraft:wing:load_fraction,1.0,unitless +aircraft:wing:load_path_sweep_dist,0.,22.,deg +aircraft:wing:mass_scaler,1.23,unitless +aircraft:wing:max_camber_at_70_semispan,0.0,unitless +aircraft:wing:misc_mass_scaler,1.0,unitless +aircraft:wing:num_integration_stations,50,unitless +aircraft:wing:shear_control_mass_scaler,1.0,unitless +aircraft:wing:span_efficiency_reduction,False,unitless +aircraft:wing:span,117.83,ft +aircraft:wing:strut_bracing_factor,0.0,unitless +aircraft:wing:surface_ctrl_mass_scaler,1.0,unitless +aircraft:wing:sweep,25.0,deg +aircraft:wing:taper_ratio,0.278,unitless +aircraft:wing:thickness_to_chord_dist,0.145,0.115,0.104,unitless +aircraft:wing:thickness_to_chord,0.13,unitless +aircraft:wing:ultimate_load_factor,3.75,unitless +aircraft:wing:var_sweep_mass_penalty,0.0,unitless +aircraft:wing:wetted_area_scaler,1.0,unitless +aircraft:wing:wetted_area,2396.56,ft**2 +mission:constraints:max_mach,0.785,unitless +mission:design:cruise_altitude,35000,ft +mission:design:gross_mass,175400.0,lbm +mission:design:range,3500,NM +mission:design:thrust_takeoff_per_eng,28928.1,lbf +mission:landing:lift_coefficient_max,2.0,unitless +mission:summary:cruise_mach,0.785,unitless +mission:summary:fuel_flow_scaler,1.0,unitless +mission:takeoff:fuel_simple,577,lbm +mission:takeoff:lift_coefficient_max,3.0,unitless +mission:takeoff:lift_over_drag,17.354,unitless +settings:equations_of_motion,height_energy +settings:mass_method,FLOPS diff --git a/aviary/docs/examples/more_advanced_example.ipynb b/aviary/docs/examples/more_advanced_example.ipynb index 23e944d18..e1bb5f382 100644 --- a/aviary/docs/examples/more_advanced_example.ipynb +++ b/aviary/docs/examples/more_advanced_example.ipynb @@ -11,7 +11,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import glue_variable\n", + "from aviary.utils.doctape import glue_variable\n", "import aviary.api as av\n", "glue_variable('fuel_burned', av.Mission.Summary.FUEL_BURNED, True)" ] @@ -137,7 +137,7 @@ "# Testing Cell\n", "from aviary.interface.default_phase_info.height_energy import phase_info as HE_phase_info\n", "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", - "from aviary.docs.tests.utils import glue_keys\n", + "from aviary.utils.doctape import glue_keys\n", "\n", "check_phase_info(phase_info, HEIGHT_ENERGY);\n", "\n", @@ -245,7 +245,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import glue_variable\n", + "from aviary.utils.doctape import glue_variable\n", "new_filename = 'modified_aircraft.csv'\n", "glue_variable(new_filename, md_code=True)" ] diff --git a/aviary/docs/examples/multi_mission.ipynb b/aviary/docs/examples/multi_mission.ipynb new file mode 100644 index 000000000..6372aa40e --- /dev/null +++ b/aviary/docs/examples/multi_mission.ipynb @@ -0,0 +1,175 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_variable, get_variable_name\n", + "from aviary.api import Aircraft, Mission, AviaryProblem\n", + "from aviary.examples.multi_mission import run_multimission_example_large_single_aisle\n", + "\n", + "glue_variable('capi',AviaryProblem.check_and_preprocess_inputs.__name__,md_code=True)\n", + "\n", + "glue_variable(get_variable_name(Mission.Design.RANGE), md_code=True)\n", + "\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.NUM_PASSENGERS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.NUM_BUSINESS_CLASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.NUM_FIRST_CLASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.NUM_TOURIST_CLASS), md_code=True)\n", + "\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.Design.NUM_PASSENGERS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS), md_code=True)\n", + "\n", + "glue_variable(get_variable_name(Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO), md_code=True)\n", + "glue_variable(get_variable_name(Mission.Summary.CRUISE_MACH), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.LandingGear.MAIN_GEAR_MASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.LandingGear.NOSE_GEAR_MASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Wing.SWEEP), md_code=True)\n", + "glue_variable(get_variable_name(Mission.Design.GROSS_MASS), md_code=True)\n", + "glue_variable(get_variable_name(Mission.Summary.GROSS_MASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Design.EMPTY_MASS), md_code=True)\n", + "glue_variable(get_variable_name(Mission.Summary.FUEL_BURNED), md_code=True)\n", + "\n", + "glue_variable(get_variable_name(Aircraft.Furnishings.MASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.PASSENGER_SERVICE_MASS), md_code=True)\n", + "\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.CARGO_MASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.PASSENGER_MASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS), md_code=True)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multi-Mission Example\n", + "\n", + "The [Multi-mission Example](\n", + "https://github.com/OpenMDAO/Aviary/tree/main/aviary/examples/multi_mission/run_multimission_example_large_single_aisle.py) demonstrates the capability to optimize an aircraft design considering two missions that the aircraft will perform. For a background on this example see [Multi-Mission Overview](../user_guide/multi_mission).\n", + "\n", + "## Implementation\n", + "At a minimum, the user must supply the following inputs for a multi-mission:\n", + "* 2 aircraft configuration examples (i.e. .csv files)\n", + "* 2 `phase_info` describing the different aircraft missions\n", + "* a weighting of the relative importance of each mission\n", + "* {glue:md}Mission.Design.RANGE\n", + "* {glue:md}Aircraft.CrewPayload.Design.NUM_PASSENGERS\n", + "* {glue:md}Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO\n", + "\n", + "### Aircraft Configuration\n", + "In the example, we import a single aircraft configuration (LargeSingleAisle2FLOPS) and then modify it to create a primary mission which carries 162 passengers and a deadhead mission. The deadhead mission is a mission with a single passengers, but it still has the same number of seats in the aircraft, even though those seats are mostly empty. The number of seats for passenters in the aircraft, as well as some other systems like passenger airconditioning mass, is set by values of {glue:md}Aircraft.CrewPayload.Design.NUM_PASSENGERS, {glue:md}Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, {glue:md}Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, and {glue:md}Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS. Whereas the actual number of passengers on the flight is specified by variables of {glue:md}Aircraft.CrewPayload.NUM_PASSENGERS, {glue:md}Aircraft.CrewPayload.NUM_TOURIST_CLASS, {glue:md}Aircraft.CrewPayload.NUM_BUSINESS_CLASS, and {glue:md}Aircraft.CrewPayload.NUM_BUSINESS_CLASS.\n", + "\n", + "### Phase Info\n", + "The same mission distance and profile (takeoff, climb, cruise, descent, landing) is being flown for both missions. To enable this, a single phase_info is imported and then deepcopied. The user could modify the deadhead mission to be different from the primary mission by changing the target_range of the deadhead mission to a different value, for example by changing `phase_info_deadhead['post_mission']['target_range'] = [1500, \"nmi\"]` \n", + "\n", + "### Weighting\n", + "The `weights` input value describes the relative importance or frequence of one mission over the other. In the example, the the weigting is [9,1] indicating that for every nine times the aircraft flies a full passenger load, it flies a single deadhead leg. These weightings are based on user input and are converted into fractions. This weighting can be estimated from examining historical passenger loads on a typical aircraf route of interest. The objective function is based on combining the fuel-burn values from both missions and multiplying that by the weights. Other objectives, like max range, have not been tested yet.\n", + "\n", + "### Setting Values\n", + "The {glue:md}Mission.Design.RANGE value must be set to size some of Aviary's subsystems. These subsystems, such as avionics, have increasing mass as {glue:md}Mission.Design.RANGE increases. These are first order approximations that come with aviary. But because of these, we must ensure that both pre-missions have the same {glue:md}Mission.Design.RANGE, even if the actual range flown buy each mission (target_rage) is different. Without this, the avoinics mass calculated in pre-mission would be different for the two missions, resulting in a different aircraft design, which is counter to what is intended with the multi-mission feature. \n", + "\n", + "The total number of passengers ({glue:md}Aircraft.CrewPayload.Design.NUM_PASSENGERS) and the design number of passengers of each type (business, tourist, first class), help to define the passenger air conditioning subsystems and the passenger support mass (seats) respectively. Thus when these values are set equal in the primary and deadhead missions, we ensure the aircraft will be designed similarly. \n", + "\n", + "It is good practice, but not required, to set {glue:md}Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO in Aviary Values to ensure consistent design of the landing gear for both missions. This combined with Design.GROSS_MASS helps to ensure that {glue:md}Aircraft.LandingGear.MAIN_GEAR_MASS and {glue:md}Aircraft.LandingGear.NOSE_GEAR_MASS are the same for both missions. If {glue:md}Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO is not set, Landing Gear Masses will be caluclated based on {glue:md}Mission.Summary.CRUISE_MACH and {glue:md}Mission.Design.RANGE. This is potentially problematic because {glue:md}Mission.Summary.CRUISE_MACH may not be set, and instead cruse mach may be optimized. In that case, {glue:md}Mission.Summary.CRUISE_MACH could vary between the Primary and Deadhead missions, which would then cascade into differeing {glue:md}Aircraft.LandingGear.MAIN_GEAR_MASS which causes the aircraft designs to diverge.\n", + "\n", + "## Theory\n", + "Each of the two missions in the example are instantiated as separate aviary problems before copying those two groups over to a single `super_prob`. This means there are two pre-missions, two missions run in parallel. Two get the pre-missions to have the same aircraft design, {glue:md}Mission.Design.GROSS_MASS, {glue:md}Mission.Design.RANGE, {glue:md}Aircraft.Wing.SWEEP, are promoted out of the pre-missions to a single values. This ensures that the aircrafts in both pre-missions have the same design even though their passenger count and fuel mass are different. There is no post-mission for the example, but if one was required for calculating cost or acoustic constraints, there would need to be two post-mission systems as well.\n", + "\n", + "To impact the structure of aviary problems as little as possible, after instantiation of the pre-mission, mission, and post-mission systems, the connections between those systems are created. Then those groups are then copied over into a regular openmdao problem called `super_prob`. This enables the use all the basic aviary connection and checking functions with minimal modification. There originally was a desire to use openmdao subproblems for this implementation but derivatives through subproblems were not available at that time.\n", + "\n", + "Initialization of states and variables is conducted last through `prob.set_initial_guesses()`. This has to be completed after the aviary groups are added to `super_prob`. Setting initial guesses and then copying over a group into `super_prob` will not work in this case because initial guesses is set on the problem, not the group. \n", + "\n", + "Some custom graphing and print functions were added to this example because the basic aviary graphing programs have not yet been modified to handle two database file from two separate missions. The user can see detailed info of each mission result using the `super_prob.model.group_1.list_vars()` commands listed in the comments at the bottom of the example.\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. This was done to provide backward compatability for older aircraft models which only specify design passenger information. However, due to current limitations in Aviary's ability to detect user input vs. default values, the only way to set an aircraft to exactly zero passengers is by setting {glue:md}Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS to zero plus any {glue:md}Aircraft.CrewPayload.CARGO_MASS being carried. This zeros out passenger and baggage mass regardless of what value is input to {glue:md}Aircraft.CrewPayload.NUM_PASSENGERS, {glue:md}Aircraft.CrewPayload.NUM_TOURIST_CLASS, {glue:md}Aircraft.CrewPayload.NUM_BUSINESS_CLASS, and {glue:md}Aircraft.CrewPayload.NUM_FIRST_CLASS. Once issue #610 is resolved the user should be able to set passenger and bags mass to exactly zero by setting {glue:md}Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS to zero.\n", + "\n", + "## Best Pratices\n", + "The user should be cognizant of the implications of having two pre-mission systems, one for each mission. Both of the pre-mission systems should be nearly identical in setup, except for fuel-mass, passenger, and payload calculations. There are numerous opportunities for the user to get this wrong, and accidentally create two different aircraft as a result. For example, in a previous iteration of this example, {glue:md}Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO was not specified, which resulted in two different landing gears being designed, one for the Primary mission, one for the Deadhead mission.\n", + "\n", + "If you are having trouble getting your {glue:md}Aircraft.Design.EMPTY_MASS (the final drymass mass summation from pre-mission) to be equal for both pre-missions, use the following OpenMDAO commends at the end of the example to list out and compare the mass from each subsystem.\n", + "\n", + "```\n", + "super_prob.model.group_1.list_vars(val=True, units=True, print_arrays=False)\n", + "super_prob.model.group_2.list_vars(val=True, units=True, print_arrays=False)\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Results\n", + "The results of the [Multi-mission Example](\n", + "https://github.com/OpenMDAO/Aviary/tree/main/aviary/examples/multi_mission/run_multimission_example_large_single_aisle.py) are included in the data table and plots below.\n", + "\n", + "From the table results we can see that the Primary mission have the same {glue:md}Mission.Design.GROSS_MASS. However, the {glue:md}Mission.Summary.GROSS_MASS varies as expected because these represent \"as-flown\" values. The Primary mission has the higher {glue:md}Mission.Summary.GROSS_MASS which corresponds to the full passenger load and bags. Consequently, the {glue:md}Mission.Summary.FUEL_BURNED for each mission is different, higher for the Primary mission, as expected because this mission is carrying more mass for the same mission. {glue:md}Aircraft.Wing.SWEEP is the same for both missions, indicating that the aircraft has been designed similarly in both cases. We do not want to see different values for the wing design because it would mean that the two pre-mission systems are not mirroring eachother. If they were not the same it would mean we are designing two different aircraft. \n", + "\n", + "The {glue:md}Aircraft.LandingGear.MAIN_GEAR_MASS and {glue:md}Aircraft.LandingGear.NOSE_GEAR_MASS masses were also displayed because they are sensitive to {glue:md}Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO. We expect these landing gear masses to be the same and they are which is good news for us and indicates that both pre-mission designs are mirroring eachother.\n", + "\n", + "The {glue:md}Aircraft.Furnishings.MASS and {glue:md}Aircraft.CrewPayload.PASSENGER_SERVICE_MASS are displayed. These values represent the weight of the seats and the air conditioning system for the passengers. They are both the same which is what we expect to see.\n", + "\n", + "A summary colum called 'Expectations' is included as a summary of what we want to see when evaluating this data. \n", + "\n", + "| Variable | Primary | Deadhead | Expectations |\n", + "|:-------------------------------------------------|:-----------------------------:|:--------------------:|---:|\n", + "{glue:md}Mission.Design.GROSS_MASS | 157432.51366187233 (lbm) | 157432.51366187233 (lbm) | Equal |\n", + "{glue:md}Aircraft.Design.EMPTY_MASS | 87415.21921741116 (lbm) | 87415.21921741116 (lbm) | Equal |\n", + "{glue:md}Aircraft.Wing.SWEEP | 22.99999998488638 (deg) | 22.99999998488638 (deg) | Equal |\n", + "{glue:md}Aircraft.LandingGear.MAIN_GEAR_MASS | 5766.748146883955 (lbm) | 5766.748146883955 (lbm) | Equal |\n", + "{glue:md}Aircraft.LandingGear.NOSE_GEAR_MASS | 747.1260464958017 (lbm) | 747.1260464958017 (lbm) | Equal |\n", + "{glue:md}Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO | 0.84 (unitless) | 0.84 (unitless) | Equal |\n", + "{glue:md}Aircraft.Furnishings.MASS | 14690.33988 (lbm) | 14690.33988 (lbm) | Equal |\n", + "{glue:md}Aircraft.CrewPayload.PASSENGER_SERVICE_MASS | 2524.475592961527 (lbm) | 2524.475592961527 (lbm) | Equal |\n", + "{glue:md}Mission.Summary.GROSS_MASS | 157432.51316817472 (lbm) | 120023.28881408491 (lbm) | Different |\n", + "{glue:md}Mission.Summary.FUEL_BURNED | 27042.6844662215 (lbm) | 22883.460112131652 (lbm) | Different |\n", + "{glue:md}Aircraft.CrewPayload.PASSENGER_MASS | 26730.0 (lbm) | 165.0 (lbm) | Different |\n", + "{glue:md}Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS | 32400.0 (lbm) | 200.0 (lbm) | Different |\n", + "{glue:md}Aircraft.CrewPayload.CARGO_MASS | 4077.0 (lbm) | 4077.0 (lbm) | Different |\n", + "{glue:md}Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS | 36477.0 (lbm) | 4277.0 (lbm) | Different |\n", + "\n", + "\n", + "In the graph below The Altitude, Drag force, Throttle command, Mass, Distance, and Mach number of the Primary and Deadhead missions are displayed. The Deadhead mission shows a characteristic smaller mass throughout the flight as expected since we have fewer passengers, and a slightly lower throttle profile to match, indicating the engine is not being pushed as hard to meet the demands of a lighter plane. Otherwise the missions themselves match, showing Mach, Distance, and Altitude all identical for every part of the mission. We did not allow the mach or altitude to be optimized for this mission so these results are not surprising. \n", + "\n", + "![Results](images/multi_mission.png \"Primary vs. Deadhead mission results\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "latest_env", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/aviary/docs/examples/outputted_phase_info.py b/aviary/docs/examples/outputted_phase_info.py new file mode 100644 index 000000000..daf97400c --- /dev/null +++ b/aviary/docs/examples/outputted_phase_info.py @@ -0,0 +1,2 @@ +phase_info = {'pre_mission': {'include_takeoff': True, 'optimize_mass': True}, 'climb_1': {'subsystem_options': {'core_aerodynamics': {'method': 'computed'}}, 'user_options': {'optimize_mach': True, 'optimize_altitude': True, 'polynomial_control_order': [1, 2], 'use_polynomial_control': True, 'num_segments': [1], 'order': 1, 'solve_for_distance': True, 'initial_mach': (1, None), 'final_mach': (2, None), 'mach_bounds': ( + (0.98, 2.02), None), 'initial_altitude': (1, None), 'final_altitude': (2, None), 'altitude_bounds': ((0.0, 502), None), 'throttle_enforcement': 'path_constraint', 'fix_initial': True, 'constrain_final': True, 'fix_duration': False, 'initial_bounds': ((0.0, 0.0), None), 'duration_bounds': ((0.5, 1.5), None)}, 'initial_guesses': {'time': ([1, 1], None)}}, 'post_mission': {'include_landing': True, 'constrain_range': True, 'target_range': (514.5, None)}} diff --git a/aviary/docs/examples/reserve_missions.ipynb b/aviary/docs/examples/reserve_missions.ipynb index 4b34da01b..15b3b0e7c 100644 --- a/aviary/docs/examples/reserve_missions.ipynb +++ b/aviary/docs/examples/reserve_missions.ipynb @@ -12,7 +12,7 @@ "source": [ "# Testing Cell\n", "from aviary.utils.functions import get_path, get_model\n", - "from aviary.docs.tests.utils import glue_variable\n", + "from aviary.utils.doctape import glue_variable\n", "\n", "folder = get_path('examples/reserve_missions')\n", "aviary_top_dir = get_path('docs').parent.parent\n", @@ -90,8 +90,8 @@ "# Testing Cell\n", "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", "from aviary.utils.functions import get_path\n", - "from aviary.docs.tests.utils import glue_variable, check_value, get_all_keys\n", - "# from aviary.docs.tests.utils import check_contains, expected_error\n", + "from aviary.utils.doctape import glue_variable, check_value, get_all_keys\n", + "# from aviary.utils.doctape import check_contains, expected_error\n", "\n", "folder = get_path('examples/reserve_missions')\n", "\n", @@ -115,7 +115,7 @@ " glue_variable(key.replace('.','-'), md_code=True)\n", "print(all_keys)\n", "\n", - "# ****NOTE**** These were not removed, as the docs seem to indicate\n", + "# ******NOTE****** These were not removed, as the docs seem to indicate\n", "# time = 'initial_guesses:time'\n", "# duration_bounds = 'user_options:duration_bounds'\n", "# fixed_duration = 'user_options:fixed_duration'\n", diff --git a/aviary/docs/examples/simple_mission_example.ipynb b/aviary/docs/examples/simple_mission_example.ipynb index 0e7b15798..e712dd1ed 100644 --- a/aviary/docs/examples/simple_mission_example.ipynb +++ b/aviary/docs/examples/simple_mission_example.ipynb @@ -79,7 +79,7 @@ "source": [ "# Testing Cell\n", "import aviary.api as av\n", - "from aviary.docs.tests.utils import check_value, glue_variable\n", + "from aviary.utils.doctape import check_value, glue_variable\n", "from aviary.interface.cmd_entry_points import _command_map\n", "\n", "check_value(av.LegacyCode.FLOPS.value, 'FLOPS')\n", @@ -278,7 +278,7 @@ "source": [ "# Testing Cell\n", "from aviary.interface.cmd_entry_points import _command_map\n", - "from aviary.docs.tests.utils import glue_variable\n", + "from aviary.utils.doctape import glue_variable\n", "\n", "run_mission = 'run_mission'\n", "_command_map[run_mission];\n", diff --git a/aviary/docs/getting_started/input_csv_phase_info.ipynb b/aviary/docs/getting_started/input_csv_phase_info.ipynb index f46dfcde5..1195b3b9f 100644 --- a/aviary/docs/getting_started/input_csv_phase_info.ipynb +++ b/aviary/docs/getting_started/input_csv_phase_info.ipynb @@ -1,5 +1,34 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.functions import get_model\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "csv_snippet = '```\\n'\n", + "filename = 'aircraft_for_bench_FwFm.csv'\n", + "with open(get_model(filename)) as f_in:\n", + " lines = f_in.readlines()\n", + " l, s = [], 1\n", + " for ii in range(7):\n", + " l.append(lines[ii*2*s])\n", + " s*=-1\n", + " l.sort()\n", + " csv_snippet+=''.join(l)\n", + "\n", + "csv_snippet+='...\\n```'\n", + "glue_variable('csv_snippet', csv_snippet)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -18,15 +47,8 @@ "The vehicle .csv file is structured as multiple rows, each containing a specific vehicle parameter's name, value, and units.\n", "A portion of an example vehicle .csv file is shown below:\n", "\n", - "```\n", - "aircraft:avionics:mass_scaler,1.2,unitless\n", - "aircraft:crew_and_payload:baggage_mass_per_passenger,45.0,lbm\n", - "aircraft:crew_and_payload:mass_per_passenger,180.0,lbm\n", - "aircraft:wing:span,117.83,ft\n", - "aircraft:wing:strut_bracing_factor,0.0,unitless\n", - "aircraft:wing:surface_ctrl_mass_scaler,1.0,unitless\n", - "aircraft:wing:sweep,25.0,deg\n", - "...\n", + "```{glue:md} csv_snippet\n", + ":format: myst\n", "```\n", "\n", "Depending on which analysis options you use with Aviary, you might need to define certain parameters within the vehicle .csv file.\n", @@ -38,38 +60,62 @@ "execution_count": null, "metadata": { "tags": [ - "remove-input" + "remove-cell" ] }, "outputs": [], "source": [ + "# Testing Cell\n", "from aviary.utils.process_input_decks import create_vehicle\n", "from aviary.utils.aviary_values import AviaryValues\n", + "from aviary.utils.process_input_decks import initialization_guessing\n", + "from aviary.api import Aircraft, LegacyCode\n", + "from aviary.interface.cmd_entry_points import _command_map\n", + "from aviary.utils.doctape import glue_variable, get_variable_name\n", + "\n", + "default_guesses = '```\\n'\n", "vehicle_deck = AviaryValues()\n", "_ , initialization_guesses = create_vehicle(vehicle_deck=vehicle_deck)\n", "for key, val in initialization_guesses.items():\n", - " print(f\"{key}: {val}\")" + " default_guesses+=f\"{key},{val}\\n\"\n", + " glue_variable(key, md_code=True)\n", + "default_guesses+='```'\n", + "glue_variable('default_guesses', default_guesses)\n", + "\n", + "\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", + "\n", + "f2a = 'fortran_to_aviary'\n", + "_command_map[f2a];\n", + "glue_variable(f2a)\n", + "glue_variable(LegacyCode.GASP.name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In the example vehicle input .csv files there is a section headed '# Initial Guesses' which contains the above list in the format: \"actual_takeoff_mass,0\"\n", + "In vehicle .csv files that were created with the {glue:md}`fortran_to_aviary` converter that were created from {glue:md}`GASP` files, there is a section with the heading '# Initialization Guesses' that is used to initialize the trajectory. It contains the following keys along with default initialization values:\n", + "\n", + "```{glue:md} default_guesses\n", + ":format: myst\n", + "```\n", + "\n", "The user can also specify these parameters with the prefix 'initialization_guesses:'\n", "e.g. 'initialization_guesses:actual_takeoff_mass,150000' would set actual_takeoff_mass in the initialization_guesses dictionary to 150000.\n", "\n", - "If mission_method is TWO_DEGREES_OF_FREEDOM or mass_method is GASP then the initialization_guessing() method is called and wherever the initialization_guesses values are equal to 0, they are updated with calculated estimates based off the problem type (sizing, alternate, fallout) and mass, speed, range, thrust, and payload data specified in the vehicle input .csv file.\n", + "When the initialization_guessing() method is called and wherever the initialization_guesses values are equal to 0, they are updated with calculated estimates based off the problem type (sizing, alternate, fallout) and mass, speed, range, thrust, and payload data specified in the vehicle input .csv file.\n", "\n", - "The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than or equal to 0. There are two Aviary variables to control the reserve fuel in the model file (`.csv`):\n", - "- `Aircraft.Design.RESERVE_FUEL_ADDITIONAL`: the required fuel reserves: directly in lbm,\n", - "- `Aircraft.Design.RESERVE_FUEL_FRACTION`: the required fuel reserves: given as a proportion of mission fuel.\n", + "The initial guess of {glue:md}`reserves` is used to define the reserve fuel. Initially, its value can be anything larger than or equal to 0. There are two Aviary variables to control the reserve fuel in the model file (`.csv`):\n", + "- {glue:md}`Aircraft.Design.RESERVE_FUEL_ADDITIONAL`: the required fuel reserves: directly in lbm,\n", + "- {glue:md}`Aircraft.Design.RESERVE_FUEL_FRACTION`: the required fuel reserves: given as a proportion of mission fuel.\n", "\n", - "If the value of initial guess of `reserves` (also in the model file if any) is 0, the initial guess of reserve fuel comes from the above two Aviary variables. Otherwise, it is determined by the parameter `reserves`:\n", + "If the value of initial guess of {glue:md}`reserves` (also in the model file if any) is 0, the initial guess of reserve fuel comes from the above two Aviary variables. Otherwise, it is determined by the parameter {glue:md}`reserves`:\n", "- if `reserves > 10`, we assume it is the actual fuel reserves.\n", "- if `0.0 <= reserves <= 10`, we assume it is the fraction of the mission fuel.\n", "\n", - "The initial guess of `reserves` is always converted to the actual design reserves (instead of reserve factor) and is used to update the initial guesses of `fuel_burn_per_passenger_mile` and `cruise_mass_final`." + "The initial guess of {glue:md}`reserves` is always converted to the actual design reserves (instead of reserve factor) and is used to update the initial guesses of {glue:md}`fuel_burn_per_passenger_mile` and {glue:md}`cruise_mass_final`." ] }, { @@ -83,10 +129,47 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.utils.process_input_decks import initialization_guessing\n", - "from aviary.api import Aircraft\n", - "Aircraft.Design.RESERVE_FUEL_ADDITIONAL;\n", - "Aircraft.Design.RESERVE_FUEL_FRACTION;" + "from aviary.interface.default_phase_info.height_energy import phase_info as HE_phase_info\n", + "from aviary.interface.default_phase_info.two_dof import phase_info as TwoDOF_phase_info\n", + "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY, TWO_DEGREES_OF_FREEDOM\n", + "from aviary.utils.doctape import glue_keys\n", + "from aviary.interface.methods_for_level2 import AviaryProblem\n", + "from copy import deepcopy\n", + "import openmdao.api as om\n", + "\n", + "check_phase_info(HE_phase_info, HEIGHT_ENERGY);\n", + "check_phase_info(TwoDOF_phase_info, TWO_DEGREES_OF_FREEDOM);\n", + "\n", + "def get_completed_phase_info(filename, phase_info=None):\n", + " prob = AviaryProblem()\n", + " prob.load_inputs(filename, phase_info=phase_info)\n", + " prob.check_and_preprocess_inputs()\n", + " prob.add_phases()\n", + " complete_phase_info = {}\n", + " for phase in prob.phase_objects:\n", + " phase_name, info = phase.to_phase_info()\n", + " complete_phase_info[phase_name] = info\n", + " return complete_phase_info\n", + "\n", + "solved_alpha = deepcopy(HE_phase_info['cruise'])\n", + "solved_alpha['subsystem_options']['core_aerodynamics']['method'] = 'solved_alpha'\n", + "solved_alpha['subsystem_options']['core_aerodynamics']['aero_data'] = \\\n", + " \"subsystems/aerodynamics/gasp_based/data/large_single_aisle_1_aero_free.txt\"\n", + "\n", + "pre_mission = deepcopy(HE_phase_info['pre_mission'])\n", + "pre_mission['linear_solver'] = om.DirectSolver()\n", + "pre_mission['nonlinear_solver'] = om.NewtonSolver()\n", + "\n", + "custom_phase_info = {'pre_mission':pre_mission, 'solved_alpha':solved_alpha}\n", + "\n", + "dummy_phase_info = {}\n", + "dummy_phase_info.update(HE_phase_info)\n", + "dummy_phase_info.update(get_completed_phase_info('aircraft_for_bench_FwFm.csv'))\n", + "dummy_phase_info.update(custom_phase_info)\n", + "dummy_phase_info.update(get_completed_phase_info('aircraft_for_bench_FwFm.csv', custom_phase_info))\n", + "dummy_phase_info.update(TwoDOF_phase_info)\n", + "dummy_phase_info.update(get_completed_phase_info('aircraft_for_bench_GwGm.csv'))\n", + "glue_keys(dummy_phase_info)\n" ] }, { @@ -100,61 +183,54 @@ "We will now discuss the meaning of the keys within the `phase_info` objects.\n", "\n", "- If a key starts with `min_` or `max_` or ends with `_lower` or `_upper`, it is a lower or upper bound of a state variable. The following keys are not state variables:\n", - " - `required_available_climb_rate`: the minimum rate of climb required from the aircraft at the top of climb (beginning of cruise) point in the mission. You don't want your available rate-of-climb to be 0 in case you need to gain altitude during cruise.\n", - " - `EAS_limit`: the maximum descending EAS in knots.\n", - " - `throttle_setting`: the prescribed throttle setting. This is only used for `GASP` and `solved` missions.\n", - "- If a key ends with `_ref` or `_ref0` (except `duration_ref`, `duration_ref0`, `initial_ref` and `initial_ref0`), it is the unit-reference and zero-reference values of the control variable at the nodes. This option is invalid if opt=False. Note that it is a simple usage of ref and ref0. We refer to [Dymos](https://openmdao.github.io/dymos/api/phase_api.html?highlight=ref0#add-state) for details.\n", + " - {glue:md}`required_available_climb_rate`: the minimum rate of climb required from the aircraft at the top of climb (beginning of cruise) point in the mission. You don't want your available rate-of-climb to be 0 in case you need to gain altitude during cruise.\n", + " - {glue:md}`EAS_limit`: the maximum descending EAS in knots.\n", + " - {glue:md}`throttle`: the prescribed throttle setting. This is only used for `GASP` and `solved` missions.\n", + "- If a key ends with `_ref` or `_ref0` (except {glue:md}`duration_ref` and {glue:md}`initial_ref`), it is the unit-reference and zero-reference values of the control variable at the nodes. This option is invalid if opt=False. Note that it is a simple usage of ref and ref0. We refer to [Dymos](https://openmdao.github.io/dymos/api/phase_api.html?highlight=ref0#add-state) for details.\n", "- Some keys are for phase time only.\n", - " - `duration_ref` and `duration_ref0` are unit-reference and zero reference for phase time duration.\n", - " - `duration_bounds` are the bounds (lower, upper) for the time duration of the phase.\n", - " - `initial_ref` and `initial_ref0` are the unit-reference and zero references for the initial value of time.\n", - " - `time_initial_ref` and `time_initial_ref0` are the unit-reference and zero-reference for the initial value of time.\n", - " - `initial_bounds`: the lower and upper bounds of initial time. For `GASP`, it is `time_initial_bounds`.\n", + " - {glue:md}`duration_ref` is the unit-reference for phase time duration.\n", + " - {glue:md}`duration_bounds` are the bounds (lower, upper) for the time duration of the phase.\n", + " - {glue:md}`initial_ref` is the unit-reference for the initial value of time.\n", + " - {glue:md}`initial_bounds`: the lower and upper bounds of initial time.\n", "- If a key starts with `final_`, it is the final value of a state variable.\n", "- If a key ends with `_constraint_eq`, it is an equality constraint.\n", "\n", "- Keys related to altitude:\n", - " - We use `final_altitude` to indicate the final altitude of the phase.\n", - " - Meanwhile, `alt` is a key in acceleration phase parameter for altitude in `GASP` missions and `altitude` is a key in all other phases of all missions.\n", + " - We use {glue:md}`final_altitude` to indicate the final altitude of the phase.\n", + " - Meanwhile, {glue:md}`alt` is a key in acceleration phase parameter for altitude in `GASP` missions and {glue:md}`altitude` is a key in all other phases of all missions.\n", "\n", "- Some keys are a boolean flag of True or False:\n", - " - `input_initial`: the flag to indicate whether initial values of of a state (such as: altitude, velocity, mass, etc.) is taken.\n", - " - `add_initial_mass_constraint`: the flag to indicate whether to add initial mass constraint\n", - " - `clean`: the flag to indicate no flaps or gear are included.\n", - " - `connect_initial_mass`: the flag to indicate whether the initial mass is the same as the final mass of previous phase.\n", - " - `fix_initial`: the flag to indicate whether the initial state variables is fixed.\n", - " - `fix_initial_time`: the flag to indicate whether the initial time is fixed.\n", - " - `no_climb`: if True for the descent phase, the aircraft is not allowed to climb during the descent phase.\n", - " - `no_descent`: if True for the climb phase, the aircraft is not allowed to descend during the climb phase.\n", - " - `include_landing`: the flag to indicate whether there is a landing phase.\n", - " - `include_takeoff`: the flag to indicate whether there is a takeoff phase.\n", - " - `optimize_mass`: if True, the gross takeoff mass of the aircraft is a design variable.\n", - " - `target_mach`: the flag to indicate whether to target mach number.\n", - "- `initial_guesses`: initial guesses of state variables.\n", + " - {glue:md}`input_initial`: the flag to indicate whether initial values of of a state (such as: altitude, velocity, mass, etc.) is taken.\n", + " - {glue:md}`add_initial_mass_constraint`: the flag to indicate whether to add initial mass constraint\n", + " - {glue:md}`clean`: the flag to indicate no flaps or gear are included.\n", + " - {glue:md}`connect_initial_mass`: the flag to indicate whether the initial mass is the same as the final mass of previous phase.\n", + " - {glue:md}`fix_initial`: the flag to indicate whether the initial state variables is fixed.\n", + " - {glue:md}`no_climb`: if True for the descent phase, the aircraft is not allowed to climb during the descent phase.\n", + " - {glue:md}`no_descent`: if True for the climb phase, the aircraft is not allowed to descend during the climb phase.\n", + " - {glue:md}`include_landing`: the flag to indicate whether there is a landing phase.\n", + " - {glue:md}`include_takeoff`: the flag to indicate whether there is a takeoff phase.\n", + " - {glue:md}`optimize_mass`: if True, the gross takeoff mass of the aircraft is a design variable.\n", + " - {glue:md}`target_mach`: the flag to indicate whether to target mach number.\n", + "- {glue:md}`initial_guesses`: initial guesses of state variables.\n", "- `COLLOCATION` related keys:\n", - " - `num_segments`: the number of segments in transcription creation in Dymos. The minimum value is 1. This is needed if 'AnalysisScheme' is `COLLOCATION`.\n", - " - `order`: the order of polynomials for interpolation in transcription creation in Dymos. The minimum value is 3. This is needed if 'AnalysisScheme' is `COLLOCATION`.\n", + " - {glue:md}`num_segments`: the number of segments in transcription creation in Dymos. The minimum value is 1. This is needed if 'AnalysisScheme' is `COLLOCATION`.\n", + " - {glue:md}`order`: the order of polynomials for interpolation in transcription creation in Dymos. The minimum value is 3. This is needed if 'AnalysisScheme' is `COLLOCATION`.\n", "- Other Aviary keys:\n", - " - `subsystem_options`: The `aerodynamics` key allows two methods: `computed` and `solved_alpha`. In case of `solved_alpha`, it requires an additional key `aero_data_file`.\n", - " - `external_subsystems`: a list of external subsystems.\n", + " - {glue:md}`subsystem_options`: The {glue:md}`core_aerodynamics` key allows two methods: `computed` and `solved_alpha`. In case of `solved_alpha`, it requires an additional key {glue:md}`aero_data`.\n", + " - {glue:md}`external_subsystems`: a list of external subsystems.\n", "- other keys that are self-explanatory:\n", - " - `clean`: a flag for low speed aero (which includes high-lift devices) or cruise aero (clean, because it does not include high-lift devices).\n", - " - `EAS_target`: the target equivalent airspeed.\n", - " - `initial_mach`: initial Mach number.\n", - " - `linear_solver`: provide an instance of a [LinearSolver](https://openmdao.org/newdocs/versions/latest/features/core_features/controlling_solver_behavior/set_solvers.html) to the phase.\n", - " - `mach_cruise`: the cruise mach number.\n", - " - `mass_f_cruise`: final cruise mass (kg). It is used as `ref` and `defect_ref` in cruise phase.\n", - " - `nonlinear_solver`: provide an instance of a [NonlinearSolver](https://openmdao.org/newdocs/versions/latest/features/core_features/controlling_solver_behavior/set_solvers.html) to the phase.\n", - " - `ode_class`: default to `MissionODE`.\n", - " - `range_f_cruise`: final cruise range (m). It is used as `ref` and `defect_ref` in cruise phase.\n", - " - `solve_segments`: False, 'forward', 'backward'. This is a Radau option.\n", - " - `polynomial_control_order`: default to `None`.\n", - " - `use_actual_takeoff_mass`: default to `False`.\n", - " - `fix_duration`: default to `False`.\n", - " - `solve_for_distance`: if True, use a nonlinear solver to converge the `distance` state variable to the desired value. Otherwise use the optimizer to converge the `distance` state.\n", - " - `optimize_mach`: if True, the Mach number is a design variable.\n", - " - `optimize_altitude`: if True, the altitude is a design variable.\n", - " - `constraints`: a dictionary of user-defined constraints. The keys are the names of the constraints and the values are the keyword arguments expected by Dymos.\n", + " - {glue:md}`clean`: a flag for low speed aero (which includes high-lift devices) or cruise aero (clean, because it does not include high-lift devices).\n", + " - {glue:md}`EAS_target`: the target equivalent airspeed.\n", + " - {glue:md}`initial_mach`: initial Mach number.\n", + " - {glue:md}`linear_solver`: provide an instance of a [LinearSolver](https://openmdao.org/newdocs/versions/latest/features/core_features/controlling_solver_behavior/set_solvers.html) to the phase. \n", + " - {glue:md}`mach_cruise`: the cruise mach number.\n", + " - {glue:md}`nonlinear_solver`: provide an instance of a [NonlinearSolver](https://openmdao.org/newdocs/versions/latest/features/core_features/controlling_solver_behavior/set_solvers.html) to the phase. \n", + " - {glue:md}`polynomial_control_order`: default to `None`.\n", + " - {glue:md}`fix_duration`: default to `False`.\n", + " - {glue:md}`solve_for_distance`: if True, use a nonlinear solver to converge the `distance` state variable to the desired value. Otherwise use the optimizer to converge the `distance` state.\n", + " - {glue:md}`optimize_mach`: if True, the Mach number is a design variable.\n", + " - {glue:md}`optimize_altitude`: if True, the altitude is a design variable.\n", + " - {glue:md}`constraints`: a dictionary of user-defined constraints. The keys are the names of the constraints and the values are the keyword arguments expected by Dymos.\n", "\n", "```{note}\n", "Not all the keys apply to all phases. The users should select the right keys for each phase of interest. The required keys for each phase are defined in [check_phase_info](https://github.com/OpenMDAO/Aviary/blob/main/aviary/interface/utils.py) function. Currently, this function does the check only for `FLOPS` and `GASP` missions.\n", diff --git a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb index 9d9a491fc..72c54d7a2 100644 --- a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb +++ b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb @@ -217,7 +217,7 @@ "\n", "The steps in bold are related specifically to subsystems. So, almost all of the steps involve subsystems. As long as your external subsystem is built based on the guidelines, Aviary will take care of your subsystem.\n", "\n", - "The next example is the [battery subsystem](https://github.com/OpenMDAO/Aviary/blob/main/aviary/docs/user_guide/battery_subsystem_example). The battery subsystem provides methods to define the battery subsystem's states, design variables, fixed values, initial guesses, and mass names. It also provides methods to build OpenMDAO systems for the pre-mission and mission computations of the subsystem, to get the constraints for the subsystem, and to preprocess the inputs for the subsystem. This subsystem has its own set of variables. We will build an Aviary model with full phases (namely, `climb`, `cruise` and `descent`) and maximize the final total mass: `Dynamic.Mission.MASS`." + "The next example is the [battery subsystem](https://github.com/OpenMDAO/Aviary/blob/main/aviary/docs/user_guide/battery_subsystem_example). The battery subsystem provides methods to define the battery subsystem's states, design variables, fixed values, initial guesses, and mass names. It also provides methods to build OpenMDAO systems for the pre-mission and mission computations of the subsystem, to get the constraints for the subsystem, and to preprocess the inputs for the subsystem. This subsystem has its own set of variables. We will build an Aviary model with full phases (namely, `climb`, `cruise` and `descent`) and maximize the final total mass: `Dynamic.Vehicle.MASS`." ] }, { @@ -233,7 +233,7 @@ "source": [ "# Testing Cell\n", "from aviary.api import Dynamic\n", - "Dynamic.Mission.MASS;" + "Dynamic.Vehicle.MASS;" ] }, { @@ -399,7 +399,7 @@ "id": "ed8c764a", "metadata": {}, "source": [ - "Since our objective is `mass`, we want to print the value of `Dynamic.Mission.Mass`. Remember, we have imported Dynamic from aviary.variable_info.variables for this purpose.\n", + "Since our objective is `mass`, we want to print the value of `Dynamic.Vehicle.MASS`. Remember, we have imported Dynamic from aviary.variable_info.variables for this purpose.\n", "\n", "So, we have to print the final mass in a different way. Keep in mind that we have three phases in the mission and that final mass is our objective. So, we can get the final mass of the descent phase instead. Let us try this approach. Let us comment out the print statement of final mass (and the import of Dynamic), then add the following lines:" ] diff --git a/aviary/docs/getting_started/onboarding_level1.ipynb b/aviary/docs/getting_started/onboarding_level1.ipynb index c6afb1456..bbae17fe3 100644 --- a/aviary/docs/getting_started/onboarding_level1.ipynb +++ b/aviary/docs/getting_started/onboarding_level1.ipynb @@ -474,7 +474,7 @@ "\n", "In ground roll phase, throttle setting is set to maximum (1.0). Aviary sets a phase parameter:\n", "```\n", - "Dynamic.Mission.THROTTLE = 1.0\n", + "Dynamic.Vehicle.Propulsion.THROTTLE = 1.0\n", "```\n", "For the [`COLLOCATION`](https://openmdao.github.io/dymos/getting_started/collocation.html) setting, there is one [segment](https://openmdao.github.io/dymos/getting_started/intro_to_dymos/intro_segments.html) (`'num_segments': 1`) and polynomial interpolation degree is 3 (`'order': 3`). Increasing the number of segments and/or increasing the degree of polynomial will improve accuracy but will also increase the complexity of computation. For groundroll, it is unnecessary.\n", "\n", diff --git a/aviary/docs/getting_started/onboarding_level2.ipynb b/aviary/docs/getting_started/onboarding_level2.ipynb index 49c82a5ca..8998c978e 100644 --- a/aviary/docs/getting_started/onboarding_level2.ipynb +++ b/aviary/docs/getting_started/onboarding_level2.ipynb @@ -47,7 +47,7 @@ "from aviary.api import Mission\n", "from aviary.variable_info.enums import ProblemType as PT, EquationsOfMotion as EOM\n", "from aviary.interface.methods_for_level2 import AviaryProblem\n", - "from aviary.docs.tests.utils import check_contains\n", + "from aviary.utils.doctape import check_contains\n", "\n", "EOM.HEIGHT_ENERGY;\n", "mo = Mission.Objectives\n", @@ -558,7 +558,7 @@ "import aviary.api as av\n", "from aviary.validation_cases.validation_tests import get_flops_inputs\n", "from aviary.models.large_single_aisle_1.V3_bug_fixed_IO import V3_bug_fixed_options\n", - "from aviary.docs.tests.utils import check_contains\n", + "from aviary.utils.doctape import check_contains\n", "\n", "av.EquationsOfMotion.HEIGHT_ENERGY; #check that HEIGHT_ENERGY exists\n", "\n", @@ -629,12 +629,12 @@ "\n", "| objective_type | objective |\n", "| -------------- | --------- |\n", - "| mass | `Dynamic.Mission.MASS` |\n", + "| mass | `Dynamic.Vehicle.MASS` |\n", "| hybrid_objective | `-final_mass / {takeoff_mass} + final_time / 5.` |\n", "| fuel_burned | `initial_mass - mass_final` (for `FLOPS` mission only)|\n", "| fuel | `Mission.Objectives.FUEL` |\n", "\n", - "As listed in the above, if `objective_type=\"mass\"`, the objective is the final value of `Dynamic.Mission.MASS` at the end of the mission.\n", + "As listed in the above, if `objective_type=\"mass\"`, the objective is the final value of `Dynamic.Vehicle.MASS` at the end of the mission.\n", "If `objective_type=\"fuel\"`, the objective is the `Mission.Objectives.FUEL`.\n", "There is a special objective type: `hybrid_objective`. When `objective_type=\"hybrid_objective\"`, the objective is a mix of minimizing fuel burn and minimizing the mission duration:" ] @@ -656,10 +656,10 @@ "from aviary.variable_info.enums import EquationsOfMotion as EOM, AnalysisScheme as AS\n", "from aviary.interface.methods_for_level2 import AviaryProblem\n", "from aviary.utils.aviary_values import AviaryValues\n", - "from aviary.docs.tests.utils import check_contains\n", + "from aviary.utils.doctape import check_contains\n", "\n", "mo = Mission.Objectives\n", - "dm = Dynamic.Mission\n", + "dm = Dynamic.Vehicle\n", "expected_objective = {'mass':dm.MASS, 'hybrid_objective':'obj_comp.obj',\n", " 'fuel_burned':Mission.Summary.FUEL_BURNED, 'fuel':mo.FUEL}\n", "\n", @@ -993,7 +993,7 @@ "As you see, level 2 is more flexible than level 1. In level 2, you can:\n", "- add/remove pre-defined mission phases (via `phase_info`, see example above);\n", "- scale design variables (via reference value in `phase_info`)\n", - "- import additional files (e.g. `aero_data_file`);\n", + "- import additional files (e.g. `aero_data`);\n", "- set pre-defined objective (e.g. `hybrid_objective`);\n", "- add external subsystems (via `phase_info`);\n", "- set `use_coloring` (see example above).\n", @@ -1006,7 +1006,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "latest_env", "language": "python", "name": "python3" }, @@ -1020,7 +1020,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index f235936b5..f710cf9c2 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -95,6 +95,7 @@ "\n", "import aviary.api as av\n", "from aviary.validation_cases.validation_tests import get_flops_inputs\n", + "from aviary.variable_info.functions import setup_model_options\n", "\n", "\n", "prob = om.Problem(model=om.Group())\n", @@ -334,7 +335,7 @@ "# link phases #\n", "###############\n", "\n", - "traj.link_phases([\"climb\", \"cruise\", \"descent\"], [\"time\", av.Dynamic.Mission.MASS, av.Dynamic.Mission.DISTANCE], connected=strong_couple)\n", + "traj.link_phases([\"climb\", \"cruise\", \"descent\"], [\"time\", av.Dynamic.Vehicle.MASS, av.Dynamic.Mission.DISTANCE], connected=strong_couple)\n", "\n", "param_vars = [av.Aircraft.Nacelle.CHARACTERISTIC_LENGTH,\n", " av.Aircraft.Nacelle.FINENESS,\n", @@ -459,6 +460,8 @@ "]\n", "av.set_aviary_input_defaults(prob.model, varnames, aviary_inputs)\n", "\n", + "av.setup_model_options(prob, aviary_inputs)\n", + "\n", "prob.setup(force_alloc_complex=True)\n", "\n", "av.set_aviary_initial_values(prob, aviary_inputs)\n", @@ -474,9 +477,9 @@ " av.Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m')\n", "prob.set_val(\n", " 'traj.climb.controls:mach', climb.interp(\n", - " av.Dynamic.Mission.MACH, ys=[mach_i_climb, mach_f_climb]), units='unitless')\n", + " av.Dynamic.Atmosphere.MACH, ys=[mach_i_climb, mach_f_climb]), units='unitless')\n", "prob.set_val('traj.climb.states:mass', climb.interp(\n", - " av.Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", + " av.Dynamic.Vehicle.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", "prob.set_val('traj.climb.states:distance', climb.interp(\n", " av.Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m')\n", "\n", @@ -487,9 +490,9 @@ " av.Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m')\n", "prob.set_val(\n", " 'traj.cruise.controls:mach', cruise.interp(\n", - " av.Dynamic.Mission.MACH, ys=[cruise_mach, cruise_mach]), units='unitless')\n", + " av.Dynamic.Atmosphere.MACH, ys=[cruise_mach, cruise_mach]), units='unitless')\n", "prob.set_val('traj.cruise.states:mass', cruise.interp(\n", - " av.Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", + " av.Dynamic.Vehicle.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", "prob.set_val('traj.cruise.states:distance', cruise.interp(\n", " av.Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m')\n", "\n", @@ -500,9 +503,9 @@ " av.Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m')\n", "prob.set_val(\n", " 'traj.descent.controls:mach', descent.interp(\n", - " av.Dynamic.Mission.MACH, ys=[mach_i_descent, mach_f_descent]), units='unitless')\n", + " av.Dynamic.Atmosphere.MACH, ys=[mach_i_descent, mach_f_descent]), units='unitless')\n", "prob.set_val('traj.descent.states:mass', descent.interp(\n", - " av.Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", + " av.Dynamic.Vehicle.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", "prob.set_val('traj.descent.states:distance', descent.interp(\n", " av.Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m')\n", "\n", @@ -709,7 +712,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.12.3" } }, "nbformat": 4, 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 e346a650b..80456bf57 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 @@ -45,6 +45,7 @@ "import aviary.api as av\n", "\n", "from aviary.models.N3CC.N3CC_data import inputs\n", + "from aviary.utils.preprocessors import preprocess_options\n", "\n", "aviary_options = inputs.deepcopy()\n", "\n", @@ -82,6 +83,7 @@ "# We also need propulsion analysis for takeoff and landing. No additional configuration\n", "# is needed for this builder\n", "engine = av.build_engine_deck(aviary_options)\n", + "preprocess_options(aviary_options, engine_models=engine)\n", "prop_builder = av.CorePropulsionBuilder(engine_models=engine)" ] }, @@ -633,7 +635,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "base", "language": "python", "name": "python3" }, @@ -647,7 +649,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.12.5" } }, "nbformat": 4, diff --git a/aviary/docs/user_guide/SGM_capabilities.ipynb b/aviary/docs/user_guide/SGM_capabilities.ipynb index f417757cc..f6ff901cd 100644 --- a/aviary/docs/user_guide/SGM_capabilities.ipynb +++ b/aviary/docs/user_guide/SGM_capabilities.ipynb @@ -100,7 +100,7 @@ "source": [ "# Testing Cell\n", "from aviary.mission.gasp_based.ode.time_integration_base_classes import SimuPyProblem\n", - "from aviary.docs.tests.utils import check_args, check_value\n", + "from aviary.utils.doctape import check_args, check_value\n", "import inspect\n", "\n", "rate_suffix = inspect.signature(SimuPyProblem).parameters['rate_suffix'].default\n", @@ -132,14 +132,14 @@ " problem_name=phase_name,\n", " outputs=[\"normal_force\", \"alpha\"],\n", " states=[\n", - " Dynamic.Mission.MASS,\n", + " Dynamic.Vehicle.MASS,\n", " Dynamic.Mission.DISTANCE,\n", " Dynamic.Mission.ALTITUDE,\n", " Dynamic.Mission.VELOCITY,\n", " ],\n", " # state_units=['lbm','nmi','ft'],\n", " alternate_state_rate_names={\n", - " Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL},\n", + " Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL},\n", " **simupy_args,\n", " )\n", "\n", @@ -167,7 +167,7 @@ "# Testing Cell\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.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "\n", "rotation_trigger: event_trigger = SGMRotation(ode_args=ode_args).triggers[0]\n", "check_value(rotation_trigger.state,'normal_force')\n" @@ -196,11 +196,11 @@ "full_traj = FlexibleTraj(\n", " Phases=phase_info,\n", " traj_final_state_output=[\n", - " Dynamic.Mission.MASS,\n", + " Dynamic.Vehicle.MASS,\n", " Dynamic.Mission.DISTANCE,\n", " ],\n", " traj_initial_state_input=[\n", - " Dynamic.Mission.MASS,\n", + " Dynamic.Vehicle.MASS,\n", " Dynamic.Mission.DISTANCE,\n", " Dynamic.Mission.ALTITUDE,\n", " ],\n", @@ -210,11 +210,11 @@ " # third key is event_idx associated with input\n", " ('groundroll', Dynamic.Mission.VELOCITY, 0,),\n", " ('climb3', Dynamic.Mission.ALTITUDE, 0,),\n", - " ('cruise', Dynamic.Mission.MASS, 0,),\n", + " ('cruise', Dynamic.Vehicle.MASS, 0,),\n", " ],\n", " traj_intermediate_state_output=[\n", " ('cruise', Dynamic.Mission.DISTANCE),\n", - " ('cruise', Dynamic.Mission.MASS),\n", + " ('cruise', Dynamic.Vehicle.MASS),\n", " ]\n", ")" ] @@ -275,10 +275,10 @@ "source": [ "# Testing Cell\n", "from aviary.interface.default_phase_info.two_dof_fiti import descent_phases\n", - "from aviary.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "\n", "for phase_name, phase in descent_phases.items():\n", - " check_value(phase['user_options'][Dynamic.Mission.THROTTLE],(0, 'unitless'))" + " check_value(phase['user_options'][Dynamic.Vehicle.Propulsion.THROTTLE],(0, 'unitless'))" ] } ], @@ -298,7 +298,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/aviary/docs/user_guide/aerodynamics.ipynb b/aviary/docs/user_guide/aerodynamics.ipynb index cf06282ff..023e8883a 100644 --- a/aviary/docs/user_guide/aerodynamics.ipynb +++ b/aviary/docs/user_guide/aerodynamics.ipynb @@ -42,7 +42,7 @@ "source": [ "# Testing Cell\n", "from aviary.api import CoreAerodynamicsBuilder\n", - "from aviary.docs.tests.utils import check_args\n", + "from aviary.utils.doctape import check_args\n", "check_args(CoreAerodynamicsBuilder.build_pre_mission,['aviary_inputs'])" ] }, diff --git a/aviary/docs/user_guide/aviary_commands.ipynb b/aviary/docs/user_guide/aviary_commands.ipynb index 6d0f55573..853d6ec5e 100644 --- a/aviary/docs/user_guide/aviary_commands.ipynb +++ b/aviary/docs/user_guide/aviary_commands.ipynb @@ -302,7 +302,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_TP` string. If multiple are specified, the last one will be used.\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", "\n", "Notes for input decks:\n", "- Turbofan decks for both FLOPS and GASP can be converted\n", @@ -329,10 +329,10 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import run_command_no_file_error\n", + "from aviary.utils.doctape import run_command_no_file_error\n", "commands = [\n", - " 'turbofan_23k_1.eng turbofan_23k_1_lbm_s.deck -f GASP',\n", - " 'turbofan_22k.eng turbofan_22k.txt -f FLOPS',\n", + " 'utils/test/data/GASP_turbofan_23k_1.eng turbofan_23k_1_lbm_s.deck -f GASP',\n", + " 'utils/test/data/FLOPS_turbofan_22k.txt turbofan_22k.txt -f FLOPS',\n", " 'turboshaft_4465hp.eng turboshaft_4465hp.deck -f GASP_TS',\n", " ]\n", "for command in commands:\n", @@ -407,7 +407,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import run_command_no_file_error\n", + "from aviary.utils.doctape import run_command_no_file_error\n", "commands = [\n", " '-f GASP subsystems/aerodynamics/gasp_based/data/GASP_aero_free.txt large_single_aisle_1_aero_flaps.txt',\n", " '-f FLOPS utils/test/flops_test_polar.txt aviary_flops_polar.txt',\n", @@ -558,7 +558,7 @@ "metadata": { "celltoolbar": "Tags", "kernelspec": { - "display_name": "Python 3", + "display_name": "latest_env", "language": "python", "name": "python3" }, @@ -572,7 +572,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.10.13" } }, "nbformat": 4, 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 d5e1c2d64..42dd8bad5 100644 --- a/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb +++ b/aviary/docs/user_guide/drawing_and_running_simple_missions.ipynb @@ -180,7 +180,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import run_command_no_file_error\n", + "from aviary.utils.doctape import run_command_no_file_error\n", "command = 'aviary run_mission --optimizer IPOPT --phase_info outputted_phase_info.py '\\\n", " 'validation_cases/benchmark_tests/test_aircraft/aircraft_for_bench_FwFm.csv'\n", "command += ' --max_iter 0'\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..be08a70b0 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 @@ -434,6 +434,8 @@ "]\n", "av.set_aviary_input_defaults(prob.model, varnames, aviary_inputs)\n", "\n", + "av.setup_model_options(prob, aviary_inputs)\n", + "\n", "prob.setup(force_alloc_complex=True)\n", "\n", "av.set_aviary_initial_values(prob, aviary_inputs)\n", @@ -449,9 +451,9 @@ " av.Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m')\n", "prob.set_val(\n", " 'traj.climb.controls:mach', climb.interp(\n", - " av.Dynamic.Mission.MACH, ys=[mach_i_climb, mach_f_climb]), units='unitless')\n", + " av.Dynamic.Atmosphere.MACH, ys=[mach_i_climb, mach_f_climb]), units='unitless')\n", "prob.set_val('traj.climb.states:mass', climb.interp(\n", - " av.Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", + " av.Dynamic.Vehicle.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", "prob.set_val('traj.climb.states:distance', climb.interp(\n", " av.Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m')\n", "\n", @@ -462,9 +464,9 @@ " av.Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m')\n", "prob.set_val(\n", " 'traj.cruise.controls:mach', cruise.interp(\n", - " av.Dynamic.Mission.MACH, ys=[cruise_mach, cruise_mach]), units='unitless')\n", + " av.Dynamic.Atmosphere.MACH, ys=[cruise_mach, cruise_mach]), units='unitless')\n", "prob.set_val('traj.cruise.states:mass', cruise.interp(\n", - " av.Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", + " av.Dynamic.Vehicle.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", "prob.set_val('traj.cruise.states:distance', cruise.interp(\n", " av.Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m')\n", "\n", @@ -475,9 +477,9 @@ " av.Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m')\n", "prob.set_val(\n", " 'traj.descent.controls:mach', descent.interp(\n", - " av.Dynamic.Mission.MACH, ys=[mach_i_descent, mach_f_descent]), units='unitless')\n", + " av.Dynamic.Atmosphere.MACH, ys=[mach_i_descent, mach_f_descent]), units='unitless')\n", "prob.set_val('traj.descent.states:mass', descent.interp(\n", - " av.Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", + " av.Dynamic.Vehicle.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", "prob.set_val('traj.descent.states:distance', descent.interp(\n", " av.Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m')\n", "\n", @@ -505,7 +507,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/aviary/docs/user_guide/features_and_functionalities.ipynb b/aviary/docs/user_guide/features_and_functionalities.ipynb index 35b69a1db..27a2ef86e 100644 --- a/aviary/docs/user_guide/features_and_functionalities.ipynb +++ b/aviary/docs/user_guide/features_and_functionalities.ipynb @@ -86,7 +86,7 @@ "source": [ "# Testing Cell\n", "from aviary.interface.utils.check_phase_info import phase_keys_gasp\n", - "from aviary.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "expected_keys = ['groundroll', 'rotation', 'ascent', 'accel', 'climb1', 'climb2', 'cruise', 'desc1', 'desc2']\n", "check_value(list(phase_keys_gasp.keys()), expected_keys)" ] diff --git a/aviary/docs/user_guide/hamilton_standard.ipynb b/aviary/docs/user_guide/hamilton_standard.ipynb index b6fa18475..ff1cfa736 100644 --- a/aviary/docs/user_guide/hamilton_standard.ipynb +++ b/aviary/docs/user_guide/hamilton_standard.ipynb @@ -91,21 +91,20 @@ "import aviary.api as av\n", "\n", "options = get_option_defaults()\n", - "options.set_val(av.Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, val=True, units='unitless')\n", - "options.set_val(av.Aircraft.Engine.NUM_PROPELLER_BLADES, val=4, units='unitless')\n", + "options.set_val(av.Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, val=True, units='unitless')\n", + "options.set_val(av.Aircraft.Engine.Propeller.NUM_BLADES, val=4, units='unitless')\n", "options.set_val(av.Aircraft.Engine.GENERATE_FLIGHT_IDLE, False)\n", "options.set_val(av.Aircraft.Engine.DATA_FILE, 'models/engines/turboshaft_4465hp.deck')\n", - "options.set_val(av.Aircraft.Engine.USE_PROPELLER_MAP, val=False)\n", "\n", "prob = om.Problem()\n", "group = prob.model\n", "for name in ('traj','cruise','rhs_all'):\n", " group = group.add_subsystem(name, om.Group())\n", "var_names = [\n", - " (av.Aircraft.Engine.PROPELLER_TIP_SPEED_MAX,0,{'units':'ft/s'}),\n", + " (av.Aircraft.Engine.Propeller.TIP_SPEED_MAX,0,{'units':'ft/s'}),\n", " # (av.Dynamic.Mission.PERCENT_ROTOR_RPM_CORRECTED,0,{'units':'unitless'}),\n", - " (av.Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR,0,{'units':'unitless'}),\n", - " (av.Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT,0,{'units':'unitless'}),\n", + " (av.Aircraft.Engine.Propeller.ACTIVITY_FACTOR,0,{'units':'unitless'}),\n", + " (av.Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT,0,{'units':'unitless'}),\n", " ]\n", "group.add_subsystem('ivc',om.IndepVarComp(var_names),promotes=['*'])\n", "\n", @@ -121,10 +120,10 @@ " promotes_inputs=['*'],\n", " promotes_outputs=[\"*\"],\n", ")\n", - "pp.set_input_defaults(av.Aircraft.Engine.PROPELLER_DIAMETER, 10, units=\"ft\")\n", - "pp.set_input_defaults(av.Dynamic.Mission.MACH, .7, units=\"unitless\")\n", - "# pp.set_input_defaults(av.Dynamic.Mission.TEMPERATURE, 650, units=\"degR\")\n", - "pp.set_input_defaults(av.Dynamic.Mission.PROPELLER_TIP_SPEED, 800, units=\"ft/s\")\n", + "pp.set_input_defaults(av.Aircraft.Engine.Propeller.DIAMETER, 10, units=\"ft\")\n", + "pp.set_input_defaults(av.Dynamic.Atmosphere.MACH, .7, units=\"unitless\")\n", + "# pp.set_input_defaults(av.Dynamic.Atmosphere.TEMPERATURE, 650, units=\"degR\")\n", + "pp.set_input_defaults(av.Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, 800, units=\"ft/s\")\n", "pp.set_input_defaults(av.Dynamic.Mission.VELOCITY, 100, units=\"knot\")\n", "prob.setup()\n", "\n", @@ -203,20 +202,20 @@ }, "outputs": [], "source": [ - "Aircraft.Engine.PROPELLER_DIAMETER\n", - "Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT\n", - "Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR\n", - "Aircraft.Engine.NUM_PROPELLER_BLADES\n", - "Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS\n", - "Dynamic.Mission.PROPELLER_TIP_SPEED\n", - "Dynamic.Mission.SHAFT_POWER" + "Aircraft.Engine.Propeller.DIAMETER\n", + "Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT\n", + "Aircraft.Engine.Propeller.ACTIVITY_FACTOR\n", + "Aircraft.Engine.Propeller.NUM_BLADES\n", + "Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS\n", + "Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED\n", + "Dynamic.Vehicle.Propulsion.SHAFT_POWER" ] }, { "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 `TurbopropModel` object without providing a custom `propeller_model`, here it is set to `None` (the default). In this example, we also set `shaft_power_model` to `None`, another default that assumes we are using a turboshaft engine deck:" ] }, { @@ -229,7 +228,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)" ] }, { @@ -249,9 +248,9 @@ }, "outputs": [], "source": [ - "options.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10, units='ft')\n", - "options.set_val(Aircraft.Engine.NUM_PROPELLER_BLADES, val=4, units='unitless')\n", - "options.set_val(Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, val=True, units='unitless')" + "options.set_val(Aircraft.Engine.Propeller.DIAMETER, 10, units='ft')\n", + "options.set_val(Aircraft.Engine.Propeller.NUM_BLADES, val=4, units='unitless')\n", + "options.set_val(Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, val=True, units='unitless')" ] }, { @@ -271,9 +270,9 @@ }, "outputs": [], "source": [ - "prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_TIP_SPEED_MAX}', 710., units='ft/s')\n", - "prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR}', 150., units='unitless')\n", - "prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT}', 0.5, units='unitless')" + "prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.Propeller.TIP_SPEED_MAX}', 710., units='ft/s')\n", + "prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.Propeller.ACTIVITY_FACTOR}', 150., units='unitless')\n", + "prob.set_val(f'traj.cruise.rhs_all.{Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT}', 0.5, units='unitless')" ] }, { @@ -284,7 +283,7 @@ "\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", "\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 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.Atmosphere.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." ] diff --git a/aviary/docs/user_guide/input_files.ipynb b/aviary/docs/user_guide/input_files.ipynb index 2d1b413fe..40465df57 100644 --- a/aviary/docs/user_guide/input_files.ipynb +++ b/aviary/docs/user_guide/input_files.ipynb @@ -188,7 +188,7 @@ "source": [ "# Testing Cell\n", "from aviary.api import Aircraft\n", - "from aviary.docs.tests.utils import check_value\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')" ] diff --git a/aviary/docs/user_guide/mass.ipynb b/aviary/docs/user_guide/mass.ipynb index 40f16dc4f..912484e2e 100644 --- a/aviary/docs/user_guide/mass.ipynb +++ b/aviary/docs/user_guide/mass.ipynb @@ -59,7 +59,7 @@ "source": [ "# Testing Cell\n", "from aviary.api import Aircraft, Settings\n", - "from aviary.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "check_value(Settings.MASS_METHOD,'settings:mass_method')\n", "check_value(Aircraft.CrewPayload.MASS_PER_PASSENGER,'aircraft:crew_and_payload:mass_per_passenger')\n", "check_value(Aircraft.Engine.ADDITIONAL_MASS_FRACTION,'aircraft:engine:additional_mass_fraction')" diff --git a/aviary/docs/user_guide/multi_mission.ipynb b/aviary/docs/user_guide/multi_mission.ipynb new file mode 100644 index 000000000..6c18ad0e8 --- /dev/null +++ b/aviary/docs/user_guide/multi_mission.ipynb @@ -0,0 +1,71 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "\n", + "from aviary.utils.doctape import glue_variable, get_variable_name\n", + "from aviary.api import Aircraft, AviaryProblem\n", + "glue_variable('capi',AviaryProblem.check_and_preprocess_inputs.__name__,md_code=True)\n", + "\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.Design.NUM_PASSENGERS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.NUM_PASSENGERS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.NUM_BUSINESS_CLASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.NUM_FIRST_CLASS), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.CrewPayload.NUM_TOURIST_CLASS), md_code=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multi-Mission Optimization\n", + "\n", + "## Overview\n", + "\n", + "Multi-missions adds the capability to optimize an aircraft design considering two or more missions that the aircraft will perform. This is in contrast to designing an aircraft for a single mission, and hopefully helps to represent the conditions the aircraft will be flying in better. In the example provided, a large single aisle passenger aircraft is designed based on a mission with every seat filled, and a second 'deadhead' mission where there are no passengers. A weighting is provided by the user to determine how often the missions are full of passengers vs. how often the flights are empty. A cargo example could be constructed where one mission is designed for maximum range and a second mission designed for maximum payload. \n", + "\n", + "To impact the structure of aviaryproblems as little as possible, after instantiation of the pre-mission, mission, and post-mission systems, the connections between those systems are created. Then those groups are then copied over into a regular openmdao problem. This enables the use all the basic aviary connection and checking functions with minimal modification. \n", + "\n", + "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", + "\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", + "## Example\n", + "An example of a multi-mission as well as Setup, Theory, and Results, is presented in [Multi-Mission Examples](../examples/multi_mission)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/aviary/docs/user_guide/off_design_missions.ipynb b/aviary/docs/user_guide/off_design_missions.ipynb index 78b214d3a..3798fe65d 100644 --- a/aviary/docs/user_guide/off_design_missions.ipynb +++ b/aviary/docs/user_guide/off_design_missions.ipynb @@ -48,7 +48,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import check_contains\n", + "from aviary.utils.doctape import check_contains\n", "import aviary.api as av\n", "import os\n", "\n", diff --git a/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb b/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb index 2acb598d1..a24c03ef1 100644 --- a/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb +++ b/aviary/docs/user_guide/postprocessing_and_visualizing_results.ipynb @@ -66,8 +66,10 @@ "from aviary.utils.functions import get_path\n", "import shutil\n", "file_name = 'run_aviary_example'\n", - "commands = ['python '+file_name+'.py', 'aviary dashboard '+file_name+\n", - " ' --problem_recorder=problem_final_case.db --driver_recorder=driver_cases.db']\n", + "commands = [\n", + " 'python '+file_name+'.py',\n", + " 'aviary dashboard '+file_name+' --problem_recorder=problem_final_case.db --driver_recorder=driver_cases.db --background'\n", + " ]\n", "with tempfile.TemporaryDirectory() as tempdir:\n", " os.chdir(tempdir)\n", " shutil.copy2(get_path('examples/'+file_name+'.py'), '.')\n", @@ -177,7 +179,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import check_args\n", + "from aviary.utils.doctape import check_args\n", "from aviary.interface.methods_for_level2 import AviaryProblem\n", "check_args(AviaryProblem.run_aviary_problem,{'record_filename':\"problem_history.db\"},exact=False)" ] @@ -212,7 +214,7 @@ "from openmdao.core.problem import _clear_problem_names\n", "from openmdao.utils.reports_system import clear_reports\n", "import aviary.api as av\n", - "from aviary.docs.tests.utils import check_contains, expected_error, gramatical_list, glue_variable, Markdown\n", + "from aviary.utils.doctape import check_contains, expected_error, gramatical_list, glue_variable\n", "\n", "list_files = ['input_list.txt', 'output_list.txt']\n", "optimizer_files = {\n", @@ -259,7 +261,7 @@ " glue_variable(optimizer_file,md_code=True)\n", "glue_variable('SLSQP.out',md_code=True) # only possible at level3\n", "string = f\"If `{av.Verbosity.__qualname__}` is set to {gramatical_list(['`'+v.name+'`' for v in vtsplf],'or')}, {gramatical_list(list_files,add_accents=True)} are generated.\"\n", - "glue_variable('verbosity_files',Markdown(string))\n", + "glue_variable('verbosity_files',string)\n", "\n", "run_and_check(av.Verbosity.QUIET)\n", "run_and_check(av.Verbosity.BRIEF)\n", diff --git a/aviary/docs/user_guide/pre_mission_and_mission.ipynb b/aviary/docs/user_guide/pre_mission_and_mission.ipynb index 217ef34a1..e82566fc6 100644 --- a/aviary/docs/user_guide/pre_mission_and_mission.ipynb +++ b/aviary/docs/user_guide/pre_mission_and_mission.ipynb @@ -51,7 +51,7 @@ "source": [ "# Testing Cell\n", "from aviary.mission.phase_builder_base import PhaseBuilderBase\n", - "from aviary.docs.tests.utils import check_args\n", + "from aviary.utils.doctape import check_args\n", "check_args(PhaseBuilderBase.__init__,'num_nodes')" ] }, diff --git a/aviary/docs/user_guide/propulsion.ipynb b/aviary/docs/user_guide/propulsion.ipynb index c10568fc2..83489c562 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.docs.tests.utils import check_value, check_contains, Markdown, glue_variable\n", + "from aviary.utils.doctape import check_value, check_contains, glue_variable\n", "from aviary.variable_info.variable_meta_data import CoreMetaData\n", "\n", "vars = ['Mach Number', 'Altitude', 'Throttle', 'Hybrid Throttle', 'Net Thrust',\n", @@ -122,7 +122,7 @@ " 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", - "glue_variable('required_options', Markdown(required_options_list), display=True)\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", @@ -131,7 +131,7 @@ "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", - "glue_variable('flight_idle_options', Markdown(flight_idle_options), display=True)\n", + "glue_variable('flight_idle_options', flight_idle_options, display=True)\n", "\n" ] }, @@ -184,7 +184,7 @@ "# Testing Cell\n", "from aviary.api import Aircraft\n", "from aviary.subsystems.propulsion.engine_deck import dependent_options\n", - "from aviary.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "ae = Aircraft.Engine\n", "\n", "required = (ae.FLIGHT_IDLE_THRUST_FRACTION, ae.FLIGHT_IDLE_MIN_FRACTION, ae.FLIGHT_IDLE_MAX_FRACTION)\n", @@ -217,7 +217,7 @@ "# Testing Cell\n", "from aviary.subsystems.propulsion.engine_model import EngineModel\n", "from aviary.subsystems.propulsion.engine_deck import EngineDeck\n", - "from aviary.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "from aviary.utils.aviary_values import AviaryValues\n", "import inspect\n", "\n", @@ -332,7 +332,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "latest_env", "language": "python", "name": "python3" }, diff --git a/aviary/docs/user_guide/reserve_missions.ipynb b/aviary/docs/user_guide/reserve_missions.ipynb index 65ef7bf45..42a13eb58 100644 --- a/aviary/docs/user_guide/reserve_missions.ipynb +++ b/aviary/docs/user_guide/reserve_missions.ipynb @@ -45,7 +45,7 @@ "import os\n", "import aviary.api as av\n", "from importlib.machinery import SourceFileLoader\n", - "from aviary.docs.tests.utils import check_contains\n", + "from aviary.utils.doctape import check_contains\n", "\n", "gasp_phase_path = av.get_path(os.path.join('mission','gasp_based','phases'))\n", "files = os.listdir(gasp_phase_path)\n", @@ -87,7 +87,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import check_contains\n", + "from aviary.utils.doctape import check_contains\n", "import aviary.api as av\n", "import os\n", "\n", @@ -135,7 +135,7 @@ "source": [ "# Testing Cell\n", "from aviary.interface.utils.check_phase_info import phase_keys_gasp\n", - "from aviary.docs.tests.utils import check_contains\n", + "from aviary.utils.doctape import check_contains\n", "\n", "expected_phases = [phase for phase in phase_keys_gasp if phase!='groundroll'] # no reserve groundroll\n", "check_contains(\n", @@ -183,7 +183,7 @@ "from aviary.interface.methods_for_level2 import AviaryProblem\n", "from aviary.interface.default_phase_info.two_dof import phase_info\n", "from aviary.interface.download_models import get_model\n", - "from aviary.docs.tests.utils import check_contains\n", + "from aviary.utils.doctape import check_contains\n", "import aviary.api as av\n", "import os\n", "\n", @@ -232,7 +232,7 @@ "from aviary.interface.default_phase_info.two_dof import phase_info\n", "from aviary.interface.download_models import get_model\n", "from copy import deepcopy\n", - "from aviary.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "\n", "climb1_info = deepcopy(phase_info['climb1'])\n", "phase_info_for_test = {'climb1': climb1_info}\n", diff --git a/aviary/docs/user_guide/subsystems.ipynb b/aviary/docs/user_guide/subsystems.ipynb index f29e1cb82..c84c0584c 100644 --- a/aviary/docs/user_guide/subsystems.ipynb +++ b/aviary/docs/user_guide/subsystems.ipynb @@ -1,5 +1,77 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "import aviary.interface.methods_for_level2 as methods_for_level2\n", + "from aviary.utils.doctape import glue_variable\n", + "from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase\n", + "from aviary.utils.functions import get_path\n", + "\n", + "expected_flow = {\n", + " 'load_inputs':'loads the aviary_values inputs and options that the user specifies.',\n", + " 'check_and_preprocess_inputs':{'desc':'checks the user-supplied input values for any potential problems.',\n", + " 'preprocess_inputs':''},\n", + " 'add_pre_mission_systems':{'desc':'adds pre-mission Systems to the Aviary problem',\n", + " 'get_mass_names':'',\n", + " 'build_pre_mission':''},\n", + " 'add_phases':{'desc':'adds mission phases to the Aviary problem',\n", + " 'get_states':'',\n", + " 'get_constraints':'',\n", + " 'get_controls':'',\n", + " 'get_parameters':'',\n", + " 'needs_mission_solver':'',\n", + " 'build_mission':''},\n", + " 'add_post_mission_systems':{'desc':'adds the post-mission Systems to the Aviary problem',\n", + " 'build_post_mission':''},\n", + " 'link_phases':{'desc':'links variables between phases',\n", + " 'get_linked_variables':'',\n", + " 'get_bus_variables':''},\n", + " 'add_driver':'adds the driver (usually an optimizer)',\n", + " 'add_design_variables':{'desc':'adds the optimization design variables',\n", + " 'get_design_vars':''},\n", + " 'add_objective':'adds the user-selected objective',\n", + " 'setup':{'desc':'sets up the Aviary problem',\n", + " 'get_outputs':'',\n", + " 'define_order':''},\n", + " 'set_initial_guesses':{'desc':'sets the initial guesses for the Aviary problem',\n", + " 'get_initial_guesses':''},\n", + " 'run_aviary_problem':'actually runs the Aviary problem',\n", + "}\n", + "\n", + "bulleted_list = ''\n", + "def build_list(dict_of_dicts:dict, layer=0, bulleted_list=''):\n", + " for key, val in dict_of_dicts.items():\n", + " # check that the function exists where we expect it\n", + " if layer == 0: getattr(methods_for_level2.AviaryProblem, key)\n", + " else: getattr(SubsystemBuilderBase, key)\n", + "\n", + " if isinstance(val,str): desc = val\n", + " elif isinstance(val,dict): desc = val.pop('desc')\n", + " else: desc = str(val)\n", + " # add indents as necessary only add the \"-\" if there is a description\n", + " line = (' '*layer) + '- ' + f'`{key}`' + (f' - {desc}')*(len(desc)>0) + '\\n'\n", + " bulleted_list += line\n", + " if isinstance(val,dict):\n", + " bulleted_list = build_list(val, layer+1, bulleted_list)\n", + " return bulleted_list\n", + "\n", + "bulleted_list = build_list(expected_flow)\n", + "\n", + "glue_variable('expected_flow', bulleted_list, display=True)\n", + "glue_variable(SubsystemBuilderBase.__name__, md_code=True)\n", + "glue_variable('methods_for_level2.py',\n", + " str(get_path(methods_for_level2.__file__).name), md_code=True)\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -8,78 +80,28 @@ "\n", "## Method Overview\n", "\n", - "Here is a brief overview of the available methods that are used in the `SubsystemBuilderBase` object.\n", + "Here is a brief overview of the available methods that are used in the {glue:md}`SubsystemBuilderBase` object.\n", "The docstrings within this builder base class go into much more detail.\n", "This overview is automatically generated from the docstrings in the builder base class.\n", "\n", "We'll now detail where in the Aviary stack each one of these methods is used.\n", "Understanding this can be helpful for knowing which parts of the Aviary problem will be impacted by your subsystem.\n", - "In the following outline, the methods listed at the top-level are defined in `methods_for_level2.py` and are called in this order to run an Aviary problem.\n", + "In the following outline, the methods listed at the top-level are defined in {glue:md}`methods_for_level2.py` and are called in this order to run an Aviary problem.\n", "Any sub-listed method is one that you can provide with your subsystem builder, showing where within the level 3 method hierarchy that subsystem method gets used.\n", "\n", - "- `load_inputs` - loads the aviary_values inputs and options that the user specifies.\n", - "- `check_and_preprocess_inputs` - checks the user-supplied input values for any potential problems.\n", - " - `preprocess_inputs`\n", - "- `add_pre_mission_systems` - adds pre-mission Systems to the Aviary problem\n", - " - `get_mass_names`\n", - " - `build_pre_mission`\n", - "- `add_phases` - adds mission phases to the Aviary problem\n", - " - `get_states`\n", - " - `get_constraints`\n", - " - `get_controls`\n", - " - `get_parameters`\n", - " - `build_mission`\n", - "- `add_post_mission_systems` - adds the post-mission Systems to the Aviary problem\n", - " - `build_post_mission`\n", - "- `link_phases` - links variables between phases\n", - " - `get_linked_variables`\n", - " - `get_bus_variables`\n", - "- `add_driver` - adds the driver (usually an optimizer)\n", - "- `add_design_variables` - adds the optimization design variables\n", - " - `get_design_vars`\n", - "- `add_objective` - adds the user-selected objective\n", - "- `setup` - sets up the Aviary problem\n", - " - `get_outputs`\n", - " - `define_order`\n", - "- `set_initial_guesses` - sets the initial guesses for the Aviary problem\n", - " - `get_initial_guesses`\n", - "- `run_aviary_problem` - actually runs the Aviary problem\n", + "```{glue:md} expected_flow\n", + ":format: myst\n", + "```\n", "\n", "```{note}\n", "Understanding the flow of the above methods and how the subsystem methods are used within Aviary is pretty important! Make sure to review these methods and where in the stack they're used before digging too deep into debugging your subsystem.\n", "```\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "# Testing Cell\n", - "from aviary.api import AviaryProblem\n", - "\n", - "expected_flow = [\n", - " 'load_inputs','check_and_preprocess_inputs','add_pre_mission_systems',\n", - " 'add_phases','add_post_mission_systems','link_phases','add_driver',\n", - " 'add_design_variables','add_objective','setup','set_initial_guesses',\n", - " 'run_aviary_problem'\n", - " ]\n", - "\n", - "for func in expected_flow:\n", - " getattr(AviaryProblem, func)\n", - " # ****NOTE****\n", - " # check functions in each function?" - ] } ], "metadata": { "kernelspec": { - "display_name": "latest_env", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -93,9 +115,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.12.3" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/aviary/docs/user_guide/troubleshooting.ipynb b/aviary/docs/user_guide/troubleshooting.ipynb index 65803ed76..1f1ddea42 100644 --- a/aviary/docs/user_guide/troubleshooting.ipynb +++ b/aviary/docs/user_guide/troubleshooting.ipynb @@ -62,7 +62,7 @@ "from aviary.interface.cmd_entry_points import _command_map\n", "import argparse\n", "from aviary.api import Settings\n", - "from aviary.docs.tests.utils import check_value, check_contains\n", + "from aviary.utils.doctape import check_value, check_contains\n", "\n", "_command_map['run_mission'];\n", "check_value(Settings.VERBOSITY,'settings:verbosity')\n", diff --git a/aviary/docs/user_guide/variable_hierarchy.ipynb b/aviary/docs/user_guide/variable_hierarchy.ipynb index 45ca31593..8f213a134 100644 --- a/aviary/docs/user_guide/variable_hierarchy.ipynb +++ b/aviary/docs/user_guide/variable_hierarchy.ipynb @@ -27,7 +27,7 @@ "source": [ "# Testing Cell\n", "from aviary.api import Aircraft\n", - "from aviary.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "\n", "check_value(Aircraft.Wing.SPAN,'aircraft:wing:span')" ] @@ -103,7 +103,7 @@ "outputs": [], "source": [ "# Testing Cell\n", - "from aviary.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "\n", "Aircraft.Fuselage.LENGTH;\n", "Aircraft.HorizontalTail.ROOT_CHORD;\n", diff --git a/aviary/docs/user_guide/variable_metadata.ipynb b/aviary/docs/user_guide/variable_metadata.ipynb index efe042655..a8bf93016 100644 --- a/aviary/docs/user_guide/variable_metadata.ipynb +++ b/aviary/docs/user_guide/variable_metadata.ipynb @@ -33,7 +33,7 @@ "source": [ "# Testing Cell\n", "from aviary.utils.develop_metadata import add_meta_data\n", - "from aviary.docs.tests.utils import check_value\n", + "from aviary.utils.doctape import check_value\n", "\n", "expected_meta_data = {\n", " 'units': 'unitless',\n", @@ -42,6 +42,7 @@ " 'option': False,\n", " 'types': None,\n", " 'historical_name': None,\n", + " 'multivalue': False,\n", " }\n", "\n", "meta_data = {}\n", @@ -447,7 +448,7 @@ "hash": "e6c7471802ed76737b16357fb02af5587f3a4cbee5ea7658f3f9a6981469039b" }, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -461,7 +462,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.12.3" }, "orphan": true }, diff --git a/aviary/examples/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py b/aviary/examples/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py index 3d38ed265..ae6215974 100644 --- a/aviary/examples/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py +++ b/aviary/examples/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py @@ -491,7 +491,6 @@ def compute(self, inputs, outputs): prob.driver = om.ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-8 - # Set up the problem with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=om.PromotionWarning) diff --git a/aviary/examples/external_subsystems/engine_NPSS/table_engine_builder.py b/aviary/examples/external_subsystems/engine_NPSS/table_engine_builder.py index bd2f9e53a..af8baae33 100644 --- a/aviary/examples/external_subsystems/engine_NPSS/table_engine_builder.py +++ b/aviary/examples/external_subsystems/engine_NPSS/table_engine_builder.py @@ -2,10 +2,19 @@ import numpy as np import openmdao.api as om -from aviary.examples.external_subsystems.engine_NPSS.engine_variable_meta_data import ExtendedMetaData -from aviary.examples.external_subsystems.engine_NPSS.engine_variables import Aircraft, Dynamic -from aviary.examples.external_subsystems.engine_NPSS.NPSS_Model.DesignEngineGroup import DesignEngineGroup -from aviary.examples.external_subsystems.engine_NPSS.table_engine_connected_variables import vars_to_connect +from aviary.examples.external_subsystems.engine_NPSS.engine_variable_meta_data import ( + ExtendedMetaData, +) +from aviary.examples.external_subsystems.engine_NPSS.engine_variables import ( + Aircraft, + Dynamic, +) +from aviary.examples.external_subsystems.engine_NPSS.NPSS_Model.DesignEngineGroup import ( + DesignEngineGroup, +) +from aviary.examples.external_subsystems.engine_NPSS.table_engine_connected_variables import ( + vars_to_connect, +) from aviary.subsystems.propulsion.engine_model import EngineModel from aviary.utils.aviary_values import AviaryValues from aviary.utils.functions import get_aviary_resource_path @@ -79,16 +88,27 @@ def build_mission(self, num_nodes, aviary_inputs): # interpolator object for engine data engine = om.MetaModelSemiStructuredComp( - method=interp_method, extrapolate=True, vec_size=num_nodes, training_data_gradients=True) - - ref = os.path.join("examples", "external_subsystems", "engine_NPSS", - "NPSS_Model", "Output", "RefEngine.outputAviary") + method=interp_method, + extrapolate=True, + vec_size=num_nodes, + training_data_gradients=True, + ) + + ref = os.path.join( + "examples", + "external_subsystems", + "engine_NPSS", + "NPSS_Model", + "Output", + "RefEngine.outputAviary", + ) csv_path = get_aviary_resource_path(ref) engine_data = np.genfromtxt(csv_path, skip_header=0) # Sort the data by Mach, then altitude, then throttle - engine_data = engine_data[np.lexsort( - (engine_data[:, 2], engine_data[:, 1], engine_data[:, 0]))] + engine_data = engine_data[ + np.lexsort((engine_data[:, 2], engine_data[:, 1], engine_data[:, 0])) + ] zeros_array = np.zeros((engine_data.shape[0], 1)) # create a new array for thrust_max. here we take the values where throttle=1.0 @@ -97,49 +117,72 @@ def build_mission(self, num_nodes, aviary_inputs): # for a given mach, altitude, and hybrid throttle setting, the thrust_max is the value where throttle=1.0 for i in range(engine_data.shape[0]): # find the index of the first instance where throttle=1.0 - index = np.where((engine_data[:, 0] == engine_data[i, 0]) & ( - engine_data[:, 1] == engine_data[i, 1]) & (engine_data[:, 2] == 1.0))[0][0] + index = np.where( + (engine_data[:, 0] == engine_data[i, 0]) + & (engine_data[:, 1] == engine_data[i, 1]) + & (engine_data[:, 2] == 1.0) + )[0][0] thrust_max[i] = engine_data[index, 3] - print(Dynamic.Mission.THRUST, '--------------------------------------') + print( + Dynamic.Vehicle.Propulsion.THRUST, '--------------------------------------' + ) # add inputs and outputs to interpolator - engine.add_input(Dynamic.Mission.MACH, - engine_data[:, 0], - units='unitless', - desc='Current flight Mach number') - engine.add_input(Dynamic.Mission.ALTITUDE, - engine_data[:, 1], - units='ft', - desc='Current flight altitude') - engine.add_input(Dynamic.Mission.THROTTLE, - engine_data[:, 2], - units='unitless', - desc='Current engine throttle') - engine.add_output(Dynamic.Mission.THRUST, - engine_data[:, 3], - units='lbf', - desc='Current net thrust produced') - engine.add_output(Dynamic.Mission.THRUST_MAX, - thrust_max, - units='lbf', - desc='Max net thrust produced') - engine.add_output(Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, - -engine_data[:, 4], - units='lbm/s', - desc='Current fuel flow rate ') - engine.add_output(Dynamic.Mission.ELECTRIC_POWER_IN, - zeros_array, - units='kW', - desc='Current electric energy rate') - engine.add_output(Dynamic.Mission.NOX_RATE, - zeros_array, - units='lb/h', - desc='Current NOx emission rate') - engine.add_output(Dynamic.Mission.TEMPERATURE_T4, - zeros_array, - units='degR', - desc='Current turbine exit temperature') + engine.add_input( + Dynamic.Atmosphere.MACH, + engine_data[:, 0], + units='unitless', + desc='Current flight Mach number', + ) + engine.add_input( + Dynamic.Mission.ALTITUDE, + engine_data[:, 1], + units='ft', + desc='Current flight altitude', + ) + engine.add_input( + Dynamic.Vehicle.Propulsion.THROTTLE, + engine_data[:, 2], + units='unitless', + desc='Current engine throttle', + ) + engine.add_output( + Dynamic.Vehicle.Propulsion.THRUST, + engine_data[:, 3], + units='lbf', + desc='Current net thrust produced', + ) + engine.add_output( + Dynamic.Vehicle.Propulsion.THRUST_MAX, + thrust_max, + units='lbf', + desc='Max net thrust produced', + ) + engine.add_output( + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, + -engine_data[:, 4], + units='lbm/s', + desc='Current fuel flow rate ', + ) + engine.add_output( + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, + zeros_array, + units='kW', + desc='Current electric energy rate', + ) + engine.add_output( + Dynamic.Vehicle.Propulsion.NOX_RATE, + zeros_array, + units='lb/h', + desc='Current NOx emission rate', + ) + engine.add_output( + Dynamic.Vehicle.Propulsion.TEMPERATURE_T4, + zeros_array, + units='degR', + desc='Current turbine exit temperature', + ) return engine def get_bus_variables(self): @@ -170,8 +213,12 @@ def get_design_vars(self): Dictionary with keys that are names of variables to be made design variables and the values are dictionaries with the keys `units`, `upper`, `lower`, and `ref`. ''' - mass_flow_dict = {'units': 'lbm/s', 'upper': 450, 'lower': 100, - 'ref': 450} # upper and lower are just notional for now + mass_flow_dict = { + 'units': 'lbm/s', + 'upper': 450, + 'lower': 100, + 'ref': 450, + } # upper and lower are just notional for now design_vars = { Aircraft.Engine.DESIGN_MASS_FLOW: mass_flow_dict, } diff --git a/aviary/examples/external_subsystems/engine_NPSS/table_engine_connected_variables.py b/aviary/examples/external_subsystems/engine_NPSS/table_engine_connected_variables.py index 2450f0ae1..35e534e90 100755 --- a/aviary/examples/external_subsystems/engine_NPSS/table_engine_connected_variables.py +++ b/aviary/examples/external_subsystems/engine_NPSS/table_engine_connected_variables.py @@ -3,19 +3,19 @@ vars_to_connect = { "Fn_train": { "mission_name": [ - Dynamic.Mission.THRUST+"_train", + Dynamic.Vehicle.Propulsion.THRUST + "_train", ], "units": "lbf", }, "Fn_max_train": { "mission_name": [ - Dynamic.Mission.THRUST_MAX+"_train", + Dynamic.Vehicle.Propulsion.THRUST_MAX + "_train", ], "units": "lbf", }, "Wf_inv_train": { "mission_name": [ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE+"_train", + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE + "_train", ], "units": "lbm/s", }, diff --git a/aviary/examples/level2_shooting_traj.py b/aviary/examples/level2_shooting_traj.py index e51261736..89739c427 100644 --- a/aviary/examples/level2_shooting_traj.py +++ b/aviary/examples/level2_shooting_traj.py @@ -62,7 +62,7 @@ def custom_run_aviary(aircraft_filename, optimizer=None, 'alt_trigger': (10000, 'ft'), 'mach': (0, 'unitless'), 'speed_trigger': (350, 'kn'), - Dynamic.Mission.THROTTLE: (0, 'unitless'), + Dynamic.Vehicle.Propulsion.THROTTLE: (0, 'unitless'), }, 'descent_phase': True, }, @@ -86,18 +86,30 @@ def custom_run_aviary(aircraft_filename, optimizer=None, traj = FlexibleTraj( Phases=phase_info, traj_final_state_output=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, ], traj_initial_state_input=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, ], traj_event_trigger_input=[ - ('groundroll', Dynamic.Mission.VELOCITY, 0,), - ('climb3', Dynamic.Mission.ALTITUDE, 0,), - ('cruise', Dynamic.Mission.DISTANCE, 0,), + ( + 'groundroll', + Dynamic.Mission.VELOCITY, + 0, + ), + ( + 'climb3', + Dynamic.Mission.ALTITUDE, + 0, + ), + ( + 'cruise', + Dynamic.Mission.DISTANCE, + 0, + ), ], ) prob.traj = prob.model.add_subsystem('traj', traj) diff --git a/aviary/examples/multi_mission/run_multimission_example_large_single_aisle.py b/aviary/examples/multi_mission/run_multimission_example_large_single_aisle.py new file mode 100644 index 000000000..135952441 --- /dev/null +++ b/aviary/examples/multi_mission/run_multimission_example_large_single_aisle.py @@ -0,0 +1,312 @@ +""" +authors: Jatin Soni, Eliot Aretskin +Multi Mission Optimization Example using Aviary + +In this example, a monolithic optimization is created by instantiating two aviary problems +using typical AviaryProblem calls like load_inputs(), check_and_preprocess_payload(), +etc. Once those problems are setup and all of their phases are linked together, we copy +those problems as group into a super_problem. We then promote GROSS_MASS, RANGE, and +wing SWEEP from each of those sub-groups (group1 and group2) up to the super_probem so +the optimizer can control them. The fuel_burn results from each of the group1 and group2 +dymos missions are summed and weighted to create the objective function the optimizer sees. + +""" +import copy as copy +from aviary.examples.example_phase_info import phase_info +from aviary.variable_info.functions import setup_model_options +from aviary.variable_info.variables import Mission, Aircraft, Settings +from aviary.variable_info.enums import ProblemType +import aviary.api as av +import openmdao.api as om +import matplotlib.pyplot as plt +from os.path import join +import numpy as np +import dymos as dm +import warnings +import sys +from aviary.subsystems.mass.flops_based.furnishings import TransportFurnishingsGroupMass +from aviary.api import SubsystemBuilderBase +from aviary.validation_cases.validation_tests import get_flops_inputs + +# fly the same mission twice with two different passenger loads +phase_info_primary = copy.deepcopy(phase_info) +phase_info_deadhead = copy.deepcopy(phase_info) +# get large single aisle values +aviary_inputs_primary = get_flops_inputs('LargeSingleAisle2FLOPS') +aviary_inputs_primary.set_val(Mission.Design.GROSS_MASS, val=100000, units='lbm') +aviary_inputs_primary.set_val(Settings.VERBOSITY, val=1) + +aviary_inputs_deadhead = copy.deepcopy(aviary_inputs_primary) + +# Due to current limitations in Aviary's ability to detect user input vs. default values, +# the only way to set an aircraft to zero passengers is by setting +# TOTAL_PAYLOAD_MASS = X CARGO_MASS + 0 PASSENGER_PAYLOAD_MASS. +# This zeros out passenger and baggage mass. +# Due to issue #610, setting PASSENGER_PAYLOAD_MASS = 0 will not work yet. +# aviary_inputs_deadhead.set_val(Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS, 4077, 'lbm') + +aviary_inputs_deadhead.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 1, 'unitless') +aviary_inputs_deadhead.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 1, 'unitless') +aviary_inputs_deadhead.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0, 'unitless') +aviary_inputs_deadhead.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 0, 'unitless') + +Optimizer = 'SLSQP' # SLSQP or SNOPT + + +class MultiMissionProblem(om.Problem): + def __init__(self, aviary_values, phase_infos, weights): + super().__init__() + self.num_missions = len(aviary_values) + # phase infos and aviary_values length must match - this maybe unnecessary if + # different aviary_values (payloads) fly same mission (say pax vs cargo) + # or if same payload flies 2 different missions (altitude/mach differences) + if self.num_missions != len(phase_infos): + raise Exception("Length of aviary_values and phase_infos must be the same!") + + # if fewer weights than aviary_values are provided, assign equal weights for all aviary_values + if len(weights) < self.num_missions: + weights = [1]*self.num_missions + # if more weights than aviary_values, raise exception + elif len(weights) > self.num_missions: + raise Exception("Length of weights cannot exceed length of aviary_values!") + self.weights = weights + self.phase_infos = phase_infos + + self.group_prefix = 'group' + self.probs = [] + self.fuel_vars = [] + self.phases = {} + # define individual aviary problems + for i, (aviary_values, phase_info) in enumerate(zip(aviary_values, phase_infos)): + prob = av.AviaryProblem() + prob.load_inputs(aviary_values, phase_info) + prob.check_and_preprocess_inputs() + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + prob.link_phases() + + # alternate prevents use of equality constraint b/w design and summary gross mass + prob.problem_type = ProblemType.MULTI_MISSION + prob.add_design_variables() + self.probs.append(prob) + # phase names for each traj (can be used later to make plots/print outputs) + self.phases[f"{self.group_prefix}_{i}"] = list(prob.traj._phases.keys()) + + # design range and gross mass are promoted, these are Max Range/Max Takeoff Mass + # and must be the same for each aviary problem. Subsystems within aviary are sized + # using these - empty mass is same across all aviary problems. + # the fuel objective is also promoted since that's used in the compound objective + promoted_name = f"{self.group_prefix}_{i}_fuelobj" + self.fuel_vars.append(promoted_name) + self.model.add_subsystem( + self.group_prefix + f'_{i}', prob.model, + promotes_inputs=[Mission.Design.GROSS_MASS, + Mission.Design.RANGE, + Aircraft.Wing.SWEEP], + promotes_outputs=[(Mission.Summary.FUEL_BURNED, promoted_name)]) + + def add_design_variables(self): + self.model.add_design_var(Mission.Design.GROSS_MASS, + lower=10., upper=900e3, units='lbm') + self.model.add_design_var(Aircraft.Wing.SWEEP, lower=23., upper=27., units='deg') + + def add_driver(self): + self.driver = om.pyOptSparseDriver() + if Optimizer == "SLSQP": + self.driver.options["optimizer"] = "SLSQP" + elif Optimizer == "SNOPT": + self.driver.options["optimizer"] = "SNOPT" + self.driver.opt_settings["Major optimality tolerance"] = 1e-7 + self.driver.opt_settings["Major feasibility tolerance"] = 1e-7 + # self.driver.opt_settings["Major iterations"] = 0 + self.driver.opt_settings["iSumm"] = 6 + self.driver.opt_settings["iPrint"] = 9 + self.driver.opt_settings['Verify level'] = -1 + self.driver.opt_settings["Nonderivative linesearch"] = None + self.driver.declare_coloring() + # linear solver causes nan entry error for landing to takeoff mass ratio param + # self.model.linear_solver = om.DirectSolver() + + def add_objective(self): + # weights are normalized - e.g. for given weights 3:1, the normalized + # weights are 0.75:0.25 + weights = [float(weight/sum(self.weights)) for weight in self.weights] + weighted_str = "+".join([f"{fuelobj}*{weight}" + for fuelobj, weight in zip(self.fuel_vars, weights)]) + # weighted_str looks like: fuel_0 * weight[0] + fuel_1 * weight[1] + # note that the fuel objective itself is the base aviary fuel objective + # which is also a function of climb time becuse climb is not very sensitive to fuel + + # adding compound execComp to super problem + self.model.add_subsystem('compound_fuel_burn_objective', om.ExecComp( + "compound = "+weighted_str, has_diag_partials=True), + promotes_inputs=self.fuel_vars, + promotes_outputs=["compound"]) + self.model.add_objective('compound') + + def setup_wrapper(self): + """Wrapper for om.Problem setup with warning ignoring and setting options""" + for i, prob in enumerate(self.probs): + prob.model.options['aviary_options'] = prob.aviary_inputs + prob.model.options['aviary_metadata'] = prob.meta_data + prob.model.options['phase_info'] = prob.phase_info + + # Use OpenMDAO's model options to pass all options through the system hierarchy. + prefix = self.group_prefix + f'_{i}' + setup_model_options(self, prob.aviary_inputs, prob.meta_data, + prefix=f'{prefix}.') + + # Aviary's problem setup wrapper uses these ignored warnings to suppress + # some warnings related to variable promotion. Replicating that here with + # setup for the super problem + with warnings.catch_warnings(): + warnings.simplefilter("ignore", om.OpenMDAOWarning) + warnings.simplefilter("ignore", om.PromotionWarning) + self.setup(check='all') + + def run(self): + self.model.set_solver_print(0) + dm.run_problem(self, make_plots=False) + + def get_design_range(self): + """Finds the longest mission and sets its range as the design range for all + Aviary problems. Used within Aviary for sizing subsystems (avionics and AC).""" + design_range = [] + for phase_info in self.phase_infos: + design_range.append(phase_info['post_mission'] + ['target_range'][0]) # TBD add units + design_range_min = np.min(design_range) + design_range_max = np.max(design_range) + return design_range_max, design_range_min # design_range_min + + def create_timeseries_plots(self, plotvars=[], show=True): + """ + Temporary create plots manually because graphing won't work for dual-trajectories. + Creates timeseries plots for any variables within timeseries. Specify variables + and units by setting plotvars = [('altitude','ft')]. Any number of vars can be added. + """ + plt.figure() + for plotidx, (var, unit) in enumerate(plotvars): + plt.subplot(int(np.ceil(len(plotvars)/2)), 2, plotidx+1) + for i in range(self.num_missions): + time = np.array([]) + yvar = np.array([]) + # this loop concatenates data from all phases + for phase in self.phases[f"{self.group_prefix}_{i}"]: + rawt = self.get_val( + f"{self.group_prefix}_{i}.traj.{phase}.timeseries.time", + units='s') + rawy = self.get_val( + f"{self.group_prefix}_{i}.traj.{phase}.timeseries.{var}", + units=unit) + time = np.hstack([time, np.ndarray.flatten(rawt)]) + yvar = np.hstack([yvar, np.ndarray.flatten(rawy)]) + plt.plot(time, yvar, linewidth=self.num_missions-i) + plt.xlabel("Time (s)") + plt.ylabel(f"{var.title()} ({unit})") + plt.grid() + plt.figlegend([f"Mission {i}" for i in range(self.num_missions)]) + if show: + plt.show() + + def print_vars(self, vars=[]): + """Specify vars with name and unit in a tuple, e.g. vars = [ (Mission.Summary.FUEL_BURNED, 'lbm') ]""" + + print("\n\n=========================\n") + print(f"{'':40}", end=': ') + for i in range(self.num_missions): + name = f"Mission {i}" + print(f"{name:^30}", end='| ') + print() + for var, unit in vars: + varname = f"{var.replace(':', '.').upper()}" + print(f"{varname:40}", end=": ") + for i in range(self.num_missions): + try: + val = self.get_val(f'group_{i}.{var}', units=unit)[0] + printstatement = f"{val} ({unit})" + except: + printstatement = f"unable get get_val({var})" + print(f"{printstatement:^30}", end="| ") + print() + + +def large_single_aisle_example(makeN2=False): + aviary_values = [aviary_inputs_primary, + aviary_inputs_deadhead] + phase_infos = [phase_info_primary, + phase_info_deadhead] + optalt, optmach = False, False + for phaseinfo in phase_infos: + for key in phaseinfo.keys(): + if "user_options" in phaseinfo[key].keys(): + phaseinfo[key]["user_options"]["optimize_mach"] = optmach + phaseinfo[key]["user_options"]["optimize_altitude"] = optalt + + # how much each mission should be valued by the optimizer, larger numbers = more significance + weights = [9, 1] + + super_prob = MultiMissionProblem(aviary_values, phase_infos, weights) + super_prob.add_driver() + super_prob.add_design_variables() + super_prob.add_objective() + # set input default to prevent error, value doesn't matter since set val is used later + super_prob.model.set_input_defaults(Mission.Design.RANGE, val=1.) + super_prob.setup_wrapper() + super_prob.set_val(Mission.Design.RANGE, super_prob.get_design_range()[0]) + + for i, prob in enumerate(super_prob.probs): + prob.set_initial_guesses(super_prob, super_prob.group_prefix+f"_{i}.") + + if makeN2: + # TODO: Not sure we need this at all. + from openmdao.api import n2 + from os.path import basename, dirname, join, abspath + + def createN2(fileref, prob): + n2folder = join(dirname(abspath(__file__)), "N2s") + n2(prob, outfile=join(n2folder, + f"n2_{basename(fileref).split('.')[0]}.html")) + + createN2(__file__, super_prob) + + super_prob.run() + printoutputs = [ + (Mission.Design.GROSS_MASS, 'lbm'), + (Aircraft.Design.EMPTY_MASS, 'lbm'), + (Aircraft.Wing.SWEEP, 'deg'), + (Aircraft.LandingGear.MAIN_GEAR_MASS, 'lbm'), + (Aircraft.LandingGear.NOSE_GEAR_MASS, 'lbm'), + (Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO, 'unitless'), + (Aircraft.Furnishings.MASS, 'lbm'), + (Aircraft.CrewPayload.PASSENGER_SERVICE_MASS, 'lbm'), + (Mission.Summary.GROSS_MASS, 'lbm'), + (Mission.Summary.FUEL_BURNED, 'lbm'), + (Aircraft.CrewPayload.PASSENGER_MASS, 'lbm'), + (Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, 'lbm'), + (Aircraft.CrewPayload.CARGO_MASS, 'lbm'), + (Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS, 'lbm')] + super_prob.print_vars(vars=printoutputs) + + plotvars = [('altitude', 'ft'), + ('mass', 'lbm'), + ('drag', 'lbf'), + ('distance', 'nmi'), + ('throttle', 'unitless'), + ('mach', 'unitless')] + super_prob.create_timeseries_plots(plotvars=plotvars, show=False) + + plt.show() + + return super_prob + + +if __name__ == '__main__': + makeN2 = True if (len(sys.argv) > 1 and "n2" in sys.argv[1]) else False + + super_prob = large_single_aisle_example(makeN2=makeN2) + + # Uncomment the following lines to see mass breakdown details for each mission. + # super_prob.model.group_1.list_vars(val=True, units=True, print_arrays=False) + # super_prob.model.group_2.list_vars(val=True, units=True, print_arrays=False) diff --git a/aviary/examples/run_detailed_landing_in_level2.py b/aviary/examples/run_detailed_landing_in_level2.py index 82c6fd220..fb611ce78 100644 --- a/aviary/examples/run_detailed_landing_in_level2.py +++ b/aviary/examples/run_detailed_landing_in_level2.py @@ -1,3 +1,5 @@ + + import openmdao.api as om import aviary.api as av @@ -179,7 +181,12 @@ prob.run_aviary_problem(record_filename='detailed_landing.db') - cr = om.CaseReader('detailed_landing.db') + try: + loc = prob.get_outputs_dir() + cr = om.CaseReader(f'{loc}/detailed_landing.db') + except: + cr = om.CaseReader('detailed_landing.db') + cases = cr.get_cases('problem') case = cases[0] diff --git a/aviary/examples/run_detailed_takeoff_in_level2.py b/aviary/examples/run_detailed_takeoff_in_level2.py index 9b1607ea9..4a79899c2 100644 --- a/aviary/examples/run_detailed_takeoff_in_level2.py +++ b/aviary/examples/run_detailed_takeoff_in_level2.py @@ -355,7 +355,12 @@ prob.run_aviary_problem(record_filename='detailed_takeoff.db') - cr = om.CaseReader('detailed_takeoff.db') + try: + loc = prob.get_outputs_dir() + cr = om.CaseReader(f'{loc}/detailed_takeoff.db') + except: + cr = om.CaseReader('detailed_takeoff.db') + cases = cr.get_cases('problem') case = cases[0] diff --git a/aviary/interface/default_phase_info/height_energy_fiti.py b/aviary/interface/default_phase_info/height_energy_fiti.py index d96443ef6..dfb0b5901 100644 --- a/aviary/interface/default_phase_info/height_energy_fiti.py +++ b/aviary/interface/default_phase_info/height_energy_fiti.py @@ -34,13 +34,13 @@ "user_options": { 'mach': (cruise_mach, 'unitless'), 'alt_trigger': (1000, 'ft'), - Dynamic.Mission.THROTTLE: (0, 'unitless'), + Dynamic.Vehicle.Propulsion.THROTTLE: (0, 'unitless'), }, }, "post_mission": { "include_landing": False, "constrain_range": True, - "target_range": (1906., "nmi"), + "target_range": (1906.0, "nmi"), }, } diff --git a/aviary/interface/default_phase_info/two_dof_fiti.py b/aviary/interface/default_phase_info/two_dof_fiti.py index 0c4318f04..e8e66d501 100644 --- a/aviary/interface/default_phase_info/two_dof_fiti.py +++ b/aviary/interface/default_phase_info/two_dof_fiti.py @@ -109,7 +109,7 @@ 'alt_trigger': (10000, 'ft'), 'mach': (cruise_mach, 'unitless'), 'speed_trigger': (350, 'kn'), - Dynamic.Mission.THROTTLE: (0, 'unitless'), + Dynamic.Vehicle.Propulsion.THROTTLE: (0, 'unitless'), }, 'descent_phase': True, }, @@ -124,7 +124,7 @@ 'alt_trigger': (10000, 'ft'), 'EAS': (350, 'kn'), 'speed_trigger': (0, 'kn'), - Dynamic.Mission.THROTTLE: (0, 'unitless'), + Dynamic.Vehicle.Propulsion.THROTTLE: (0, 'unitless'), }, 'descent_phase': True, }, @@ -139,7 +139,7 @@ 'alt_trigger': (1000, 'ft'), 'EAS': (250, 'kn'), 'speed_trigger': (0, 'kn'), - Dynamic.Mission.THROTTLE: (0, 'unitless'), + Dynamic.Vehicle.Propulsion.THROTTLE: (0, 'unitless'), }, 'descent_phase': True, }, diff --git a/aviary/interface/methods_for_level1.py b/aviary/interface/methods_for_level1.py index 363f58e6c..35b59dc61 100644 --- a/aviary/interface/methods_for_level1.py +++ b/aviary/interface/methods_for_level1.py @@ -101,7 +101,9 @@ def run_aviary(aircraft_filename, phase_info, optimizer=None, prob.set_initial_guesses() prob.run_aviary_problem( - record_filename, restart_filename=restart_filename, run_driver=run_driver, make_plots=make_plots, optimization_history_filename=optimization_history_filename) + record_filename, restart_filename=restart_filename, run_driver=run_driver, + make_plots=make_plots, + optimization_history_filename=optimization_history_filename) return prob @@ -112,6 +114,7 @@ def run_level_1( optimizer='SNOPT', phase_info=None, max_iter=50, + verbosity=1, analysis_scheme=AnalysisScheme.COLLOCATION, ): ''' @@ -129,6 +132,7 @@ def run_level_1( # kwargs['optimizer'] = 'IPOPT' # else: kwargs['optimizer'] = optimizer + kwargs['verbosity'] = Verbosity(verbosity) if isinstance(phase_info, str): phase_info_path = get_path(phase_info) @@ -155,9 +159,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, 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" ) @@ -184,6 +187,12 @@ def _setup_level1_parser(parser): action="store_true", help="Use shooting instead of collocation", ) + parser.add_argument( + "--verbosity", + type=int, + default=1, + help="verbosity settings: 0=quiet, 1=brief, 2=verbose, 3=debug", + choices=(0, 1, 2, 3)) def _exec_level1(args, user_args): @@ -210,5 +219,6 @@ def _exec_level1(args, user_args): optimizer=args.optimizer, phase_info=args.phase_info, max_iter=args.max_iter, + verbosity=args.verbosity, analysis_scheme=analysis_scheme, ) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index f1e95ec82..09c782bf3 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -54,15 +54,14 @@ from aviary.utils.functions import create_opts2vals, add_opts2vals, promote_aircraft_and_mission_vars, wrapped_convert_units from aviary.utils.functions import convert_strings_to_data, set_value from aviary.utils.merge_variable_metadata import merge_meta_data -from aviary.utils.preprocessors import preprocess_crewpayload, preprocess_propulsion +from aviary.utils.preprocessors import preprocess_options from aviary.utils.process_input_decks import create_vehicle, update_GASP_options, initialization_guessing from aviary.variable_info.enums import AnalysisScheme, ProblemType, EquationsOfMotion, LegacyCode, Verbosity -from aviary.variable_info.functions import setup_trajectory_params, override_aviary_vars +from aviary.variable_info.functions import setup_trajectory_params, override_aviary_vars, setup_model_options from aviary.variable_info.variables import Aircraft, Mission, Dynamic, Settings from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData - FLOPS = LegacyCode.FLOPS GASP = LegacyCode.GASP @@ -260,7 +259,9 @@ def __init__(self, analysis_scheme=AnalysisScheme.COLLOCATION, **kwargs): self.regular_phases = [] self.reserve_phases = [] - def load_inputs(self, aviary_inputs, phase_info=None, engine_builders=None, meta_data=BaseMetaData, verbosity=Verbosity.BRIEF): + def load_inputs( + self, aviary_inputs, phase_info=None, engine_builders=None, + meta_data=BaseMetaData, verbosity=Verbosity.BRIEF): """ This method loads the aviary_values inputs and options that the user specifies. They could specify files to load and values to @@ -285,9 +286,10 @@ def load_inputs(self, aviary_inputs, phase_info=None, engine_builders=None, meta self.mass_method = mass_method = aviary_inputs.get_val(Settings.MASS_METHOD) if mission_method is TWO_DEGREES_OF_FREEDOM or mass_method is GASP: + # TODO this should be a preprocessor step if it is required here aviary_inputs = update_GASP_options(aviary_inputs) - initialization_guesses = initialization_guessing(aviary_inputs, initialization_guesses, - engine_builders) + initialization_guesses = initialization_guessing( + aviary_inputs, initialization_guesses, engine_builders) self.aviary_inputs = aviary_inputs self.initialization_guesses = initialization_guesses @@ -307,7 +309,8 @@ def load_inputs(self, aviary_inputs, phase_info=None, engine_builders=None, meta # Access the phase_info variable from the loaded module phase_info = outputted_phase_info.phase_info - # if verbosity level is BRIEF or higher, print that we're using the outputted phase info + # if verbosity level is BRIEF or higher, print that we're using the + # outputted phase info if verbosity is not None and verbosity >= Verbosity.BRIEF: print('Using outputted phase_info from current working directory') @@ -358,10 +361,14 @@ def load_inputs(self, aviary_inputs, phase_info=None, engine_builders=None, meta self.aviary_inputs = aviary_inputs if mission_method is TWO_DEGREES_OF_FREEDOM: - aviary_inputs.set_val(Mission.Summary.CRUISE_MASS_FINAL, - val=self.initialization_guesses['cruise_mass_final'], units='lbm') - aviary_inputs.set_val(Mission.Summary.GROSS_MASS, - val=self.initialization_guesses['actual_takeoff_mass'], units='lbm') + aviary_inputs.set_val( + Mission.Summary.CRUISE_MASS_FINAL, + val=self.initialization_guesses['cruise_mass_final'], + units='lbm') + aviary_inputs.set_val( + Mission.Summary.GROSS_MASS, + val=self.initialization_guesses['actual_takeoff_mass'], + units='lbm') # Commonly referenced values self.cruise_alt = aviary_inputs.get_val( @@ -371,24 +378,38 @@ def load_inputs(self, aviary_inputs, phase_info=None, engine_builders=None, meta self.cruise_mass_final = aviary_inputs.get_val( Mission.Summary.CRUISE_MASS_FINAL, units='lbm') - self.target_range = aviary_inputs.get_val( - Mission.Design.RANGE, units='NM') + + if self.post_mission_info is True and 'target_range' in self.post_mission_info: + self.target_range = wrapped_convert_units( + phase_info['post_mission']['target_range'], 'NM') + aviary_inputs.set_val(Mission.Summary.RANGE, + self.target_range, units='NM') + else: + self.target_range = aviary_inputs.get_val( + Mission.Design.RANGE, units='NM') + aviary_inputs.set_val(Mission.Summary.RANGE, aviary_inputs.get_val( + Mission.Design.RANGE, units='NM'), units='NM') self.cruise_mach = aviary_inputs.get_val(Mission.Design.MACH) self.require_range_residual = True elif mission_method is HEIGHT_ENERGY: self.problem_type = aviary_inputs.get_val(Settings.PROBLEM_TYPE) - aviary_inputs.set_val(Mission.Summary.GROSS_MASS, - val=self.initialization_guesses['actual_takeoff_mass'], units='lbm') + aviary_inputs.set_val( + Mission.Summary.GROSS_MASS, + val=self.initialization_guesses['actual_takeoff_mass'], + units='lbm') if 'target_range' in self.post_mission_info: - aviary_inputs.set_val(Mission.Design.RANGE, wrapped_convert_units( + aviary_inputs.set_val(Mission.Summary.RANGE, wrapped_convert_units( phase_info['post_mission']['target_range'], 'NM'), units='NM') self.require_range_residual = True + self.target_range = wrapped_convert_units( + phase_info['post_mission']['target_range'], 'NM') else: self.require_range_residual = False - - self.target_range = aviary_inputs.get_val( - Mission.Design.RANGE, units='NM') + # still instantiate target_range because it is used for default guesses + # for phase comps + self.target_range = aviary_inputs.get_val( + Mission.Design.RANGE, units='NM') return aviary_inputs @@ -457,7 +478,8 @@ def check_and_preprocess_inputs(self): for idx, phase_name in enumerate(self.phase_info): if 'user_options' in self.phase_info[phase_name]: if 'target_distance' in self.phase_info[phase_name]["user_options"]: - target_distance = self.phase_info[phase_name]["user_options"]["target_distance"] + target_distance = self.phase_info[phase_name]["user_options"][ + "target_distance"] if target_distance[0] <= 0: raise ValueError( f"Invalid target_distance in [{phase_name}].[user_options]. " @@ -470,19 +492,25 @@ def check_and_preprocess_inputs(self): for idx, phase_name in enumerate(self.phase_info): if 'user_options' in self.phase_info[phase_name]: analytic = False - if (self.analysis_scheme is AnalysisScheme.COLLOCATION) and (self.mission_method is EquationsOfMotion.TWO_DEGREES_OF_FREEDOM): + if (self.analysis_scheme is AnalysisScheme.COLLOCATION) and ( + self.mission_method is EquationsOfMotion.TWO_DEGREES_OF_FREEDOM): try: # if the user provided an option, use it - analytic = self.phase_info[phase_name]["user_options"]['analytic'] + analytic = self.phase_info[phase_name]["user_options"][ + 'analytic'] except KeyError: - # if it isn't specified, only the default 2DOF cruise for collocation is analytic + # if it isn't specified, only the default 2DOF cruise for + # collocation is analytic if 'cruise' in phase_name: - analytic = self.phase_info[phase_name]["user_options"]['analytic'] = True + analytic = self.phase_info[phase_name]["user_options"][ + 'analytic'] = True else: - analytic = self.phase_info[phase_name]["user_options"]['analytic'] = False + analytic = self.phase_info[phase_name]["user_options"][ + 'analytic'] = False if 'target_duration' in self.phase_info[phase_name]["user_options"]: - target_duration = self.phase_info[phase_name]["user_options"]["target_duration"] + target_duration = self.phase_info[phase_name]["user_options"][ + "target_duration"] if target_duration[0] <= 0: raise ValueError( f'Invalid target_duration in phase_info[{phase_name}]' @@ -495,11 +523,12 @@ def check_and_preprocess_inputs(self): # Set duration_bounds and initial_guesses for time: self.phase_info[phase_name]["user_options"].update({ "duration_bounds": ((target_duration[0], target_duration[0]), target_duration[1])}) - self.phase_info[phase_name].update({ - "initial_guesses": {"time": ((target_duration[0], target_duration[0]), target_duration[1])}}) + self.phase_info[phase_name].update({"initial_guesses": {"time": ( + (target_duration[0], target_duration[0]), target_duration[1])}}) # Set Fixed_duration to true: - self.phase_info[phase_name]["user_options"].update({ - "fix_duration": True}) + self.phase_info[phase_name]["user_options"].update( + {"fix_duration": True} + ) if self.analysis_scheme is AnalysisScheme.COLLOCATION: check_phase_info(self.phase_info, self.mission_method) @@ -511,8 +540,7 @@ def check_and_preprocess_inputs(self): # PREPROCESSORS # # Fill in anything missing in the options with computed defaults. - preprocess_propulsion(aviary_inputs, self.engine_builders) - preprocess_crewpayload(aviary_inputs) + preprocess_options(aviary_inputs, engine_models=self.engine_builders) mission_method = aviary_inputs.get_val(Settings.EQUATIONS_OF_MOTION) mass_method = aviary_inputs.get_val(Settings.MASS_METHOD) @@ -602,8 +630,9 @@ def add_pre_mission_systems(self): # Propulsion isn't included in core pre-mission group to avoid override step in # configure() - instead add it now - pre_mission.add_subsystem('core_propulsion', - subsystems['propulsion'].build_pre_mission(self.aviary_inputs),) + pre_mission.add_subsystem( + 'core_propulsion', subsystems['propulsion'].build_pre_mission( + self.aviary_inputs),) default_subsystems = [subsystems['geometry'], subsystems['aerodynamics'], @@ -648,7 +677,8 @@ def _add_two_dof_takeoff_systems(self): # Create options to values OptionsToValues = create_opts2vals( [Aircraft.CrewPayload.NUM_PASSENGERS, - Mission.Design.CRUISE_ALTITUDE, ]) + Mission.Design.CRUISE_ALTITUDE, ]) + add_opts2vals(self.model, OptionsToValues, self.aviary_inputs) if self.analysis_scheme is AnalysisScheme.SHOOTING: @@ -779,14 +809,16 @@ def _add_premission_external_subsystems(self): # Define the expression for computing the sum of masses expr = 'subsystem_mass = ' + ' + '.join(formatted_names) - promotes_inputs_list = [(formatted_name, original_name) - for formatted_name, original_name in zip(formatted_names, mass_names)] + promotes_inputs_list = [ + (formatted_name, original_name) for formatted_name, + original_name in zip(formatted_names, mass_names)] # Create the ExecComp - self.pre_mission.add_subsystem('external_comp_sum', om.ExecComp(expr, units='kg'), - promotes_inputs=promotes_inputs_list, - promotes_outputs=[ - ('subsystem_mass', Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS)]) + self.pre_mission.add_subsystem( + 'external_comp_sum', om.ExecComp(expr, units='kg'), + promotes_inputs=promotes_inputs_list, + promotes_outputs=[('subsystem_mass', Aircraft.Design. + EXTERNAL_SUBSYSTEMS_MASS)]) def _add_groundroll_eq_constraint(self): """ @@ -854,8 +886,8 @@ def _get_phase(self, phase_name, phase_idx): if 'phase_builder' in phase_options: phase_builder = phase_options['phase_builder'] if not issubclass(phase_builder, PhaseBuilderBase): - raise TypeError( - f"phase_builder for the phase called {phase_name} must be a PhaseBuilderBase object.") + raise TypeError(f"phase_builder for the phase called " + "{phase_name} must be a PhaseBuilderBase object.") else: phase_builder = EnergyPhase @@ -866,7 +898,8 @@ def _get_phase(self, phase_name, phase_idx): phase_builder = TwoDOFPhase phase_object = phase_builder.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data) + phase_name, phase_options, default_mission_subsystems, + meta_data=self.meta_data) phase = phase_object.build_phase(aviary_options=self.aviary_inputs) @@ -874,7 +907,8 @@ def _get_phase(self, phase_name, phase_idx): # TODO: add logic to filter which phases get which controls. # right now all phases get all controls added from every subsystem. - # for example, we might only want ELECTRIC_SHAFT_POWER applied during the climb phase. + # for example, we might only want ELECTRIC_SHAFT_POWER applied during the + # climb phase. all_subsystems = self._get_all_subsystems( phase_options['external_subsystems']) @@ -965,7 +999,8 @@ def _get_phase(self, phase_name, phase_idx): if fix_initial or input_initial: if self.comm.size > 1: - # Phases are disconnected to run in parallel, so initial ref is valid. + # Phases are disconnected to run in parallel, so initial ref is + # valid. initial_ref = user_options.get_val("initial_ref", time_units) else: # Redundant on a fixed input; raises a warning if specified. @@ -996,7 +1031,9 @@ def _get_phase(self, phase_name, phase_idx): if 'cruise' not in phase_name and self.mission_method is TWO_DEGREES_OF_FREEDOM: phase.add_control( - Dynamic.Mission.THROTTLE, targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, + units='unitless', opt=False, ) @@ -1017,9 +1054,8 @@ def add_phases(self, phase_info_parameterization=None): traj: The Dymos Trajectory object containing the added mission phases. """ if phase_info_parameterization is not None: - self.phase_info, self.post_mission_info = phase_info_parameterization(self.phase_info, - self.post_mission_info, - self.aviary_inputs) + self.phase_info, self.post_mission_info = phase_info_parameterization( + self.phase_info, self.post_mission_info, self.aviary_inputs) phase_info = self.phase_info @@ -1034,11 +1070,11 @@ def add_phases(self, phase_info_parameterization=None): full_traj = FlexibleTraj( Phases=self.phase_info, traj_final_state_output=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, ], traj_initial_state_input=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, ], @@ -1046,25 +1082,37 @@ def add_phases(self, phase_info_parameterization=None): # specify ODE, output_name, with units that SimuPyProblem expects # assume event function is of form ODE.output_name - value # third key is event_idx associated with input - ('groundroll', Dynamic.Mission.VELOCITY, 0,), - ('climb3', Dynamic.Mission.ALTITUDE, 0,), - ('cruise', Dynamic.Mission.MASS, 0,), + ( + 'groundroll', + Dynamic.Mission.VELOCITY, + 0, + ), + ( + 'climb3', + Dynamic.Mission.ALTITUDE, + 0, + ), + ( + 'cruise', + Dynamic.Vehicle.MASS, + 0, + ), ], traj_intermediate_state_output=[ ('cruise', Dynamic.Mission.DISTANCE), - ('cruise', Dynamic.Mission.MASS), - ] + ('cruise', Dynamic.Vehicle.MASS), + ], ) - traj = self.model.add_subsystem('traj', full_traj, promotes_inputs=[ - ('altitude_initial', Mission.Design.CRUISE_ALTITUDE)]) + traj = self.model.add_subsystem( + 'traj', full_traj, promotes_inputs=[ + ('altitude_initial', Mission.Design.CRUISE_ALTITUDE)]) self.model.add_subsystem( - 'actual_descent_fuel', - om.ExecComp('actual_descent_fuel = traj_cruise_mass_final - traj_mass_final', - actual_descent_fuel={'units': 'lbm'}, - traj_cruise_mass_final={'units': 'lbm'}, - traj_mass_final={'units': 'lbm'}, - )) + 'actual_descent_fuel', om.ExecComp( + 'actual_descent_fuel = traj_cruise_mass_final - traj_mass_final', + actual_descent_fuel={'units': 'lbm'}, + traj_cruise_mass_final={'units': 'lbm'}, + traj_mass_final={'units': 'lbm'},)) self.model.connect('start_of_descent_mass', 'traj.SGMCruise_mass_trigger') self.model.connect( @@ -1131,8 +1179,9 @@ def add_subsystem_timeseries_outputs(phase, phase_name): if not self.pre_mission_info['include_takeoff']: first_flight_phase_name = list(phase_info.keys())[0] first_flight_phase = traj._phases[first_flight_phase_name] - first_flight_phase.set_state_options(Dynamic.Mission.MASS, - fix_initial=False) + first_flight_phase.set_state_options( + Dynamic.Vehicle.MASS, fix_initial=False + ) self.traj = traj @@ -1185,7 +1234,7 @@ def add_post_mission_systems(self, include_landing=True): # Check if regular_phases[] is accessible try: self.regular_phases[0] - except: + except BaseException: raise ValueError( f"regular_phases[] dictionary is not accessible." f" For HEIGHT_ENERGY and SOLVED_2DOF missions, check_and_preprocess_inputs()" @@ -1197,8 +1246,9 @@ def add_post_mission_systems(self, include_landing=True): mass_final={'units': 'lbm'}, fuel_burned={'units': 'lbm'}) - self.post_mission.add_subsystem('fuel_burned', ecomp, - promotes=[('fuel_burned', Mission.Summary.FUEL_BURNED)]) + self.post_mission.add_subsystem( + 'fuel_burned', ecomp, + promotes=[('fuel_burned', Mission.Summary.FUEL_BURNED)]) if self.analysis_scheme is AnalysisScheme.SHOOTING: # shooting method currently doesn't have timeseries @@ -1212,7 +1262,8 @@ def add_post_mission_systems(self, include_landing=True): ('initial_mass', Mission.Summary.GROSS_MASS), ]) else: - # timeseries has to be used because Breguet cruise phases don't have states + # timeseries has to be used because Breguet cruise phases don't have + # states self.model.connect(f"traj.{self.regular_phases[0]}.timeseries.mass", "fuel_burned.initial_mass", src_indices=[0]) @@ -1226,28 +1277,34 @@ def add_post_mission_systems(self, include_landing=True): mass_final={'units': 'lbm'}, reserve_fuel_burned={'units': 'lbm'}) - self.post_mission.add_subsystem('reserve_fuel_burned', ecomp, - promotes=[('reserve_fuel_burned', Mission.Summary.RESERVE_FUEL_BURNED)]) + self.post_mission.add_subsystem( + 'reserve_fuel_burned', ecomp, promotes=[ + ('reserve_fuel_burned', Mission.Summary.RESERVE_FUEL_BURNED)]) if self.analysis_scheme is AnalysisScheme.SHOOTING: # shooting method currently doesn't have timeseries self.post_mission.promotes('reserve_fuel_burned', [ ('initial_mass', Mission.Landing.TOUCHDOWN_MASS), ]) - self.model.connect(f"traj.{self.reserve_phases[-1]}.states:mass", - "reserve_fuel_burned.mass_final", src_indices=[-1]) + self.model.connect( + f"traj.{self.reserve_phases[-1]}.states:mass", + "reserve_fuel_burned.mass_final", src_indices=[-1]) else: - # timeseries has to be used because Breguet cruise phases don't have states - self.model.connect(f"traj.{self.reserve_phases[0]}.timeseries.mass", - "reserve_fuel_burned.initial_mass", src_indices=[0]) - self.model.connect(f"traj.{self.reserve_phases[-1]}.timeseries.mass", - "reserve_fuel_burned.mass_final", src_indices=[-1]) + # timeseries has to be used because Breguet cruise phases don't have + # states + self.model.connect( + f"traj.{self.reserve_phases[0]}.timeseries.mass", + "reserve_fuel_burned.initial_mass", src_indices=[0]) + self.model.connect( + f"traj.{self.reserve_phases[-1]}.timeseries.mass", + "reserve_fuel_burned.mass_final", src_indices=[-1]) self._add_fuel_reserve_component() # TODO: need to add some sort of check that this value is less than the fuel capacity # TODO: the overall_fuel variable is the burned fuel plus the reserve, but should - # also include the unused fuel, and the hierarchy variable name should be more clear + # also include the unused fuel, and the hierarchy variable name should be + # more clear ecomp = om.ExecComp('overall_fuel = (1 + fuel_margin/100)*fuel_burned + reserve_fuel', overall_fuel={'units': 'lbm', 'shape': 1}, fuel_margin={"units": "unitless", 'val': 0}, @@ -1264,26 +1321,29 @@ def add_post_mission_systems(self, include_landing=True): promotes_outputs=[('overall_fuel', Mission.Summary.TOTAL_FUEL_MASS)]) # If a target distance (or time) has been specified for this phase - # distance (or time) is measured from the start of this phase to the end of this phase + # distance (or time) is measured from the start of this phase to the end + # of this phase for phase_name in self.phase_info: if 'target_distance' in self.phase_info[phase_name]["user_options"]: target_distance = wrapped_convert_units( - self.phase_info[phase_name]["user_options"]["target_distance"], 'nmi') + self.phase_info[phase_name]["user_options"] + ["target_distance"], + 'nmi') self.post_mission.add_subsystem( - f"{phase_name}_distance_constraint", - om.ExecComp( + f"{phase_name}_distance_constraint", om.ExecComp( "distance_resid = target_distance - (final_distance - initial_distance)", distance_resid={'units': 'nmi'}, target_distance={'val': target_distance, 'units': 'nmi'}, final_distance={'units': 'nmi'}, - initial_distance={'units': 'nmi'}, - )) + initial_distance={'units': 'nmi'},)) self.model.connect( f"traj.{phase_name}.timeseries.distance", - f"{phase_name}_distance_constraint.final_distance", src_indices=[-1]) + f"{phase_name}_distance_constraint.final_distance", + src_indices=[-1]) self.model.connect( f"traj.{phase_name}.timeseries.distance", - f"{phase_name}_distance_constraint.initial_distance", src_indices=[0]) + f"{phase_name}_distance_constraint.initial_distance", + src_indices=[0]) self.model.add_constraint( f"{phase_name}_distance_constraint.distance_resid", equals=0.0, ref=1e2) @@ -1291,22 +1351,23 @@ def add_post_mission_systems(self, include_landing=True): if 'target_duration' in self.phase_info[phase_name]["user_options"] and \ self.phase_info[phase_name]["user_options"].get("analytic", False): target_duration = wrapped_convert_units( - self.phase_info[phase_name]["user_options"]["target_duration"], 'min') + self.phase_info[phase_name]["user_options"] + ["target_duration"], + 'min') self.post_mission.add_subsystem( - f"{phase_name}_duration_constraint", - om.ExecComp( + f"{phase_name}_duration_constraint", om.ExecComp( "duration_resid = target_duration - (final_time - initial_time)", duration_resid={'units': 'min'}, target_duration={'val': target_duration, 'units': 'min'}, final_time={'units': 'min'}, - initial_time={'units': 'min'}, - )) + initial_time={'units': 'min'},)) self.model.connect( f"traj.{phase_name}.timeseries.time", f"{phase_name}_duration_constraint.final_time", src_indices=[-1]) self.model.connect( f"traj.{phase_name}.timeseries.time", - f"{phase_name}_duration_constraint.initial_time", src_indices=[0]) + f"{phase_name}_duration_constraint.initial_time", + src_indices=[0]) self.model.add_constraint( f"{phase_name}_duration_constraint.duration_resid", equals=0.0, ref=1e2) @@ -1341,13 +1402,12 @@ def add_post_mission_systems(self, include_landing=True): Mission.Constraints.MASS_RESIDUAL, equals=0.0, ref=1.e5) if self.mission_method is HEIGHT_ENERGY: - + # connect summary mass to the initial guess of mass in the first phase if not self.pre_mission_info['include_takeoff']: first_flight_phase_name = list(self.phase_info.keys())[0] - eq = self.model.add_subsystem(f'link_{first_flight_phase_name}_mass', - om.EQConstraintComp(), - promotes_inputs=[('rhs:mass', - Mission.Summary.GROSS_MASS)]) + eq = self.model.add_subsystem( + f'link_{first_flight_phase_name}_mass', om.EQConstraintComp(), + promotes_inputs=[('rhs:mass', Mission.Summary.GROSS_MASS)]) eq.add_eq_output('mass', eq_units='lbm', normalize=False, ref=100000., add_constraint=True) self.model.connect( @@ -1385,7 +1445,8 @@ def _link_phases_helper_with_options(self, phases, option_name, var, **kwargs): # Loop through each group and determine the phases to link for group in groups_to_link: - # Extend the group to include the phase before the first True option and after the last True option, if applicable + # Extend the group to include the phase before the first True option and + # after the last True option, if applicable if group[0] > 0: group.insert(0, group[0] - 1) if group[-1] < len(phases) - 1: @@ -1451,22 +1512,33 @@ def link_phases(self): if self.mission_method in (HEIGHT_ENERGY, SOLVED_2DOF): # connect regular_phases with each other if you are optimizing alt or mach self._link_phases_helper_with_options( - self.regular_phases, 'optimize_altitude', Dynamic.Mission.ALTITUDE, ref=1.e4) + self.regular_phases, + 'optimize_altitude', + Dynamic.Mission.ALTITUDE, + ref=1.0e4, + ) self._link_phases_helper_with_options( - self.regular_phases, 'optimize_mach', Dynamic.Mission.MACH) + self.regular_phases, 'optimize_mach', Dynamic.Atmosphere.MACH + ) # connect reserve phases with each other if you are optimizing alt or mach self._link_phases_helper_with_options( - self.reserve_phases, 'optimize_altitude', Dynamic.Mission.ALTITUDE, ref=1.e4) + self.reserve_phases, + 'optimize_altitude', + Dynamic.Mission.ALTITUDE, + ref=1.0e4, + ) self._link_phases_helper_with_options( - self.reserve_phases, 'optimize_mach', Dynamic.Mission.MACH) + self.reserve_phases, 'optimize_mach', Dynamic.Atmosphere.MACH + ) if self.mission_method is HEIGHT_ENERGY: - # connect mass and distance between all phases regardless of reserve / non-reserve status + # connect mass and distance between all phases regardless of reserve / + # non-reserve status self.traj.link_phases(phases, ["time"], ref=None if true_unless_mpi else 1e3, connected=true_unless_mpi) - self.traj.link_phases(phases, [Dynamic.Mission.MASS], + self.traj.link_phases(phases, [Dynamic.Vehicle.MASS], ref=None if true_unless_mpi else 1e6, connected=true_unless_mpi) self.traj.link_phases(phases, [Dynamic.Mission.DISTANCE], @@ -1474,13 +1546,14 @@ def link_phases(self): connected=true_unless_mpi) self.model.connect(f'traj.{self.regular_phases[-1]}.timeseries.distance', - Mission.Summary.RANGE, + 'actual_range', src_indices=[-1], flat_src_indices=True) elif self.mission_method is SOLVED_2DOF: - self.traj.link_phases(phases, [Dynamic.Mission.MASS], connected=True) + self.traj.link_phases(phases, [Dynamic.Vehicle.MASS], connected=True) self.traj.link_phases( - phases, [Dynamic.Mission.DISTANCE], units='ft', ref=1.e3, connected=False) + phases, [Dynamic.Mission.DISTANCE], + units='ft', ref=1.e3, connected=False) self.traj.link_phases(phases, ["time"], connected=False) if len(phases) > 2: @@ -1489,8 +1562,8 @@ def link_phases(self): elif self.mission_method is TWO_DEGREES_OF_FREEDOM: if self.analysis_scheme is AnalysisScheme.COLLOCATION: - for ii in range(len(phases)-1): - phase1, phase2 = phases[ii:ii+2] + for ii in range(len(phases) - 1): + phase1, phase2 = phases[ii:ii + 2] analytic1 = self.phase_info[phase1]['user_options']['analytic'] analytic2 = self.phase_info[phase2]['user_options']['analytic'] @@ -1499,7 +1572,7 @@ def link_phases(self): states_to_link = { 'time': true_unless_mpi, Dynamic.Mission.DISTANCE: true_unless_mpi, - Dynamic.Mission.MASS: False, + Dynamic.Vehicle.MASS: False, } # if both phases are reserve phases or neither is a reserve phase @@ -1513,18 +1586,23 @@ def link_phases(self): # if either phase is rotation, we need to connect velocity # ascent to accel also requires velocity - if 'rotation' in (phase1, phase2) or ('ascent', 'accel') == (phase1, phase2): + if 'rotation' in ( + phase1, phase2) or ( + 'ascent', 'accel') == ( + phase1, phase2): states_to_link[Dynamic.Mission.VELOCITY] = true_unless_mpi # if the first phase is rotation, we also need alpha if phase1 == 'rotation': states_to_link['alpha'] = False for state, connected in states_to_link.items(): - # in initial guesses, all of the states, other than time use the same name + # in initial guesses, all of the states, other than time use + # the same name initial_guesses1 = self.phase_info[phase1]['initial_guesses'] initial_guesses2 = self.phase_info[phase2]['initial_guesses'] - # if a state is in the initial guesses, get the units of the initial guess + # if a state is in the initial guesses, get the units of the + # initial guess kwargs = {} if not connected: if state in initial_guesses1: @@ -1537,16 +1615,18 @@ def link_phases(self): # if either phase is analytic we have to use a linkage_constraint else: - # analytic phases use the prefix "initial" for time and distance, but not mass + # analytic phases use the prefix "initial" for time and distance, + # but not mass if analytic2: prefix = 'initial_' else: prefix = '' self.traj.add_linkage_constraint( - phase1, phase2, 'time', prefix+'time', connected=True) + phase1, phase2, 'time', prefix + 'time', connected=True) self.traj.add_linkage_constraint( - phase1, phase2, 'distance', prefix+'distance', connected=True) + phase1, phase2, 'distance', prefix + 'distance', + connected=True) self.traj.add_linkage_constraint( phase1, phase2, 'mass', 'mass', connected=False, ref=1.0e5) @@ -1592,14 +1672,14 @@ def link_phases(self): Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) connect_map = { - f"traj.{self.regular_phases[-1]}.timeseries.distance": Mission.Summary.RANGE, + f"traj.{self.regular_phases[-1]}.timeseries.distance": 'actual_range', } else: connect_map = { "taxi.mass": "traj.mass_initial", Mission.Takeoff.ROTATION_VELOCITY: "traj.SGMGroundroll_velocity_trigger", - "traj.distance_final": Mission.Summary.RANGE, + "traj.distance_final": 'actual_range', "traj.mass_final": Mission.Landing.TOUCHDOWN_MASS, } @@ -1626,7 +1706,9 @@ def connect_with_common_params(self, source, target): for source, target in connect_map.items(): connect_with_common_params(self, source, target) - def add_driver(self, optimizer=None, use_coloring=None, max_iter=50, verbosity=Verbosity.BRIEF): + def add_driver( + self, optimizer=None, use_coloring=None, max_iter=50, + verbosity=Verbosity.BRIEF): """ Add an optimization driver to the Aviary problem. @@ -1751,7 +1833,8 @@ def add_design_variables(self): In all cases, a design variable is added for the final cruise mass of the aircraft, with no upper bound, and a residual mass constraint is added to ensure that the mass balances. """ - # add the engine builder `get_design_vars` dict to a collected dict from the external subsystems + # add the engine builder `get_design_vars` dict to a collected dict from + # the external subsystems # TODO : maybe in the most general case we need to handle DVs in the mission and post-mission as well. # for right now we just handle pre_mission @@ -1771,7 +1854,8 @@ def add_design_variables(self): elif self.mission_method in (HEIGHT_ENERGY, TWO_DEGREES_OF_FREEDOM): # vehicle sizing problem - # size the vehicle (via design GTOW) to meet a target range using all fuel capacity + # size the vehicle (via design GTOW) to meet a target range using all fuel + # capacity if self.problem_type is ProblemType.SIZING: self.model.add_design_var( Mission.Design.GROSS_MASS, @@ -1808,12 +1892,13 @@ def add_design_variables(self): ) # target range problem - # fixed vehicle (design GTOW) but variable actual GTOW for off-design mission range + # fixed vehicle (design GTOW) but variable actual GTOW for off-design + # mission range elif self.problem_type is ProblemType.ALTERNATE: self.model.add_design_var( Mission.Summary.GROSS_MASS, - lower=0, - upper=None, + lower=10., + upper=900e3, units='lbm', ref=175e3, ) @@ -1825,6 +1910,42 @@ def add_design_variables(self): elif self.problem_type is ProblemType.FALLOUT: print('No design variables for Fallout missions') + elif self.problem_type is ProblemType.MULTI_MISSION: + self.model.add_design_var( + Mission.Summary.GROSS_MASS, + lower=10., + upper=900e3, + units='lbm', + ref=175e3, + ) + + self.model.add_constraint( + Mission.Constraints.RANGE_RESIDUAL, equals=0, ref=10 + ) + + # We must ensure that design.gross_mass is greater than mission.summary.gross_mass + # and this must hold true for each of the different missions that is flown + # the result will be the design.gross_mass should be equal to the mission.summary.gross_mass + # of the heaviest mission + self.model.add_subsystem( + "GROSS_MASS_constraint", + om.ExecComp( + "gross_mass_resid = design_mass - actual_mass", + design_mass={"val": 1, "units": "kg"}, + actual_mass={"val": 0, "units": "kg"}, + gross_mass_resid={"val": 30, "units": "kg"}, + ), + promotes_inputs=[ + ("design_mass", Mission.Design.GROSS_MASS), + ("actual_mass", Mission.Summary.GROSS_MASS), + ], + promotes_outputs=["gross_mass_resid"], + ) + + self.model.add_constraint( + "gross_mass_resid", lower=0 + ) + if self.mission_method is TWO_DEGREES_OF_FREEDOM and self.analysis_scheme is AnalysisScheme.COLLOCATION: # problem formulation to make the trajectory work self.model.add_design_var(Mission.Takeoff.ASCENT_T_INTIIAL, @@ -1878,11 +1999,14 @@ def add_objective(self, objective_type=None, ref=None): if objective_type == 'mass': if self.analysis_scheme is AnalysisScheme.COLLOCATION: self.model.add_objective( - f"traj.{final_phase_name}.timeseries.{Dynamic.Mission.MASS}", index=-1, ref=ref) + f"traj.{final_phase_name}.timeseries.{Dynamic.Vehicle.MASS}", + index=-1, + ref=ref + ) else: last_phase = self.traj._phases.items()[final_phase_name] last_phase.add_objective( - Dynamic.Mission.MASS, loc='final', ref=ref) + Dynamic.Vehicle.MASS, loc='final', ref=ref) elif objective_type == 'time': self.model.add_objective( f"traj.{final_phase_name}.timeseries.time", index=-1, ref=ref) @@ -1894,8 +2018,9 @@ def add_objective(self, objective_type=None, ref=None): elif objective_type == "fuel": self.model.add_objective(Mission.Objectives.FUEL, ref=ref) else: - raise ValueError(f"{objective_type} is not a valid objective.\nobjective_type must" - " be one of mass, time, hybrid_objective, fuel_burned, or fuel") + raise ValueError( + f"{objective_type} is not a valid objective.\nobjective_type must" + " be one of mass, time, hybrid_objective, fuel_burned, or fuel") else: # If no 'objective_type' is specified, we handle based on 'problem_type' # If 'ref' is not specified, assign a default value @@ -1925,7 +2050,8 @@ def _add_bus_variables_and_connect(self): if not isinstance(mission_variable_name, list): mission_variable_name = [mission_variable_name] - # loop over the mission_variable_name list and add each variable to the trajectory + # loop over the mission_variable_name list and add each variable to + # the trajectory for mission_var_name in mission_variable_name: if mission_var_name not in self.meta_data: # base_units = self.model.get_io_metadata(includes=f'pre_mission.{external_subsystem.name}.{bus_variable}')[f'pre_mission.{external_subsystem.name}.{bus_variable}']['units'] @@ -1944,28 +2070,39 @@ def _add_bus_variables_and_connect(self): for phase_name in variable_data['phases']: phase = getattr(self.traj.phases, phase_name) - phase.add_parameter(mission_var_name, opt=False, static_target=True, - units=base_units, shape=shape, targets=targets) + phase.add_parameter( + mission_var_name, opt=False, static_target=True, + units=base_units, shape=shape, targets=targets) - self.model.connect(f'pre_mission.{bus_variable}', - f'traj.{phase_name}.parameters:{mission_var_name}') + self.model.connect( + f'pre_mission.{bus_variable}', + f'traj.{phase_name}.parameters:{mission_var_name}') else: - self.traj.add_parameter(mission_var_name, opt=False, static_target=True, - units=base_units, shape=shape, targets={ - phase_name: [mission_var_name] for phase_name in base_phases}) + self.traj.add_parameter( + mission_var_name, opt=False, static_target=True, + units=base_units, shape=shape, + targets={phase_name: [mission_var_name] + for phase_name in base_phases}) self.model.connect( - f'pre_mission.{bus_variable}', f'traj.parameters:'+mission_var_name) + f'pre_mission.{bus_variable}', + f'traj.parameters:' + mission_var_name) if 'post_mission_name' in variable_data: - self.model.connect(f'pre_mission.{external_subsystem.name}.{bus_variable}', - f'post_mission.{external_subsystem.name}.{variable_data["post_mission_name"]}') + self.model.connect( + f'pre_mission.{external_subsystem.name}.{bus_variable}', + f'post_mission.{external_subsystem.name}.' + f'{variable_data["post_mission_name"]}', + ) def setup(self, **kwargs): """ Lightly wrapped setup() method for the problem. """ + # Use OpenMDAO's model options to pass all options through the system hierarchy. + setup_model_options(self, self.aviary_inputs, self.meta_data) + # suppress warnings: # "input variable '...' promoted using '*' was already promoted using 'aircraft:*' with warnings.catch_warnings(): @@ -1976,14 +2113,14 @@ def setup(self, **kwargs): warnings.simplefilter("ignore", om.OpenMDAOWarning) warnings.simplefilter("ignore", om.PromotionWarning) + super().setup(**kwargs) - def set_initial_guesses(self): + def set_initial_guesses(self, parent_prob=None, parent_prefix=""): """ Call `set_val` on the trajectory for states and controls to seed the problem with reasonable initial guesses. This is especially important for collocation methods. - This method first identifies all phases in the trajectory then loops over each phase. Specific initial guesses are added depending on the phase and mission method. Cruise is treated @@ -1993,14 +2130,20 @@ def set_initial_guesses(self): guesses for states and controls according to the information available in the 'initial_guesses' attribute of the phase. """ + setvalprob = self + if parent_prob is not None and parent_prefix != "": + setvalprob = parent_prob # Grab the trajectory object from the model if self.analysis_scheme is AnalysisScheme.SHOOTING: if self.problem_type is ProblemType.SIZING: - self.set_val(Mission.Summary.GROSS_MASS, - self.get_val(Mission.Design.GROSS_MASS)) + setvalprob.set_val(parent_prefix + Mission.Summary.GROSS_MASS, + self.get_val(Mission.Design.GROSS_MASS)) - self.set_val("traj.SGMClimb_"+Dynamic.Mission.ALTITUDE + - "_trigger", val=self.cruise_alt, units="ft") + setvalprob.set_val(parent_prefix + + "traj.SGMClimb_" + Dynamic.Mission.ALTITUDE + "_trigger", + val=self.cruise_alt, + units="ft", + ) return @@ -2009,7 +2152,8 @@ def set_initial_guesses(self): # Determine which phases to loop over, fetching them from the trajectory phase_items = traj._phases.items() - # Loop over each phase and set initial guesses for the state and control variables + # Loop over each phase and set initial guesses for the state and control + # variables for idx, (phase_name, phase) in enumerate(phase_items): if self.mission_method is SOLVED_2DOF: self.phase_objects[idx].apply_initial_guesses(self, 'traj', phase) @@ -2031,37 +2175,42 @@ def set_initial_guesses(self): if 'mass' == guess_key: # Set initial and duration mass for the analytic cruise phase. # Note we are integrating over mass, not time for this phase. - self.set_val(f'traj.{phase_name}.t_initial', - val[0], units=units) - self.set_val(f'traj.{phase_name}.t_duration', - val[1], units=units) + setvalprob.set_val( + parent_prefix + + f'traj.{phase_name}.t_initial', + val[0], + units=units) + setvalprob.set_val( + parent_prefix + + f'traj.{phase_name}.t_duration', + val[1], + units=units) else: - # Otherwise, set the value of the parameter in the trajectory phase - self.set_val(f'traj.{phase_name}.parameters:{guess_key}', - val, units=units) + # Otherwise, set the value of the parameter in the trajectory + # phase + setvalprob.set_val( + parent_prefix + f'traj.{phase_name}.parameters:{guess_key}', + val, units=units) continue # If not cruise and GASP, add subsystem guesses - self._add_subsystem_guesses(phase_name, phase) + self._add_subsystem_guesses(phase_name, phase, setvalprob, parent_prefix) # Set initial guesses for states and controls for each phase - self._add_guesses(phase_name, phase, guesses) + self._add_guesses(phase_name, phase, guesses, setvalprob, parent_prefix) def _process_guess_var(self, val, key, phase): """ Process the guess variable, which can either be a float or an array of floats. - This method is responsible for interpolating initial guesses when the user provides a list or array of values rather than a single float. It interpolates the guess values across the phase's domain for a given variable, be it a control or a state variable. The interpolation is performed between -1 and 1 (representing the normalized phase time domain), using the numpy linspace function. - The result of this method is a single value or an array of interpolated values that can be used to seed the optimization problem with initial guesses. - Parameters ---------- val : float or list/array of floats @@ -2070,13 +2219,11 @@ def _process_guess_var(self, val, key, phase): The key identifying the variable for which the initial guess is provided. phase : Phase The phase for which the variable is being set. - Returns ------- val : float or array of floats The processed guess value(s) to be used in the optimization problem. """ - # Check if val is not a single float if not isinstance(val, float): # If val is an array of values @@ -2090,28 +2237,28 @@ def _process_guess_var(self, val, key, phase): # Check if the key indicates a control or state variable if "controls:" in key or "states:" in key: - # If so, strip the first part of the key to match the variable name in phase + # If so, strip the first part of the key to match the variable name + # in phase stripped_key = ":".join(key.split(":")[1:]) # Interpolate the initial guess values across the phase's domain val = phase.interp(stripped_key, xs=xs, ys=val) else: - # If not a control or state variable, interpolate the initial guess values directly + # If not a control or state variable, interpolate the initial guess + # values directly val = phase.interp(key, xs=xs, ys=val) # Return the processed guess value(s) return val - def _add_subsystem_guesses(self, phase_name, phase): + def _add_subsystem_guesses(self, phase_name, phase, setvalprob, parent_prefix): """ Adds the initial guesses for each subsystem of a given phase to the problem. - This method first fetches all subsystems associated with the given phase. It then loops over each subsystem and fetches its initial guesses. For each guess, it identifies whether the guess corresponds to a state or a control variable and then processes the guess variable. After this, the initial guess is set in the problem using the `set_val` method. - Parameters ---------- phase_name : str @@ -2142,18 +2289,17 @@ def _add_subsystem_guesses(self, phase_name, phase): val['val'] = self._process_guess_var(val['val'], key, phase) # Set the initial guess in the problem - self.set_val(f'traj.{phase_name}.{path_string}:{key}', **val) + setvalprob.set_val( + parent_prefix + f'traj.{phase_name}.{path_string}:{key}', **val) - def _add_guesses(self, phase_name, phase, guesses): + def _add_guesses(self, phase_name, phase, guesses, setvalprob, parent_prefix): """ Adds the initial guesses for each variable of a given phase to the problem. - This method sets the initial guesses for time, control, state, and problem-specific variables for a given phase. If using the GASP model, it also handles some special cases that are not covered in the `phase_info` object. These include initial guesses for mass, time, and distance, which are determined based on the phase name and other mission-related variables. - Parameters ---------- phase_name : str @@ -2163,8 +2309,8 @@ def _add_guesses(self, phase_name, phase, guesses): guesses : dict A dictionary containing the initial guesses for the phase. """ - - # If using the GASP model, set initial guesses for the rotation mass and flight duration + # If using the GASP model, set initial guesses for the rotation mass and + # flight duration if self.mission_method is TWO_DEGREES_OF_FREEDOM: rotation_mass = self.initialization_guesses['rotation_mass'] flight_duration = self.initialization_guesses['flight_duration'] @@ -2174,15 +2320,22 @@ def _add_guesses(self, phase_name, phase, guesses): state_keys = ["mass", Dynamic.Mission.DISTANCE] else: control_keys = ["velocity_rate", "throttle"] - state_keys = ["altitude", "mass", - Dynamic.Mission.DISTANCE, Dynamic.Mission.VELOCITY, "flight_path_angle", "alpha"] + state_keys = [ + "altitude", + "mass", + Dynamic.Mission.DISTANCE, + Dynamic.Mission.VELOCITY, + "flight_path_angle", + "alpha", + ] if self.mission_method is TWO_DEGREES_OF_FREEDOM and phase_name == 'ascent': # Alpha is a control for ascent. control_keys.append('alpha') prob_keys = ["tau_gear", "tau_flaps"] - # for the simple mission method, use the provided initial and final mach and altitude values from phase_info + # for the simple mission method, use the provided initial and final mach + # and altitude values from phase_info if self.mission_method in (HEIGHT_ENERGY, SOLVED_2DOF): initial_altitude = wrapped_convert_units( self.phase_info[phase_name]['user_options']['initial_altitude'], 'ft') @@ -2195,7 +2348,8 @@ def _add_guesses(self, phase_name, phase, guesses): guesses["altitude"] = ([initial_altitude, final_altitude], 'ft') if self.mission_method is HEIGHT_ENERGY: - # if time not in initial guesses, set it to the average of the initial_bounds and the duration_bounds + # if time not in initial guesses, set it to the average of the + # initial_bounds and the duration_bounds if 'time' not in guesses: initial_bounds = wrapped_convert_units( self.phase_info[phase_name]['user_options']['initial_bounds'], 's') @@ -2204,14 +2358,20 @@ def _add_guesses(self, phase_name, phase, guesses): guesses["time"] = ([np.mean(initial_bounds[0]), np.mean( duration_bounds[0])], 's') - # if time not in initial guesses, set it to the average of the initial_bounds and the duration_bounds + # if time not in initial guesses, set it to the average of the + # initial_bounds and the duration_bounds if 'time' not in guesses: - initial_bounds = self.phase_info[phase_name]['user_options']['initial_bounds'] - duration_bounds = self.phase_info[phase_name]['user_options']['duration_bounds'] - # Add a check for the initial and duration bounds, raise an error if they are not consistent + initial_bounds = self.phase_info[phase_name]['user_options'][ + 'initial_bounds'] + duration_bounds = self.phase_info[phase_name]['user_options'][ + 'duration_bounds'] + # Add a check for the initial and duration bounds, raise an error if they + # are not consistent if initial_bounds[1] != duration_bounds[1]: raise ValueError( - f"Initial and duration bounds for {phase_name} are not consistent.") + f"Initial and duration bounds for {phase_name} " + "are not consistent." + ) guesses["time"] = ([np.mean(initial_bounds[0]), np.mean( duration_bounds[0])], initial_bounds[1]) @@ -2220,24 +2380,33 @@ def _add_guesses(self, phase_name, phase, guesses): # Set initial guess for time variables if 'time' == guess_key and self.mission_method is not SOLVED_2DOF: - self.set_val(f'traj.{phase_name}.t_initial', - val[0], units=units) - self.set_val(f'traj.{phase_name}.t_duration', - val[1], units=units) + setvalprob.set_val(parent_prefix + f'traj.{phase_name}.t_initial', + val[0], units=units) + setvalprob.set_val(parent_prefix + f'traj.{phase_name}.t_duration', + val[1], units=units) else: # Set initial guess for control variables if guess_key in control_keys: try: - self.set_val(f'traj.{phase_name}.controls:{guess_key}', self._process_guess_var( - val, guess_key, phase), units=units) + setvalprob.set_val( + parent_prefix + f'traj.{phase_name}.controls:{guess_key}', + self._process_guess_var(val, guess_key, phase), + units=units) except KeyError: try: - self.set_val(f'traj.{phase_name}.polynomial_controls:{guess_key}', self._process_guess_var( - val, guess_key, phase), units=units) + setvalprob.set_val( + parent_prefix + + f'traj.{phase_name}.polynomial_controls:{guess_key}', + self._process_guess_var(val, guess_key, phase), + units=units) except KeyError: - self.set_val(f'traj.{phase_name}.bspline_controls:{guess_key}', self._process_guess_var( - val, guess_key, phase), units=units) + setvalprob.set_val(parent_prefix + + f'traj.{phase_name}.bspline_controls:', + {guess_key}, + self._process_guess_var( + val, guess_key, phase), + units=units) if self.mission_method is SOLVED_2DOF: continue @@ -2246,17 +2415,27 @@ def _add_guesses(self, phase_name, phase, guesses): pass # Set initial guess for state variables elif guess_key in state_keys: - self.set_val(f'traj.{phase_name}.states:{guess_key}', self._process_guess_var( - val, guess_key, phase), units=units) + setvalprob.set_val(parent_prefix + + f'traj.{phase_name}.states:{guess_key}', self. + _process_guess_var(val, guess_key, phase), + units=units) elif guess_key in prob_keys: - self.set_val(guess_key, val, units=units) + setvalprob.set_val(parent_prefix + guess_key, val, units=units) elif ":" in guess_key: - self.set_val(f'traj.{phase_name}.{guess_key}', self._process_guess_var( - val, guess_key, phase), units=units) + setvalprob.set_val( + parent_prefix + + f'traj.{phase_name}.{guess_key}', + self._process_guess_var( + val, + guess_key, + phase), + units=units) else: # raise error if the guess key is not recognized raise ValueError( - f"Initial guess key {guess_key} in {phase_name} is not recognized.") + f"Initial guess key {guess_key} in {phase_name} is not " + "recognized." + ) if self.mission_method is SOLVED_2DOF: return @@ -2282,40 +2461,42 @@ def _add_guesses(self, phase_name, phase, guesses): mass_guess = self.aviary_inputs.get_val( Mission.Design.GROSS_MASS, units='lbm') # Set the mass guess as the initial value for the mass state variable - self.set_val(f'traj.{phase_name}.states:mass', - mass_guess, units='lbm') + setvalprob.set_val(parent_prefix + f'traj.{phase_name}.states:mass', + mass_guess, units='lbm') if 'time' not in guesses: # Determine initial time and duration guesses depending on the phase name if 'desc1' == base_phase: - t_initial = flight_duration*.9 - t_duration = flight_duration*.04 + t_initial = flight_duration * .9 + t_duration = flight_duration * .04 elif 'desc2' in base_phase: - t_initial = flight_duration*.94 + t_initial = flight_duration * .94 t_duration = 5000 - # Set the time guesses as the initial values for the time-related trajectory variables - self.set_val(f"traj.{phase_name}.t_initial", - t_initial, units='s') - self.set_val(f"traj.{phase_name}.t_duration", - t_duration, units='s') + # Set the time guesses as the initial values for the time-related + # trajectory variables + setvalprob.set_val(parent_prefix + f"traj.{phase_name}.t_initial", + t_initial, units='s') + setvalprob.set_val(parent_prefix + f"traj.{phase_name}.t_duration", + t_duration, units='s') if self.mission_method is TWO_DEGREES_OF_FREEDOM: if 'distance' not in guesses: # Determine initial distance guesses depending on the phase name if 'desc1' == base_phase: - ys = [self.target_range*.97, self.target_range*.99] + ys = [self.target_range * .97, self.target_range * .99] elif 'desc2' in base_phase: - ys = [self.target_range*.99, self.target_range] - # Set the distance guesses as the initial values for the distance state variable - self.set_val( - f"traj.{phase_name}.states:distance", phase.interp( - Dynamic.Mission.DISTANCE, ys=ys) - ) - - def run_aviary_problem(self, - record_filename="problem_history.db", - optimization_history_filename=None, - restart_filename=None, suppress_solver_print=True, run_driver=True, simulate=False, make_plots=True): + ys = [self.target_range * .99, self.target_range] + # Set the distance guesses as the initial values for the distance state + # variable + setvalprob.set_val(parent_prefix + + f"traj.{phase_name}.states:distance", phase.interp( + Dynamic.Mission.DISTANCE, ys=ys) + ) + + def run_aviary_problem(self, record_filename="problem_history.db", + optimization_history_filename=None, restart_filename=None, + suppress_solver_print=True, run_driver=True, simulate=False, + make_plots=True): """ This function actually runs the Aviary problem, which could be a simulation, optimization, or a driver execution, depending on the arguments provided. @@ -2351,8 +2532,9 @@ def run_aviary_problem(self, # and run mission, and dynamics if run_driver: - failed = dm.run_problem(self, run_driver=run_driver, simulate=simulate, make_plots=make_plots, - solution_record_file=record_filename, restart=restart_filename) + failed = dm.run_problem( + self, run_driver=run_driver, simulate=simulate, make_plots=make_plots, + solution_record_file=record_filename, restart=restart_filename) else: # prevent UserWarning that is displayed when an event is triggered warnings.filterwarnings('ignore', category=UserWarning) @@ -2401,8 +2583,13 @@ def alternate_mission(self, run_mission=True, mission_mass = self.get_val(Mission.Design.GROSS_MASS) optimizer = self.driver.options["optimizer"] - prob_alternate = _load_off_design(json_filename, ProblemType.ALTERNATE, - phase_info, payload_mass, design_range, mission_mass) + prob_alternate = _load_off_design( + json_filename, + ProblemType.ALTERNATE, + phase_info, + payload_mass, + design_range, + mission_mass) prob_alternate.check_and_preprocess_inputs() prob_alternate.add_pre_mission_systems() @@ -2492,7 +2679,8 @@ def save_sizing_to_json(self, json_filename='sizing_problem.json'): (name, (value, units)) = data type_value = type(value) - # Get the gross mass value from the sizing problem and add it to input list + # Get the gross mass value from the sizing problem and add it to input + # list if name == Mission.Summary.GROSS_MASS or name == Mission.Design.GROSS_MASS: Mission_Summary_GROSS_MASS_val = self.get_val( Mission.Summary.GROSS_MASS, units=units) @@ -2548,12 +2736,14 @@ def _add_vrotate_comp(self): 'vrot_comp.mass', src_indices=om.slicer[0, ...]) vrot_eq_comp = self.model.add_subsystem("vrot_eq_comp", om.EQConstraintComp()) - vrot_eq_comp.add_eq_output("v_rotate_error", eq_units="kn", - lhs_name="v_rot_computed", rhs_name="groundroll_v_final", add_constraint=True) + vrot_eq_comp.add_eq_output( + "v_rotate_error", eq_units="kn", lhs_name="v_rot_computed", + rhs_name="groundroll_v_final", add_constraint=True) self.model.connect('vrot_comp.Vrot', 'vrot_eq_comp.v_rot_computed') - self.model.connect('traj.groundroll.timeseries.velocity', - 'vrot_eq_comp.groundroll_v_final', src_indices=om.slicer[-1, ...]) + self.model.connect( + 'traj.groundroll.timeseries.velocity', 'vrot_eq_comp.groundroll_v_final', + src_indices=om.slicer[-1, ...]) def _save_to_csv_file(self, filename): with open(filename, 'w', newline='') as csvfile: @@ -2591,7 +2781,8 @@ def _add_height_energy_landing_systems(self): last_flight_phase_name = list(self.phase_info.keys())[-1] control_type_string = 'control_values' - if self.phase_info[last_flight_phase_name]['user_options'].get('use_polynomial_control', True): + if self.phase_info[last_flight_phase_name]['user_options'].get( + 'use_polynomial_control', True): if not use_new_dymos_syntax: control_type_string = 'polynomial_control_values' @@ -2604,8 +2795,8 @@ def _add_height_energy_landing_systems(self): def _add_post_mission_takeoff_systems(self): first_flight_phase_name = list(self.phase_info.keys())[0] - connect_takeoff_to_climb = not self.phase_info[first_flight_phase_name]['user_options'].get( - 'add_initial_mass_constraint', True) + connect_takeoff_to_climb = not self.phase_info[first_flight_phase_name][ + 'user_options'].get('add_initial_mass_constraint', True) if connect_takeoff_to_climb: self.model.connect(Mission.Takeoff.FINAL_MASS, @@ -2614,11 +2805,13 @@ def _add_post_mission_takeoff_systems(self): f'traj.{first_flight_phase_name}.initial_states:distance') control_type_string = 'control_values' - if self.phase_info[first_flight_phase_name]['user_options'].get('use_polynomial_control', True): + if self.phase_info[first_flight_phase_name]['user_options'].get( + 'use_polynomial_control', True): if not use_new_dymos_syntax: control_type_string = 'polynomial_control_values' - if self.phase_info[first_flight_phase_name]['user_options'].get('optimize_mach', False): + if self.phase_info[first_flight_phase_name]['user_options'].get( + 'optimize_mach', False): # Create an ExecComp to compute the difference in mach mach_diff_comp = om.ExecComp( 'mach_resid_for_connecting_takeoff = final_mach - initial_mach') @@ -2627,14 +2820,16 @@ def _add_post_mission_takeoff_systems(self): # Connect the inputs to the mach difference component self.model.connect(Mission.Takeoff.FINAL_MACH, 'mach_diff_comp.final_mach') - self.model.connect(f'traj.{first_flight_phase_name}.{control_type_string}:mach', - 'mach_diff_comp.initial_mach', src_indices=[0]) + self.model.connect( + f'traj.{first_flight_phase_name}.{control_type_string}:mach', + 'mach_diff_comp.initial_mach', src_indices=[0]) # Add constraint for mach difference self.model.add_constraint( 'mach_diff_comp.mach_resid_for_connecting_takeoff', equals=0.0) - if self.phase_info[first_flight_phase_name]['user_options'].get('optimize_altitude', False): + if self.phase_info[first_flight_phase_name]['user_options'].get( + 'optimize_altitude', False): # Similar steps for altitude difference alt_diff_comp = om.ExecComp( 'altitude_resid_for_connecting_takeoff = final_altitude - initial_altitude', units='ft') @@ -2642,8 +2837,9 @@ def _add_post_mission_takeoff_systems(self): self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, 'alt_diff_comp.final_altitude') - self.model.connect(f'traj.{first_flight_phase_name}.{control_type_string}:altitude', - 'alt_diff_comp.initial_altitude', src_indices=[0]) + self.model.connect( + f'traj.{first_flight_phase_name}.{control_type_string}:altitude', + 'alt_diff_comp.initial_altitude', src_indices=[0]) self.model.add_constraint( 'alt_diff_comp.altitude_resid_for_connecting_takeoff', equals=0.0) @@ -2654,7 +2850,7 @@ def _add_two_dof_landing_systems(self): LandingSegment( **(self.ode_args)), promotes_inputs=['aircraft:*', 'mission:*', - (Dynamic.Mission.MASS, Mission.Landing.TOUCHDOWN_MASS)], + (Dynamic.Vehicle.MASS, Mission.Landing.TOUCHDOWN_MASS)], promotes_outputs=['mission:*'], ) self.model.connect( @@ -2691,7 +2887,7 @@ def _add_objectives(self): "val": self.target_range, "units": "NM"}, ), promotes_inputs=[ - ("actual_range", Mission.Summary.RANGE), + "actual_range", ("ascent_duration", Mission.Takeoff.ASCENT_DURATION), ], promotes_outputs=[("reg_objective", Mission.Objectives.RANGE)], @@ -2713,12 +2909,12 @@ def _add_objectives(self): om.ExecComp( "range_resid = target_range - actual_range", target_range={"val": self.target_range, "units": "NM"}, - actual_range={"val": self.target_range - 25, "units": "NM"}, + actual_range={"val": self.target_range, "units": "NM"}, range_resid={"val": 30, "units": "NM"}, ), promotes_inputs=[ - ("actual_range", Mission.Summary.RANGE), - ("target_range", Mission.Design.RANGE), + "actual_range", + ("target_range", Mission.Summary.RANGE), ], promotes_outputs=[ ("range_resid", Mission.Constraints.RANGE_RESIDUAL)], @@ -2734,38 +2930,47 @@ def _add_fuel_reserve_component(self, post_mission=True, RESERVE_FUEL_FRACTION = self.aviary_inputs.get_val( Aircraft.Design.RESERVE_FUEL_FRACTION, units='unitless') if RESERVE_FUEL_FRACTION != 0: - reserve_fuel_frac = om.ExecComp('reserve_fuel_frac_mass = reserve_fuel_fraction * (takeoff_mass - final_mass)', - reserve_fuel_frac_mass={"units": "lbm"}, - reserve_fuel_fraction={ - "units": "unitless", "val": RESERVE_FUEL_FRACTION}, - final_mass={"units": "lbm"}, - takeoff_mass={"units": "lbm"}) - - reserve_calc_location.add_subsystem("reserve_fuel_frac", reserve_fuel_frac, - promotes_inputs=[("takeoff_mass", Mission.Summary.GROSS_MASS), - ("final_mass", - Mission.Landing.TOUCHDOWN_MASS), - ("reserve_fuel_fraction", Aircraft.Design.RESERVE_FUEL_FRACTION)], - promotes_outputs=["reserve_fuel_frac_mass"]) + reserve_fuel_frac = om.ExecComp( + 'reserve_fuel_frac_mass = reserve_fuel_fraction * (takeoff_mass - final_mass)', + reserve_fuel_frac_mass={ + "units": "lbm"}, + reserve_fuel_fraction={ + "units": "unitless", + "val": RESERVE_FUEL_FRACTION}, + final_mass={ + "units": "lbm"}, + takeoff_mass={ + "units": "lbm"}) + + reserve_calc_location.add_subsystem( + "reserve_fuel_frac", reserve_fuel_frac, + promotes_inputs=[("takeoff_mass", Mission.Summary.GROSS_MASS), + ("final_mass", Mission.Landing.TOUCHDOWN_MASS), + ("reserve_fuel_fraction", Aircraft.Design. + RESERVE_FUEL_FRACTION)], + promotes_outputs=["reserve_fuel_frac_mass"]) RESERVE_FUEL_ADDITIONAL = self.aviary_inputs.get_val( Aircraft.Design.RESERVE_FUEL_ADDITIONAL, units='lbm') - reserve_fuel = om.ExecComp('reserve_fuel = reserve_fuel_frac_mass + reserve_fuel_additional + reserve_fuel_burned', - reserve_fuel={"units": "lbm", 'shape': 1}, - reserve_fuel_frac_mass={"units": "lbm", "val": 0}, - reserve_fuel_additional={ - "units": "lbm", "val": RESERVE_FUEL_ADDITIONAL}, - reserve_fuel_burned={"units": "lbm", "val": 0}) - - reserve_calc_location.add_subsystem("reserve_fuel", reserve_fuel, - promotes_inputs=["reserve_fuel_frac_mass", - ("reserve_fuel_additional", - Aircraft.Design.RESERVE_FUEL_ADDITIONAL), - ("reserve_fuel_burned", - Mission.Summary.RESERVE_FUEL_BURNED)], - promotes_outputs=[ - ("reserve_fuel", reserves_name)] - ) + reserve_fuel = om.ExecComp( + 'reserve_fuel = reserve_fuel_frac_mass + reserve_fuel_additional + reserve_fuel_burned', + reserve_fuel={"units": "lbm", 'shape': 1}, + reserve_fuel_frac_mass={"units": "lbm", "val": 0}, + reserve_fuel_additional={"units": "lbm", "val": RESERVE_FUEL_ADDITIONAL}, + reserve_fuel_burned={"units": "lbm", "val": 0}) + + reserve_calc_location.add_subsystem( + "reserve_fuel", + reserve_fuel, + promotes_inputs=[ + "reserve_fuel_frac_mass", + ("reserve_fuel_additional", + Aircraft.Design.RESERVE_FUEL_ADDITIONAL), + ("reserve_fuel_burned", + Mission.Summary.RESERVE_FUEL_BURNED)], + promotes_outputs=[ + ("reserve_fuel", + reserves_name)]) def _read_sizing_json(aviary_problem, json_filename): @@ -2838,14 +3043,34 @@ def _read_sizing_json(aviary_problem, json_filename): aviary_problem.aviary_inputs = set_value( var_name, var_values, aviary_problem.aviary_inputs, units=var_units, is_array=is_array, meta_data=BaseMetaData) - except: + except BaseException: # Print helpful error - print("FAILURE: list_num = ", counter, "Input String = ", inputs, - "Attempted to set_value(", var_name, ",", var_values, ",", var_units, ")") + print( + "FAILURE: list_num = ", + counter, + "Input String = ", + inputs, + "Attempted to set_value(", + var_name, + ",", + var_values, + ",", + var_units, + ")") else: # Not in the MetaData - print("Name not found in MetaData: list_num =", counter, "Input String =", - inputs, "Attempted set_value(", var_name, ",", var_values, ",", var_units, ")") + print( + "Name not found in MetaData: list_num =", + counter, + "Input String =", + inputs, + "Attempted set_value(", + var_name, + ",", + var_values, + ",", + var_units, + ")") counter = counter + 1 # increment index tracker return aviary_problem diff --git a/aviary/interface/test/test_height_energy_mission.py b/aviary/interface/test/test_height_energy_mission.py index 1c257c23c..d33bfd4cc 100644 --- a/aviary/interface/test/test_height_energy_mission.py +++ b/aviary/interface/test/test_height_energy_mission.py @@ -180,7 +180,7 @@ def test_mission_optimize_altitude_and_mach(self): modified_phase_info[phase]["user_options"]["optimize_altitude"] = True modified_phase_info[phase]["user_options"]["optimize_mach"] = True modified_phase_info['climb']['user_options']['constraints'] = { - Dynamic.Mission.THROTTLE: { + Dynamic.Vehicle.Propulsion.THROTTLE: { 'lower': 0.2, 'upper': 0.9, 'type': 'path', @@ -259,13 +259,13 @@ def test_support_constraint_aliases(self): modified_phase_info = deepcopy(self.phase_info) modified_phase_info['climb']['user_options']['constraints'] = { 'throttle_1': { - 'target': Dynamic.Mission.THROTTLE, + 'target': Dynamic.Vehicle.Propulsion.THROTTLE, 'equals': 0.2, 'loc': 'initial', 'type': 'boundary', }, 'throttle_2': { - 'target': Dynamic.Mission.THROTTLE, + 'target': Dynamic.Vehicle.Propulsion.THROTTLE, 'equals': 0.8, 'loc': 'final', 'type': 'boundary', diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index dd3b8ac82..9d4c0aca9 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -146,8 +146,8 @@ def test_phase_info_parameterization_height_energy(self): prob.run_model() - range_resid = prob.get_val(Mission.Constraints.RANGE_RESIDUAL, units='km')[-1] - assert_near_equal(range_resid, 5000.0 - 1.e-3) + range_resid = prob.get_val(Mission.Constraints.RANGE_RESIDUAL, units='nmi')[-1] + assert_near_equal(range_resid, 1906, tolerance=1e-3) assert_near_equal(prob.get_val("traj.cruise.timeseries.altitude", units='ft')[0], 31000.0) assert_near_equal(prob.get_val("traj.cruise.timeseries.mach")[0], diff --git a/aviary/mission/energy_phase.py b/aviary/mission/energy_phase.py index 35a28c128..194b6bc98 100644 --- a/aviary/mission/energy_phase.py +++ b/aviary/mission/energy_phase.py @@ -3,7 +3,6 @@ from aviary.mission.flight_phase_builder import FlightPhaseBase, register from aviary.mission.initial_guess_builders import InitialGuessIntegrationVariable, InitialGuessState -from aviary.utils.aviary_values import AviaryValues from aviary.mission.flops_based.ode.mission_ODE import MissionODE diff --git a/aviary/mission/flight_phase_builder.py b/aviary/mission/flight_phase_builder.py index 874da3dd0..d744efc20 100644 --- a/aviary/mission/flight_phase_builder.py +++ b/aviary/mission/flight_phase_builder.py @@ -105,8 +105,8 @@ def build_phase(self, aviary_options: AviaryValues = None, phase_type=EquationsO ############## # TODO: critically think about how we should handle fix_initial and input_initial defaults. # In keeping with Dymos standards, the default should be False instead of True. - input_initial_mass = get_initial(input_initial, Dynamic.Mission.MASS) - fix_initial_mass = get_initial(fix_initial, Dynamic.Mission.MASS, True) + input_initial_mass = get_initial(input_initial, Dynamic.Vehicle.MASS) + fix_initial_mass = get_initial(fix_initial, Dynamic.Vehicle.MASS, True) # Experiment: use a constraint for mass instead of connected initial. # This is due to some problems in mpi. @@ -118,15 +118,15 @@ def build_phase(self, aviary_options: AviaryValues = None, phase_type=EquationsO input_initial_mass = False if phase_type is EquationsOfMotion.HEIGHT_ENERGY: - rate_source = Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL + rate_source = Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL else: rate_source = "dmass_dr" phase.add_state( - Dynamic.Mission.MASS, fix_initial=fix_initial_mass, fix_final=False, + Dynamic.Vehicle.MASS, fix_initial=fix_initial_mass, fix_final=False, lower=0.0, ref=1e4, defect_ref=1e6, units='kg', rate_source=rate_source, - targets=Dynamic.Mission.MASS, + targets=Dynamic.Vehicle.MASS, input_initial=input_initial_mass, ) @@ -149,23 +149,30 @@ def build_phase(self, aviary_options: AviaryValues = None, phase_type=EquationsO # Add Controls # ################ if phase_type is EquationsOfMotion.HEIGHT_ENERGY: - rate_targets = [Dynamic.Mission.MACH_RATE] + rate_targets = [Dynamic.Atmosphere.MACH_RATE] else: rate_targets = ['dmach_dr'] if use_polynomial_control: phase.add_polynomial_control( - Dynamic.Mission.MACH, - targets=Dynamic.Mission.MACH, units=mach_bounds[1], - opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], + Dynamic.Atmosphere.MACH, + targets=Dynamic.Atmosphere.MACH, + units=mach_bounds[1], + opt=optimize_mach, + lower=mach_bounds[0][0], + upper=mach_bounds[0][1], rate_targets=rate_targets, - order=polynomial_control_order, ref=0.5, + order=polynomial_control_order, + ref=0.5, ) else: phase.add_control( - Dynamic.Mission.MACH, - targets=Dynamic.Mission.MACH, units=mach_bounds[1], - opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], + Dynamic.Atmosphere.MACH, + targets=Dynamic.Atmosphere.MACH, + units=mach_bounds[1], + opt=optimize_mach, + lower=mach_bounds[0][0], + upper=mach_bounds[0][1], rate_targets=rate_targets, ref=0.5, ) @@ -211,25 +218,39 @@ def build_phase(self, aviary_options: AviaryValues = None, phase_type=EquationsO ground_roll = user_options.get_val('ground_roll') if ground_roll: - phase.add_polynomial_control(Dynamic.Mission.ALTITUDE, - order=1, val=0, opt=False, - fix_initial=fix_initial, - rate_targets=['dh_dr'], rate2_targets=['d2h_dr2']) + phase.add_polynomial_control( + Dynamic.Mission.ALTITUDE, + order=1, + val=0, + opt=False, + fix_initial=fix_initial, + rate_targets=['dh_dr'], + rate2_targets=['d2h_dr2'], + ) else: if use_polynomial_control: phase.add_polynomial_control( Dynamic.Mission.ALTITUDE, - targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], - opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], - rate_targets=rate_targets, rate2_targets=rate2_targets, - order=polynomial_control_order, ref=altitude_bounds[0][1], + targets=Dynamic.Mission.ALTITUDE, + units=altitude_bounds[1], + opt=optimize_altitude, + lower=altitude_bounds[0][0], + upper=altitude_bounds[0][1], + rate_targets=rate_targets, + rate2_targets=rate2_targets, + order=polynomial_control_order, + ref=altitude_bounds[0][1], ) else: phase.add_control( Dynamic.Mission.ALTITUDE, - targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], - opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], - rate_targets=rate_targets, rate2_targets=rate2_targets, + targets=Dynamic.Mission.ALTITUDE, + units=altitude_bounds[1], + opt=optimize_altitude, + lower=altitude_bounds[0][0], + upper=altitude_bounds[0][1], + rate_targets=rate_targets, + rate2_targets=rate2_targets, ref=altitude_bounds[0][1], ) @@ -237,46 +258,53 @@ def build_phase(self, aviary_options: AviaryValues = None, phase_type=EquationsO # Add Timeseries # ################## phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units='unitless' + Dynamic.Atmosphere.MACH, + output_name=Dynamic.Atmosphere.MACH, + units='unitless', ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, - output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, units='m/s' + output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, + units='m/s', ) phase.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - output_name=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h' + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + units='lbm/h', ) phase.add_timeseries_output( - Dynamic.Mission.ELECTRIC_POWER_IN_TOTAL, - output_name=Dynamic.Mission.ELECTRIC_POWER_IN_TOTAL, units='kW' + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN_TOTAL, + units='kW', ) phase.add_timeseries_output( Dynamic.Mission.ALTITUDE_RATE, - output_name=Dynamic.Mission.ALTITUDE_RATE, units='ft/s' + output_name=Dynamic.Mission.ALTITUDE_RATE, + units='ft/s', ) phase.add_timeseries_output( - Dynamic.Mission.THROTTLE, - output_name=Dynamic.Mission.THROTTLE, units='unitless' + Dynamic.Vehicle.Propulsion.THROTTLE, + output_name=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless' ) phase.add_timeseries_output( Dynamic.Mission.VELOCITY, - output_name=Dynamic.Mission.VELOCITY, units='m/s' + output_name=Dynamic.Mission.VELOCITY, + units='m/s', ) phase.add_timeseries_output(Dynamic.Mission.ALTITUDE) @@ -293,24 +321,48 @@ def build_phase(self, aviary_options: AviaryValues = None, phase_type=EquationsO ################### # Add Constraints # ################### - if optimize_mach and fix_initial and not Dynamic.Mission.MACH in constraints: + if optimize_mach and fix_initial and not Dynamic.Atmosphere.MACH in constraints: phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc='initial', equals=initial_mach, + Dynamic.Atmosphere.MACH, + loc='initial', + equals=initial_mach, ) - if optimize_mach and constrain_final and not Dynamic.Mission.MACH in constraints: + if ( + optimize_mach + and constrain_final + and not Dynamic.Atmosphere.MACH in constraints + ): phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc='final', equals=final_mach, + Dynamic.Atmosphere.MACH, + loc='final', + equals=final_mach, ) - if optimize_altitude and fix_initial and not Dynamic.Mission.ALTITUDE in constraints: + if ( + optimize_altitude + and fix_initial + and not Dynamic.Mission.ALTITUDE in constraints + ): phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='initial', equals=initial_altitude, units=altitude_bounds[1], ref=1.e4, + Dynamic.Mission.ALTITUDE, + loc='initial', + equals=initial_altitude, + units=altitude_bounds[1], + ref=1.0e4, ) - if optimize_altitude and constrain_final and not Dynamic.Mission.ALTITUDE in constraints: + if ( + optimize_altitude + and constrain_final + and not Dynamic.Mission.ALTITUDE in constraints + ): phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='final', equals=final_altitude, units=altitude_bounds[1], ref=1.e4, + Dynamic.Mission.ALTITUDE, + loc='final', + equals=final_altitude, + units=altitude_bounds[1], + ref=1.0e4, ) if no_descent and not Dynamic.Mission.ALTITUDE_RATE in constraints: @@ -322,23 +374,27 @@ def build_phase(self, aviary_options: AviaryValues = None, phase_type=EquationsO required_available_climb_rate, units = user_options.get_item( 'required_available_climb_rate') - if required_available_climb_rate is not None and not Dynamic.Mission.ALTITUDE_RATE_MAX in constraints: + if ( + required_available_climb_rate is not None + and not Dynamic.Mission.ALTITUDE_RATE_MAX in constraints + ): phase.add_path_constraint( Dynamic.Mission.ALTITUDE_RATE_MAX, - lower=required_available_climb_rate, units=units + lower=required_available_climb_rate, + units=units, ) - if not Dynamic.Mission.THROTTLE in constraints: + if not Dynamic.Vehicle.Propulsion.THROTTLE in constraints: if throttle_enforcement == 'boundary_constraint': phase.add_boundary_constraint( - Dynamic.Mission.THROTTLE, loc='initial', lower=0.0, upper=1.0, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, loc='initial', lower=0.0, upper=1.0, units='unitless', ) phase.add_boundary_constraint( - Dynamic.Mission.THROTTLE, loc='final', lower=0.0, upper=1.0, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, loc='final', lower=0.0, upper=1.0, units='unitless', ) elif throttle_enforcement == 'path_constraint': phase.add_path_constraint( - Dynamic.Mission.THROTTLE, lower=0.0, upper=1.0, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, lower=0.0, upper=1.0, units='unitless', ) self._add_user_defined_constraints(phase, constraints) diff --git a/aviary/mission/flops_based/ode/landing_eom.py b/aviary/mission/flops_based/ode/landing_eom.py index 10c2304aa..1ebf06ec4 100644 --- a/aviary/mission/flops_based/ode/landing_eom.py +++ b/aviary/mission/flops_based/ode/landing_eom.py @@ -53,8 +53,13 @@ def setup(self): 'aviary_options': aviary_options} inputs = [ - Dynamic.Mission.MASS, Dynamic.Mission.LIFT, Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, - 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE] + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE, + ] outputs = ['forces_horizontal', 'forces_vertical'] @@ -64,7 +69,7 @@ def setup(self): promotes_inputs=inputs, promotes_outputs=outputs) - inputs = ['forces_horizontal', 'forces_vertical', Dynamic.Mission.MASS] + inputs = ['forces_horizontal', 'forces_vertical', Dynamic.Vehicle.MASS] outputs = ['acceleration_horizontal', 'acceleration_vertical'] self.add_subsystem( @@ -74,10 +79,15 @@ def setup(self): promotes_outputs=outputs) inputs = [ - 'acceleration_horizontal', 'acceleration_vertical', - Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE] + 'acceleration_horizontal', + 'acceleration_vertical', + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.ALTITUDE_RATE, + ] - outputs = [Dynamic.Mission.VELOCITY_RATE,] + outputs = [ + Dynamic.Mission.VELOCITY_RATE, + ] self.add_subsystem( 'velocity_rate', @@ -86,8 +96,11 @@ def setup(self): promotes_outputs=outputs) inputs = [ - Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE, - 'acceleration_horizontal', 'acceleration_vertical'] + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.ALTITUDE_RATE, + 'acceleration_horizontal', + 'acceleration_vertical', + ] outputs = [Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE] @@ -97,8 +110,12 @@ def setup(self): promotes_outputs=outputs) inputs = [ - Dynamic.Mission.MASS, Dynamic.Mission.LIFT, Dynamic.Mission.DRAG, - 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE] + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.DRAG, + 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE, + ] outputs = ['forces_perpendicular', 'required_thrust'] @@ -144,14 +161,15 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Vehicle.LIFT, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.DRAG, val=np.ones(nn), units='N') self.add_input('angle_of_attack', val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units='rad') + add_aviary_input( + self, Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad' + ) self.add_output( 'forces_perpendicular', val=np.zeros(nn), units='N', @@ -180,9 +198,9 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') total_num_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) - mass = inputs[Dynamic.Mission.MASS] - lift = inputs[Dynamic.Mission.LIFT] - drag = inputs[Dynamic.Mission.DRAG] + mass = inputs[Dynamic.Vehicle.MASS] + lift = inputs[Dynamic.Vehicle.LIFT] + drag = inputs[Dynamic.Vehicle.DRAG] weight = mass * grav_metric @@ -218,9 +236,9 @@ def compute_partials(self, inputs, J, discrete_inputs=None): t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') total_num_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) - mass = inputs[Dynamic.Mission.MASS] - lift = inputs[Dynamic.Mission.LIFT] - drag = inputs[Dynamic.Mission.DRAG] + mass = inputs[Dynamic.Vehicle.MASS] + lift = inputs[Dynamic.Vehicle.LIFT] + drag = inputs[Dynamic.Vehicle.DRAG] weight = mass * grav_metric @@ -244,20 +262,20 @@ def compute_partials(self, inputs, J, discrete_inputs=None): f_h = -grav_metric * s_gamma / c_angle f_v = grav_metric * c_gamma / s_angle - J[forces_key, Dynamic.Mission.MASS] = f_h - f_v - J[thrust_key, Dynamic.Mission.MASS] = (f_h + f_v) / (2.) + J[forces_key, Dynamic.Vehicle.MASS] = f_h - f_v + J[thrust_key, Dynamic.Vehicle.MASS] = (f_h + f_v) / (2.) f_h = 0. f_v = -1. / s_angle - J[forces_key, Dynamic.Mission.LIFT] = -f_v - J[thrust_key, Dynamic.Mission.LIFT] = f_v / (2.) + J[forces_key, Dynamic.Vehicle.LIFT] = -f_v + J[thrust_key, Dynamic.Vehicle.LIFT] = f_v / (2.) f_h = 1. / c_angle f_v = 0. - J[forces_key, Dynamic.Mission.DRAG] = f_h - J[thrust_key, Dynamic.Mission.DRAG] = f_h / (2.) + J[forces_key, Dynamic.Vehicle.DRAG] = f_h + J[thrust_key, Dynamic.Vehicle.DRAG] = f_h / (2.) # ddx(1 / cos(x)) = sec(x) * tan(x) = tan(x) / cos(x) # ddx(1 / sin(x)) = -csc(x) * cot(x) = -1 / (sin(x) * tan(x)) @@ -272,8 +290,8 @@ def compute_partials(self, inputs, J, discrete_inputs=None): f_h = -weight * c_gamma / c_angle f_v = -weight * s_gamma / s_angle - J[forces_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = - f_h + f_v - J[thrust_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = -(f_h + f_v) / (2.) + J[forces_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = -f_h + f_v + J[thrust_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = -(f_h + f_v) / (2.0) class FlareSumForces(om.ExplicitComponent): @@ -296,15 +314,17 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.Mission.THRUST_TOTAL, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Vehicle.LIFT, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.DRAG, val=np.ones(nn), units='N') self.add_input('angle_of_attack', val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units='rad') + add_aviary_input( + self, Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad' + ) self.add_output( 'forces_horizontal', val=np.zeros(nn), units='N', @@ -321,15 +341,19 @@ def setup_partials(self): rows_cols = np.arange(nn) - self.declare_partials('forces_horizontal', Dynamic.Mission.MASS, dependent=False) + self.declare_partials('forces_horizontal', Dynamic.Vehicle.MASS, dependent=False) self.declare_partials( - 'forces_vertical', Dynamic.Mission.MASS, val=-grav_metric, rows=rows_cols, + 'forces_vertical', Dynamic.Vehicle.MASS, val=-grav_metric, rows=rows_cols, cols=rows_cols) wrt = [ - Dynamic.Mission.LIFT, Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, 'angle_of_attack', - Dynamic.Mission.FLIGHT_PATH_ANGLE] + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE, + ] self.declare_partials('*', wrt, rows=rows_cols, cols=rows_cols) @@ -341,10 +365,10 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.Mission.MASS] - lift = inputs[Dynamic.Mission.LIFT] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] + mass = inputs[Dynamic.Vehicle.MASS] + lift = inputs[Dynamic.Vehicle.LIFT] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] alpha = inputs['angle_of_attack'] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] @@ -379,10 +403,10 @@ def compute_partials(self, inputs, J, discrete_inputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.Mission.MASS] - lift = inputs[Dynamic.Mission.LIFT] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] + mass = inputs[Dynamic.Vehicle.MASS] + lift = inputs[Dynamic.Vehicle.LIFT] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] alpha = inputs['angle_of_attack'] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] @@ -399,16 +423,16 @@ def compute_partials(self, inputs, J, discrete_inputs=None): s_gamma = np.sin(gamma) f_h_key = 'forces_horizontal' - J[f_h_key, Dynamic.Mission.LIFT] = -s_gamma + J[f_h_key, Dynamic.Vehicle.LIFT] = -s_gamma f_v_key = 'forces_vertical' - J[f_v_key, Dynamic.Mission.LIFT] = c_gamma + J[f_v_key, Dynamic.Vehicle.LIFT] = c_gamma - J[f_h_key, Dynamic.Mission.THRUST_TOTAL] = -c_angle - J[f_v_key, Dynamic.Mission.THRUST_TOTAL] = s_angle + J[f_h_key, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = -c_angle + J[f_v_key, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = s_angle - J[f_h_key, Dynamic.Mission.DRAG] = c_gamma - J[f_v_key, Dynamic.Mission.DRAG] = s_gamma + J[f_h_key, Dynamic.Vehicle.DRAG] = c_gamma + J[f_v_key, Dynamic.Vehicle.DRAG] = s_gamma J[f_h_key, 'angle_of_attack'] = thrust * s_angle J[f_v_key, 'angle_of_attack'] = thrust * c_angle @@ -441,10 +465,11 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.Mission.THRUST_TOTAL, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Vehicle.LIFT, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.DRAG, val=np.ones(nn), units='N') self.add_output( 'forces_horizontal', val=np.zeros(nn), units='N', @@ -462,25 +487,25 @@ def setup_partials(self): rows_cols = np.arange(nn) self.declare_partials( - 'forces_vertical', Dynamic.Mission.MASS, val=-grav_metric, rows=rows_cols, + 'forces_vertical', Dynamic.Vehicle.MASS, val=-grav_metric, rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_vertical', Dynamic.Mission.LIFT, val=1., rows=rows_cols, cols=rows_cols) + 'forces_vertical', Dynamic.Vehicle.LIFT, val=1., rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_vertical', [Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG], dependent=False) + 'forces_vertical', [Dynamic.Vehicle.Propulsion.THRUST_TOTAL, Dynamic.Vehicle.DRAG], dependent=False) self.declare_partials( - 'forces_horizontal', [Dynamic.Mission.MASS, Dynamic.Mission.LIFT], rows=rows_cols, + 'forces_horizontal', [Dynamic.Vehicle.MASS, Dynamic.Vehicle.LIFT], rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_horizontal', Dynamic.Mission.THRUST_TOTAL, val=-1., rows=rows_cols, + 'forces_horizontal', Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=-1., rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_horizontal', Dynamic.Mission.DRAG, val=1., rows=rows_cols, cols=rows_cols) + 'forces_horizontal', Dynamic.Vehicle.DRAG, val=1., rows=rows_cols, cols=rows_cols) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): options = self.options @@ -488,10 +513,10 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): nn = options['num_nodes'] friction_coefficient = options['friction_coefficient'] - mass = inputs[Dynamic.Mission.MASS] - lift = inputs[Dynamic.Mission.LIFT] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] + mass = inputs[Dynamic.Vehicle.MASS] + lift = inputs[Dynamic.Vehicle.LIFT] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] weight = mass * grav_metric @@ -511,8 +536,8 @@ def compute_partials(self, inputs, J, discrete_inputs=None): nn = options['num_nodes'] friction_coefficient = options['friction_coefficient'] - mass = inputs[Dynamic.Mission.MASS] - lift = inputs[Dynamic.Mission.LIFT] + mass = inputs[Dynamic.Vehicle.MASS] + lift = inputs[Dynamic.Vehicle.LIFT] weight = mass * grav_metric @@ -522,8 +547,8 @@ def compute_partials(self, inputs, J, discrete_inputs=None): friction = np.zeros(nn) friction[idx_sup] = friction_coefficient * grav_metric - J['forces_horizontal', Dynamic.Mission.MASS] = friction + J['forces_horizontal', Dynamic.Vehicle.MASS] = friction friction = np.zeros(nn) friction[idx_sup] = -friction_coefficient - J['forces_horizontal', Dynamic.Mission.LIFT] = friction + J['forces_horizontal', Dynamic.Vehicle.LIFT] = friction diff --git a/aviary/mission/flops_based/ode/landing_ode.py b/aviary/mission/flops_based/ode/landing_ode.py index cad16438a..4945a0455 100644 --- a/aviary/mission/flops_based/ode/landing_ode.py +++ b/aviary/mission/flops_based/ode/landing_ode.py @@ -109,7 +109,7 @@ def setup(self): StallSpeed(num_nodes=nn), promotes_inputs=[ "mass", - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, ('area', Aircraft.Wing.AREA), ("lift_coefficient_max", Mission.Landing.LIFT_COEFFICIENT_MAX), ], @@ -170,10 +170,10 @@ def setup(self): promotes_inputs=[ Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, 'angle_of_attack', 'angle_of_attack_rate', Mission.Landing.FLARE_RATE, diff --git a/aviary/mission/flops_based/ode/mission_EOM.py b/aviary/mission/flops_based/ode/mission_EOM.py index 1bb2bf10b..04b7706e2 100644 --- a/aviary/mission/flops_based/ode/mission_EOM.py +++ b/aviary/mission/flops_based/ode/mission_EOM.py @@ -20,37 +20,57 @@ def setup(self): self.add_subsystem( name='required_thrust', subsys=RequiredThrust(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.DRAG, - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.VELOCITY, - Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.MASS], - promotes_outputs=['thrust_required']) + promotes_inputs=[ + Dynamic.Vehicle.DRAG, + Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.VELOCITY, + Dynamic.Mission.VELOCITY_RATE, + Dynamic.Vehicle.MASS, + ], + promotes_outputs=['thrust_required'], + ) self.add_subsystem( name='groundspeed', subsys=RangeRate(num_nodes=nn), promotes_inputs=[ Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.VELOCITY], - promotes_outputs=[Dynamic.Mission.DISTANCE_RATE]) + Dynamic.Mission.VELOCITY, + ], + promotes_outputs=[Dynamic.Mission.DISTANCE_RATE], + ) self.add_subsystem( name='excess_specific_power', subsys=SpecificEnergyRate(num_nodes=nn), promotes_inputs=[ - (Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), + ( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, + ), Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, Dynamic.Mission.DRAG], - promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)]) + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.DRAG, + ], + promotes_outputs=[ + ( + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, + ) + ], + ) self.add_subsystem( name=Dynamic.Mission.ALTITUDE_RATE_MAX, - subsys=AltitudeRate( - num_nodes=nn), + subsys=AltitudeRate(num_nodes=nn), promotes_inputs=[ - (Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + ( + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, + ), Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.VELOCITY], + Dynamic.Mission.VELOCITY, + ], promotes_outputs=[ - (Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.ALTITUDE_RATE_MAX)]) + (Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.ALTITUDE_RATE_MAX) + ], + ) diff --git a/aviary/mission/flops_based/ode/mission_ODE.py b/aviary/mission/flops_based/ode/mission_ODE.py index 95d95c81f..389ce80a5 100644 --- a/aviary/mission/flops_based/ode/mission_ODE.py +++ b/aviary/mission/flops_based/ode/mission_ODE.py @@ -114,14 +114,17 @@ def setup(self): has_diag_partials=True, ), promotes_inputs=[ - ('mach_rate', Dynamic.Mission.MACH_RATE), - ('sos', Dynamic.Mission.SPEED_OF_SOUND), + ('mach_rate', Dynamic.Atmosphere.MACH_RATE), + ('sos', Dynamic.Atmosphere.SPEED_OF_SOUND), ], promotes_outputs=[('velocity_rate', Dynamic.Mission.VELOCITY_RATE)], ) base_options = {'num_nodes': nn, 'aviary_inputs': aviary_options} + sub1 = self.add_subsystem('solver_sub', om.Group(), + promotes=['*']) + for subsystem in core_subsystems: # check if subsystem_options has entry for a subsystem of this name if subsystem.name in subsystem_options: @@ -133,7 +136,7 @@ def setup(self): system = subsystem.build_mission(**kwargs) if system is not None: - self.add_subsystem( + sub1.add_subsystem( subsystem.name, system, promotes_inputs=subsystem.mission_inputs(**kwargs), @@ -144,15 +147,24 @@ def setup(self): # to the ODE with a special configure() method that promotes # all aircraft:* and mission:* variables to the ODE. external_subsystem_group = ExternalSubsystemGroup() + external_subsystem_group_solver = ExternalSubsystemGroup() add_subsystem_group = False + add_subsystem_group_solver = False for subsystem in self.options['external_subsystems']: subsystem_mission = subsystem.build_mission( num_nodes=nn, aviary_inputs=aviary_options ) if subsystem_mission is not None: - add_subsystem_group = True - external_subsystem_group.add_subsystem( + + if subsystem.needs_mission_solver(aviary_options): + add_subsystem_group_solver = True + target = external_subsystem_group_solver + else: + add_subsystem_group = True + target = external_subsystem_group + + target.add_subsystem( subsystem.name, subsystem_mission ) @@ -165,15 +177,22 @@ def setup(self): promotes_inputs=['*'], promotes_outputs=['*'], ) + if add_subsystem_group_solver: + sub1.add_subsystem( + name='external_subsystems', + subsys=external_subsystem_group_solver, + promotes_inputs=['*'], + promotes_outputs=['*'], + ) - self.add_subsystem( + sub1.add_subsystem( name='mission_EOM', subsys=MissionEOM(num_nodes=nn), promotes_inputs=[ Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_MAX_TOTAL, - Dynamic.Mission.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, + Dynamic.Vehicle.DRAG, Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY_RATE, ], @@ -191,14 +210,14 @@ def setup(self): # Multi Engine - self.add_subsystem( + sub1.add_subsystem( name='throttle_balance', subsys=om.BalanceComp( name="aggregate_throttle", units="unitless", val=np.ones((nn,)), lhs_name='thrust_required', - rhs_name=Dynamic.Mission.THRUST_TOTAL, + rhs_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, eq_units="lbf", normalize=False, res_ref=1.0e6, @@ -207,12 +226,11 @@ def setup(self): promotes_outputs=['*'], ) - self.add_subsystem( + sub1.add_subsystem( "throttle_allocator", ThrottleAllocator( num_nodes=nn, - aviary_options=aviary_options, - throttle_allocation=self.options['throttle_allocation'], + throttle_allocation=self.options['throttle_allocation'] ), promotes_inputs=['*'], promotes_outputs=['*'], @@ -223,14 +241,14 @@ def setup(self): # Single Engine # Add a balance comp to compute throttle based on the required thrust. - self.add_subsystem( + sub1.add_subsystem( name='throttle_balance', subsys=om.BalanceComp( - name=Dynamic.Mission.THROTTLE, + name=Dynamic.Vehicle.Propulsion.THROTTLE, units="unitless", val=np.ones((nn,)), lhs_name='thrust_required', - rhs_name=Dynamic.Mission.THRUST_TOTAL, + rhs_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, eq_units="lbf", normalize=False, lower=0.0 if options['throttle_enforcement'] == 'bounded' else None, @@ -241,10 +259,14 @@ def setup(self): promotes_outputs=['*'], ) - self.set_input_defaults(Dynamic.Mission.THROTTLE, val=1.0, units='unitless') + self.set_input_defaults( + Dynamic.Vehicle.Propulsion.THROTTLE, val=1.0, units='unitless' + ) - self.set_input_defaults(Dynamic.Mission.MACH, val=np.ones(nn), units='unitless') - self.set_input_defaults(Dynamic.Mission.MASS, val=np.ones(nn), units='kg') + self.set_input_defaults( + Dynamic.Atmosphere.MACH, val=np.ones(nn), units='unitless' + ) + self.set_input_defaults(Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.ones(nn), units='m') self.set_input_defaults( @@ -271,7 +293,7 @@ def setup(self): initial_mass_residual_constraint, promotes_inputs=[ ('initial_mass', initial_mass_string), - ('mass', Dynamic.Mission.MASS), + ('mass', Dynamic.Vehicle.MASS), ], promotes_outputs=['initial_mass_residual'], ) @@ -284,12 +306,14 @@ def setup(self): print_level = 0 if analysis_scheme is AnalysisScheme.SHOOTING else 2 - self.nonlinear_solver = om.NewtonSolver( + sub1.nonlinear_solver = om.NewtonSolver( solve_subsystems=True, atol=1.0e-10, rtol=1.0e-10, ) - self.nonlinear_solver.linesearch = om.BoundsEnforceLS() - self.linear_solver = om.DirectSolver(assemble_jac=True) - self.nonlinear_solver.options['err_on_non_converge'] = True - self.nonlinear_solver.options['iprint'] = print_level + sub1.nonlinear_solver.linesearch = om.BoundsEnforceLS() + sub1.linear_solver = om.DirectSolver(assemble_jac=True) + sub1.nonlinear_solver.options['err_on_non_converge'] = True + sub1.nonlinear_solver.options['iprint'] = print_level + + self.options['auto_order'] = True diff --git a/aviary/mission/flops_based/ode/range_rate.py b/aviary/mission/flops_based/ode/range_rate.py index 12f4fcc0f..c1602c514 100644 --- a/aviary/mission/flops_based/ode/range_rate.py +++ b/aviary/mission/flops_based/ode/range_rate.py @@ -20,12 +20,14 @@ def setup(self): Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), desc='climb rate', - units='m/s') + units='m/s', + ) self.add_input( Dynamic.Mission.VELOCITY, val=np.ones(nn), desc='current velocity', - units='m/s') + units='m/s', + ) self.add_output( Dynamic.Mission.DISTANCE_RATE, val=np.ones(nn), @@ -45,14 +47,19 @@ def compute(self, inputs, outputs): def setup_partials(self): arange = np.arange(self.options['num_nodes']) self.declare_partials( - Dynamic.Mission.DISTANCE_RATE, [ - Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], rows=arange, cols=arange) + Dynamic.Mission.DISTANCE_RATE, + [Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], + rows=arange, + cols=arange, + ) def compute_partials(self, inputs, J): climb_rate = inputs[Dynamic.Mission.ALTITUDE_RATE] velocity = inputs[Dynamic.Mission.VELOCITY] - J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE] = -climb_rate / \ - (velocity**2 - climb_rate**2)**0.5 - J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = velocity / \ - (velocity**2 - climb_rate**2)**0.5 + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE] = ( + -climb_rate / (velocity**2 - climb_rate**2) ** 0.5 + ) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = ( + velocity / (velocity**2 - climb_rate**2) ** 0.5 + ) diff --git a/aviary/mission/flops_based/ode/required_thrust.py b/aviary/mission/flops_based/ode/required_thrust.py index af3c5ed62..440636c22 100644 --- a/aviary/mission/flops_based/ode/required_thrust.py +++ b/aviary/mission/flops_based/ode/required_thrust.py @@ -16,35 +16,50 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - self.add_input(Dynamic.Mission.DRAG, val=np.zeros(nn), + self.add_input(Dynamic.Vehicle.DRAG, val=np.zeros(nn), units='N', desc='drag force') - self.add_input(Dynamic.Mission.ALTITUDE_RATE, val=np.zeros(nn), - units='m/s', desc='rate of change of altitude') - self.add_input(Dynamic.Mission.VELOCITY, val=np.zeros(nn), - units='m/s', desc=Dynamic.Mission.VELOCITY) - self.add_input(Dynamic.Mission.VELOCITY_RATE, val=np.zeros( - nn), units='m/s**2', desc='rate of change of velocity') - self.add_input(Dynamic.Mission.MASS, val=np.zeros( + self.add_input( + Dynamic.Mission.ALTITUDE_RATE, + val=np.zeros(nn), + units='m/s', + desc='rate of change of altitude', + ) + self.add_input( + Dynamic.Mission.VELOCITY, + val=np.zeros(nn), + units='m/s', + desc=Dynamic.Mission.VELOCITY, + ) + self.add_input( + Dynamic.Mission.VELOCITY_RATE, + val=np.zeros(nn), + units='m/s**2', + desc='rate of change of velocity', + ) + self.add_input(Dynamic.Vehicle.MASS, val=np.zeros( nn), units='kg', desc='mass of the aircraft') self.add_output('thrust_required', val=np.zeros( nn), units='N', desc='required thrust') ar = np.arange(nn) - self.declare_partials('thrust_required', Dynamic.Mission.DRAG, rows=ar, cols=ar) + self.declare_partials('thrust_required', Dynamic.Vehicle.DRAG, rows=ar, cols=ar) self.declare_partials( - 'thrust_required', Dynamic.Mission.ALTITUDE_RATE, rows=ar, cols=ar) + 'thrust_required', Dynamic.Mission.ALTITUDE_RATE, rows=ar, cols=ar + ) self.declare_partials( - 'thrust_required', Dynamic.Mission.VELOCITY, rows=ar, cols=ar) + 'thrust_required', Dynamic.Mission.VELOCITY, rows=ar, cols=ar + ) self.declare_partials( - 'thrust_required', Dynamic.Mission.VELOCITY_RATE, rows=ar, cols=ar) - self.declare_partials('thrust_required', Dynamic.Mission.MASS, rows=ar, cols=ar) + 'thrust_required', Dynamic.Mission.VELOCITY_RATE, rows=ar, cols=ar + ) + self.declare_partials('thrust_required', Dynamic.Vehicle.MASS, rows=ar, cols=ar) def compute(self, inputs, outputs): - drag = inputs[Dynamic.Mission.DRAG] + drag = inputs[Dynamic.Vehicle.DRAG] altitude_rate = inputs[Dynamic.Mission.ALTITUDE_RATE] velocity = inputs[Dynamic.Mission.VELOCITY] velocity_rate = inputs[Dynamic.Mission.VELOCITY_RATE] - mass = inputs[Dynamic.Mission.MASS] + mass = inputs[Dynamic.Vehicle.MASS] thrust_required = drag + (altitude_rate*gravity/velocity + velocity_rate) * mass @@ -54,12 +69,15 @@ def compute_partials(self, inputs, partials): altitude_rate = inputs[Dynamic.Mission.ALTITUDE_RATE] velocity = inputs[Dynamic.Mission.VELOCITY] velocity_rate = inputs[Dynamic.Mission.VELOCITY_RATE] - mass = inputs[Dynamic.Mission.MASS] + mass = inputs[Dynamic.Vehicle.MASS] - partials['thrust_required', Dynamic.Mission.DRAG] = 1.0 - partials['thrust_required', Dynamic.Mission.ALTITUDE_RATE] = gravity/velocity * mass - partials['thrust_required', Dynamic.Mission.VELOCITY] = - \ - altitude_rate*gravity/velocity**2 * mass + partials['thrust_required', Dynamic.Vehicle.DRAG] = 1.0 + partials['thrust_required', Dynamic.Mission.ALTITUDE_RATE] = ( + gravity / velocity * mass + ) + partials['thrust_required', Dynamic.Mission.VELOCITY] = ( + -altitude_rate * gravity / velocity**2 * mass + ) partials['thrust_required', Dynamic.Mission.VELOCITY_RATE] = mass - partials['thrust_required', Dynamic.Mission.MASS] = altitude_rate * \ + partials['thrust_required', Dynamic.Vehicle.MASS] = altitude_rate * \ gravity/velocity + velocity_rate diff --git a/aviary/mission/flops_based/ode/takeoff_eom.py b/aviary/mission/flops_based/ode/takeoff_eom.py index d0d1ab4d0..3ab97bd1d 100644 --- a/aviary/mission/flops_based/ode/takeoff_eom.py +++ b/aviary/mission/flops_based/ode/takeoff_eom.py @@ -32,7 +32,7 @@ def setup(self): add_aviary_input( self, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, val=np.ones(nn), units='kg/m**3', desc='current atmospheric density', @@ -57,7 +57,7 @@ def setup_partials(self): self.declare_partials( 'stall_speed', - ['mass', Dynamic.Mission.DENSITY], + ['mass', Dynamic.Atmosphere.DENSITY], rows=rows_cols, cols=rows_cols, ) @@ -66,7 +66,7 @@ def setup_partials(self): def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): mass = inputs['mass'] - density = inputs[Dynamic.Mission.DENSITY] + density = inputs[Dynamic.Atmosphere.DENSITY] area = inputs['area'] lift_coefficient_max = inputs['lift_coefficient_max'] @@ -77,7 +77,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): def compute_partials(self, inputs, J, discrete_inputs=None): mass = inputs['mass'] - density = inputs[Dynamic.Mission.DENSITY] + density = inputs[Dynamic.Atmosphere.DENSITY] area = inputs['area'] lift_coefficient_max = inputs['lift_coefficient_max'] @@ -88,7 +88,7 @@ def compute_partials(self, inputs, J, discrete_inputs=None): J['stall_speed', 'mass'] = \ grav_metric / (stall_speed * density * area * lift_coefficient_max) - J['stall_speed', Dynamic.Mission.DENSITY] = -weight / ( + J['stall_speed', Dynamic.Atmosphere.DENSITY] = -weight / ( stall_speed * density**2 * area * lift_coefficient_max ) @@ -203,14 +203,16 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units='rad') + add_aviary_input( + self, Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad' + ) add_aviary_input(self, Dynamic.Mission.VELOCITY, val=np.zeros(nn), units='m/s') add_aviary_output(self, Dynamic.Mission.DISTANCE_RATE, val=np.zeros(nn), units='m/s') - add_aviary_output(self, Dynamic.Mission.ALTITUDE_RATE, - val=np.zeros(nn), units='m/s') + add_aviary_output( + self, Dynamic.Mission.ALTITUDE_RATE, val=np.zeros(nn), units='m/s' + ) def setup_partials(self): options = self.options @@ -224,10 +226,16 @@ def setup_partials(self): else: self.declare_partials( - Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE, dependent=False) + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + dependent=False, + ) self.declare_partials( - Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY, val=np.identity(nn)) + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.VELOCITY, + val=np.identity(nn), + ) self.declare_partials(Dynamic.Mission.ALTITUDE_RATE, '*', dependent=False) @@ -258,10 +266,14 @@ def compute_partials(self, inputs, J, discrete_inputs=None): cgam = np.cos(flight_path_angle) sgam = np.sin(flight_path_angle) - J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = -sgam * velocity + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -sgam * velocity + ) J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = cgam - J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = cgam * velocity + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + cgam * velocity + ) J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = sgam @@ -278,7 +290,7 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') self.add_input( 'forces_horizontal', val=np.zeros(nn), units='N', @@ -302,10 +314,18 @@ def setup_partials(self): rows_cols = np.arange(nn) self.declare_partials( - 'acceleration_horizontal', Dynamic.Mission.MASS, rows=rows_cols, cols=rows_cols) + 'acceleration_horizontal', + Dynamic.Vehicle.MASS, + rows=rows_cols, + cols=rows_cols, + ) self.declare_partials( - 'acceleration_vertical', Dynamic.Mission.MASS, rows=rows_cols, cols=rows_cols) + 'acceleration_vertical', + Dynamic.Vehicle.MASS, + rows=rows_cols, + cols=rows_cols, + ) self.declare_partials( 'acceleration_horizontal', 'forces_horizontal', rows=rows_cols, @@ -321,7 +341,7 @@ def setup_partials(self): 'acceleration_vertical', 'forces_vertical', rows=rows_cols, cols=rows_cols) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - mass = inputs[Dynamic.Mission.MASS] + mass = inputs[Dynamic.Vehicle.MASS] f_h = inputs['forces_horizontal'] f_v = inputs['forces_vertical'] @@ -332,14 +352,14 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): outputs['acceleration_vertical'] = a_v def compute_partials(self, inputs, J, discrete_inputs=None): - mass = inputs[Dynamic.Mission.MASS] + mass = inputs[Dynamic.Vehicle.MASS] f_h = inputs['forces_horizontal'] f_v = inputs['forces_vertical'] m2 = mass * mass - J['acceleration_horizontal', Dynamic.Mission.MASS] = -f_h / m2 - J['acceleration_vertical', Dynamic.Mission.MASS] = -f_v / m2 + J['acceleration_horizontal', Dynamic.Vehicle.MASS] = -f_h / m2 + J['acceleration_vertical', Dynamic.Vehicle.MASS] = -f_v / m2 J['acceleration_horizontal', 'forces_horizontal'] = 1. / mass @@ -369,11 +389,13 @@ def setup(self): add_aviary_input(self, Dynamic.Mission.DISTANCE_RATE, val=np.zeros(nn), units='m/s') - add_aviary_input(self, Dynamic.Mission.ALTITUDE_RATE, - val=np.zeros(nn), units='m/s') + add_aviary_input( + self, Dynamic.Mission.ALTITUDE_RATE, val=np.zeros(nn), units='m/s' + ) - add_aviary_output(self, Dynamic.Mission.VELOCITY_RATE, - val=np.ones(nn), units='m/s**2') + add_aviary_output( + self, Dynamic.Mission.VELOCITY_RATE, val=np.ones(nn), units='m/s**2' + ) rows_cols = np.arange(nn) @@ -401,11 +423,13 @@ def compute_partials(self, inputs, J, discrete_inputs=None): J[Dynamic.Mission.VELOCITY_RATE, 'acceleration_horizontal'] = v_h / den J[Dynamic.Mission.VELOCITY_RATE, 'acceleration_vertical'] = v_v / den - J[Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.DISTANCE_RATE] = a_h / den - 0.5 * num / fact**(3/2) * 2.0 * v_h + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.DISTANCE_RATE] = ( + a_h / den - 0.5 * num / fact ** (3 / 2) * 2.0 * v_h + ) - J[Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.ALTITUDE_RATE] = a_v / den - 0.5 * num / fact**(3/2) * 2.0 * v_v + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.ALTITUDE_RATE] = ( + a_v / den - 0.5 * num / fact ** (3 / 2) * 2.0 * v_v + ) class FlightPathAngleRate(om.ExplicitComponent): @@ -423,8 +447,9 @@ def setup(self): add_aviary_input(self, Dynamic.Mission.DISTANCE_RATE, val=np.zeros(nn), units='m/s') - add_aviary_input(self, Dynamic.Mission.ALTITUDE_RATE, - val=np.zeros(nn), units='m/s') + add_aviary_input( + self, Dynamic.Mission.ALTITUDE_RATE, val=np.zeros(nn), units='m/s' + ) self.add_input( 'acceleration_horizontal', val=np.zeros(nn), @@ -439,7 +464,11 @@ def setup(self): ) add_aviary_output( - self, Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, val=np.zeros(nn), units='rad/s') + self, + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + val=np.zeros(nn), + units='rad/s', + ) rows_cols = np.arange(nn) @@ -472,8 +501,12 @@ def compute_partials(self, inputs, J, discrete_inputs=None): df_dav = v_h / den - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.DISTANCE_RATE] = df_dvh - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.ALTITUDE_RATE] = df_dvv + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.DISTANCE_RATE] = ( + df_dvh + ) + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.ALTITUDE_RATE] = ( + df_dvv + ) J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, 'acceleration_horizontal'] = df_dah J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, 'acceleration_vertical'] = df_dav @@ -508,15 +541,17 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.Mission.THRUST_TOTAL, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Vehicle.LIFT, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.DRAG, val=np.ones(nn), units='N') self.add_input('angle_of_attack', val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units='rad') + add_aviary_input( + self, Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad' + ) self.add_output( 'forces_horizontal', val=np.zeros(nn), units='N', @@ -535,16 +570,25 @@ def setup_partials(self): rows_cols = np.arange(nn) if climbing: - self.declare_partials('forces_horizontal', - Dynamic.Mission.MASS, dependent=False) + self.declare_partials( + 'forces_horizontal', Dynamic.Vehicle.MASS, dependent=False + ) self.declare_partials( - 'forces_vertical', Dynamic.Mission.MASS, val=-grav_metric, rows=rows_cols, - cols=rows_cols) + 'forces_vertical', + Dynamic.Vehicle.MASS, + val=-grav_metric, + rows=rows_cols, + cols=rows_cols, + ) wrt = [ - Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.LIFT, Dynamic.Mission.DRAG, 'angle_of_attack', - Dynamic.Mission.FLIGHT_PATH_ANGLE] + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.DRAG, + 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE, + ] self.declare_partials('*', wrt, rows=rows_cols, cols=rows_cols) @@ -555,28 +599,45 @@ def setup_partials(self): val = -grav_metric * mu self.declare_partials( - 'forces_horizontal', Dynamic.Mission.MASS, val=val, rows=rows_cols, - cols=rows_cols) + 'forces_horizontal', + Dynamic.Vehicle.MASS, + val=val, + rows=rows_cols, + cols=rows_cols, + ) self.declare_partials( - 'forces_horizontal', Dynamic.Mission.LIFT, val=mu, rows=rows_cols, - cols=rows_cols) + 'forces_horizontal', + Dynamic.Vehicle.LIFT, + val=mu, + rows=rows_cols, + cols=rows_cols, + ) t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') val = np.cos(t_inc) + np.sin(t_inc) * mu self.declare_partials( - 'forces_horizontal', Dynamic.Mission.THRUST_TOTAL, val=val, rows=rows_cols, - cols=rows_cols) + 'forces_horizontal', + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + val=val, + rows=rows_cols, + cols=rows_cols, + ) self.declare_partials( - 'forces_horizontal', Dynamic.Mission.DRAG, val=-1., rows=rows_cols, - cols=rows_cols) + 'forces_horizontal', + Dynamic.Vehicle.DRAG, + val=-1.0, + rows=rows_cols, + cols=rows_cols, + ) self.declare_partials( - 'forces_horizontal', ['angle_of_attack', - Dynamic.Mission.FLIGHT_PATH_ANGLE], - dependent=False) + 'forces_horizontal', + ['angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE], + dependent=False, + ) self.declare_partials('forces_vertical', ['*'], dependent=False) @@ -588,10 +649,10 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.Mission.MASS] - lift = inputs[Dynamic.Mission.LIFT] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] + mass = inputs[Dynamic.Vehicle.MASS] + lift = inputs[Dynamic.Vehicle.LIFT] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] weight = mass * grav_metric @@ -648,9 +709,9 @@ def compute_partials(self, inputs, J, discrete_inputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - lift = inputs[Dynamic.Mission.LIFT] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] + lift = inputs[Dynamic.Vehicle.LIFT] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] alpha = inputs['angle_of_attack'] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] @@ -663,23 +724,25 @@ def compute_partials(self, inputs, J, discrete_inputs=None): c_gamma = np.cos(gamma) s_gamma = np.sin(gamma) - J['forces_horizontal', Dynamic.Mission.THRUST_TOTAL] = c_angle - J['forces_vertical', Dynamic.Mission.THRUST_TOTAL] = s_angle + J['forces_horizontal', Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = c_angle + J['forces_vertical', Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = s_angle - J['forces_horizontal', Dynamic.Mission.LIFT] = -s_gamma - J['forces_vertical', Dynamic.Mission.LIFT] = c_gamma + J['forces_horizontal', Dynamic.Vehicle.LIFT] = -s_gamma + J['forces_vertical', Dynamic.Vehicle.LIFT] = c_gamma - J['forces_horizontal', Dynamic.Mission.DRAG] = -c_gamma - J['forces_vertical', Dynamic.Mission.DRAG] = -s_gamma + J['forces_horizontal', Dynamic.Vehicle.DRAG] = -c_gamma + J['forces_vertical', Dynamic.Vehicle.DRAG] = -s_gamma J['forces_horizontal', 'angle_of_attack'] = -thrust * s_angle J['forces_vertical', 'angle_of_attack'] = thrust * c_angle - J['forces_horizontal', Dynamic.Mission.FLIGHT_PATH_ANGLE] = \ + J['forces_horizontal', Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( -thrust * s_angle + drag * s_gamma - lift * c_gamma + ) - J['forces_vertical', Dynamic.Mission.FLIGHT_PATH_ANGLE] = \ + J['forces_vertical', Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( thrust * c_angle - drag * c_gamma - lift * s_gamma + ) class ClimbGradientForces(om.ExplicitComponent): @@ -702,15 +765,18 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.Mission.THRUST_TOTAL, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Vehicle.LIFT, val=np.ones(nn), units='N') + add_aviary_input( + self, Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=np.ones(nn), units='N' + ) + add_aviary_input(self, Dynamic.Vehicle.DRAG, val=np.ones(nn), units='N') self.add_input('angle_of_attack', val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units='rad') + add_aviary_input( + self, Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad' + ) self.add_output( 'climb_gradient_forces_horizontal', val=np.zeros(nn), units='N', @@ -732,23 +798,38 @@ def setup_partials(self): self.declare_partials( '*', [ - Dynamic.Mission.MASS, Dynamic.Mission.THRUST_TOTAL, 'angle_of_attack', - Dynamic.Mission.FLIGHT_PATH_ANGLE], - rows=rows_cols, cols=rows_cols) + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE, + ], + rows=rows_cols, + cols=rows_cols, + ) self.declare_partials( - 'climb_gradient_forces_horizontal', Dynamic.Mission.DRAG, val=-1., - rows=rows_cols, cols=rows_cols) + 'climb_gradient_forces_horizontal', + Dynamic.Vehicle.DRAG, + val=-1.0, + rows=rows_cols, + cols=rows_cols, + ) self.declare_partials( - 'climb_gradient_forces_vertical', Dynamic.Mission.DRAG, dependent=False) + 'climb_gradient_forces_vertical', Dynamic.Vehicle.DRAG, dependent=False + ) self.declare_partials( - 'climb_gradient_forces_horizontal', Dynamic.Mission.LIFT, dependent=False) + 'climb_gradient_forces_horizontal', Dynamic.Vehicle.LIFT, dependent=False + ) self.declare_partials( - 'climb_gradient_forces_vertical', Dynamic.Mission.LIFT, val=1., - rows=rows_cols, cols=rows_cols) + 'climb_gradient_forces_vertical', + Dynamic.Vehicle.LIFT, + val=1.0, + rows=rows_cols, + cols=rows_cols, + ) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): options = self.options @@ -758,10 +839,10 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.Mission.MASS] - lift = inputs[Dynamic.Mission.LIFT] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] + mass = inputs[Dynamic.Vehicle.MASS] + lift = inputs[Dynamic.Vehicle.LIFT] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] weight = mass * grav_metric @@ -792,10 +873,10 @@ def compute_partials(self, inputs, J, discrete_inputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.Mission.MASS] - lift = inputs[Dynamic.Mission.LIFT] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] + mass = inputs[Dynamic.Vehicle.MASS] + lift = inputs[Dynamic.Vehicle.LIFT] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] weight = mass * grav_metric @@ -813,11 +894,11 @@ def compute_partials(self, inputs, J, discrete_inputs=None): f_h_key = 'climb_gradient_forces_horizontal' f_v_key = 'climb_gradient_forces_vertical' - J[f_h_key, Dynamic.Mission.MASS] = -grav_metric * s_gamma - J[f_v_key, Dynamic.Mission.MASS] = -grav_metric * c_gamma + J[f_h_key, Dynamic.Vehicle.MASS] = -grav_metric * s_gamma + J[f_v_key, Dynamic.Vehicle.MASS] = -grav_metric * c_gamma - J[f_h_key, Dynamic.Mission.THRUST_TOTAL] = c_angle - J[f_v_key, Dynamic.Mission.THRUST_TOTAL] = s_angle + J[f_h_key, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = c_angle + J[f_v_key, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = s_angle J[f_h_key, 'angle_of_attack'] = -thrust * s_angle J[f_v_key, 'angle_of_attack'] = thrust * c_angle diff --git a/aviary/mission/flops_based/ode/takeoff_ode.py b/aviary/mission/flops_based/ode/takeoff_ode.py index 57278f53f..1cb0354e0 100644 --- a/aviary/mission/flops_based/ode/takeoff_ode.py +++ b/aviary/mission/flops_based/ode/takeoff_ode.py @@ -110,7 +110,7 @@ def setup(self): StallSpeed(num_nodes=nn), promotes_inputs=[ "mass", - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, ('area', Aircraft.Wing.AREA), ("lift_coefficient_max", self.stall_speed_lift_coefficient_name), ], @@ -176,10 +176,10 @@ def setup(self): promotes_inputs=[ Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, 'angle_of_attack', ], promotes_outputs=[ diff --git a/aviary/mission/flops_based/ode/test/test_landing_eom.py b/aviary/mission/flops_based/ode/test/test_landing_eom.py index 1b0a58be7..ca92b53bf 100644 --- a/aviary/mission/flops_based/ode/test/test_landing_eom.py +++ b/aviary/mission/flops_based/ode/test/test_landing_eom.py @@ -12,6 +12,8 @@ from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import do_validation_test from aviary.variable_info.variables import Dynamic +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.preprocessors import preprocess_options class FlareEOMTest(unittest.TestCase): @@ -25,6 +27,8 @@ def setUp(self): time, _ = detailed_landing_flare.get_item('time') nn = len(time) aviary_options = inputs + engine = build_engine_deck(aviary_options) + preprocess_options(aviary_options, engine_models=engine) prob.model.add_subsystem( "landing_flare_eom", @@ -45,14 +49,19 @@ def test_case(self): 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG], + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + ], output_keys=[ Dynamic.Mission.DISTANCE_RATE, - Dynamic.Mission.ALTITUDE_RATE], - tol=1e-2, atol=1e-8, rtol=5e-10) + Dynamic.Mission.ALTITUDE_RATE, + ], + tol=1e-2, + atol=1e-8, + rtol=5e-10, + ) def test_IO(self): exclude_inputs = { @@ -87,13 +96,15 @@ def test_GlideSlopeForces(self): "glide", GlideSlopeForces(num_nodes=2, aviary_options=aviary_options), promotes=["*"] ) prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([106292, 106292]), units="lbm" + Dynamic.Vehicle.MASS, np.array([106292, 106292]), units="lbm" ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" + Dynamic.Vehicle.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" ) prob.model.set_input_defaults( - Dynamic.Mission.LIFT, np.array([482117.47027692, 568511.57097785]), units="N" + Dynamic.Vehicle.LIFT, + np.array([482117.47027692, 568511.57097785]), + units="N", ) prob.model.set_input_defaults( "angle_of_attack", np.array([5.086, 6.834]), units="deg" @@ -128,22 +139,24 @@ def test_FlareSumForces(self): # use data from detailed_landing_flare in models/N3CC/N3CC_data.py prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([106292, 106292]), units="lbm" + Dynamic.Vehicle.MASS, np.array([106292, 106292]), units="lbm" ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" + Dynamic.Vehicle.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" ) prob.model.set_input_defaults( - Dynamic.Mission.LIFT, np.array([482117.47027692, 568511.57097785]), units="N" + Dynamic.Vehicle.LIFT, + np.array([482117.47027692, 568511.57097785]), + units="N", ) prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" ) prob.model.set_input_defaults( "angle_of_attack", np.array([5.086, 6.834]), units="deg" ) prob.model.set_input_defaults( - Dynamic.Mission.FLIGHT_PATH_ANGLE, np.array([-3., -2.47]), units="deg" + Dynamic.Mission.FLIGHT_PATH_ANGLE, np.array([-3.0, -2.47]), units="deg" ) prob.setup(check=False, force_alloc_complex=True) prob.run_model() @@ -171,16 +184,18 @@ def test_GroundSumForces(self): # use data from detailed_landing_flare in models/N3CC/N3CC_data.py prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([106292, 106292]), units="lbm" + Dynamic.Vehicle.MASS, np.array([106292, 106292]), units="lbm" ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" + Dynamic.Vehicle.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" ) prob.model.set_input_defaults( - Dynamic.Mission.LIFT, np.array([482117.47027692, 568511.57097785]), units="N" + Dynamic.Vehicle.LIFT, + np.array([482117.47027692, 568511.57097785]), + units="N", ) prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" ) prob.setup(check=False, force_alloc_complex=True) prob.run_model() diff --git a/aviary/mission/flops_based/ode/test/test_landing_ode.py b/aviary/mission/flops_based/ode/test/test_landing_ode.py index 0c863e6d5..454bf0e32 100644 --- a/aviary/mission/flops_based/ode/test/test_landing_ode.py +++ b/aviary/mission/flops_based/ode/test/test_landing_ode.py @@ -11,6 +11,7 @@ detailed_landing_flare, inputs, landing_subsystem_options) from aviary.validation_cases.validation_tests import do_validation_test from aviary.variable_info.variables import Dynamic, Aircraft +from aviary.utils.preprocessors import preprocess_options class FlareODETest(unittest.TestCase): @@ -24,8 +25,12 @@ def test_case(self): nn = len(time) aviary_options = inputs + engine = build_engine_deck(aviary_options) + + preprocess_options(aviary_options, engine_models=engine) + default_mission_subsystems = get_default_mission_subsystems( - 'FLOPS', build_engine_deck(aviary_options)) + 'FLOPS', engine) prob.model.add_subsystem( "landing_flare_ode", @@ -52,15 +57,21 @@ def test_case(self): 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG], + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + ], output_keys=[ Dynamic.Mission.DISTANCE_RATE, - Dynamic.Mission.ALTITUDE_RATE], - tol=1e-2, atol=5e-9, rtol=5e-9, - check_values=False, check_partials=True) + Dynamic.Mission.ALTITUDE_RATE, + ], + tol=1e-2, + atol=5e-9, + rtol=5e-9, + check_values=False, + check_partials=True, + ) if __name__ == "__main__": diff --git a/aviary/mission/flops_based/ode/test/test_mission_eom.py b/aviary/mission/flops_based/ode/test/test_mission_eom.py index 648c3a111..8c2a7bd05 100644 --- a/aviary/mission/flops_based/ode/test/test_mission_eom.py +++ b/aviary/mission/flops_based/ode/test/test_mission_eom.py @@ -21,22 +21,34 @@ def setUp(self): "mission", MissionEOM(num_nodes=3), promotes=["*"] ) prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([81796.1389890711, 74616.9849763798, 65193.7423491884]), units="kg" + Dynamic.Vehicle.MASS, + np.array([81796.1389890711, 74616.9849763798, 65193.7423491884]), + units="kg", ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([9978.32211087097, 8769.90342254821, 7235.03338269778]), units="lbf" + Dynamic.Vehicle.DRAG, + np.array([9978.32211087097, 8769.90342254821, 7235.03338269778]), + units="lbf", ) prob.model.set_input_defaults( - Dynamic.Mission.ALTITUDE_RATE, np.array([29.8463233754212, -5.69941245767868E-09, -4.32644785970493]), units="ft/s" + Dynamic.Mission.ALTITUDE_RATE, + np.array([29.8463233754212, -5.69941245767868e-09, -4.32644785970493]), + units="ft/s", ) prob.model.set_input_defaults( - Dynamic.Mission.VELOCITY_RATE, np.array([0.558739800813549, 3.33665416459715E-17, -0.38372209277242]), units="m/s**2" + Dynamic.Mission.VELOCITY_RATE, + np.array([0.558739800813549, 3.33665416459715e-17, -0.38372209277242]), + units="m/s**2", ) prob.model.set_input_defaults( - Dynamic.Mission.VELOCITY, np.array([164.029012458452, 232.775306059091, 117.638805929526]), units="m/s" + Dynamic.Mission.VELOCITY, + np.array([164.029012458452, 232.775306059091, 117.638805929526]), + units="m/s", ) prob.model.set_input_defaults( - Dynamic.Mission.THRUST_MAX_TOTAL, np.array([40799.6009633346, 11500.32, 42308.2709683461]), units="lbf" + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, + np.array([40799.6009633346, 11500.32, 42308.2709683461]), + units="lbf", ) prob.setup(check=False, force_alloc_complex=True) @@ -48,8 +60,11 @@ def test_case(self): tol = 1e-6 self.prob.run_model() - assert_near_equal(self.prob.get_val(Dynamic.Mission.ALTITUDE_RATE_MAX, units='ft/min'), - np.array([3679.0525544843, 760.55416759, 6557.07891846677]), tol) + assert_near_equal( + self.prob.get_val(Dynamic.Mission.ALTITUDE_RATE_MAX, units='ft/min'), + np.array([3679.0525544843, 760.55416759, 6557.07891846677]), + tol, + ) partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-8, rtol=1e-12) diff --git a/aviary/mission/flops_based/ode/test/test_range_rate.py b/aviary/mission/flops_based/ode/test/test_range_rate.py index 3d6d3ab2a..f9ea57dfc 100644 --- a/aviary/mission/flops_based/ode/test/test_range_rate.py +++ b/aviary/mission/flops_based/ode/test/test_range_rate.py @@ -31,14 +31,15 @@ def setUp(self): def test_case1(self): - do_validation_test(self.prob, - 'full_mission_test_data', - input_validation_data=data, - output_validation_data=data, - input_keys=[Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.VELOCITY], - output_keys=Dynamic.Mission.DISTANCE_RATE, - tol=1e-12) + do_validation_test( + self.prob, + 'full_mission_test_data', + input_validation_data=data, + output_validation_data=data, + input_keys=[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], + output_keys=Dynamic.Mission.DISTANCE_RATE, + tol=1e-12, + ) def test_IO(self): assert_match_varnames(self.prob.model) diff --git a/aviary/mission/flops_based/ode/test/test_required_thrust.py b/aviary/mission/flops_based/ode/test/test_required_thrust.py index 4e55b5b7a..5a7cdd826 100644 --- a/aviary/mission/flops_based/ode/test/test_required_thrust.py +++ b/aviary/mission/flops_based/ode/test/test_required_thrust.py @@ -21,10 +21,10 @@ def setUp(self): "req_thrust", RequiredThrust(num_nodes=2), promotes=["*"] ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" + Dynamic.Vehicle.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" ) prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([106292, 106292]), units="lbm" + Dynamic.Vehicle.MASS, np.array([106292, 106292]), units="lbm" ) prob.model.set_input_defaults( Dynamic.Mission.ALTITUDE_RATE, np.array([1.72, 11.91]), units="m/s" diff --git a/aviary/mission/flops_based/ode/test/test_takeoff_eom.py b/aviary/mission/flops_based/ode/test/test_takeoff_eom.py index e3e35fc21..3718ebd5b 100644 --- a/aviary/mission/flops_based/ode/test/test_takeoff_eom.py +++ b/aviary/mission/flops_based/ode/test/test_takeoff_eom.py @@ -32,15 +32,18 @@ def test_case_ground(self): 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG], + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + ], output_keys=[ Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.VELOCITY_RATE], - tol=1e-2) + Dynamic.Mission.VELOCITY_RATE, + ], + tol=1e-2, + ) def test_case_climbing(self): prob = self._make_prob(climbing=True) @@ -54,15 +57,20 @@ def test_case_climbing(self): 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG], + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + ], output_keys=[ Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.VELOCITY_RATE], - tol=1e-2, atol=1e-9, rtol=1e-11) + Dynamic.Mission.VELOCITY_RATE, + ], + tol=1e-2, + atol=1e-9, + rtol=1e-11, + ) @staticmethod def _make_prob(climbing): @@ -106,7 +114,7 @@ def test_StallSpeed(self): "stall_speed", StallSpeed(num_nodes=2), promotes=["*"] ) prob.model.set_input_defaults( - Dynamic.Mission.DENSITY, np.array([1, 2]), units="kg/m**3" + Dynamic.Atmosphere.DENSITY, np.array([1, 2]), units="kg/m**3" ) prob.model.set_input_defaults( "area", 10, units="m**2" @@ -151,8 +159,9 @@ def test_DistanceRates_1(self): [4.280758, -1.56085]), tol ) assert_near_equal( - prob[Dynamic.Mission.ALTITUDE_RATE], np.array( - [3.004664, -2.203122]), tol + prob[Dynamic.Mission.ALTITUDE_RATE], + np.array([3.004664, -2.203122]), + tol, ) partial_data = prob.check_partials(out_stream=None, method="cs") @@ -238,8 +247,9 @@ def test_VelocityRate(self): prob.run_model() assert_near_equal( - prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [100.5284, 206.6343]), tol + prob[Dynamic.Mission.VELOCITY_RATE], + np.array([100.5284, 206.6343]), + tol, ) partial_data = prob.check_partials(out_stream=None, method="cs") @@ -268,8 +278,9 @@ def test_FlightPathAngleRate(self): prob.run_model() assert_near_equal( - prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array( - [0.3039257, 0.51269018]), tol + prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], + np.array([0.3039257, 0.51269018]), + tol, ) partial_data = prob.check_partials(out_stream=None, method="cs") @@ -287,16 +298,18 @@ def test_SumForcese_1(self): "sum1", SumForces(num_nodes=2, climbing=True, aviary_options=aviary_options), promotes=["*"] ) prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([106292, 106292]), units="lbm" + Dynamic.Vehicle.MASS, np.array([106292, 106292]), units="lbm" ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" + Dynamic.Vehicle.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" ) prob.model.set_input_defaults( - Dynamic.Mission.LIFT, np.array([482117.47027692, 568511.57097785]), units="N" + Dynamic.Vehicle.LIFT, + np.array([482117.47027692, 568511.57097785]), + units="N", ) prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" ) prob.setup(check=False, force_alloc_complex=True) @@ -326,16 +339,18 @@ def test_SumForcese_2(self): "sum2", SumForces(num_nodes=2, climbing=False, aviary_options=aviary_options), promotes=["*"] ) prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([106292, 106292]), units="lbm" + Dynamic.Vehicle.MASS, np.array([106292, 106292]), units="lbm" ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" + Dynamic.Vehicle.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" ) prob.model.set_input_defaults( - Dynamic.Mission.LIFT, np.array([482117.47027692, 568511.57097785]), units="N" + Dynamic.Vehicle.LIFT, + np.array([482117.47027692, 568511.57097785]), + units="N", ) prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" ) prob.setup(check=False, force_alloc_complex=True) @@ -363,16 +378,18 @@ def test_ClimbGradientForces(self): "climb_grad", ClimbGradientForces(num_nodes=2, aviary_options=aviary_options), promotes=["*"] ) prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([106292, 106292]), units="lbm" + Dynamic.Vehicle.MASS, np.array([106292, 106292]), units="lbm" ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" + Dynamic.Vehicle.DRAG, np.array([47447.13138523, 44343.01567596]), units="N" ) prob.model.set_input_defaults( - Dynamic.Mission.LIFT, np.array([482117.47027692, 568511.57097785]), units="N" + Dynamic.Vehicle.LIFT, + np.array([482117.47027692, 568511.57097785]), + units="N", ) prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, np.array([4980.3, 4102]), units="N" ) prob.model.set_input_defaults( Dynamic.Mission.FLIGHT_PATH_ANGLE, np.array([0.612, 4.096]), units="rad" diff --git a/aviary/mission/flops_based/ode/test/test_takeoff_ode.py b/aviary/mission/flops_based/ode/test/test_takeoff_ode.py index daecf73cb..453422c7b 100644 --- a/aviary/mission/flops_based/ode/test/test_takeoff_ode.py +++ b/aviary/mission/flops_based/ode/test/test_takeoff_ode.py @@ -11,6 +11,7 @@ detailed_takeoff_climbing, detailed_takeoff_ground, takeoff_subsystem_options, inputs) from aviary.validation_cases.validation_tests import do_validation_test from aviary.variable_info.variables import Dynamic, Mission, Aircraft +from aviary.utils.preprocessors import preprocess_options takeoff_subsystem_options = deepcopy(takeoff_subsystem_options) @@ -33,16 +34,22 @@ def test_case_ground(self): Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.ALTITUDE, Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG], + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + ], output_keys=[ Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.VELOCITY_RATE], - tol=1e-2, atol=1e-9, rtol=1e-11, - check_values=False, check_partials=True) + Dynamic.Mission.VELOCITY_RATE, + ], + tol=1e-2, + atol=1e-9, + rtol=1e-11, + check_values=False, + check_partials=True, + ) def test_case_climbing(self): prob = self._make_prob(climbing=True) @@ -57,16 +64,22 @@ def test_case_climbing(self): Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.ALTITUDE, Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG], + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + ], output_keys=[ Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.VELOCITY_RATE], - tol=1e-2, atol=1e-9, rtol=1e-11, - check_values=False, check_partials=True) + Dynamic.Mission.VELOCITY_RATE, + ], + tol=1e-2, + atol=1e-9, + rtol=1e-11, + check_values=False, + check_partials=True, + ) @staticmethod def _make_prob(climbing): @@ -75,9 +88,12 @@ def _make_prob(climbing): time, _ = detailed_takeoff_climbing.get_item('time') nn = len(time) aviary_options = inputs + engine = build_engine_deck(aviary_options) + + preprocess_options(aviary_options, engine_models=engine) default_mission_subsystems = get_default_mission_subsystems( - 'FLOPS', build_engine_deck(aviary_options)) + 'FLOPS', engine) prob.model.add_subsystem( "takeoff_ode", diff --git a/aviary/mission/flops_based/phases/build_takeoff.py b/aviary/mission/flops_based/phases/build_takeoff.py index ff99291bd..eff33f9a1 100644 --- a/aviary/mission/flops_based/phases/build_takeoff.py +++ b/aviary/mission/flops_based/phases/build_takeoff.py @@ -64,8 +64,7 @@ def build_phase(self, use_detailed=False): takeoff = TakeoffGroup(num_engines=self.num_engines) takeoff.set_input_defaults( - Dynamic.Mission.ALTITUDE, - val=self.airport_altitude, - units="ft") + Dynamic.Mission.ALTITUDE, val=self.airport_altitude, units="ft" + ) return takeoff diff --git a/aviary/mission/flops_based/phases/detailed_landing_phases.py b/aviary/mission/flops_based/phases/detailed_landing_phases.py index 4dffa24e7..adccdb346 100644 --- a/aviary/mission/flops_based/phases/detailed_landing_phases.py +++ b/aviary/mission/flops_based/phases/detailed_landing_phases.py @@ -155,31 +155,47 @@ def build_phase(self, aviary_options: AviaryValues = None): altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=False, fix_final=False, + Dynamic.Mission.ALTITUDE, + fix_initial=False, + fix_final=False, ref=altitude_ref, - defect_ref=altitude_ref, units=units, - rate_source=Dynamic.Mission.ALTITUDE_RATE) + defect_ref=altitude_ref, + units=units, + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, fix_final=False, - lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + fix_final=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) - phase.add_control(Dynamic.Mission.FLIGHT_PATH_ANGLE, opt=False, fix_initial=True) + phase.add_control( + Dynamic.Mission.FLIGHT_PATH_ANGLE, opt=False, fix_initial=True + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=True, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=True, + fix_final=False, + lower=0.0, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -195,12 +211,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) initial_height, units = user_options.get_item('initial_height') @@ -211,7 +227,13 @@ def build_phase(self, aviary_options: AviaryValues = None): h = initial_height + airport_altitude phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='initial', equals=h, ref=h, units=units, linear=True) + Dynamic.Mission.ALTITUDE, + loc='initial', + equals=h, + ref=h, + units=units, + linear=True, + ) return phase @@ -258,7 +280,8 @@ def _extra_ode_init_kwargs(self): LandingApproachToMicP3._add_initial_guess_meta_data(InitialGuessState('altitude')) LandingApproachToMicP3._add_initial_guess_meta_data( - InitialGuessControl(Dynamic.Mission.FLIGHT_PATH_ANGLE)) + InitialGuessControl(Dynamic.Mission.FLIGHT_PATH_ANGLE) +) # @_init_initial_guess_meta_data # <--- inherited from base class @@ -355,7 +378,7 @@ def build_phase(self, aviary_options: AviaryValues = None): # this class and phases of its base class phase.set_state_options(Dynamic.Mission.DISTANCE, fix_final=True) phase.set_state_options(Dynamic.Mission.VELOCITY, fix_final=True) - phase.set_state_options(Dynamic.Mission.MASS, fix_initial=False) + phase.set_state_options(Dynamic.Vehicle.MASS, fix_initial=False) return phase @@ -464,42 +487,58 @@ def build_phase(self, aviary_options: AviaryValues = None): altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, - defect_ref=altitude_ref, units=units, - rate_source=Dynamic.Mission.ALTITUDE_RATE) + Dynamic.Mission.ALTITUDE, + fix_initial=False, + lower=0, + ref=altitude_ref, + defect_ref=altitude_ref, + units=units, + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=True, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=True, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) - phase.add_control(Dynamic.Mission.FLIGHT_PATH_ANGLE, - opt=False, fix_initial=False) + phase.add_control( + Dynamic.Mission.FLIGHT_PATH_ANGLE, opt=False, fix_initial=False + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) phase.add_control('angle_of_attack', opt=False, units='deg') phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) obstacle_height, units = aviary_options.get_item( @@ -515,7 +554,13 @@ def build_phase(self, aviary_options: AviaryValues = None): h = obstacle_height + airport_altitude phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='initial', equals=h, ref=h, units=units, linear=True) + Dynamic.Mission.ALTITUDE, + loc='initial', + equals=h, + ref=h, + units=units, + linear=True, + ) return phase @@ -550,7 +595,8 @@ def _extra_ode_init_kwargs(self): LandingObstacleToFlare._add_initial_guess_meta_data(InitialGuessState('altitude')) LandingObstacleToFlare._add_initial_guess_meta_data( - InitialGuessControl(Dynamic.Mission.FLIGHT_PATH_ANGLE)) + InitialGuessControl(Dynamic.Mission.FLIGHT_PATH_ANGLE) +) @_init_initial_guess_meta_data @@ -664,33 +710,49 @@ def build_phase(self, aviary_options: AviaryValues = None): altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=False, fix_final=True, - lower=0, ref=altitude_ref, - defect_ref=altitude_ref, units=units, - rate_source=Dynamic.Mission.ALTITUDE_RATE) + Dynamic.Mission.ALTITUDE, + fix_initial=False, + fix_final=True, + lower=0, + ref=altitude_ref, + defect_ref=altitude_ref, + units=units, + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) - phase.add_control(Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=False, opt=False) + phase.add_control( + Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, opt=False + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) # TODO: Upper limit is a bit of a hack. It hopefully won't be needed if we # can get some other constraints working. phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', lower=0.0, upper=0.2, opt=True ) @@ -708,12 +770,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( @@ -772,7 +834,8 @@ def _extra_ode_init_kwargs(self): LandingFlareToTouchdown._add_initial_guess_meta_data(InitialGuessState('altitude')) LandingFlareToTouchdown._add_initial_guess_meta_data( - InitialGuessControl(Dynamic.Mission.FLIGHT_PATH_ANGLE)) + InitialGuessControl(Dynamic.Mission.FLIGHT_PATH_ANGLE) +) @_init_initial_guess_meta_data @@ -880,20 +943,30 @@ def build_phase(self, aviary_options=None): max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -906,12 +979,12 @@ def build_phase(self, aviary_options=None): fix_initial=False, ref=max_angle_of_attack) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) return phase @@ -1053,34 +1126,44 @@ def build_phase(self, aviary_options=None): max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, fix_final=True, - lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + fix_final=True, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) # TODO: Energy phase places this under an if num_engines > 0. phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) phase.add_parameter('angle_of_attack', val=0.0, opt=False, units='deg') phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) return phase diff --git a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py index 5c5d716c9..38e6f2ac9 100644 --- a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py +++ b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py @@ -188,33 +188,39 @@ def build_phase(self, aviary_options=None): max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=True, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=True, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + upper=max_velocity, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=True, fix_final=False, + Dynamic.Vehicle.MASS, fix_initial=True, fix_final=False, lower=0.0, upper=1e9, ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) # TODO: Energy phase places this under an if num_engines > 0. phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) phase.add_parameter('angle_of_attack', val=0.0, opt=False, units='deg') phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) return phase @@ -355,21 +361,33 @@ def build_phase(self, aviary_options=None): max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + upper=max_velocity, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + upper=1e9, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) # TODO: Energy phase places this under an if num_engines > 0. phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -378,12 +396,12 @@ def build_phase(self, aviary_options=None): phase.add_parameter('angle_of_attack', val=0.0, opt=False, units='deg') phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( @@ -630,22 +648,34 @@ def build_phase(self, aviary_options=None): max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + upper=max_velocity, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) max_angle_of_attack, units = user_options.get_item('max_angle_of_attack') phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + upper=1e9, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -655,12 +685,12 @@ def build_phase(self, aviary_options=None): ref=max_angle_of_attack) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( @@ -815,35 +845,58 @@ def build_phase(self, aviary_options: AviaryValues = None): altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=True, lower=0, ref=altitude_ref, - defect_ref=altitude_ref, units=units, upper=altitude_ref, - rate_source=Dynamic.Mission.ALTITUDE_RATE) + Dynamic.Mission.ALTITUDE, + fix_initial=True, + lower=0, + ref=altitude_ref, + defect_ref=altitude_ref, + units=units, + upper=altitude_ref, + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + upper=max_velocity, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=True, lower=0, - ref=flight_path_angle_ref, upper=flight_path_angle_ref, - defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) + Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=True, + lower=0, + ref=flight_path_angle_ref, + upper=flight_path_angle_ref, + defect_ref=flight_path_angle_ref, + units=units, + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + upper=1e9, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -857,12 +910,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) obstacle_height, units = aviary_options.get_item( @@ -878,7 +931,13 @@ def build_phase(self, aviary_options: AviaryValues = None): h = obstacle_height + airport_altitude phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='final', equals=h, ref=h, units=units, linear=True) + Dynamic.Mission.ALTITUDE, + loc='final', + equals=h, + ref=h, + units=units, + linear=True, + ) phase.add_path_constraint( 'v_over_v_stall', lower=1.25, ref=2.0) @@ -931,7 +990,8 @@ def _extra_ode_init_kwargs(self): TakeoffLiftoffToObstacle._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffLiftoffToObstacle._add_initial_guess_meta_data( - InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE) +) @_init_initial_guess_meta_data @@ -1048,35 +1108,56 @@ def build_phase(self, aviary_options: AviaryValues = None): altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, - defect_ref=altitude_ref, units=units, - rate_source=Dynamic.Mission.ALTITUDE_RATE) + Dynamic.Mission.ALTITUDE, + fix_initial=False, + lower=0, + ref=altitude_ref, + defect_ref=altitude_ref, + units=units, + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + upper=max_velocity, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=False, + lower=0, ref=flight_path_angle_ref, - defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) + defect_ref=flight_path_angle_ref, + units=units, + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + upper=1e9, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -1090,12 +1171,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) final_altitude, units = user_options.get_item('mic_altitude') @@ -1106,7 +1187,13 @@ def build_phase(self, aviary_options: AviaryValues = None): h = final_altitude + airport_altitude phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='final', equals=h, ref=h, units=units, linear=True) + Dynamic.Mission.ALTITUDE, + loc='final', + equals=h, + ref=h, + units=units, + linear=True, + ) phase.add_boundary_constraint( 'v_over_v_stall', loc='final', lower=1.25, ref=1.25) @@ -1160,7 +1247,8 @@ def _extra_ode_init_kwargs(self): TakeoffObstacleToMicP2._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffObstacleToMicP2._add_initial_guess_meta_data( - InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE) +) @_init_initial_guess_meta_data @@ -1277,35 +1365,56 @@ def build_phase(self, aviary_options: AviaryValues = None): altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, - defect_ref=altitude_ref, units=units, - rate_source=Dynamic.Mission.ALTITUDE_RATE) + Dynamic.Mission.ALTITUDE, + fix_initial=False, + lower=0, + ref=altitude_ref, + defect_ref=altitude_ref, + units=units, + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + upper=max_velocity, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=False, + lower=0, ref=flight_path_angle_ref, - defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) + defect_ref=flight_path_angle_ref, + units=units, + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + upper=1e9, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -1319,12 +1428,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) # start engine cutback phase at this range, where this phase ends @@ -1390,7 +1499,8 @@ def _extra_ode_init_kwargs(self): TakeoffMicP2ToEngineCutback._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffMicP2ToEngineCutback._add_initial_guess_meta_data( - InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE) +) @_init_initial_guess_meta_data @@ -1502,35 +1612,56 @@ def build_phase(self, aviary_options: AviaryValues = None): altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, - defect_ref=altitude_ref, units=units, - rate_source=Dynamic.Mission.ALTITUDE_RATE) + Dynamic.Mission.ALTITUDE, + fix_initial=False, + lower=0, + ref=altitude_ref, + defect_ref=altitude_ref, + units=units, + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + upper=max_velocity, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=False, + lower=0, ref=flight_path_angle_ref, - defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) + defect_ref=flight_path_angle_ref, + units=units, + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + upper=1e9, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -1544,12 +1675,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) phase.add_boundary_constraint( @@ -1598,7 +1729,8 @@ def _extra_ode_init_kwargs(self): TakeoffEngineCutback._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffEngineCutback._add_initial_guess_meta_data( - InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE) +) @_init_initial_guess_meta_data @@ -1715,35 +1847,56 @@ def build_phase(self, aviary_options: AviaryValues = None): altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, - defect_ref=altitude_ref, units=units, - rate_source=Dynamic.Mission.ALTITUDE_RATE) + Dynamic.Mission.ALTITUDE, + fix_initial=False, + lower=0, + ref=altitude_ref, + defect_ref=altitude_ref, + units=units, + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + upper=max_velocity, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=False, + lower=0, ref=flight_path_angle_ref, - defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) + defect_ref=flight_path_angle_ref, + units=units, + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + upper=1e9, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -1757,12 +1910,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) mic_range, units = user_options.get_item('mic_range') @@ -1824,7 +1977,8 @@ def _extra_ode_init_kwargs(self): TakeoffEngineCutbackToMicP1._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffEngineCutbackToMicP1._add_initial_guess_meta_data( - InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE) +) @_init_initial_guess_meta_data @@ -1941,35 +2095,56 @@ def build_phase(self, aviary_options: AviaryValues = None): altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, - defect_ref=altitude_ref, units=units, - rate_source=Dynamic.Mission.ALTITUDE_RATE) + Dynamic.Mission.ALTITUDE, + fix_initial=False, + lower=0, + ref=altitude_ref, + defect_ref=altitude_ref, + units=units, + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, - defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + lower=0, + ref=max_velocity, + defect_ref=max_velocity, + units=units, + upper=max_velocity, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=False, + lower=0, ref=flight_path_angle_ref, - defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) + defect_ref=flight_path_angle_ref, + units=units, + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + upper=1e9, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) @@ -1983,12 +2158,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + Dynamic.Vehicle.DRAG, output_name=Dynamic.Vehicle.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf' ) mic_range, units = user_options.get_item('mic_range') @@ -2049,7 +2224,8 @@ def _extra_ode_init_kwargs(self): TakeoffMicP1ToClimb._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffMicP1ToClimb._add_initial_guess_meta_data( - InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE) +) @_init_initial_guess_meta_data @@ -2158,21 +2334,33 @@ def build_phase(self, aviary_options=None): max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=False, fix_final=True, - lower=0, ref=max_velocity, upper=max_velocity, - defect_ref=max_velocity, units=units, - rate_source=Dynamic.Mission.VELOCITY_RATE) + Dynamic.Mission.VELOCITY, + fix_initial=False, + fix_final=True, + lower=0, + ref=max_velocity, + upper=max_velocity, + defect_ref=max_velocity, + units=units, + rate_source=Dynamic.Mission.VELOCITY_RATE, + ) phase.add_state( - Dynamic.Mission.MASS, fix_initial=False, fix_final=False, - lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, + fix_initial=False, + fix_final=False, + lower=0.0, + upper=1e9, + ref=5e4, + defect_ref=5e4, + units='kg', + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ) phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', + Dynamic.Vehicle.Propulsion.THROTTLE, + targets=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', opt=False ) diff --git a/aviary/mission/flops_based/phases/groundroll_phase.py b/aviary/mission/flops_based/phases/groundroll_phase.py index f779ab9a5..99ddfdf8a 100644 --- a/aviary/mission/flops_based/phases/groundroll_phase.py +++ b/aviary/mission/flops_based/phases/groundroll_phase.py @@ -78,9 +78,14 @@ def build_phase(self, aviary_options: AviaryValues = None): duration_ref = user_options.get_val('duration_ref', units='kn') constraints = user_options.get_val('constraints') - phase.set_time_options(fix_initial=True, fix_duration=False, - units="kn", name=Dynamic.Mission.VELOCITY, - duration_bounds=duration_bounds, duration_ref=duration_ref) + phase.set_time_options( + fix_initial=True, + fix_duration=False, + units="kn", + name=Dynamic.Mission.VELOCITY, + duration_bounds=duration_bounds, + duration_ref=duration_ref, + ) phase.set_state_options("time", rate_source="dt_dv", units="s", fix_initial=True, fix_final=False, ref=1., defect_ref=1., solve_segments='forward') @@ -100,20 +105,20 @@ def build_phase(self, aviary_options: AviaryValues = None): self._add_user_defined_constraints(phase, constraints) - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output(Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units="lbf") phase.add_timeseries_output("thrust_req", units="lbf") phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output(Dynamic.Atmosphere.MACH) phase.add_timeseries_output("EAS", units="kn") phase.add_timeseries_output(Dynamic.Mission.VELOCITY, units="kn") - phase.add_timeseries_output(Dynamic.Mission.LIFT) - phase.add_timeseries_output(Dynamic.Mission.DRAG) + phase.add_timeseries_output(Dynamic.Vehicle.LIFT) + phase.add_timeseries_output(Dynamic.Vehicle.DRAG) phase.add_timeseries_output("time") phase.add_timeseries_output("mass") phase.add_timeseries_output(Dynamic.Mission.ALTITUDE) phase.add_timeseries_output("alpha") phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE) - phase.add_timeseries_output(Dynamic.Mission.THROTTLE) + phase.add_timeseries_output(Dynamic.Vehicle.Propulsion.THROTTLE) return phase diff --git a/aviary/mission/flops_based/phases/simplified_landing.py b/aviary/mission/flops_based/phases/simplified_landing.py index 2fc6dddcb..1c19060d0 100644 --- a/aviary/mission/flops_based/phases/simplified_landing.py +++ b/aviary/mission/flops_based/phases/simplified_landing.py @@ -17,7 +17,7 @@ def setup(self): add_aviary_input( self, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, val=1.225, units="kg/m**3", desc="atmospheric density", @@ -40,7 +40,7 @@ def compute(self, inputs, outputs): rho_SL = RHO_SEA_LEVEL_METRIC landing_weight = inputs[Mission.Landing.TOUCHDOWN_MASS] * \ GRAV_ENGLISH_LBM - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] planform_area = inputs[Aircraft.Wing.AREA] Cl_ldg_max = inputs[Mission.Landing.LIFT_COEFFICIENT_MAX] @@ -63,7 +63,7 @@ def compute_partials(self, inputs, J): rho_SL = RHO_SEA_LEVEL_METRIC landing_weight = inputs[Mission.Landing.TOUCHDOWN_MASS] * \ GRAV_ENGLISH_LBM - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] planform_area = inputs[Aircraft.Wing.AREA] Cl_ldg_max = inputs[Mission.Landing.LIFT_COEFFICIENT_MAX] @@ -106,7 +106,7 @@ def compute_partials(self, inputs, J): / (planform_area * rho_ratio * Cl_app ** 2 * 1.69) / 1.3 ** 2 ) - J[Mission.Landing.GROUND_DISTANCE, Dynamic.Mission.DENSITY] = ( + J[Mission.Landing.GROUND_DISTANCE, Dynamic.Atmosphere.DENSITY] = ( -105 * landing_weight / (planform_area * rho_ratio**2 * Cl_app * 1.69) @@ -136,7 +136,7 @@ def setup(self): LandingCalc(), promotes_inputs=[ Mission.Landing.TOUCHDOWN_MASS, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, Aircraft.Wing.AREA, Mission.Landing.LIFT_COEFFICIENT_MAX, ], diff --git a/aviary/mission/flops_based/phases/simplified_takeoff.py b/aviary/mission/flops_based/phases/simplified_takeoff.py index 3f7ef9d31..6969d6a80 100644 --- a/aviary/mission/flops_based/phases/simplified_takeoff.py +++ b/aviary/mission/flops_based/phases/simplified_takeoff.py @@ -25,7 +25,7 @@ def setup(self): ) self.add_input( - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, val=1.225, units="kg/m**3", desc="atmospheric density", @@ -56,7 +56,7 @@ def compute(self, inputs, outputs): # This is only necessary because the equation expects newtons, # but the mission expects pounds mass instead of pounds force. weight = weight*4.44822 - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] S = inputs["planform_area"] Cl_max = inputs["Cl_max"] @@ -67,7 +67,7 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): weight = inputs["mass"] * GRAV_ENGLISH_LBM - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] S = inputs["planform_area"] Cl_max = inputs["Cl_max"] @@ -75,7 +75,7 @@ def compute_partials(self, inputs, J): J["v_stall", "mass"] = 0.5 * 4.44822**.5 * \ rad ** (-0.5) * 2 * GRAV_ENGLISH_LBM / (rho * S * Cl_max) - J["v_stall", Dynamic.Mission.DENSITY] = ( + J["v_stall", Dynamic.Atmosphere.DENSITY] = ( 0.5 * 4.44822**0.5 * rad ** (-0.5) * (-2 * weight) / (rho**2 * S * Cl_max) ) J["v_stall", "planform_area"] = ( @@ -109,7 +109,7 @@ def setup(self): add_aviary_input(self, Mission.Takeoff.FUEL_SIMPLE, val=10.e3) self.add_input( - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, val=1.225, units="kg/m**3", desc="atmospheric density", @@ -143,7 +143,7 @@ def setup_partials(self): Mission.Takeoff.GROUND_DISTANCE, [ Mission.Summary.GROSS_MASS, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, Aircraft.Wing.AREA, Mission.Takeoff.LIFT_COEFFICIENT_MAX, Mission.Design.THRUST_TAKEOFF_PER_ENG, @@ -168,7 +168,7 @@ def compute(self, inputs, outputs): v_stall = inputs["v_stall"] gross_mass = inputs[Mission.Summary.GROSS_MASS] ramp_weight = gross_mass * GRAV_ENGLISH_LBM - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] S = inputs[Aircraft.Wing.AREA] Cl_max = inputs[Mission.Takeoff.LIFT_COEFFICIENT_MAX] thrust = inputs[Mission.Design.THRUST_TAKEOFF_PER_ENG] @@ -220,7 +220,7 @@ def compute_partials(self, inputs, J): rho_SL = RHO_SEA_LEVEL_METRIC ramp_weight = inputs[Mission.Summary.GROSS_MASS] * GRAV_ENGLISH_LBM - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] S = inputs[Aircraft.Wing.AREA] Cl_max = inputs[Mission.Takeoff.LIFT_COEFFICIENT_MAX] thrust = inputs[Mission.Design.THRUST_TAKEOFF_PER_ENG] @@ -362,7 +362,7 @@ def compute_partials(self, inputs, J): J[Mission.Takeoff.GROUND_DISTANCE, Mission.Summary.GROSS_MASS] = dRD_dM + dRot_dM + dCout_dM - J[Mission.Takeoff.GROUND_DISTANCE, Dynamic.Mission.DENSITY] = ( + J[Mission.Takeoff.GROUND_DISTANCE, Dynamic.Atmosphere.DENSITY] = ( dRD_dRho + dRot_dRho + dCout_dRho ) J[Mission.Takeoff.GROUND_DISTANCE, @@ -402,7 +402,7 @@ def setup(self): ], promotes_inputs=[ ("mass", Mission.Summary.GROSS_MASS), - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, ('planform_area', Aircraft.Wing.AREA), ("Cl_max", Mission.Takeoff.LIFT_COEFFICIENT_MAX), ], @@ -414,7 +414,7 @@ def setup(self): promotes_inputs=[ "v_stall", Mission.Summary.GROSS_MASS, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, Aircraft.Wing.AREA, Mission.Takeoff.FUEL_SIMPLE, Mission.Takeoff.LIFT_COEFFICIENT_MAX, diff --git a/aviary/mission/flops_based/phases/test/test_simplified_landing.py b/aviary/mission/flops_based/phases/test/test_simplified_landing.py index 1d011a8f7..818047cad 100644 --- a/aviary/mission/flops_based/phases/test/test_simplified_landing.py +++ b/aviary/mission/flops_based/phases/test/test_simplified_landing.py @@ -28,7 +28,9 @@ def setUp(self): Mission.Landing.TOUCHDOWN_MASS, val=152800.0, units="lbm" ) # check (this is the design landing mass) self.prob.model.set_input_defaults( - Dynamic.Mission.DENSITY, val=constants.RHO_SEA_LEVEL_METRIC, units="kg/m**3" + Dynamic.Atmosphere.DENSITY, + val=constants.RHO_SEA_LEVEL_METRIC, + units="kg/m**3", ) # not exact value but should be close enough self.prob.model.set_input_defaults( Aircraft.Wing.AREA, val=1370.0, units="ft**2" diff --git a/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py b/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py index 588e5bc03..0496b4d91 100644 --- a/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py +++ b/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py @@ -32,7 +32,7 @@ def setUp(self): self.prob.model.set_input_defaults("mass", val=181200.0, units="lbm") # check self.prob.model.set_input_defaults( - Dynamic.Mission.DENSITY, val=constants.RHO_SEA_LEVEL_METRIC, units="kg/m**3" + Dynamic.Atmosphere.DENSITY, val=constants.RHO_SEA_LEVEL_METRIC, units="kg/m**3" ) # check self.prob.model.set_input_defaults( "planform_area", val=1370.0, units="ft**2" @@ -104,7 +104,7 @@ def setUp(self): Mission.Takeoff.FUEL_SIMPLE, val=577, units="lbm" ) # check self.prob.model.set_input_defaults( - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, val=constants.RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3", ) # check @@ -197,7 +197,8 @@ def setUp(self): self.prob.model.set_input_defaults( Mission.Takeoff.LIFT_OVER_DRAG, val=17.354, units='unitless') # check self.prob.model.set_input_defaults( - Dynamic.Mission.ALTITUDE, val=0, units="ft") # check + Dynamic.Mission.ALTITUDE, val=0, units="ft" + ) # check self.prob.setup(check=False, force_alloc_complex=True) diff --git a/aviary/mission/flops_based/phases/test/test_time_integration_phases.py b/aviary/mission/flops_based/phases/test/test_time_integration_phases.py index 790969a39..ce7055735 100644 --- a/aviary/mission/flops_based/phases/test/test_time_integration_phases.py +++ b/aviary/mission/flops_based/phases/test/test_time_integration_phases.py @@ -1,3 +1,7 @@ +import warnings +import unittest +import importlib + import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal @@ -12,13 +16,10 @@ from aviary.utils.process_input_decks import create_vehicle from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems from aviary.variable_info.enums import EquationsOfMotion +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings -import warnings -import unittest -import importlib - @unittest.skipUnless(importlib.util.find_spec("pyoptsparse") is not None, "pyoptsparse is not installed") class HE_SGMDescentTestCase(unittest.TestCase): @@ -31,7 +32,8 @@ def setUp(self): aviary_inputs, initialization_guesses = create_vehicle( 'models/test_aircraft/aircraft_for_bench_FwFm.csv') aviary_inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, val=28690, units="lbf") - aviary_inputs.set_val(Dynamic.Mission.THROTTLE, val=0, units="unitless") + aviary_inputs.set_val(Dynamic.Vehicle.Propulsion.THROTTLE, + val=0, units="unitless") aviary_inputs.set_val(Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, val=0.0175, units="unitless") aviary_inputs.set_val(Mission.Takeoff.BRAKING_FRICTION_COEFFICIENT, @@ -69,11 +71,13 @@ def setup_prob(self, phases) -> om.Problem: traj = FlexibleTraj( Phases=phases, promote_all_auto_ivc=True, - traj_final_state_output=[Dynamic.Mission.MASS, - Dynamic.Mission.DISTANCE, - Dynamic.Mission.ALTITUDE], + traj_final_state_output=[ + Dynamic.Vehicle.MASS, + Dynamic.Mission.DISTANCE, + Dynamic.Mission.ALTITUDE, + ], traj_initial_state_input=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, ], @@ -105,6 +109,8 @@ def setup_prob(self, phases) -> om.Problem: prob.model.add_objective(Mission.Objectives.FUEL, ref=1e4) + setup_model_options(prob, aviary_options) + with warnings.catch_warnings(): warnings.simplefilter("ignore", om.PromotionWarning) diff --git a/aviary/mission/flops_based/phases/time_integration_phases.py b/aviary/mission/flops_based/phases/time_integration_phases.py index 6f8f1c752..1405cfb6a 100644 --- a/aviary/mission/flops_based/phases/time_integration_phases.py +++ b/aviary/mission/flops_based/phases/time_integration_phases.py @@ -20,24 +20,25 @@ def __init__( simupy_args={}, mass_trigger=(150000, 'lbm') ): - super().__init__(MissionODE( - analysis_scheme=AnalysisScheme.SHOOTING, - **ode_args), + super().__init__( + MissionODE(analysis_scheme=AnalysisScheme.SHOOTING, **ode_args), problem_name=phase_name, outputs=[], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, - ], + ], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, aviary_options=ode_args['aviary_options'], - **simupy_args) + **simupy_args + ) self.phase_name = phase_name self.mass_trigger = mass_trigger - self.add_trigger(Dynamic.Mission.MASS, 'mass_trigger') + self.add_trigger(Dynamic.Vehicle.MASS, 'mass_trigger') class SGMDetailedTakeoff(SimuPyProblem): @@ -54,20 +55,21 @@ def __init__( phase_name='detailed_takeoff', simupy_args={}, ): - super().__init__(TakeoffODE( - analysis_scheme=AnalysisScheme.SHOOTING, - **ode_args), + super().__init__( + TakeoffODE(analysis_scheme=AnalysisScheme.SHOOTING, **ode_args), problem_name=phase_name, outputs=[], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, - ], + ], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, aviary_options=ode_args['aviary_options'], - **simupy_args) + **simupy_args + ) self.phase_name = phase_name self.add_trigger(Dynamic.Mission.ALTITUDE, 50, units='ft') @@ -87,20 +89,21 @@ def __init__( phase_name='detailed_landing', simupy_args={}, ): - super().__init__(LandingODE( - analysis_scheme=AnalysisScheme.SHOOTING, - **ode_args), + super().__init__( + LandingODE(analysis_scheme=AnalysisScheme.SHOOTING, **ode_args), problem_name=phase_name, outputs=[], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, - ], + ], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, aviary_options=ode_args['aviary_options'], - **simupy_args) + **simupy_args + ) self.phase_name = phase_name self.add_trigger(Dynamic.Mission.ALTITUDE, 0, units='ft') diff --git a/aviary/mission/gasp_based/idle_descent_estimation.py b/aviary/mission/gasp_based/idle_descent_estimation.py index be3efca5b..58a7e432b 100644 --- a/aviary/mission/gasp_based/idle_descent_estimation.py +++ b/aviary/mission/gasp_based/idle_descent_estimation.py @@ -33,12 +33,12 @@ def add_descent_estimation_as_submodel( traj = FlexibleTraj( Phases=phases, traj_initial_state_input=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, ], traj_final_state_output=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, ], @@ -158,7 +158,7 @@ def add_descent_estimation_as_submodel( model.set_input_defaults(Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, 0) model.set_input_defaults( Aircraft.Design.OPERATING_MASS, val=0, units='lbm') - model.set_input_defaults('descent_traj.'+Dynamic.Mission.THROTTLE, 0) + model.set_input_defaults('descent_traj.' + Dynamic.Vehicle.Propulsion.THROTTLE, 0) promote_aircraft_and_mission_vars(model) diff --git a/aviary/mission/gasp_based/ode/accel_eom.py b/aviary/mission/gasp_based/ode/accel_eom.py index 04f0d3ac9..fff79efe6 100644 --- a/aviary/mission/gasp_based/ode/accel_eom.py +++ b/aviary/mission/gasp_based/ode/accel_eom.py @@ -21,19 +21,19 @@ def setup(self): arange = np.arange(nn) self.add_input( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, val=np.ones(nn) * 1e6, units="lbm", desc="total mass of the aircraft", ) self.add_input( - Dynamic.Mission.DRAG, + Dynamic.Vehicle.DRAG, val=np.zeros(nn), units="lbf", desc="drag on aircraft", ) self.add_input( - Dynamic.Mission.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=np.zeros(nn), units="lbf", desc="total thrust", @@ -59,28 +59,45 @@ def setup(self): ) self.declare_partials( - Dynamic.Mission.VELOCITY_RATE, [ - Dynamic.Mission.MASS, Dynamic.Mission.DRAG, Dynamic.Mission.THRUST_TOTAL], rows=arange, cols=arange) - self.declare_partials(Dynamic.Mission.DISTANCE_RATE, [ - Dynamic.Mission.VELOCITY], rows=arange, cols=arange, val=1.) + Dynamic.Mission.VELOCITY_RATE, + [ + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + ], + rows=arange, + cols=arange, + ) + self.declare_partials( + Dynamic.Mission.DISTANCE_RATE, + [Dynamic.Mission.VELOCITY], + rows=arange, + cols=arange, + val=1.0, + ) def compute(self, inputs, outputs): - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - drag = inputs[Dynamic.Mission.DRAG] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + drag = inputs[Dynamic.Vehicle.DRAG] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] TAS = inputs[Dynamic.Mission.VELOCITY] - outputs[Dynamic.Mission.VELOCITY_RATE] = ( - GRAV_ENGLISH_GASP / weight) * (thrust - drag) + outputs[Dynamic.Mission.VELOCITY_RATE] = (GRAV_ENGLISH_GASP / weight) * ( + thrust - drag + ) outputs[Dynamic.Mission.DISTANCE_RATE] = TAS def compute_partials(self, inputs, J): - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - drag = inputs[Dynamic.Mission.DRAG] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + drag = inputs[Dynamic.Vehicle.DRAG] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.MASS] = \ + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.MASS] = ( -(GRAV_ENGLISH_GASP / weight**2) * (thrust - drag) * GRAV_ENGLISH_LBM - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.DRAG] = - \ - (GRAV_ENGLISH_GASP / weight) - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.THRUST_TOTAL] = GRAV_ENGLISH_GASP / weight + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.DRAG] = -( + GRAV_ENGLISH_GASP / weight + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( + GRAV_ENGLISH_GASP / weight + ) diff --git a/aviary/mission/gasp_based/ode/accel_ode.py b/aviary/mission/gasp_based/ode/accel_ode.py index 1278e99c4..91781f45c 100644 --- a/aviary/mission/gasp_based/ode/accel_ode.py +++ b/aviary/mission/gasp_based/ode/accel_ode.py @@ -28,9 +28,12 @@ def setup(self): 't_curr': {'units': 's'}, Dynamic.Mission.DISTANCE: {'units': 'ft'}, }) - add_SGM_required_outputs(self, { - Dynamic.Mission.ALTITUDE_RATE: {'units': 'ft/s'}, - }) + add_SGM_required_outputs( + self, + { + Dynamic.Mission.ALTITUDE_RATE: {'units': 'ft/s'}, + }, + ) # TODO: paramport self.add_subsystem("params", ParamPort(), promotes=["*"]) @@ -40,8 +43,8 @@ def setup(self): self.add_subsystem( "calc_weight", MassToWeight(num_nodes=nn), - promotes_inputs=[("mass", Dynamic.Mission.MASS)], - promotes_outputs=["weight"] + promotes_inputs=[("mass", Dynamic.Vehicle.MASS)], + promotes_outputs=["weight"], ) kwargs = {'num_nodes': nn, 'aviary_inputs': aviary_options, @@ -58,21 +61,26 @@ def setup(self): "accel_eom", AccelerationRates(num_nodes=nn), promotes_inputs=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.VELOCITY, - Dynamic.Mission.DRAG, - Dynamic.Mission.THRUST_TOTAL, ], + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + ], promotes_outputs=[ Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.DISTANCE_RATE, ], + Dynamic.Mission.DISTANCE_RATE, + ], ) self.add_excess_rate_comps(nn) ParamPort.set_default_vals(self) - self.set_input_defaults(Dynamic.Mission.MASS, val=14e4 * - np.ones(nn), units="lbm") - self.set_input_defaults(Dynamic.Mission.ALTITUDE, - val=500 * np.ones(nn), units="ft") - self.set_input_defaults(Dynamic.Mission.VELOCITY, val=200*np.ones(nn), - units="m/s") # val here is nominal + self.set_input_defaults( + Dynamic.Vehicle.MASS, val=14e4 * np.ones(nn), units="lbm" + ) + self.set_input_defaults( + Dynamic.Mission.ALTITUDE, val=500 * np.ones(nn), units="ft" + ) + self.set_input_defaults( + Dynamic.Mission.VELOCITY, val=200 * np.ones(nn), units="m/s" + ) # val here is nominal diff --git a/aviary/mission/gasp_based/ode/ascent_eom.py b/aviary/mission/gasp_based/ode/ascent_eom.py index 00d379462..761ed6d9f 100644 --- a/aviary/mission/gasp_based/ode/ascent_eom.py +++ b/aviary/mission/gasp_based/ode/ascent_eom.py @@ -19,38 +19,58 @@ def initialize(self): def setup(self): nn = self.options["num_nodes"] - self.add_input(Dynamic.Mission.MASS, val=np.ones(nn), - desc="aircraft mass", units="lbm") - self.add_input(Dynamic.Mission.THRUST_TOTAL, val=np.ones( - nn), desc=Dynamic.Mission.THRUST_TOTAL, units="lbf") self.add_input( - Dynamic.Mission.LIFT, + Dynamic.Vehicle.MASS, val=np.ones(nn), desc="aircraft mass", units="lbm" + ) + self.add_input( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + val=np.ones(nn), + desc=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + units="lbf", + ) + self.add_input( + Dynamic.Vehicle.LIFT, + val=np.ones(nn), + desc=Dynamic.Vehicle.LIFT, + units="lbf", + ) + self.add_input( + Dynamic.Vehicle.DRAG, val=np.ones(nn), - desc=Dynamic.Mission.LIFT, - units="lbf") + desc=Dynamic.Vehicle.DRAG, + units="lbf", + ) self.add_input( - Dynamic.Mission.DRAG, + Dynamic.Mission.VELOCITY, val=np.ones(nn), desc="Velocity", units="ft/s" + ) + self.add_input( + Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.ones(nn), - desc=Dynamic.Mission.DRAG, - units="lbf") - self.add_input(Dynamic.Mission.VELOCITY, val=np.ones(nn), - desc="Velocity", units="ft/s") - self.add_input(Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.ones(nn), - desc="flight path angle", units="rad") + desc="flight path angle", + units="rad", + ) add_aviary_input(self, Aircraft.Wing.INCIDENCE, val=0, units="deg") self.add_input("alpha", val=np.ones(nn), desc="angle of attack", units="deg") - self.add_output(Dynamic.Mission.VELOCITY_RATE, val=np.ones(nn), - desc="Velocity rate", units="ft/s**2") self.add_output( - Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, val=np.ones(nn), desc="flight path angle rate", units="rad/s" + Dynamic.Mission.VELOCITY_RATE, + val=np.ones(nn), + desc="Velocity rate", + units="ft/s**2", + ) + self.add_output( + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + val=np.ones(nn), + desc="flight path angle rate", + units="rad/s", ) self.add_output( Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), desc="altitude rate", - units="ft/s") + units="ft/s", + ) self.add_output( Dynamic.Mission.DISTANCE_RATE, val=np.ones(nn), desc="distance rate", units="ft/s" ) @@ -71,17 +91,29 @@ def setup_partials(self): self.declare_partials( Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - [Dynamic.Mission.THRUST_TOTAL, "alpha", - Dynamic.Mission.LIFT, Dynamic.Mission.MASS, Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY], + [ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.MASS, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Mission.VELOCITY, + ], rows=arange, cols=arange, ) - self.declare_partials(Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, [ - Aircraft.Wing.INCIDENCE]) + self.declare_partials( + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, [Aircraft.Wing.INCIDENCE] + ) self.declare_partials( "load_factor", - [Dynamic.Mission.LIFT, Dynamic.Mission.MASS, - Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.THRUST_TOTAL, "alpha"], + [ + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.MASS, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + ], rows=arange, cols=arange, ) @@ -89,38 +121,57 @@ def setup_partials(self): self.declare_partials( Dynamic.Mission.VELOCITY_RATE, - [Dynamic.Mission.THRUST_TOTAL, "alpha", Dynamic.Mission.DRAG, - Dynamic.Mission.MASS, Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.LIFT], + [ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Vehicle.LIFT, + ], rows=arange, cols=arange, ) self.declare_partials(Dynamic.Mission.VELOCITY_RATE, [Aircraft.Wing.INCIDENCE]) self.declare_partials( - Dynamic.Mission.ALTITUDE_RATE, [ - Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange) + Dynamic.Mission.ALTITUDE_RATE, + [Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=arange, + cols=arange, + ) self.declare_partials( - Dynamic.Mission.DISTANCE_RATE, [ - Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange + Dynamic.Mission.DISTANCE_RATE, + [Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=arange, + cols=arange, ) self.declare_partials( "normal_force", - [Dynamic.Mission.MASS, Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, "alpha"], + [ + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + ], rows=arange, cols=arange, ) self.declare_partials("normal_force", [Aircraft.Wing.INCIDENCE]) self.declare_partials( - "fuselage_pitch", Dynamic.Mission.FLIGHT_PATH_ANGLE, rows=arange, cols=arange, val=180 / np.pi, + "fuselage_pitch", + Dynamic.Mission.FLIGHT_PATH_ANGLE, + rows=arange, + cols=arange, + val=180 / np.pi, ) self.declare_partials("fuselage_pitch", "alpha", rows=arange, cols=arange, val=1) self.declare_partials("fuselage_pitch", Aircraft.Wing.INCIDENCE, val=-1) def compute(self, inputs, outputs): - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - incremented_lift = inputs[Dynamic.Mission.LIFT] - incremented_drag = inputs[Dynamic.Mission.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + incremented_lift = inputs[Dynamic.Vehicle.LIFT] + incremented_drag = inputs[Dynamic.Vehicle.DRAG] TAS = inputs[Dynamic.Mission.VELOCITY] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -168,10 +219,10 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): nn = self.options["num_nodes"] - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - incremented_lift = inputs[Dynamic.Mission.LIFT] - incremented_drag = inputs[Dynamic.Mission.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + incremented_lift = inputs[Dynamic.Vehicle.LIFT] + incremented_drag = inputs[Dynamic.Vehicle.DRAG] TAS = inputs[Dynamic.Mission.VELOCITY] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -191,17 +242,25 @@ def compute_partials(self, inputs, J): dTAcF_dAlpha = thrust * np.cos((alpha - i_wing) * np.pi / 180) * np.pi / 180 dTAcF_dIwing = -thrust * np.cos((alpha - i_wing) * np.pi / 180) * np.pi / 180 - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.THRUST_TOTAL] = dTAcF_dThrust * \ - GRAV_ENGLISH_GASP / (TAS * weight) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, "alpha"] = dTAcF_dAlpha * \ - GRAV_ENGLISH_GASP / (TAS * weight) + J[ + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + ] = ( + dTAcF_dThrust * GRAV_ENGLISH_GASP / (TAS * weight) + ) + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, "alpha"] = ( + dTAcF_dAlpha * GRAV_ENGLISH_GASP / (TAS * weight) + ) J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Aircraft.Wing.INCIDENCE] = ( dTAcF_dIwing * GRAV_ENGLISH_GASP / (TAS * weight) ) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - Dynamic.Mission.LIFT] = GRAV_ENGLISH_GASP / (TAS * weight) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.MASS] = (GRAV_ENGLISH_GASP / TAS) * GRAV_ENGLISH_LBM * ( - -thrust_across_flightpath / weight**2 - incremented_lift / weight**2 + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Vehicle.LIFT] = ( + GRAV_ENGLISH_GASP / (TAS * weight) + ) + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Vehicle.MASS] = ( + (GRAV_ENGLISH_GASP / TAS) + * GRAV_ENGLISH_LBM + * (-thrust_across_flightpath / weight**2 - incremented_lift / weight**2) ) J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( weight * np.sin(gamma) * GRAV_ENGLISH_GASP / (TAS * weight) @@ -212,17 +271,20 @@ def compute_partials(self, inputs, J): / (TAS**2 * weight) ) - J["load_factor", Dynamic.Mission.LIFT] = 1 / (weight * np.cos(gamma)) - J["load_factor", Dynamic.Mission.MASS] = -(incremented_lift + thrust_across_flightpath) / ( - weight**2 * np.cos(gamma) - ) * GRAV_ENGLISH_LBM + J["load_factor", Dynamic.Vehicle.LIFT] = 1 / (weight * np.cos(gamma)) + J["load_factor", Dynamic.Vehicle.MASS] = ( + -(incremented_lift + thrust_across_flightpath) + / (weight**2 * np.cos(gamma)) + * GRAV_ENGLISH_LBM + ) J["load_factor", Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( -(incremented_lift + thrust_across_flightpath) / (weight * (np.cos(gamma)) ** 2) * (-np.sin(gamma)) ) - J["load_factor", Dynamic.Mission.THRUST_TOTAL] = dTAcF_dThrust / \ - (weight * np.cos(gamma)) + J["load_factor", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = dTAcF_dThrust / ( + weight * np.cos(gamma) + ) J["load_factor", "alpha"] = dTAcF_dAlpha / (weight * np.cos(gamma)) J["load_factor", Aircraft.Wing.INCIDENCE] = dTAcF_dIwing / ( weight * np.cos(gamma) @@ -246,7 +308,7 @@ def compute_partials(self, inputs, J): dNF_dIwing = -np.ones(nn) * dTAcF_dIwing dNF_dIwing[normal_force1 < 0] = 0 - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.THRUST_TOTAL] = ( + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( (dTAlF_dThrust - mu * dNF_dThrust) * GRAV_ENGLISH_GASP / weight ) J[Dynamic.Mission.VELOCITY_RATE, "alpha"] = ( @@ -255,9 +317,12 @@ def compute_partials(self, inputs, J): J[Dynamic.Mission.VELOCITY_RATE, Aircraft.Wing.INCIDENCE] = ( (dTAlF_dIwing - mu * dNF_dIwing) * GRAV_ENGLISH_GASP / weight ) - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.DRAG] = -GRAV_ENGLISH_GASP / weight - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.MASS] = ( - GRAV_ENGLISH_GASP * GRAV_ENGLISH_LBM + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.DRAG] = ( + -GRAV_ENGLISH_GASP / weight + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.MASS] = ( + GRAV_ENGLISH_GASP + * GRAV_ENGLISH_LBM * ( weight * (-np.sin(gamma) - mu * dNF_dWeight) - ( @@ -269,21 +334,25 @@ def compute_partials(self, inputs, J): ) / weight**2 ) - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = - \ - np.cos(gamma) * GRAV_ENGLISH_GASP - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.LIFT] = GRAV_ENGLISH_GASP * \ - (-mu * dNF_dLift) / weight + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -np.cos(gamma) * GRAV_ENGLISH_GASP + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.LIFT] = ( + GRAV_ENGLISH_GASP * (-mu * dNF_dLift) / weight + ) J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = np.sin(gamma) - J[Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE] = TAS * np.cos(gamma) + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + TAS * np.cos(gamma) + ) J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = np.cos(gamma) - J[Dynamic.Mission.DISTANCE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -TAS * np.sin(gamma) + ) - J["normal_force", Dynamic.Mission.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM - J["normal_force", Dynamic.Mission.LIFT] = dNF_dLift - J["normal_force", Dynamic.Mission.THRUST_TOTAL] = dNF_dThrust + J["normal_force", Dynamic.Vehicle.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM + J["normal_force", Dynamic.Vehicle.LIFT] = dNF_dLift + J["normal_force", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = dNF_dThrust J["normal_force", "alpha"] = dNF_dAlpha J["normal_force", Aircraft.Wing.INCIDENCE] = dNF_dIwing diff --git a/aviary/mission/gasp_based/ode/ascent_ode.py b/aviary/mission/gasp_based/ode/ascent_ode.py index 452ea4bcd..9e1fe8d31 100644 --- a/aviary/mission/gasp_based/ode/ascent_ode.py +++ b/aviary/mission/gasp_based/ode/ascent_ode.py @@ -30,10 +30,13 @@ def setup(self): # TODO: paramport ascent_params = ParamPort() if analysis_scheme is AnalysisScheme.SHOOTING: - add_SGM_required_inputs(self, { - Dynamic.Mission.ALTITUDE: {'units': 'ft'}, - Dynamic.Mission.DISTANCE: {'units': 'ft'}, - }) + add_SGM_required_inputs( + self, + { + Dynamic.Mission.ALTITUDE: {'units': 'ft'}, + Dynamic.Mission.DISTANCE: {'units': 'ft'}, + }, + ) ascent_params.add_params({ Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE: dict(units='deg', val=0), @@ -62,14 +65,15 @@ def setup(self): "ascent_eom", AscentEOM(num_nodes=nn), promotes_inputs=[ - Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.LIFT, - Dynamic.Mission.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.DRAG, Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE, "alpha", - ] + ["aircraft:*"], + ] + + ["aircraft:*"], promotes_outputs=[ Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, @@ -88,8 +92,9 @@ def setup(self): self.set_input_defaults("t_init_flaps", val=47.5) self.set_input_defaults("t_init_gear", val=37.3) self.set_input_defaults("alpha", val=np.zeros(nn), units="deg") - self.set_input_defaults(Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units="deg") + self.set_input_defaults( + Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units="deg" + ) self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.zeros(nn), units="ft") self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.zeros(nn), units="kn") self.set_input_defaults("t_curr", val=np.zeros(nn), units="s") @@ -97,5 +102,6 @@ def setup(self): self.set_input_defaults('aero_ramps.gear_factor:final_val', val=0.) self.set_input_defaults('aero_ramps.flap_factor:initial_val', val=1.) self.set_input_defaults('aero_ramps.gear_factor:initial_val', val=1.) - self.set_input_defaults(Dynamic.Mission.MASS, val=np.ones( - nn), units='kg') # val here is nominal + self.set_input_defaults( + Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg' + ) # val here is nominal diff --git a/aviary/mission/gasp_based/ode/base_ode.py b/aviary/mission/gasp_based/ode/base_ode.py index 9aad746bd..c5321484e 100644 --- a/aviary/mission/gasp_based/ode/base_ode.py +++ b/aviary/mission/gasp_based/ode/base_ode.py @@ -94,9 +94,11 @@ def AddAlphaControl( gamma=dict(val=0., units='deg'), i_wing=dict(val=0., units='deg'), ) - alpha_comp_inputs = [("max_fus_angle", Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE), - ("gamma", Dynamic.Mission.FLIGHT_PATH_ANGLE), - ("i_wing", Aircraft.Wing.INCIDENCE)] + alpha_comp_inputs = [ + ("max_fus_angle", Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE), + ("gamma", Dynamic.Mission.FLIGHT_PATH_ANGLE), + ("i_wing", Aircraft.Wing.INCIDENCE), + ] elif alpha_mode is AlphaModes.DECELERATION: alpha_comp = om.BalanceComp( @@ -107,8 +109,8 @@ def AddAlphaControl( rhs_name='target_tas_rate', rhs_val=target_tas_rate, eq_units="kn/s", - upper=25., - lower=-2., + upper=25.0, + lower=-2.0, ) alpha_comp_inputs = [Dynamic.Mission.VELOCITY_RATE] @@ -118,12 +120,12 @@ def AddAlphaControl( val=8.0 * np.ones(nn), units="deg", rhs_name="required_lift", - lhs_name=Dynamic.Mission.LIFT, + lhs_name=Dynamic.Vehicle.LIFT, eq_units="lbf", upper=12.0, lower=-2, ) - alpha_comp_inputs = ["required_lift", Dynamic.Mission.LIFT] + alpha_comp_inputs = ["required_lift", Dynamic.Vehicle.LIFT] # Future controller modes # elif alpha_mode is AlphaModes.FLIGHT_PATH_ANGLE: @@ -198,21 +200,24 @@ def AddThrottleControl( nn = num_nodes thrust_bal = om.BalanceComp( - name=Dynamic.Mission.THROTTLE, + name=Dynamic.Vehicle.Propulsion.THROTTLE, val=np.ones(nn), upper=1.0, lower=0.0, units='unitless', - lhs_name=Dynamic.Mission.THRUST_TOTAL, + lhs_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, rhs_name="required_thrust", eq_units="lbf", ) - prop_group.add_subsystem("thrust_balance", - thrust_bal, - promotes_inputs=[ - Dynamic.Mission.THRUST_TOTAL, 'required_thrust'], - promotes_outputs=[Dynamic.Mission.THROTTLE], - ) + prop_group.add_subsystem( + "thrust_balance", + thrust_bal, + promotes_inputs=[ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + 'required_thrust', + ], + promotes_outputs=[Dynamic.Vehicle.Propulsion.THROTTLE], + ) if add_default_solver: prop_group.linear_solver = om.DirectSolver() @@ -248,21 +253,35 @@ def add_excess_rate_comps(self, nn): self.add_subsystem( name='SPECIFIC_ENERGY_RATE_EXCESS', subsys=SpecificEnergyRate(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, - (Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), - Dynamic.Mission.DRAG], - promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] + promotes_inputs=[ + Dynamic.Mission.VELOCITY, + Dynamic.Vehicle.MASS, + ( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, + ), + Dynamic.Vehicle.DRAG, + ], + promotes_outputs=[ + ( + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, + ) + ], ) self.add_subsystem( name='ALTITUDE_RATE_MAX', subsys=AltitudeRate(num_nodes=nn), promotes_inputs=[ - (Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + ( + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, + ), Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.VELOCITY], + Dynamic.Mission.VELOCITY, + ], promotes_outputs=[ - (Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.ALTITUDE_RATE_MAX)]) + (Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.ALTITUDE_RATE_MAX) + ], + ) diff --git a/aviary/mission/gasp_based/ode/breguet_cruise_eom.py b/aviary/mission/gasp_based/ode/breguet_cruise_eom.py index 1f77f98ed..00ad43505 100644 --- a/aviary/mission/gasp_based/ode/breguet_cruise_eom.py +++ b/aviary/mission/gasp_based/ode/breguet_cruise_eom.py @@ -27,7 +27,7 @@ def setup(self): self.add_input("mass", val=150000 * np.ones(nn), units="lbm", desc="mass at each node, monotonically nonincreasing") - self.add_input(Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + self.add_input(Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, 0.74 * np.ones(nn), units="lbm/h") self.add_output("cruise_time", shape=(nn,), units="s", desc="time in cruise", @@ -64,9 +64,25 @@ def setup_partials(self): self._tril_rs, self._tril_cs = rs, cs self.declare_partials( - "cruise_range", [Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, "mass", "TAS_cruise"], rows=rs, cols=cs) + "cruise_range", + [ + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + "mass", + "TAS_cruise", + ], + rows=rs, + cols=cs, + ) self.declare_partials( - "cruise_time", [Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, "mass", "TAS_cruise"], rows=rs, cols=cs) + "cruise_time", + [ + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + "mass", + "TAS_cruise", + ], + rows=rs, + cols=cs, + ) self.declare_partials("cruise_range", "cruise_distance_initial", val=1.0) self.declare_partials("cruise_time", "cruise_time_initial", val=1.0) @@ -81,7 +97,7 @@ def setup_partials(self): def compute(self, inputs, outputs): v_x = inputs["TAS_cruise"] m = inputs["mass"] - FF = -inputs[Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL] + FF = -inputs[Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL] r0 = inputs["cruise_distance_initial"] t0 = inputs["cruise_time_initial"] r0 = r0[0] @@ -121,7 +137,7 @@ def compute_partials(self, inputs, J): W1 = m[:-1] * GRAV_ENGLISH_LBM W2 = m[1:] * GRAV_ENGLISH_LBM # Final mass across each two-node pair - FF = -inputs[Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL] + FF = -inputs[Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL] FF_1 = FF[:-1] # Initial fuel flow across each two-node pair FF_2 = FF[1:] # Final fuel flow across each two_node pair @@ -161,8 +177,9 @@ def compute_partials(self, inputs, J): np.fill_diagonal(self._scratch_nn_x_nn[1:, :-1], dRange_dFF1) np.fill_diagonal(self._scratch_nn_x_nn[1:, 1:], dRange_dFF2) - J["cruise_range", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL][...] = \ - (self._d_cumsum_dx @ self._scratch_nn_x_nn)[self._tril_rs, self._tril_cs] + J["cruise_range", Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL][ + ... + ] = (self._d_cumsum_dx @ self._scratch_nn_x_nn)[self._tril_rs, self._tril_cs] # WRT Mass: dRange_dm = dRange_dW * dW_dm np.fill_diagonal(self._scratch_nn_x_nn[1:, :-1], @@ -186,9 +203,15 @@ def compute_partials(self, inputs, J): # But the jacobian is in a flat format in row-major order. The rows associated # with the nonzero elements are stored in self._tril_rs. - J["cruise_time", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL][1:] = \ - J["cruise_range", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL][1:] / \ - vx_m[self._tril_rs[1:] - 1] * 6076.1 + J["cruise_time", Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL][ + 1: + ] = ( + J["cruise_range", Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL][ + 1: + ] + / vx_m[self._tril_rs[1:] - 1] + * 6076.1 + ) J["cruise_time", "mass"][1:] = \ J["cruise_range", "mass"][1:] / vx_m[self._tril_rs[1:] - 1] * 6076.1 diff --git a/aviary/mission/gasp_based/ode/breguet_cruise_ode.py b/aviary/mission/gasp_based/ode/breguet_cruise_ode.py index 6af356f29..19a9c8094 100644 --- a/aviary/mission/gasp_based/ode/breguet_cruise_ode.py +++ b/aviary/mission/gasp_based/ode/breguet_cruise_ode.py @@ -58,13 +58,13 @@ def setup(self): promotes_outputs=subsystem.mission_outputs(**kwargs)) bal = om.BalanceComp( - name=Dynamic.Mission.THROTTLE, + name=Dynamic.Vehicle.Propulsion.THROTTLE, val=np.ones(nn), upper=1.0, lower=0.0, units="unitless", - lhs_name=Dynamic.Mission.THRUST_TOTAL, - rhs_name=Dynamic.Mission.DRAG, + lhs_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + rhs_name=Dynamic.Vehicle.DRAG, eq_units="lbf", ) @@ -104,39 +104,54 @@ def setup(self): ("cruise_distance_initial", "initial_distance"), ("cruise_time_initial", "initial_time"), "mass", - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, ("TAS_cruise", Dynamic.Mission.VELOCITY), ], - promotes_outputs=[("cruise_range", Dynamic.Mission.DISTANCE), - ("cruise_time", "time")], + promotes_outputs=[ + ("cruise_range", Dynamic.Mission.DISTANCE), + ("cruise_time", "time"), + ], ) self.add_subsystem( name='SPECIFIC_ENERGY_RATE_EXCESS', subsys=SpecificEnergyRate(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, - (Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), - Dynamic.Mission.DRAG], - promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] + promotes_inputs=[ + Dynamic.Mission.VELOCITY, + Dynamic.Vehicle.MASS, + ( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, + ), + Dynamic.Vehicle.DRAG, + ], + promotes_outputs=[ + ( + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, + ) + ], ) self.add_subsystem( name='ALTITUDE_RATE_MAX', subsys=AltitudeRate(num_nodes=nn), promotes_inputs=[ - (Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + ( + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, + ), Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.VELOCITY], + Dynamic.Mission.VELOCITY, + ], promotes_outputs=[ - (Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.ALTITUDE_RATE_MAX)]) + (Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.ALTITUDE_RATE_MAX) + ], + ) ParamPort.set_default_vals(self) self.set_input_defaults( - Dynamic.Mission.ALTITUDE, - val=37500 * np.ones(nn), - units="ft") + Dynamic.Mission.ALTITUDE, val=37500 * np.ones(nn), units="ft" + ) self.set_input_defaults("mass", val=np.linspace( 171481, 171581 - 10000, nn), units="lbm") diff --git a/aviary/mission/gasp_based/ode/climb_eom.py b/aviary/mission/gasp_based/ode/climb_eom.py index 63120bce7..fcd95977d 100644 --- a/aviary/mission/gasp_based/ode/climb_eom.py +++ b/aviary/mission/gasp_based/ode/climb_eom.py @@ -27,15 +27,15 @@ def setup(self): desc="true air speed", ) - self.add_input(Dynamic.Mission.THRUST_TOTAL, val=np.zeros(nn), + self.add_input(Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=np.zeros(nn), units="lbf", desc="net thrust") self.add_input( - Dynamic.Mission.DRAG, + Dynamic.Vehicle.DRAG, val=np.zeros(nn), units="lbf", desc="net drag on aircraft") self.add_input( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, val=np.zeros(nn), units="lbm", desc="mass of aircraft", @@ -66,39 +66,55 @@ def setup(self): desc="flight path angle", ) - self.declare_partials(Dynamic.Mission.ALTITUDE_RATE, - [Dynamic.Mission.VELOCITY, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG, - Dynamic.Mission.MASS], - rows=arange, - cols=arange) + self.declare_partials( + Dynamic.Mission.ALTITUDE_RATE, + [ + Dynamic.Mission.VELOCITY, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + ], + rows=arange, + cols=arange, + ) self.declare_partials( Dynamic.Mission.DISTANCE_RATE, - [Dynamic.Mission.VELOCITY, Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG, Dynamic.Mission.MASS], + [ + Dynamic.Mission.VELOCITY, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + ], + rows=arange, + cols=arange, + ) + self.declare_partials( + "required_lift", + [ + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + ], + rows=arange, + cols=arange, + ) + self.declare_partials( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + [ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + ], rows=arange, cols=arange, ) - self.declare_partials("required_lift", - [Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG], - rows=arange, - cols=arange) - self.declare_partials(Dynamic.Mission.FLIGHT_PATH_ANGLE, - [Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG, - Dynamic.Mission.MASS], - rows=arange, - cols=arange) def compute(self, inputs, outputs): TAS = inputs[Dynamic.Mission.VELOCITY] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM gamma = np.arcsin((thrust - drag) / weight) @@ -110,9 +126,9 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): TAS = inputs[Dynamic.Mission.VELOCITY] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM gamma = np.arcsin((thrust - drag) / weight) @@ -125,29 +141,37 @@ def compute_partials(self, inputs, J): ) J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = np.sin(gamma) - J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.THRUST_TOTAL] = TAS * \ - np.cos(gamma) * dGamma_dThrust - J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.DRAG] = TAS * \ - np.cos(gamma) * dGamma_dDrag - J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.MASS] = \ + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( + TAS * np.cos(gamma) * dGamma_dThrust + ) + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Vehicle.DRAG] = ( + TAS * np.cos(gamma) * dGamma_dDrag + ) + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Vehicle.MASS] = ( TAS * np.cos(gamma) * dGamma_dWeight * GRAV_ENGLISH_LBM + ) J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = np.cos(gamma) - J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.THRUST_TOTAL] = - \ - TAS * np.sin(gamma) * dGamma_dThrust - J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.DRAG] = - \ + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( + -TAS * np.sin(gamma) * dGamma_dThrust + ) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Vehicle.DRAG] = - \ TAS * np.sin(gamma) * dGamma_dDrag - J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.MASS] = \ + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Vehicle.MASS] = \ -TAS * np.sin(gamma) * dGamma_dWeight * GRAV_ENGLISH_LBM - J["required_lift", Dynamic.Mission.MASS] = ( + J["required_lift", Dynamic.Vehicle.MASS] = ( np.cos(gamma) - weight * np.sin(gamma) * dGamma_dWeight ) * GRAV_ENGLISH_LBM - J["required_lift", Dynamic.Mission.THRUST_TOTAL] = - \ - weight * np.sin(gamma) * dGamma_dThrust - J["required_lift", Dynamic.Mission.DRAG] = -weight * np.sin(gamma) * dGamma_dDrag - - J[Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.THRUST_TOTAL] = dGamma_dThrust - J[Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.DRAG] = dGamma_dDrag - J[Dynamic.Mission.FLIGHT_PATH_ANGLE, - Dynamic.Mission.MASS] = dGamma_dWeight * GRAV_ENGLISH_LBM + J["required_lift", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( + -weight * np.sin(gamma) * dGamma_dThrust + ) + J["required_lift", Dynamic.Vehicle.DRAG] = -weight * np.sin(gamma) * dGamma_dDrag + + J[ + Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL + ] = dGamma_dThrust + J[Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Vehicle.DRAG] = dGamma_dDrag + J[Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Vehicle.MASS] = ( + dGamma_dWeight * GRAV_ENGLISH_LBM + ) diff --git a/aviary/mission/gasp_based/ode/climb_ode.py b/aviary/mission/gasp_based/ode/climb_ode.py index 42c233736..19f17677e 100644 --- a/aviary/mission/gasp_based/ode/climb_ode.py +++ b/aviary/mission/gasp_based/ode/climb_ode.py @@ -5,13 +5,17 @@ from aviary.subsystems.atmosphere.flight_conditions import FlightConditions from aviary.mission.gasp_based.ode.base_ode import BaseODE from aviary.mission.gasp_based.ode.climb_eom import ClimbRates -from aviary.mission.gasp_based.ode.constraints.flight_constraints import FlightConstraints +from aviary.mission.gasp_based.ode.constraints.flight_constraints import ( + FlightConstraints, +) from aviary.mission.gasp_based.ode.constraints.speed_constraints import SpeedConstraints from aviary.mission.gasp_based.ode.params import ParamPort from aviary.subsystems.aerodynamics.aerodynamics_builder import AerodynamicsBuilderBase from aviary.variable_info.enums import AnalysisScheme, AlphaModes, SpeedType -from aviary.variable_info.variables import Dynamic -from aviary.mission.gasp_based.ode.time_integration_base_classes import add_SGM_required_inputs +from aviary.variable_info.variables import Aircraft, Dynamic +from aviary.mission.gasp_based.ode.time_integration_base_classes import ( + add_SGM_required_inputs, +) class ClimbODE(BaseODE): @@ -23,14 +27,28 @@ class ClimbODE(BaseODE): def initialize(self): super().initialize() - self.options.declare("input_speed_type", default=SpeedType.EAS, types=SpeedType, - desc="Whether the speed is given as a equivalent airspeed, true airspeed, or mach number") - self.options.declare("alt_trigger_units", default='ft', - desc='The units that the altitude trigger is provided in') - self.options.declare("speed_trigger_units", default='kn', - desc='The units that the speed trigger is provided in.') - self.options.declare("input_speed_type", default=SpeedType.EAS, types=SpeedType, - desc="Whether the speed is given as a equivalent airspeed, true airspeed, or mach number") + self.options.declare( + "input_speed_type", + default=SpeedType.EAS, + types=SpeedType, + desc="Whether the speed is given as a equivalent airspeed, true airspeed, or mach number", + ) + self.options.declare( + "alt_trigger_units", + default='ft', + desc='The units that the altitude trigger is provided in', + ) + self.options.declare( + "speed_trigger_units", + default='kn', + desc='The units that the speed trigger is provided in.', + ) + self.options.declare( + "input_speed_type", + default=SpeedType.EAS, + types=SpeedType, + desc="Whether the speed is given as a equivalent airspeed, true airspeed, or mach number", + ) self.options.declare("EAS_target", desc="target climbing EAS in knots") self.options.declare( "mach_cruise", default=0, desc="targeted cruise mach number" @@ -52,12 +70,21 @@ def setup(self): speed_outputs = ["EAS", Dynamic.Mission.VELOCITY] if analysis_scheme is AnalysisScheme.SHOOTING: - add_SGM_required_inputs(self, { - 't_curr': {'units': 's'}, - Dynamic.Mission.DISTANCE: {'units': 'ft'}, - 'alt_trigger': {'units': self.options['alt_trigger_units'], 'val': 10e3}, - 'speed_trigger': {'units': self.options['speed_trigger_units'], 'val': 100}, - }) + add_SGM_required_inputs( + self, + { + 't_curr': {'units': 's'}, + Dynamic.Mission.DISTANCE: {'units': 'ft'}, + 'alt_trigger': { + 'units': self.options['alt_trigger_units'], + 'val': 10e3, + }, + 'speed_trigger': { + 'units': self.options['speed_trigger_units'], + 'val': 100, + }, + }, + ) # TODO: paramport self.add_subsystem("params", ParamPort(), promotes=["*"]) @@ -67,10 +94,10 @@ def setup(self): subsys=Atmosphere(num_nodes=nn), promotes_inputs=[Dynamic.Mission.ALTITUDE], promotes_outputs=[ - Dynamic.Mission.DENSITY, - Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Atmosphere.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, "viscosity", ], ) @@ -95,7 +122,7 @@ def setup(self): SpeedConstraints( num_nodes=nn, EAS_target=EAS_target, mach_cruise=mach_cruise ), - promotes_inputs=["EAS", Dynamic.Mission.MACH], + promotes_inputs=["EAS", Dynamic.Atmosphere.MACH], promotes_outputs=["speed_constraint"], ) mach_balance_group.add_subsystem( @@ -133,29 +160,33 @@ def setup(self): flight_condition_group.add_subsystem( name='flight_conditions', subsys=FlightConditions(num_nodes=nn, input_speed_type=input_speed_type), - promotes_inputs=[Dynamic.Mission.DENSITY, Dynamic.Mission.SPEED_OF_SOUND] + promotes_inputs=[ + Dynamic.Atmosphere.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + ] + speed_inputs, - promotes_outputs=[Dynamic.Mission.DYNAMIC_PRESSURE] + speed_outputs, + promotes_outputs=[Dynamic.Atmosphere.DYNAMIC_PRESSURE] + speed_outputs, ) - kwargs = {'num_nodes': nn, 'aviary_inputs': aviary_options, - 'method': 'cruise'} + kwargs = {'num_nodes': nn, 'aviary_inputs': aviary_options, 'method': 'cruise'} # collect the propulsion group names for later use with for subsystem in core_subsystems: system = subsystem.build_mission(**kwargs) if system is not None: if isinstance(subsystem, AerodynamicsBuilderBase): - lift_balance_group.add_subsystem(subsystem.name, - system, - promotes_inputs=subsystem.mission_inputs( - **kwargs), - promotes_outputs=subsystem.mission_outputs(**kwargs)) + lift_balance_group.add_subsystem( + subsystem.name, + system, + promotes_inputs=subsystem.mission_inputs(**kwargs), + promotes_outputs=subsystem.mission_outputs(**kwargs), + ) else: - self.add_subsystem(subsystem.name, - system, - promotes_inputs=subsystem.mission_inputs( - **kwargs), - promotes_outputs=subsystem.mission_outputs(**kwargs)) + self.add_subsystem( + subsystem.name, + system, + promotes_inputs=subsystem.mission_inputs(**kwargs), + promotes_outputs=subsystem.mission_outputs(**kwargs), + ) # maybe replace this with the solver in AddAlphaControl? lift_balance_group.nonlinear_solver = om.NewtonSolver() @@ -170,10 +201,10 @@ def setup(self): "climb_eom", ClimbRates(num_nodes=nn), promotes_inputs=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.VELOCITY, - Dynamic.Mission.DRAG, - Dynamic.Mission.THRUST_TOTAL + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, ], promotes_outputs=[ Dynamic.Mission.ALTITUDE_RATE, @@ -187,17 +218,18 @@ def setup(self): alpha_group=lift_balance_group, alpha_mode=AlphaModes.REQUIRED_LIFT, add_default_solver=False, - num_nodes=nn) + num_nodes=nn, + ) self.add_subsystem( "constraints", FlightConstraints(num_nodes=nn), promotes_inputs=[ "alpha", - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, "CL_max", Dynamic.Mission.FLIGHT_PATH_ANGLE, - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.VELOCITY, ] + ["aircraft:*"], @@ -209,12 +241,14 @@ def setup(self): ParamPort.set_default_vals(self) self.set_input_defaults("CL_max", val=5 * np.ones(nn), units="unitless") - self.set_input_defaults(Dynamic.Mission.ALTITUDE, - val=500 * np.ones(nn), units='ft') - self.set_input_defaults(Dynamic.Mission.MASS, - val=174000 * np.ones(nn), units='lbm') - self.set_input_defaults(Dynamic.Mission.MACH, - val=0 * np.ones(nn), units="unitless") - - from aviary.variable_info.variables import Aircraft + self.set_input_defaults( + Dynamic.Mission.ALTITUDE, val=500 * np.ones(nn), units='ft' + ) + self.set_input_defaults( + Dynamic.Vehicle.MASS, val=174000 * np.ones(nn), units='lbm' + ) + self.set_input_defaults( + Dynamic.Atmosphere.MACH, val=0 * np.ones(nn), units="unitless" + ) + self.set_input_defaults(Aircraft.Wing.AREA, val=1.0, units="ft**2") diff --git a/aviary/mission/gasp_based/ode/constraints/flight_constraints.py b/aviary/mission/gasp_based/ode/constraints/flight_constraints.py index 7cc0039e1..2c3e6f2d0 100644 --- a/aviary/mission/gasp_based/ode/constraints/flight_constraints.py +++ b/aviary/mission/gasp_based/ode/constraints/flight_constraints.py @@ -25,7 +25,7 @@ def setup(self): arange = np.arange(nn) self.add_input( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, val=np.ones(nn), units="lbm", desc="mass of aircraft", @@ -35,7 +35,7 @@ def setup(self): add_aviary_input( self, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, val=np.ones(nn), units="slug/ft**3", desc="density of air", @@ -85,7 +85,11 @@ def setup(self): self.add_output("TAS_min", val=np.zeros(nn), units="ft/s") self.declare_partials( - "theta", [Dynamic.Mission.FLIGHT_PATH_ANGLE, "alpha"], rows=arange, cols=arange) + "theta", + [Dynamic.Mission.FLIGHT_PATH_ANGLE, "alpha"], + rows=arange, + cols=arange, + ) self.declare_partials( "theta", [ @@ -95,8 +99,8 @@ def setup(self): self.declare_partials( "TAS_violation", [ - Dynamic.Mission.MASS, - Dynamic.Mission.DENSITY, + Dynamic.Vehicle.MASS, + Dynamic.Atmosphere.DENSITY, "CL_max", Dynamic.Mission.VELOCITY, ], @@ -111,7 +115,7 @@ def setup(self): ) self.declare_partials( "TAS_min", - [Dynamic.Mission.MASS, Dynamic.Mission.DENSITY, "CL_max"], + [Dynamic.Vehicle.MASS, Dynamic.Atmosphere.DENSITY, "CL_max"], rows=arange, cols=arange, ) @@ -124,9 +128,9 @@ def setup(self): def compute(self, inputs, outputs): - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM wing_area = inputs[Aircraft.Wing.AREA] - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] CL_max = inputs["CL_max"] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -144,9 +148,9 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM wing_area = inputs[Aircraft.Wing.AREA] - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] CL_max = inputs["CL_max"] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -157,11 +161,11 @@ def compute_partials(self, inputs, J): J["theta", "alpha"] = 1 J["theta", Aircraft.Wing.INCIDENCE] = -1 - J["TAS_violation", Dynamic.Mission.MASS] = ( + J["TAS_violation", Dynamic.Vehicle.MASS] = ( 1.1 * 0.5 * (2 / (wing_area * rho * CL_max)) ** 0.5 * weight ** (-0.5) * GRAV_ENGLISH_LBM ) - J["TAS_violation", Dynamic.Mission.DENSITY] = ( + J["TAS_violation", Dynamic.Atmosphere.DENSITY] = ( 1.1 * (2 * weight / (wing_area * CL_max)) ** 0.5 * (-0.5) * rho ** (-1.5) ) J["TAS_violation", "CL_max"] = ( @@ -172,11 +176,11 @@ def compute_partials(self, inputs, J): 1.1 * (2 * weight / (rho * CL_max)) ** 0.5 * (-0.5) * wing_area ** (-1.5) ) - J["TAS_min", Dynamic.Mission.MASS] = 1.1 * ( + J["TAS_min", Dynamic.Vehicle.MASS] = 1.1 * ( 0.5 * (2 / (wing_area * rho * CL_max)) ** 0.5 * weight ** (-0.5) * GRAV_ENGLISH_LBM ) - J["TAS_min", Dynamic.Mission.DENSITY] = 1.1 * ( + J["TAS_min", Dynamic.Atmosphere.DENSITY] = 1.1 * ( (2 * weight / (wing_area * CL_max)) ** 0.5 * (-0.5) * rho ** (-1.5) ) J["TAS_min", "CL_max"] = 1.1 * ( @@ -194,8 +198,7 @@ class ClimbAtTopOfClimb(om.ExplicitComponent): def setup(self): self.add_input(Dynamic.Mission.VELOCITY, units="ft/s", val=-200) - self.add_input( - Dynamic.Mission.FLIGHT_PATH_ANGLE, units="rad", val=0.) + self.add_input(Dynamic.Mission.FLIGHT_PATH_ANGLE, units="rad", val=0.0) self.add_output("ROC", units="ft/s") self.declare_partials("*", "*") diff --git a/aviary/mission/gasp_based/ode/constraints/speed_constraints.py b/aviary/mission/gasp_based/ode/constraints/speed_constraints.py index d3540a45c..f171026a0 100644 --- a/aviary/mission/gasp_based/ode/constraints/speed_constraints.py +++ b/aviary/mission/gasp_based/ode/constraints/speed_constraints.py @@ -32,7 +32,7 @@ def setup(self): desc="equivalent airspeed", ) self.add_input( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, val=np.ones(nn), units="unitless", desc="mach number", @@ -50,7 +50,7 @@ def setup(self): ) self.declare_partials( "speed_constraint", - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, rows=arange * 2 + 1, cols=arange, val=self.options["EAS_target"], @@ -60,7 +60,7 @@ def compute(self, inputs, outputs): EAS = inputs["EAS"] EAS_target = self.options["EAS_target"] - mach = inputs[Dynamic.Mission.MACH] + mach = inputs[Dynamic.Atmosphere.MACH] mach_cruise = self.options["mach_cruise"] EAS_constraint = EAS - EAS_target diff --git a/aviary/mission/gasp_based/ode/constraints/test/test_climb_constraints.py b/aviary/mission/gasp_based/ode/constraints/test/test_climb_constraints.py index d2ff00e0b..8a67a4396 100644 --- a/aviary/mission/gasp_based/ode/constraints/test/test_climb_constraints.py +++ b/aviary/mission/gasp_based/ode/constraints/test/test_climb_constraints.py @@ -26,7 +26,7 @@ def setUp(self): self.prob.model.set_input_defaults("EAS", np.array([229, 229, 229]), units="kn") self.prob.model.set_input_defaults( - Dynamic.Mission.MACH, np.array([0.6, 0.6, 0.6]), units="unitless" + Dynamic.Atmosphere.MACH, np.array([0.6, 0.6, 0.6]), units="unitless" ) self.prob.setup(check=False, force_alloc_complex=True) @@ -62,7 +62,7 @@ def setUp(self): self.prob.model.set_input_defaults("EAS", np.array([229, 229, 229]), units="kn") self.prob.model.set_input_defaults( - Dynamic.Mission.MACH, np.array([0.9, 0.9, 0.9]), units="unitless" + Dynamic.Atmosphere.MACH, np.array([0.9, 0.9, 0.9]), units="unitless" ) self.prob.setup(check=False, force_alloc_complex=True) diff --git a/aviary/mission/gasp_based/ode/constraints/test/test_flight_constraints.py b/aviary/mission/gasp_based/ode/constraints/test/test_flight_constraints.py index 1992c3407..69f85811b 100644 --- a/aviary/mission/gasp_based/ode/constraints/test/test_flight_constraints.py +++ b/aviary/mission/gasp_based/ode/constraints/test/test_flight_constraints.py @@ -22,16 +22,17 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([174878.0, 174878.0]), units="lbm" + Dynamic.Vehicle.MASS, np.array([174878.0, 174878.0]), units="lbm" ) self.prob.model.set_input_defaults(Aircraft.Wing.AREA, 1370.3, units="ft**2") self.prob.model.set_input_defaults( - Dynamic.Mission.DENSITY, 0.0023081 * np.ones(2), units="slug/ft**3" + Dynamic.Atmosphere.DENSITY, 0.0023081 * np.ones(2), units="slug/ft**3" ) self.prob.model.set_input_defaults( "CL_max", 1.2596 * np.ones(2), units="unitless") self.prob.model.set_input_defaults( - Dynamic.Mission.FLIGHT_PATH_ANGLE, 7.76 * np.ones(2), units="deg") + Dynamic.Mission.FLIGHT_PATH_ANGLE, 7.76 * np.ones(2), units="deg" + ) self.prob.model.set_input_defaults(Aircraft.Wing.INCIDENCE, 0.0, units="deg") self.prob.model.set_input_defaults("alpha", 5.19 * np.ones(2), units="deg") self.prob.model.set_input_defaults( diff --git a/aviary/mission/gasp_based/ode/descent_eom.py b/aviary/mission/gasp_based/ode/descent_eom.py index 37cdc2287..57e843e53 100644 --- a/aviary/mission/gasp_based/ode/descent_eom.py +++ b/aviary/mission/gasp_based/ode/descent_eom.py @@ -22,15 +22,15 @@ def setup(self): desc="true air speed", ) - self.add_input(Dynamic.Mission.THRUST_TOTAL, val=np.zeros(nn), + self.add_input(Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=np.zeros(nn), units="lbf", desc="net thrust") self.add_input( - Dynamic.Mission.DRAG, + Dynamic.Vehicle.DRAG, val=np.zeros(nn), units="lbf", desc="net drag on aircraft") self.add_input( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, val=np.zeros(nn), units="lbm", desc="mass of aircraft", @@ -67,39 +67,56 @@ def setup(self): desc="flight path angle", ) - self.declare_partials(Dynamic.Mission.ALTITUDE_RATE, - [Dynamic.Mission.VELOCITY, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG, - Dynamic.Mission.MASS], - rows=arange, - cols=arange) + self.declare_partials( + Dynamic.Mission.ALTITUDE_RATE, + [ + Dynamic.Mission.VELOCITY, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + ], + rows=arange, + cols=arange, + ) self.declare_partials( Dynamic.Mission.DISTANCE_RATE, - [Dynamic.Mission.VELOCITY, Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG, Dynamic.Mission.MASS], + [ + Dynamic.Mission.VELOCITY, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + ], rows=arange, cols=arange, ) self.declare_partials( "required_lift", - [Dynamic.Mission.MASS, Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, "alpha"], + [ + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + "alpha", + ], + rows=arange, + cols=arange, + ) + self.declare_partials( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + [ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + ], rows=arange, cols=arange, ) - self.declare_partials(Dynamic.Mission.FLIGHT_PATH_ANGLE, - [Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG, - Dynamic.Mission.MASS], - rows=arange, - cols=arange) def compute(self, inputs, outputs): TAS = inputs[Dynamic.Mission.VELOCITY] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM alpha = inputs["alpha"] gamma = (thrust - drag) / weight @@ -112,42 +129,50 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): TAS = inputs[Dynamic.Mission.VELOCITY] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM alpha = inputs["alpha"] gamma = (thrust - drag) / weight J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = np.sin(gamma) - J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.THRUST_TOTAL] = TAS * \ - np.cos(gamma) / weight - J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.DRAG] = TAS * \ - np.cos(gamma) * (-1 / weight) - J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.MASS] = TAS * \ - np.cos(gamma) * (-(thrust - drag) / weight**2) * GRAV_ENGLISH_LBM + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( + TAS * np.cos(gamma) / weight + ) + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Vehicle.DRAG] = ( + TAS * np.cos(gamma) * (-1 / weight) + ) + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Vehicle.MASS] = ( + TAS * np.cos(gamma) * (-(thrust - drag) / weight**2) * GRAV_ENGLISH_LBM + ) J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = np.cos(gamma) - J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.THRUST_TOTAL] = - \ - TAS * np.sin(gamma) / weight - J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.DRAG] = - \ + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( + -TAS * np.sin(gamma) / weight + ) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Vehicle.DRAG] = - \ TAS * np.sin(gamma) * (-1 / weight) - J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.MASS] = ( + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Vehicle.MASS] = ( -TAS * np.sin(gamma) * (-(thrust - drag) / weight**2) * GRAV_ENGLISH_LBM ) - J["required_lift", Dynamic.Mission.MASS] = ( + J["required_lift", Dynamic.Vehicle.MASS] = ( np.cos(gamma) - weight * np.sin( (thrust - drag) / weight ) * (-(thrust - drag) / weight**2) ) * GRAV_ENGLISH_LBM - J["required_lift", Dynamic.Mission.THRUST_TOTAL] = - \ - weight * np.sin(gamma) / weight - np.sin(alpha) - J["required_lift", Dynamic.Mission.DRAG] = - \ + J["required_lift", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = -weight * np.sin( + gamma + ) / weight - np.sin(alpha) + J["required_lift", Dynamic.Vehicle.DRAG] = - \ weight * np.sin(gamma) * (-1 / weight) J["required_lift", "alpha"] = -thrust * np.cos(alpha) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.THRUST_TOTAL] = 1 / weight - J[Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.DRAG] = -1 / weight - J[Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.MASS] = - \ - (thrust - drag) / weight**2 * GRAV_ENGLISH_LBM + J[ + Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL + ] = (1 / weight) + J[Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Vehicle.DRAG] = -1 / weight + J[Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Vehicle.MASS] = ( + -(thrust - drag) / weight**2 * GRAV_ENGLISH_LBM + ) diff --git a/aviary/mission/gasp_based/ode/descent_ode.py b/aviary/mission/gasp_based/ode/descent_ode.py index 9f9b3ab1e..9cc39fed7 100644 --- a/aviary/mission/gasp_based/ode/descent_ode.py +++ b/aviary/mission/gasp_based/ode/descent_ode.py @@ -74,10 +74,10 @@ def setup(self): subsys=Atmosphere(num_nodes=nn), promotes_inputs=[Dynamic.Mission.ALTITUDE], promotes_outputs=[ - Dynamic.Mission.DENSITY, - Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Atmosphere.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, "viscosity", ], ) @@ -103,7 +103,7 @@ def setup(self): mach_balance_group.linear_solver = om.DirectSolver(assemble_jac=True) speed_bal = om.BalanceComp( - name=Dynamic.Mission.MACH, + name=Dynamic.Atmosphere.MACH, val=mach_cruise * np.ones(nn), units="unitless", lhs_name="KS", @@ -116,7 +116,7 @@ def setup(self): "speed_bal", speed_bal, promotes_inputs=["KS"], - promotes_outputs=[Dynamic.Mission.MACH], + promotes_outputs=[Dynamic.Atmosphere.MACH], ) mach_balance_group.add_subsystem( @@ -126,7 +126,7 @@ def setup(self): mach_cruise=mach_cruise, EAS_target=EAS_limit, ), - promotes_inputs=["EAS", Dynamic.Mission.MACH], + promotes_inputs=["EAS", Dynamic.Atmosphere.MACH], promotes_outputs=["speed_constraint"], ) mach_balance_group.add_subsystem( @@ -150,7 +150,7 @@ def setup(self): promotes_inputs=['*'], # + speed_inputs, promotes_outputs=[ '*' - ], # [Dynamic.Mission.DYNAMIC_PRESSURE] + speed_outputs, + ], # [Dynamic.Atmosphere.DYNAMIC_PRESSURE] + speed_outputs, ) # maybe replace this with the solver in AddAlphaControl? @@ -166,10 +166,10 @@ def setup(self): "descent_eom", DescentRates(num_nodes=nn), promotes_inputs=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.VELOCITY, - Dynamic.Mission.DRAG, - Dynamic.Mission.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, "alpha", ], promotes_outputs=[ @@ -184,9 +184,9 @@ def setup(self): "constraints", FlightConstraints(num_nodes=nn), promotes_inputs=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, "alpha", - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, "CL_max", Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY, @@ -224,13 +224,16 @@ def setup(self): self.add_excess_rate_comps(nn) ParamPort.set_default_vals(self) - self.set_input_defaults(Dynamic.Mission.ALTITUDE, - val=37500 * np.ones(nn), units="ft") - self.set_input_defaults(Dynamic.Mission.MASS, - val=147000 * np.ones(nn), units="lbm") - self.set_input_defaults(Dynamic.Mission.MACH, - val=0 * np.ones(nn), units="unitless") - self.set_input_defaults(Dynamic.Mission.THROTTLE, + self.set_input_defaults( + Dynamic.Mission.ALTITUDE, val=37500 * np.ones(nn), units="ft" + ) + self.set_input_defaults( + Dynamic.Vehicle.MASS, val=147000 * np.ones(nn), units="lbm" + ) + self.set_input_defaults( + Dynamic.Atmosphere.MACH, val=0 * np.ones(nn), units="unitless" + ) + self.set_input_defaults(Dynamic.Vehicle.Propulsion.THROTTLE, val=0 * np.ones(nn), units="unitless") self.set_input_defaults(Aircraft.Wing.AREA, val=1.0, units="ft**2") diff --git a/aviary/mission/gasp_based/ode/flight_path_eom.py b/aviary/mission/gasp_based/ode/flight_path_eom.py index 07399a23f..31dff7641 100644 --- a/aviary/mission/gasp_based/ode/flight_path_eom.py +++ b/aviary/mission/gasp_based/ode/flight_path_eom.py @@ -24,29 +24,49 @@ def setup(self): nn = self.options["num_nodes"] ground_roll = self.options["ground_roll"] - self.add_input(Dynamic.Mission.MASS, val=np.ones(nn), - desc="aircraft mass", units="lbm") - self.add_input(Dynamic.Mission.THRUST_TOTAL, val=np.ones( - nn), desc=Dynamic.Mission.THRUST_TOTAL, units="lbf") self.add_input( - Dynamic.Mission.LIFT, + Dynamic.Vehicle.MASS, val=np.ones(nn), desc="aircraft mass", units="lbm" + ) + self.add_input( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=np.ones(nn), - desc=Dynamic.Mission.LIFT, - units="lbf") + desc=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + units="lbf", + ) + self.add_input( + Dynamic.Vehicle.LIFT, + val=np.ones(nn), + desc=Dynamic.Vehicle.LIFT, + units="lbf", + ) + self.add_input( + Dynamic.Vehicle.DRAG, + val=np.ones(nn), + desc=Dynamic.Vehicle.DRAG, + units="lbf", + ) + self.add_input( + Dynamic.Mission.VELOCITY, + val=np.ones(nn), + desc="true air speed", + units="ft/s", + ) self.add_input( - Dynamic.Mission.DRAG, + Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.ones(nn), - desc=Dynamic.Mission.DRAG, - units="lbf") - self.add_input(Dynamic.Mission.VELOCITY, val=np.ones(nn), - desc="true air speed", units="ft/s") - self.add_input(Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.ones(nn), - desc="flight path angle", units="rad") + desc="flight path angle", + units="rad", + ) add_aviary_input(self, Aircraft.Wing.INCIDENCE, val=0) - self.add_output(Dynamic.Mission.VELOCITY_RATE, val=np.ones(nn), desc="TAS rate", units="ft/s**2", - tags=['dymos.state_rate_source:velocity', 'dymos.state_units:kn']) + self.add_output( + Dynamic.Mission.VELOCITY_RATE, + val=np.ones(nn), + desc="TAS rate", + units="ft/s**2", + tags=['dymos.state_rate_source:velocity', 'dymos.state_units:kn'], + ) if not ground_roll: self._mu = 0.0 @@ -55,9 +75,8 @@ def setup(self): val=np.ones(nn), desc="altitude rate", units="ft/s", - tags=[ - 'dymos.state_rate_source:altitude', - 'dymos.state_units:ft']) + tags=['dymos.state_rate_source:altitude', 'dymos.state_units:ft'], + ) self.add_output( Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, val=np.ones(nn), @@ -65,7 +84,9 @@ def setup(self): units="rad/s", tags=[ 'dymos.state_rate_source:flight_path_angle', - 'dymos.state_units:rad']) + 'dymos.state_units:rad', + ], + ) self.add_input("alpha", val=np.ones(nn), desc="angle of attack", units="deg") self.add_output( @@ -90,8 +111,12 @@ def setup_partials(self): self.declare_partials( "load_factor", - [Dynamic.Mission.LIFT, Dynamic.Mission.MASS, - Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.THRUST_TOTAL], + [ + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.MASS, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + ], rows=arange, cols=arange, ) @@ -99,8 +124,13 @@ def setup_partials(self): self.declare_partials( Dynamic.Mission.VELOCITY_RATE, - [Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, - Dynamic.Mission.MASS, Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.LIFT], + [ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Vehicle.LIFT, + ], rows=arange, cols=arange, ) @@ -109,17 +139,27 @@ def setup_partials(self): if not ground_roll: self.declare_partials( - Dynamic.Mission.ALTITUDE_RATE, [ - Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange) + Dynamic.Mission.ALTITUDE_RATE, + [Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=arange, + cols=arange, + ) self.declare_partials( Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - [Dynamic.Mission.THRUST_TOTAL, "alpha", - Dynamic.Mission.LIFT, Dynamic.Mission.MASS, Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY], + [ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.MASS, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Mission.VELOCITY, + ], rows=arange, cols=arange, ) - self.declare_partials(Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, [ - Aircraft.Wing.INCIDENCE]) + self.declare_partials( + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, [Aircraft.Wing.INCIDENCE] + ) self.declare_partials( "normal_force", "alpha", @@ -146,19 +186,29 @@ def setup_partials(self): ) self.declare_partials( - Dynamic.Mission.DISTANCE_RATE, [ - Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange + Dynamic.Mission.DISTANCE_RATE, + [Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=arange, + cols=arange, ) # self.declare_partials("alpha_rate", ["*"], val=0.0) self.declare_partials( "normal_force", - [Dynamic.Mission.MASS, Dynamic.Mission.LIFT, Dynamic.Mission.THRUST_TOTAL], + [ + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + ], rows=arange, cols=arange, ) self.declare_partials("normal_force", [Aircraft.Wing.INCIDENCE]) self.declare_partials( - "fuselage_pitch", Dynamic.Mission.FLIGHT_PATH_ANGLE, rows=arange, cols=arange, val=180 / np.pi + "fuselage_pitch", + Dynamic.Mission.FLIGHT_PATH_ANGLE, + rows=arange, + cols=arange, + val=180 / np.pi, ) self.declare_partials("fuselage_pitch", [Aircraft.Wing.INCIDENCE]) @@ -166,10 +216,10 @@ def compute(self, inputs, outputs): mu = MU_TAKEOFF if self.options['ground_roll'] else 0.0 - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - incremented_lift = inputs[Dynamic.Mission.LIFT] - incremented_drag = inputs[Dynamic.Mission.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + incremented_lift = inputs[Dynamic.Vehicle.LIFT] + incremented_drag = inputs[Dynamic.Vehicle.DRAG] TAS = inputs[Dynamic.Mission.VELOCITY] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -216,10 +266,10 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): mu = MU_TAKEOFF if self.options['ground_roll'] else 0.0 - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - incremented_lift = inputs[Dynamic.Mission.LIFT] - incremented_drag = inputs[Dynamic.Mission.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + incremented_lift = inputs[Dynamic.Vehicle.LIFT] + incremented_drag = inputs[Dynamic.Vehicle.DRAG] TAS = inputs[Dynamic.Mission.VELOCITY] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -241,17 +291,20 @@ def compute_partials(self, inputs, J): dTAcF_dAlpha = thrust * np.cos((alpha - i_wing) * np.pi / 180) * np.pi / 180 dTAcF_dIwing = -thrust * np.cos((alpha - i_wing) * np.pi / 180) * np.pi / 180 - J["load_factor", Dynamic.Mission.LIFT] = 1 / (weight * np.cos(gamma)) - J["load_factor", Dynamic.Mission.MASS] = -(incremented_lift + thrust_across_flightpath) / ( - weight**2 * np.cos(gamma) - ) * GRAV_ENGLISH_LBM + J["load_factor", Dynamic.Vehicle.LIFT] = 1 / (weight * np.cos(gamma)) + J["load_factor", Dynamic.Vehicle.MASS] = ( + -(incremented_lift + thrust_across_flightpath) + / (weight**2 * np.cos(gamma)) + * GRAV_ENGLISH_LBM + ) J["load_factor", Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( -(incremented_lift + thrust_across_flightpath) / (weight * (np.cos(gamma)) ** 2) * (-np.sin(gamma)) ) - J["load_factor", Dynamic.Mission.THRUST_TOTAL] = dTAcF_dThrust / \ - (weight * np.cos(gamma)) + J["load_factor", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = dTAcF_dThrust / ( + weight * np.cos(gamma) + ) normal_force = weight - incremented_lift - thrust_across_flightpath # normal_force = np.where(normal_force1 < 0, np.zeros(nn), normal_force1) @@ -268,13 +321,16 @@ def compute_partials(self, inputs, J): dNF_dIwing = -np.ones(nn) * dTAcF_dIwing # dNF_dIwing[normal_force1 < 0] = 0 - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.THRUST_TOTAL] = ( + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( (dTAlF_dThrust - mu * dNF_dThrust) * GRAV_ENGLISH_GASP / weight ) - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.DRAG] = -GRAV_ENGLISH_GASP / weight - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.MASS] = ( - GRAV_ENGLISH_GASP * GRAV_ENGLISH_LBM + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.DRAG] = ( + -GRAV_ENGLISH_GASP / weight + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.MASS] = ( + GRAV_ENGLISH_GASP + * GRAV_ENGLISH_LBM * ( weight * (-np.sin(gamma) - mu * dNF_dWeight) - ( @@ -286,29 +342,44 @@ def compute_partials(self, inputs, J): ) / weight**2 ) - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = - \ - np.cos(gamma) * GRAV_ENGLISH_GASP - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.LIFT] = GRAV_ENGLISH_GASP * \ - (-mu * dNF_dLift) / weight + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -np.cos(gamma) * GRAV_ENGLISH_GASP + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.LIFT] = ( + GRAV_ENGLISH_GASP * (-mu * dNF_dLift) / weight + ) # TODO: check partials, esp. for alphas if not self.options['ground_roll']: J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = np.sin(gamma) - J[Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE] = TAS * np.cos(gamma) + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + TAS * np.cos(gamma) + ) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.THRUST_TOTAL] = dTAcF_dThrust * \ - GRAV_ENGLISH_GASP / (TAS * weight) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, "alpha"] = dTAcF_dAlpha * \ - GRAV_ENGLISH_GASP / (TAS * weight) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Aircraft.Wing.INCIDENCE] = dTAcF_dIwing * \ + J[ + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + ] = ( + dTAcF_dThrust * GRAV_ENGLISH_GASP / (TAS * weight) + ) + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, "alpha"] = ( + dTAcF_dAlpha * GRAV_ENGLISH_GASP / (TAS * weight) + ) + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Aircraft.Wing.INCIDENCE] = ( + dTAcF_dIwing * GRAV_ENGLISH_GASP / (TAS * weight) + ) + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Vehicle.LIFT] = ( GRAV_ENGLISH_GASP / (TAS * weight) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - Dynamic.Mission.LIFT] = GRAV_ENGLISH_GASP / (TAS * weight) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.MASS] = (GRAV_ENGLISH_GASP / TAS) * GRAV_ENGLISH_LBM * ( - -thrust_across_flightpath / weight**2 - incremented_lift / weight**2 ) - J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Vehicle.MASS] = ( + (GRAV_ENGLISH_GASP / TAS) + * GRAV_ENGLISH_LBM + * (-thrust_across_flightpath / weight**2 - incremented_lift / weight**2) + ) + J[ + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + ] = ( weight * np.sin(gamma) * GRAV_ENGLISH_GASP / (TAS * weight) ) J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.VELOCITY] = -( @@ -334,9 +405,10 @@ def compute_partials(self, inputs, J): (weight * np.cos(gamma)) J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = np.cos(gamma) - J[Dynamic.Mission.DISTANCE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -TAS * np.sin(gamma) + ) - J["normal_force", Dynamic.Mission.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM - J["normal_force", Dynamic.Mission.LIFT] = dNF_dLift - J["normal_force", Dynamic.Mission.THRUST_TOTAL] = dNF_dThrust + J["normal_force", Dynamic.Vehicle.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM + J["normal_force", Dynamic.Vehicle.LIFT] = dNF_dLift + J["normal_force", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = dNF_dThrust diff --git a/aviary/mission/gasp_based/ode/flight_path_ode.py b/aviary/mission/gasp_based/ode/flight_path_ode.py index dd0617674..dc87ee833 100644 --- a/aviary/mission/gasp_based/ode/flight_path_ode.py +++ b/aviary/mission/gasp_based/ode/flight_path_ode.py @@ -52,10 +52,10 @@ def setup(self): kwargs['output_alpha'] = False EOM_inputs = [ - Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.LIFT, - Dynamic.Mission.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.DRAG, Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE, ] + ['aircraft:*'] @@ -71,7 +71,9 @@ def setup(self): } if kwargs['method'] == 'cruise': SGM_required_inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] = { - 'val': 0, 'units': 'deg'} + 'val': 0, + 'units': 'deg', + } add_SGM_required_inputs(self, SGM_required_inputs) prop_group = om.Group() else: @@ -102,8 +104,8 @@ def setup(self): self.add_subsystem( "calc_weight", MassToWeight(num_nodes=nn), - promotes_inputs=[("mass", Dynamic.Mission.MASS)], - promotes_outputs=["weight"] + promotes_inputs=[("mass", Dynamic.Vehicle.MASS)], + promotes_outputs=["weight"], ) self.add_subsystem( 'calc_lift', @@ -118,12 +120,12 @@ def setup(self): ), promotes_inputs=[ 'weight', - ('thrust', Dynamic.Mission.THRUST_TOTAL), + ('thrust', Dynamic.Vehicle.Propulsion.THRUST_TOTAL), 'alpha', ('gamma', Dynamic.Mission.FLIGHT_PATH_ANGLE), - ('i_wing', Aircraft.Wing.INCIDENCE) + ('i_wing', Aircraft.Wing.INCIDENCE), ], - promotes_outputs=['required_lift'] + promotes_outputs=['required_lift'], ) self.AddAlphaControl( alpha_mode=alpha_mode, @@ -161,13 +163,13 @@ def setup(self): i_wing={'val': 0, 'units': 'rad'}, ), promotes_inputs=[ - ('drag', Dynamic.Mission.DRAG), + ('drag', Dynamic.Vehicle.DRAG), # 'weight', # 'alpha', # ('gamma', Dynamic.Mission.FLIGHT_PATH_ANGLE), - ('i_wing', Aircraft.Wing.INCIDENCE) + ('i_wing', Aircraft.Wing.INCIDENCE), ], - promotes_outputs=['required_thrust'] + promotes_outputs=['required_thrust'], ) self.AddThrottleControl(prop_group=prop_group, @@ -190,8 +192,13 @@ def setup(self): ) if not self.options['ground_roll']: - self.promotes('flight_path_eom', outputs=[ - Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE]) + self.promotes( + 'flight_path_eom', + outputs=[ + Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ], + ) self.add_excess_rate_comps(nn) @@ -201,9 +208,12 @@ def setup(self): self.set_input_defaults("t_init_gear", val=37.3) self.set_input_defaults("t_curr", val=np.zeros(nn), units="s") self.set_input_defaults("alpha", val=np.zeros(nn), units="rad") - self.set_input_defaults(Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units="deg") + self.set_input_defaults( + Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units="deg" + ) self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.zeros(nn), units="ft") - self.set_input_defaults(Dynamic.Mission.MACH, val=np.zeros(nn), units="unitless") - self.set_input_defaults(Dynamic.Mission.MASS, val=np.zeros(nn), units="lbm") + self.set_input_defaults( + Dynamic.Atmosphere.MACH, val=np.zeros(nn), units="unitless" + ) + self.set_input_defaults(Dynamic.Vehicle.MASS, val=np.zeros(nn), units="lbm") self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.zeros(nn), units="kn") diff --git a/aviary/mission/gasp_based/ode/groundroll_eom.py b/aviary/mission/gasp_based/ode/groundroll_eom.py index 83ca58973..17aeb0160 100644 --- a/aviary/mission/gasp_based/ode/groundroll_eom.py +++ b/aviary/mission/gasp_based/ode/groundroll_eom.py @@ -20,28 +20,60 @@ def setup(self): nn = self.options["num_nodes"] arange = np.arange(nn) - self.add_input(Dynamic.Mission.MASS, val=np.ones(nn), - desc="aircraft mass", units="lbm") - self.add_input(Dynamic.Mission.THRUST_TOTAL, val=np.ones( - nn), desc=Dynamic.Mission.THRUST_TOTAL, units="lbf") - self.add_input(Dynamic.Mission.LIFT, val=np.ones( - nn), desc=Dynamic.Mission.LIFT, units="lbf") - self.add_input(Dynamic.Mission.DRAG, val=np.ones( - nn), desc=Dynamic.Mission.DRAG, units="lbf") - self.add_input(Dynamic.Mission.VELOCITY, val=np.ones(nn), - desc="true air speed", units="ft/s") - self.add_input(Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.ones(nn), - desc="flight path angle", units="rad") + self.add_input( + Dynamic.Vehicle.MASS, val=np.ones(nn), desc="aircraft mass", units="lbm" + ) + self.add_input( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + val=np.ones(nn), + desc=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + units="lbf", + ) + self.add_input( + Dynamic.Vehicle.LIFT, + val=np.ones(nn), + desc=Dynamic.Vehicle.LIFT, + units="lbf", + ) + self.add_input( + Dynamic.Vehicle.DRAG, + val=np.ones(nn), + desc=Dynamic.Vehicle.DRAG, + units="lbf", + ) + self.add_input( + Dynamic.Mission.VELOCITY, + val=np.ones(nn), + desc="true air speed", + units="ft/s", + ) + self.add_input( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + val=np.ones(nn), + desc="flight path angle", + units="rad", + ) add_aviary_input(self, Aircraft.Wing.INCIDENCE, val=0) self.add_input("alpha", val=np.zeros(nn), desc="angle of attack", units="deg") - self.add_output(Dynamic.Mission.VELOCITY_RATE, val=np.ones(nn), - desc="TAS rate", units="ft/s**2") self.add_output( - Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, val=np.ones(nn), desc="flight path angle rate", units="rad/s" + Dynamic.Mission.VELOCITY_RATE, + val=np.ones(nn), + desc="TAS rate", + units="ft/s**2", + ) + self.add_output( + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + val=np.ones(nn), + desc="flight path angle rate", + units="rad/s", + ) + self.add_output( + Dynamic.Mission.ALTITUDE_RATE, + val=np.ones(nn), + desc="altitude rate", + units="ft/s", ) - self.add_output(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), - desc="altitude rate", units="ft/s") self.add_output( Dynamic.Mission.DISTANCE_RATE, val=np.ones(nn), desc="distance rate", units="ft/s" ) @@ -55,28 +87,48 @@ def setup(self): self.declare_partials(Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, "*") self.declare_partials( Dynamic.Mission.VELOCITY_RATE, - [Dynamic.Mission.THRUST_TOTAL, "alpha", Dynamic.Mission.DRAG, - Dynamic.Mission.MASS, Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.LIFT], + [ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Vehicle.LIFT, + ], rows=arange, cols=arange, ) self.declare_partials(Dynamic.Mission.VELOCITY_RATE, Aircraft.Wing.INCIDENCE) - self.declare_partials(Dynamic.Mission.ALTITUDE_RATE, [ - Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange) self.declare_partials( - Dynamic.Mission.DISTANCE_RATE, [ - Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange + Dynamic.Mission.ALTITUDE_RATE, + [Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=arange, + cols=arange, + ) + self.declare_partials( + Dynamic.Mission.DISTANCE_RATE, + [Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=arange, + cols=arange, ) self.declare_partials( "normal_force", - [Dynamic.Mission.MASS, Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, "alpha"], + [ + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + ], rows=arange, cols=arange, ) self.declare_partials("normal_force", Aircraft.Wing.INCIDENCE) self.declare_partials( - "fuselage_pitch", Dynamic.Mission.FLIGHT_PATH_ANGLE, rows=arange, cols=arange, val=180 / np.pi, + "fuselage_pitch", + Dynamic.Mission.FLIGHT_PATH_ANGLE, + rows=arange, + cols=arange, + val=180 / np.pi, ) self.declare_partials("fuselage_pitch", "alpha", rows=arange, cols=arange, val=1) self.declare_partials("fuselage_pitch", Aircraft.Wing.INCIDENCE, val=-1) @@ -93,10 +145,10 @@ def compute(self, inputs, outputs): mu = MU_TAKEOFF - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - incremented_lift = inputs[Dynamic.Mission.LIFT] - incremented_drag = inputs[Dynamic.Mission.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + incremented_lift = inputs[Dynamic.Vehicle.LIFT] + incremented_drag = inputs[Dynamic.Vehicle.DRAG] TAS = inputs[Dynamic.Mission.VELOCITY] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -133,10 +185,10 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): mu = MU_TAKEOFF - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - incremented_lift = inputs[Dynamic.Mission.LIFT] - incremented_drag = inputs[Dynamic.Mission.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + incremented_lift = inputs[Dynamic.Vehicle.LIFT] + incremented_drag = inputs[Dynamic.Vehicle.DRAG] TAS = inputs[Dynamic.Mission.VELOCITY] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -173,7 +225,7 @@ def compute_partials(self, inputs, J): dNF_dIwing = -np.ones(nn) * dTAcF_dIwing dNF_dIwing[normal_force1 < 0] = 0 - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.THRUST_TOTAL] = ( + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( (dTAlF_dThrust - mu * dNF_dThrust) * GRAV_ENGLISH_GASP / weight ) J[Dynamic.Mission.VELOCITY_RATE, "alpha"] = ( @@ -182,9 +234,12 @@ def compute_partials(self, inputs, J): J[Dynamic.Mission.VELOCITY_RATE, Aircraft.Wing.INCIDENCE] = ( (dTAlF_dIwing - mu * dNF_dIwing) * GRAV_ENGLISH_GASP / weight ) - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.DRAG] = -GRAV_ENGLISH_GASP / weight - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.MASS] = ( - GRAV_ENGLISH_GASP * GRAV_ENGLISH_LBM + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.DRAG] = ( + -GRAV_ENGLISH_GASP / weight + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.MASS] = ( + GRAV_ENGLISH_GASP + * GRAV_ENGLISH_LBM * ( weight * (-np.sin(gamma) - mu * dNF_dWeight) - ( @@ -196,21 +251,25 @@ def compute_partials(self, inputs, J): ) / weight**2 ) - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = - \ - np.cos(gamma) * GRAV_ENGLISH_GASP - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.LIFT] = GRAV_ENGLISH_GASP * \ - (-mu * dNF_dLift) / weight + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -np.cos(gamma) * GRAV_ENGLISH_GASP + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.LIFT] = ( + GRAV_ENGLISH_GASP * (-mu * dNF_dLift) / weight + ) J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = np.sin(gamma) - J[Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE] = TAS * np.cos(gamma) + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + TAS * np.cos(gamma) + ) J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = np.cos(gamma) - J[Dynamic.Mission.DISTANCE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -TAS * np.sin(gamma) + ) - J["normal_force", Dynamic.Mission.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM - J["normal_force", Dynamic.Mission.LIFT] = dNF_dLift - J["normal_force", Dynamic.Mission.THRUST_TOTAL] = dNF_dThrust + J["normal_force", Dynamic.Vehicle.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM + J["normal_force", Dynamic.Vehicle.LIFT] = dNF_dLift + J["normal_force", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = dNF_dThrust J["normal_force", "alpha"] = dNF_dAlpha J["normal_force", Aircraft.Wing.INCIDENCE] = dNF_dIwing diff --git a/aviary/mission/gasp_based/ode/groundroll_ode.py b/aviary/mission/gasp_based/ode/groundroll_ode.py index a4dcb145b..85df33617 100644 --- a/aviary/mission/gasp_based/ode/groundroll_ode.py +++ b/aviary/mission/gasp_based/ode/groundroll_ode.py @@ -8,7 +8,9 @@ from aviary.variable_info.enums import AnalysisScheme from aviary.subsystems.aerodynamics.aerodynamics_builder import AerodynamicsBuilderBase from aviary.variable_info.variable_meta_data import _MetaData -from aviary.mission.gasp_based.ode.time_integration_base_classes import add_SGM_required_inputs +from aviary.mission.gasp_based.ode.time_integration_base_classes import ( + add_SGM_required_inputs, +) class GroundrollODE(BaseODE): @@ -22,14 +24,18 @@ class GroundrollODE(BaseODE): def initialize(self): super().initialize() self.options.declare( - 'external_subsystems', default=[], - desc='list of external subsystem builder instances to be added to the ODE') + 'external_subsystems', + default=[], + desc='list of external subsystem builder instances to be added to the ODE', + ) self.options.declare( - 'meta_data', default=_MetaData, - desc='metadata associated with the variables to be passed into the ODE') + 'meta_data', + default=_MetaData, + desc='metadata associated with the variables to be passed into the ODE', + ) self.options.declare( - 'set_input_defaults', default=True, - desc='set input defaults for the ODE') + 'set_input_defaults', default=True, desc='set input defaults for the ODE' + ) def setup(self): nn = self.options["num_nodes"] @@ -39,9 +45,12 @@ def setup(self): subsystem_options = self.options['subsystem_options'] if analysis_scheme is AnalysisScheme.SHOOTING: - add_SGM_required_inputs(self, { - Dynamic.Mission.DISTANCE: {'units': 'ft'}, - }) + add_SGM_required_inputs( + self, + { + Dynamic.Mission.DISTANCE: {'units': 'ft'}, + }, + ) # TODO: paramport self.add_subsystem("params", ParamPort(), promotes=["*"]) @@ -49,25 +58,33 @@ def setup(self): self.add_atmosphere(nn) # broadcast scalar i_wing to alpha for aero - self.add_subsystem("init_alpha", - om.ExecComp("alpha = i_wing", - i_wing={"units": "deg", "val": 1.1}, - alpha={"units": "deg", "val": 1.1*np.ones(nn)},), - promotes=[("i_wing", Aircraft.Wing.INCIDENCE), - "alpha"]) - - kwargs = {'num_nodes': nn, 'aviary_inputs': aviary_options, - 'method': 'low_speed'} + self.add_subsystem( + "init_alpha", + om.ExecComp( + "alpha = i_wing", + i_wing={"units": "deg", "val": 1.1}, + alpha={"units": "deg", "val": 1.1 * np.ones(nn)}, + ), + promotes=[("i_wing", Aircraft.Wing.INCIDENCE), "alpha"], + ) + + kwargs = { + 'num_nodes': nn, + 'aviary_inputs': aviary_options, + 'method': 'low_speed', + } for subsystem in core_subsystems: # check if subsystem_options has entry for a subsystem of this name if subsystem.name in subsystem_options: kwargs.update(subsystem_options[subsystem.name]) system = subsystem.build_mission(**kwargs) if system is not None: - self.add_subsystem(subsystem.name, - system, - promotes_inputs=subsystem.mission_inputs(**kwargs), - promotes_outputs=subsystem.mission_outputs(**kwargs)) + self.add_subsystem( + subsystem.name, + system, + promotes_inputs=subsystem.mission_inputs(**kwargs), + promotes_outputs=subsystem.mission_outputs(**kwargs), + ) if type(subsystem) is AerodynamicsBuilderBase: self.promotes( subsystem.name, @@ -75,66 +92,69 @@ def setup(self): src_indices=np.zeros(nn, dtype=int), ) - self.add_subsystem("groundroll_eom", GroundrollEOM(num_nodes=nn), promotes=["*"]) - - self.add_subsystem("exec", om.ExecComp(f"over_a = velocity / velocity_rate", - velocity_rate={"units": "kn/s", - "val": np.ones(nn)}, - velocity={"units": "kn", - "val": np.ones(nn)}, - over_a={"units": "s", "val": np.ones(nn)}, - has_diag_partials=True, - ), - promotes=["*"]) - - self.add_subsystem("exec2", om.ExecComp(f"dt_dv = 1 / velocity_rate", - velocity_rate={"units": "kn/s", - "val": np.ones(nn)}, - dt_dv={"units": "s/kn", - "val": np.ones(nn)}, - has_diag_partials=True, - ), - promotes=["*"]) + self.add_subsystem( + "groundroll_eom", GroundrollEOM(num_nodes=nn), promotes=["*"] + ) + + self.add_subsystem( + "exec", + om.ExecComp( + f"over_a = velocity / velocity_rate", + velocity_rate={"units": "kn/s", "val": np.ones(nn)}, + velocity={"units": "kn", "val": np.ones(nn)}, + over_a={"units": "s", "val": np.ones(nn)}, + has_diag_partials=True, + ), + promotes=["*"], + ) + + self.add_subsystem( + "exec2", + om.ExecComp( + f"dt_dv = 1 / velocity_rate", + velocity_rate={"units": "kn/s", "val": np.ones(nn)}, + dt_dv={"units": "s/kn", "val": np.ones(nn)}, + has_diag_partials=True, + ), + promotes=["*"], + ) self.add_subsystem( "exec3", om.ExecComp( "dmass_dv = mass_rate * dt_dv", - mass_rate={ - "units": "lbm/s", - "val": np.ones(nn)}, - dt_dv={ - "units": "s/kn", - "val": np.ones(nn)}, - dmass_dv={ - "units": "lbm/kn", - "val": np.ones(nn)}, + mass_rate={"units": "lbm/s", "val": np.ones(nn)}, + dt_dv={"units": "s/kn", "val": np.ones(nn)}, + dmass_dv={"units": "lbm/kn", "val": np.ones(nn)}, has_diag_partials=True, ), promotes_outputs=[ "dmass_dv", ], promotes_inputs=[ - ("mass_rate", - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL), - "dt_dv"]) + ("mass_rate", Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL), + "dt_dv", + ], + ) ParamPort.set_default_vals(self) if self.options['set_input_defaults']: - self.set_input_defaults("t_init_flaps", val=100.) - self.set_input_defaults("t_init_gear", val=100.) - self.set_input_defaults('aero_ramps.flap_factor:final_val', val=1.) - self.set_input_defaults('aero_ramps.gear_factor:final_val', val=1.) - self.set_input_defaults('aero_ramps.flap_factor:initial_val', val=1.) - self.set_input_defaults('aero_ramps.gear_factor:initial_val', val=1.) + self.set_input_defaults("t_init_flaps", val=100.0) + self.set_input_defaults("t_init_gear", val=100.0) + self.set_input_defaults('aero_ramps.flap_factor:final_val', val=1.0) + self.set_input_defaults('aero_ramps.gear_factor:final_val', val=1.0) + self.set_input_defaults('aero_ramps.flap_factor:initial_val', val=1.0) + self.set_input_defaults('aero_ramps.gear_factor:initial_val', val=1.0) self.set_input_defaults("t_curr", val=np.zeros(nn), units="s") - self.set_input_defaults(Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units="deg") + self.set_input_defaults( + Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units="deg" + ) self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.zeros(nn), units="ft") self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.zeros(nn), units="kn") - self.set_input_defaults(Dynamic.Mission.VELOCITY_RATE, - val=np.zeros(nn), units="kn/s") + self.set_input_defaults( + Dynamic.Mission.VELOCITY_RATE, val=np.zeros(nn), units="kn/s" + ) self.set_input_defaults(Aircraft.Wing.INCIDENCE, val=1.0, units="deg") diff --git a/aviary/mission/gasp_based/ode/landing_eom.py b/aviary/mission/gasp_based/ode/landing_eom.py index d7ddaa3ee..d51cf11bb 100644 --- a/aviary/mission/gasp_based/ode/landing_eom.py +++ b/aviary/mission/gasp_based/ode/landing_eom.py @@ -36,10 +36,16 @@ class GlideConditionComponent(om.ExplicitComponent): """ def setup(self): - self.add_input("rho_app", val=0.0, units="slug/ft**3", desc="air density") + self.add_input( + Dynamic.Atmosphere.DENSITY, val=0.0, units="slug/ft**3", desc="air density" + ) add_aviary_input(self, Mission.Landing.MAXIMUM_SINK_RATE, val=900.0) - self.add_input(Dynamic.Mission.MASS, val=0.0, units="lbm", - desc="aircraft mass at start of landing") + self.add_input( + Dynamic.Vehicle.MASS, + val=0.0, + units="lbm", + desc="aircraft mass at start of landing", + ) add_aviary_input(self, Aircraft.Wing.AREA, val=1.0) add_aviary_input(self, Mission.Landing.GLIDE_TO_STALL_RATIO, val=1.3) self.add_input("CL_max", val=0.0, units='unitless', @@ -94,29 +100,45 @@ def setup(self): self.declare_partials( Mission.Landing.INITIAL_VELOCITY, - [Dynamic.Mission.MASS, Aircraft.Wing.AREA, "CL_max", "rho_app", - Mission.Landing.GLIDE_TO_STALL_RATIO], + [ + Dynamic.Vehicle.MASS, + Aircraft.Wing.AREA, + "CL_max", + Dynamic.Atmosphere.DENSITY, + Mission.Landing.GLIDE_TO_STALL_RATIO, + ], ) self.declare_partials( - Mission.Landing.STALL_VELOCITY, [ - Dynamic.Mission.MASS, Aircraft.Wing.AREA, "CL_max", "rho_app"] + Mission.Landing.STALL_VELOCITY, + + [Dynamic.Vehicle.MASS, + Aircraft.Wing.AREA, + "CL_max", + Dynamic.Atmosphere.DENSITY, + ], ) self.declare_partials( "TAS_touchdown", - [Mission.Landing.GLIDE_TO_STALL_RATIO, Dynamic.Mission.MASS, - Aircraft.Wing.AREA, "CL_max", "rho_app"], + [ + Mission.Landing.GLIDE_TO_STALL_RATIO, + Dynamic.Vehicle.MASS, + Aircraft.Wing.AREA, + "CL_max", + Dynamic.Atmosphere.DENSITY, + ], + ) + self.declare_partials("density_ratio", [Dynamic.Atmosphere.DENSITY]) + self.declare_partials( + "wing_loading_land", [Dynamic.Vehicle.MASS, Aircraft.Wing.AREA] ) - self.declare_partials("density_ratio", ["rho_app"]) - self.declare_partials("wing_loading_land", [ - Dynamic.Mission.MASS, Aircraft.Wing.AREA]) self.declare_partials( "theta", [ Mission.Landing.MAXIMUM_SINK_RATE, - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Aircraft.Wing.AREA, "CL_max", - "rho_app", + Dynamic.Atmosphere.DENSITY, Mission.Landing.GLIDE_TO_STALL_RATIO, ], ) @@ -125,10 +147,10 @@ def setup(self): [ Mission.Landing.INITIAL_ALTITUDE, Mission.Landing.MAXIMUM_SINK_RATE, - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Aircraft.Wing.AREA, "CL_max", - "rho_app", + Dynamic.Atmosphere.DENSITY, Mission.Landing.GLIDE_TO_STALL_RATIO, ], ) @@ -137,10 +159,10 @@ def setup(self): [ Mission.Landing.MAXIMUM_FLARE_LOAD_FACTOR, Mission.Landing.TOUCHDOWN_SINK_RATE, - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Aircraft.Wing.AREA, "CL_max", - "rho_app", + Dynamic.Atmosphere.DENSITY, Mission.Landing.GLIDE_TO_STALL_RATIO, Mission.Landing.MAXIMUM_SINK_RATE, ], @@ -149,10 +171,10 @@ def setup(self): "delay_distance", [ Mission.Landing.GLIDE_TO_STALL_RATIO, - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Aircraft.Wing.AREA, "CL_max", - "rho_app", + Dynamic.Atmosphere.DENSITY, Mission.Landing.BRAKING_DELAY, ], ) @@ -162,10 +184,10 @@ def setup(self): Mission.Landing.MAXIMUM_FLARE_LOAD_FACTOR, Mission.Landing.TOUCHDOWN_SINK_RATE, Mission.Landing.MAXIMUM_SINK_RATE, - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Aircraft.Wing.AREA, "CL_max", - "rho_app", + Dynamic.Atmosphere.DENSITY, Mission.Landing.GLIDE_TO_STALL_RATIO, ], ) @@ -266,43 +288,45 @@ def compute_partials(self, inputs, J): * dTasGlide_dWeight ) - J[Mission.Landing.INITIAL_VELOCITY, Dynamic.Mission.MASS] = \ + J[Mission.Landing.INITIAL_VELOCITY, Dynamic.Vehicle.MASS] = ( dTasGlide_dWeight * GRAV_ENGLISH_LBM + ) J[Mission.Landing.INITIAL_VELOCITY, Aircraft.Wing.AREA] = dTasGlide_dWingArea = ( dTasStall_dWingArea * glide_to_stall_ratio ) J[Mission.Landing.INITIAL_VELOCITY, "CL_max"] = dTasGlide_dClMax = ( dTasStall_dClMax * glide_to_stall_ratio ) - J[Mission.Landing.INITIAL_VELOCITY, "rho_app"] = dTasGlide_dRhoApp = ( - dTasStall_dRhoApp * glide_to_stall_ratio - ) + J[Mission.Landing.INITIAL_VELOCITY, Dynamic.Atmosphere.DENSITY] = ( + dTasGlide_dRhoApp + ) = (dTasStall_dRhoApp * glide_to_stall_ratio) J[Mission.Landing.INITIAL_VELOCITY, Mission.Landing.GLIDE_TO_STALL_RATIO] = TAS_stall - J[Mission.Landing.STALL_VELOCITY, Dynamic.Mission.MASS] = \ + J[Mission.Landing.STALL_VELOCITY, Dynamic.Vehicle.MASS] = ( dTasStall_dWeight * GRAV_ENGLISH_LBM + ) J[Mission.Landing.STALL_VELOCITY, Aircraft.Wing.AREA] = dTasStall_dWingArea J[Mission.Landing.STALL_VELOCITY, "CL_max"] = dTasStall_dClMax - J[Mission.Landing.STALL_VELOCITY, "rho_app"] = dTasStall_dRhoApp + J[Mission.Landing.STALL_VELOCITY, Dynamic.Atmosphere.DENSITY] = dTasStall_dRhoApp J["TAS_touchdown", Mission.Landing.GLIDE_TO_STALL_RATIO] = dTasTd_dGlideToStallRatio = ( 0.5 * TAS_stall ) - J["TAS_touchdown", Dynamic.Mission.MASS] = dTasTd_dWeight * GRAV_ENGLISH_LBM + J["TAS_touchdown", Dynamic.Vehicle.MASS] = dTasTd_dWeight * GRAV_ENGLISH_LBM J["TAS_touchdown", Aircraft.Wing.AREA] = dTasTd_dWingArea = ( touchdown_velocity_ratio * dTasStall_dWingArea ) J["TAS_touchdown", "CL_max"] = dTasTd_dClMax = ( touchdown_velocity_ratio * dTasStall_dClMax ) - J["TAS_touchdown", "rho_app"] = dTasTd_dRhoApp = ( + J["TAS_touchdown", Dynamic.Atmosphere.DENSITY] = dTasTd_dRhoApp = ( touchdown_velocity_ratio * dTasStall_dRhoApp ) - J["density_ratio", "rho_app"] = 1 / RHO_SEA_LEVEL_ENGLISH + J["density_ratio", Dynamic.Atmosphere.DENSITY] = 1 / RHO_SEA_LEVEL_ENGLISH - J["wing_loading_land", Dynamic.Mission.MASS] = GRAV_ENGLISH_LBM / wing_area + J["wing_loading_land", Dynamic.Vehicle.MASS] = GRAV_ENGLISH_LBM / wing_area J["wing_loading_land", Aircraft.Wing.AREA] = -weight / wing_area**2 np.arcsin(rate_of_sink_max / (60.0 * TAS_glide)) @@ -312,7 +336,7 @@ def compute_partials(self, inputs, J): * 1 / (60.0 * TAS_glide) ) - J["theta", Dynamic.Mission.MASS] = dTheta_dWeight * GRAV_ENGLISH_LBM + J["theta", Dynamic.Vehicle.MASS] = dTheta_dWeight * GRAV_ENGLISH_LBM J["theta", Aircraft.Wing.AREA] = dTheta_dWingArea = ( (1 - (rate_of_sink_max / (60.0 * TAS_glide)) ** 2) ** (-0.5) * (-rate_of_sink_max / (60.0 * TAS_glide**2)) @@ -323,7 +347,7 @@ def compute_partials(self, inputs, J): * (-rate_of_sink_max / (60.0 * TAS_glide**2)) * dTasGlide_dClMax ) - J["theta", "rho_app"] = dTheta_dRhoApp = ( + J["theta", Dynamic.Atmosphere.DENSITY] = dTheta_dRhoApp = ( (1 - (rate_of_sink_max / (60.0 * TAS_glide)) ** 2) ** (-0.5) * (-rate_of_sink_max / (60.0 * TAS_glide**2)) * dTasGlide_dRhoApp @@ -343,11 +367,12 @@ def compute_partials(self, inputs, J): * (1 / np.cos(theta)) ** 2 * dTheta_dRateOfSinkMax ) - J["glide_distance", Dynamic.Mission.MASS] = ( + J["glide_distance", Dynamic.Vehicle.MASS] = ( -approach_alt / (np.tan(theta)) ** 2 * (1 / np.cos(theta)) ** 2 - * dTheta_dWeight * GRAV_ENGLISH_LBM + * dTheta_dWeight + * GRAV_ENGLISH_LBM ) J["glide_distance", Aircraft.Wing.AREA] = ( -approach_alt @@ -361,7 +386,7 @@ def compute_partials(self, inputs, J): * (1 / np.cos(theta)) ** 2 * dTheta_dClMax ) - J["glide_distance", "rho_app"] = ( + J["glide_distance", Dynamic.Atmosphere.DENSITY] = ( -approach_alt / (np.tan(theta)) ** 2 * (1 / np.cos(theta)) ** 2 @@ -468,14 +493,14 @@ def compute_partials(self, inputs, J): J["tr_distance", Mission.Landing.MAXIMUM_SINK_RATE] = ( dInter1_dRateOfSinkMax * inter2 + inter1 * dInter2_dRateOfSinkMax ) - J["tr_distance", Dynamic.Mission.MASS] = ( + J["tr_distance", Dynamic.Vehicle.MASS] = ( dInter1_dWeight * inter2 + inter1 * dInter2_dWeight ) * GRAV_ENGLISH_LBM J["tr_distance", Aircraft.Wing.AREA] = ( dInter1_dWingArea * inter2 + inter1 * dInter2_dWingArea ) J["tr_distance", "CL_max"] = dInter1_dClMax * inter2 + inter1 * dInter2_dClMax - J["tr_distance", "rho_app"] = ( + J["tr_distance", Dynamic.Atmosphere.DENSITY] = ( dInter1_dRhoApp * inter2 + inter1 * dInter2_dRhoApp ) J["tr_distance", Mission.Landing.GLIDE_TO_STALL_RATIO] = ( @@ -486,11 +511,12 @@ def compute_partials(self, inputs, J): J["delay_distance", Mission.Landing.GLIDE_TO_STALL_RATIO] = ( time_delay * dTasTd_dGlideToStallRatio ) - J["delay_distance", Dynamic.Mission.MASS] = \ + J["delay_distance", Dynamic.Vehicle.MASS] = ( time_delay * dTasTd_dWeight * GRAV_ENGLISH_LBM + ) J["delay_distance", Aircraft.Wing.AREA] = time_delay * dTasTd_dWingArea J["delay_distance", "CL_max"] = time_delay * dTasTd_dClMax - J["delay_distance", "rho_app"] = time_delay * dTasTd_dRhoApp + J["delay_distance", Dynamic.Atmosphere.DENSITY] = time_delay * dTasTd_dRhoApp J["delay_distance", Mission.Landing.BRAKING_DELAY] = TAS_touchdown flare_alt = ( @@ -520,14 +546,15 @@ def compute_partials(self, inputs, J): / (2.0 * G * (landing_flare_load_factor - 1.0)) * dTheta_dRateOfSinkMax ) - J["flare_alt", Dynamic.Mission.MASS] = ( + J["flare_alt", Dynamic.Vehicle.MASS] = ( 1 / (2.0 * G * (landing_flare_load_factor - 1.0)) * ( 2 * TAS_glide * dTasGlide_dWeight * (theta**2 - gamma_touchdown**2) + TAS_glide**2 * (2 * theta * dTheta_dWeight - 2 * gamma_touchdown * dGammaTd_dWeight) - ) * GRAV_ENGLISH_LBM + ) + * GRAV_ENGLISH_LBM ) J["flare_alt", Aircraft.Wing.AREA] = ( 1 @@ -553,7 +580,7 @@ def compute_partials(self, inputs, J): * (2 * theta * dTheta_dClMax - 2 * gamma_touchdown * dGammaTd_dClMax) ) ) - J["flare_alt", "rho_app"] = ( + J["flare_alt", Dynamic.Atmosphere.DENSITY] = ( 1 / (2.0 * G * (landing_flare_load_factor - 1.0)) * ( @@ -626,7 +653,7 @@ def setup(self): "CL_max", val=0.0, units="unitless", desc="CLMX: max CL at approach altitude" ) self.add_input( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, val=0.0, units="lbm", desc="WL: aircraft mass at start of landing", @@ -650,7 +677,7 @@ def setup(self): "touchdown_CD", "touchdown_CL", "thrust_idle", - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, "CL_max", Mission.Landing.STALL_VELOCITY, "TAS_touchdown", @@ -664,7 +691,7 @@ def setup(self): "touchdown_CD", "touchdown_CL", "thrust_idle", - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, "CL_max", Mission.Landing.STALL_VELOCITY, "TAS_touchdown", @@ -682,7 +709,7 @@ def setup(self): "touchdown_CD", "touchdown_CL", "thrust_idle", - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, "CL_max", Mission.Landing.STALL_VELOCITY, ], @@ -833,7 +860,9 @@ def compute_partials(self, inputs, J): J["ground_roll_distance", "thrust_idle"] = dGRD_dThrustIdle = ( -13.0287 * wing_loading_land * dALN_dThrustIdle / (density_ratio * DLRL) ) - J["ground_roll_distance", Dynamic.Mission.MASS] = dGRD_dWeight * GRAV_ENGLISH_LBM + J["ground_roll_distance", Dynamic.Vehicle.MASS] = ( + dGRD_dWeight * GRAV_ENGLISH_LBM + ) J["ground_roll_distance", "CL_max"] = dGRD_dClMax = ( -13.0287 * wing_loading_land * dALN_dClMax / (density_ratio * DLRL) ) @@ -850,8 +879,9 @@ def compute_partials(self, inputs, J): J[Mission.Landing.GROUND_DISTANCE, "touchdown_CD"] = dGRD_dTouchdownCD J[Mission.Landing.GROUND_DISTANCE, "touchdown_CL"] = dGRD_dTouchdownCL J[Mission.Landing.GROUND_DISTANCE, "thrust_idle"] = dGRD_dThrustIdle - J[Mission.Landing.GROUND_DISTANCE, Dynamic.Mission.MASS] = \ + J[Mission.Landing.GROUND_DISTANCE, Dynamic.Vehicle.MASS] = ( dGRD_dWeight * GRAV_ENGLISH_LBM + ) J[Mission.Landing.GROUND_DISTANCE, "CL_max"] = dGRD_dClMax J[Mission.Landing.GROUND_DISTANCE, Mission.Landing.STALL_VELOCITY] = dGRD_dTasStall @@ -885,10 +915,11 @@ def compute_partials(self, inputs, J): / (ground_roll_distance**2 * 2.0 * G) * dGRD_dThrustIdle ) - J["average_acceleration", Dynamic.Mission.MASS] = ( + J["average_acceleration", Dynamic.Vehicle.MASS] = ( -(TAS_touchdown**2.0) / (ground_roll_distance**2 * 2.0 * G) - * dGRD_dWeight * GRAV_ENGLISH_LBM + * dGRD_dWeight + * GRAV_ENGLISH_LBM ) J["average_acceleration", "CL_max"] = ( -(TAS_touchdown**2.0) diff --git a/aviary/mission/gasp_based/ode/landing_ode.py b/aviary/mission/gasp_based/ode/landing_ode.py index dab9b9029..6c984f03e 100644 --- a/aviary/mission/gasp_based/ode/landing_ode.py +++ b/aviary/mission/gasp_based/ode/landing_ode.py @@ -1,10 +1,14 @@ +import numpy as np + from aviary.subsystems.atmosphere.atmosphere import Atmosphere from aviary.mission.gasp_based.ode.base_ode import BaseODE from aviary.mission.gasp_based.ode.params import ParamPort from aviary.mission.gasp_based.ode.landing_eom import ( - GlideConditionComponent, LandingAltitudeComponent, - LandingGroundRollComponent) + GlideConditionComponent, + LandingAltitudeComponent, + LandingGroundRollComponent, +) from aviary.subsystems.aerodynamics.aerodynamics_builder import AerodynamicsBuilderBase from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase from aviary.variable_info.enums import SpeedType @@ -38,15 +42,15 @@ def setup(self): subsys=Atmosphere(num_nodes=1, input_speed_type=SpeedType.MACH), promotes_inputs=[ (Dynamic.Mission.ALTITUDE, Mission.Landing.INITIAL_ALTITUDE), - (Dynamic.Mission.MACH, Mission.Landing.INITIAL_MACH), + (Dynamic.Atmosphere.MACH, Mission.Landing.INITIAL_MACH), ], promotes_outputs=[ - (Dynamic.Mission.DENSITY, "rho_app"), - (Dynamic.Mission.SPEED_OF_SOUND, "sos_app"), - (Dynamic.Mission.TEMPERATURE, "T_app"), - (Dynamic.Mission.STATIC_PRESSURE, "P_app"), - ("viscosity", "viscosity_app"), - (Dynamic.Mission.DYNAMIC_PRESSURE, "q_app"), + Dynamic.Atmosphere.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, + "viscosity", + Dynamic.Atmosphere.DYNAMIC_PRESSURE, ], ) @@ -55,21 +59,24 @@ def setup(self): if isinstance(subsystem, AerodynamicsBuilderBase): kwargs = {'method': 'low_speed'} aero_builder = subsystem - aero_system = subsystem.build_mission(num_nodes=1, - aviary_inputs=aviary_options, - **kwargs) + aero_system = subsystem.build_mission( + num_nodes=1, aviary_inputs=aviary_options, **kwargs + ) self.add_subsystem( subsystem.name, aero_system, promotes_inputs=[ "*", - (Dynamic.Mission.ALTITUDE, Mission.Landing.INITIAL_ALTITUDE), - (Dynamic.Mission.DENSITY, "rho_app"), - (Dynamic.Mission.SPEED_OF_SOUND, "sos_app"), - ("viscosity", "viscosity_app"), + ( + Dynamic.Mission.ALTITUDE, + Mission.Landing.INITIAL_ALTITUDE, + ), + Dynamic.Atmosphere.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + "viscosity", ("airport_alt", Mission.Landing.AIRPORT_ALTITUDE), - (Dynamic.Mission.MACH, Mission.Landing.INITIAL_MACH), - (Dynamic.Mission.DYNAMIC_PRESSURE, "q_app"), + (Dynamic.Atmosphere.MACH, Mission.Landing.INITIAL_MACH), + Dynamic.Atmosphere.DYNAMIC_PRESSURE, ("flap_defl", Aircraft.Wing.FLAP_DEFLECTION_LANDING), ("t_init_flaps", "t_init_flaps_app"), ("t_init_gear", "t_init_gear_app"), @@ -89,20 +96,26 @@ def setup(self): if isinstance(subsystem, PropulsionBuilderBase): propulsion_system = subsystem.build_mission( num_nodes=1, aviary_inputs=aviary_options) - propulsion_mission = self.add_subsystem(subsystem.name, - propulsion_system, - promotes_inputs=[ - "*", (Dynamic.Mission.ALTITUDE, Mission.Landing.INITIAL_ALTITUDE), (Dynamic.Mission.MACH, Mission.Landing.INITIAL_MACH)], - promotes_outputs=[(Dynamic.Mission.THRUST_TOTAL, "thrust_idle")]) - propulsion_mission.set_input_defaults(Dynamic.Mission.THROTTLE, 0.0) + propulsion_mission = self.add_subsystem( + subsystem.name, + propulsion_system, + promotes_inputs=[ + "*", + (Dynamic.Atmosphere.MACH, Mission.Landing.INITIAL_MACH), + ], + promotes_outputs=[ + (Dynamic.Vehicle.Propulsion.THRUST_TOTAL, "thrust_idle")], + ) + propulsion_mission.set_input_defaults( + Dynamic.Vehicle.Propulsion.THROTTLE, 0.0) self.add_subsystem( "glide", GlideConditionComponent(), promotes_inputs=[ - "rho_app", + Dynamic.Atmosphere.DENSITY, Mission.Landing.MAXIMUM_SINK_RATE, - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Aircraft.Wing.AREA, Mission.Landing.GLIDE_TO_STALL_RATIO, "CL_max", @@ -129,22 +142,20 @@ def setup(self): name='atmosphere_td', subsys=Atmosphere(num_nodes=1), promotes_inputs=[ - (Dynamic.Mission.ALTITUDE, Mission.Landing.AIRPORT_ALTITUDE), + Dynamic.Mission.ALTITUDE, (Dynamic.Mission.VELOCITY, "TAS_touchdown"), ], promotes_outputs=[ - (Dynamic.Mission.DENSITY, "rho_td"), - (Dynamic.Mission.SPEED_OF_SOUND, "sos_td"), - (Dynamic.Mission.TEMPERATURE, "T_td"), + (Dynamic.Atmosphere.DENSITY, "rho_td"), + (Dynamic.Atmosphere.SPEED_OF_SOUND, "sos_td"), + (Dynamic.Atmosphere.TEMPERATURE, "T_td"), ("viscosity", "viscosity_td"), - (Dynamic.Mission.DYNAMIC_PRESSURE, "q_td"), - (Dynamic.Mission.MACH, "mach_td"), + (Dynamic.Atmosphere.DYNAMIC_PRESSURE, "q_td"), + (Dynamic.Atmosphere.MACH, "mach_td"), ], ) - kwargs = {'method': 'low_speed', - 'retract_flaps': True, - 'retract_gear': False} + kwargs = {'method': 'low_speed', 'retract_flaps': True, 'retract_gear': False} self.add_subsystem( "aero_td", @@ -153,13 +164,13 @@ def setup(self): ), promotes_inputs=[ "*", - (Dynamic.Mission.ALTITUDE, Mission.Landing.AIRPORT_ALTITUDE), - (Dynamic.Mission.DENSITY, "rho_td"), - (Dynamic.Mission.SPEED_OF_SOUND, "sos_td"), + Dynamic.Mission.ALTITUDE, + (Dynamic.Atmosphere.DENSITY, "rho_td"), + (Dynamic.Atmosphere.SPEED_OF_SOUND, "sos_td"), ("viscosity", "viscosity_td"), ("airport_alt", Mission.Landing.AIRPORT_ALTITUDE), - (Dynamic.Mission.MACH, "mach_td"), - (Dynamic.Mission.DYNAMIC_PRESSURE, "q_td"), + (Dynamic.Atmosphere.MACH, "mach_td"), + (Dynamic.Atmosphere.DYNAMIC_PRESSURE, "q_td"), ("alpha", Aircraft.Wing.INCIDENCE), ("flap_defl", Aircraft.Wing.FLAP_DEFLECTION_LANDING), ("CL_max_flaps", Mission.Landing.LIFT_COEFFICIENT_MAX), @@ -194,11 +205,14 @@ def setup(self): "tr_distance", "delay_distance", "CL_max", - Dynamic.Mission.MASS, - 'mission:*' + Dynamic.Vehicle.MASS, + 'mission:*', ], promotes_outputs=[ - "ground_roll_distance", "average_acceleration", 'mission:*'], + "ground_roll_distance", + "average_acceleration", + 'mission:*', + ], ) ParamPort.set_default_vals(self) @@ -208,11 +222,16 @@ def setup(self): # landing doesn't change flap or gear position self.set_input_defaults("t_init_flaps_app", val=1e10) self.set_input_defaults("t_init_gear_app", val=1e10) - self.set_input_defaults( - Mission.Landing.INITIAL_ALTITUDE, val=50, units="ft") - self.set_input_defaults('aero_ramps.flap_factor:final_val', val=1.) - self.set_input_defaults('aero_ramps.gear_factor:final_val', val=1.) - self.set_input_defaults('aero_ramps.flap_factor:initial_val', val=0.) - self.set_input_defaults('aero_ramps.gear_factor:initial_val', val=0.) + self.set_input_defaults(Mission.Landing.INITIAL_ALTITUDE, val=50, units="ft") + self.set_input_defaults('aero_ramps.flap_factor:final_val', val=1.0) + self.set_input_defaults('aero_ramps.gear_factor:final_val', val=1.0) + self.set_input_defaults('aero_ramps.flap_factor:initial_val', val=0.0) + self.set_input_defaults('aero_ramps.gear_factor:initial_val', val=0.0) self.set_input_defaults(Aircraft.Wing.AREA, val=1.0, units="ft**2") + + # Throttle Idle + num_engine_types = len(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) + self.set_input_defaults( + Dynamic.Vehicle.Propulsion.THROTTLE, np.zeros((1, num_engine_types)) + ) diff --git a/aviary/mission/gasp_based/ode/params.py b/aviary/mission/gasp_based/ode/params.py index c18e4e9c3..cd7264eff 100644 --- a/aviary/mission/gasp_based/ode/params.py +++ b/aviary/mission/gasp_based/ode/params.py @@ -141,18 +141,10 @@ def promote_params(sys, trajs=None, phases=None): Mission.Design.LIFT_COEFFICIENT_MAX_FLAPS_UP: dict(units="unitless", val=1.2596), Mission.Takeoff.LIFT_COEFFICIENT_MAX: dict(units="unitless", val=2.1886), Mission.Landing.LIFT_COEFFICIENT_MAX: dict(units="unitless", val=2.8155), - Mission.Takeoff.LIFT_COEFFICIENT_FLAP_INCREMENT: dict( - units="unitless", val=0.4182 - ), - Mission.Landing.LIFT_COEFFICIENT_FLAP_INCREMENT: dict( - units="unitless", val=1.0293 - ), - Mission.Takeoff.DRAG_COEFFICIENT_FLAP_INCREMENT: dict( - units="unitless", val=0.0085 - ), - Mission.Landing.DRAG_COEFFICIENT_FLAP_INCREMENT: dict( - units="unitless", val=0.0406 - ), + Mission.Takeoff.LIFT_COEFFICIENT_FLAP_INCREMENT: dict(units="unitless", val=0.4182), + Mission.Landing.LIFT_COEFFICIENT_FLAP_INCREMENT: dict(units="unitless", val=1.0293), + Mission.Takeoff.DRAG_COEFFICIENT_FLAP_INCREMENT: dict(units="unitless", val=0.0085), + Mission.Landing.DRAG_COEFFICIENT_FLAP_INCREMENT: dict(units="unitless", val=0.0406), } diff --git a/aviary/mission/gasp_based/ode/rotation_eom.py b/aviary/mission/gasp_based/ode/rotation_eom.py index 49c3b7400..4c0014546 100644 --- a/aviary/mission/gasp_based/ode/rotation_eom.py +++ b/aviary/mission/gasp_based/ode/rotation_eom.py @@ -19,29 +19,61 @@ def setup(self): nn = self.options["num_nodes"] analysis_scheme = self.options["analysis_scheme"] - self.add_input(Dynamic.Mission.MASS, val=np.ones(nn), - desc="aircraft mass", units="lbm") - self.add_input(Dynamic.Mission.THRUST_TOTAL, val=np.ones( - nn), desc=Dynamic.Mission.THRUST_TOTAL, units="lbf") - self.add_input(Dynamic.Mission.LIFT, val=np.ones( - nn), desc=Dynamic.Mission.LIFT, units="lbf") - self.add_input(Dynamic.Mission.DRAG, val=np.ones( - nn), desc=Dynamic.Mission.DRAG, units="lbf") - self.add_input(Dynamic.Mission.VELOCITY, val=np.ones(nn), - desc="true air speed", units="ft/s") - self.add_input(Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.ones(nn), - desc="flight path angle", units="rad") + self.add_input( + Dynamic.Vehicle.MASS, val=np.ones(nn), desc="aircraft mass", units="lbm" + ) + self.add_input( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + val=np.ones(nn), + desc=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + units="lbf", + ) + self.add_input( + Dynamic.Vehicle.LIFT, + val=np.ones(nn), + desc=Dynamic.Vehicle.LIFT, + units="lbf", + ) + self.add_input( + Dynamic.Vehicle.DRAG, + val=np.ones(nn), + desc=Dynamic.Vehicle.DRAG, + units="lbf", + ) + self.add_input( + Dynamic.Mission.VELOCITY, + val=np.ones(nn), + desc="true air speed", + units="ft/s", + ) + self.add_input( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + val=np.ones(nn), + desc="flight path angle", + units="rad", + ) add_aviary_input(self, Aircraft.Wing.INCIDENCE, val=0.0, units="deg") self.add_input("alpha", val=np.ones(nn), desc="angle of attack", units="deg") - self.add_output(Dynamic.Mission.VELOCITY_RATE, val=np.ones(nn), - desc="TAS rate", units="ft/s**2") self.add_output( - Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, val=np.ones(nn), desc="flight path angle rate", units="rad/s" + Dynamic.Mission.VELOCITY_RATE, + val=np.ones(nn), + desc="TAS rate", + units="ft/s**2", + ) + self.add_output( + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + val=np.ones(nn), + desc="flight path angle rate", + units="rad/s", + ) + self.add_output( + Dynamic.Mission.ALTITUDE_RATE, + val=np.ones(nn), + desc="altitude rate", + units="ft/s", ) - self.add_output(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), - desc="altitude rate", units="ft/s") self.add_output( Dynamic.Mission.DISTANCE_RATE, val=np.ones(nn), desc="distance rate", units="ft/s" ) @@ -65,29 +97,49 @@ def setup_partials(self): self.declare_partials(Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, "*") self.declare_partials( Dynamic.Mission.VELOCITY_RATE, - [Dynamic.Mission.THRUST_TOTAL, "alpha", Dynamic.Mission.DRAG, - Dynamic.Mission.MASS, Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.LIFT], + [ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Vehicle.LIFT, + ], rows=arange, cols=arange, ) self.declare_partials(Dynamic.Mission.VELOCITY_RATE, [Aircraft.Wing.INCIDENCE]) - self.declare_partials(Dynamic.Mission.ALTITUDE_RATE, [ - Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange) self.declare_partials( - Dynamic.Mission.DISTANCE_RATE, [ - Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange + Dynamic.Mission.ALTITUDE_RATE, + [Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=arange, + cols=arange, + ) + self.declare_partials( + Dynamic.Mission.DISTANCE_RATE, + [Dynamic.Mission.VELOCITY, Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=arange, + cols=arange, ) self.declare_partials( "normal_force", - [Dynamic.Mission.MASS, Dynamic.Mission.LIFT, - Dynamic.Mission.THRUST_TOTAL, "alpha"], + [ + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.LIFT, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + ], rows=arange, cols=arange, ) self.declare_partials("normal_force", [Aircraft.Wing.INCIDENCE]) self.declare_partials( - "fuselage_pitch", Dynamic.Mission.FLIGHT_PATH_ANGLE, rows=arange, cols=arange, val=180 / np.pi, + "fuselage_pitch", + Dynamic.Mission.FLIGHT_PATH_ANGLE, + rows=arange, + cols=arange, + val=180 / np.pi, ) self.declare_partials("fuselage_pitch", "alpha", rows=arange, cols=arange, val=1) self.declare_partials("fuselage_pitch", Aircraft.Wing.INCIDENCE, val=-1) @@ -95,10 +147,10 @@ def setup_partials(self): def compute(self, inputs, outputs): analysis_scheme = self.options["analysis_scheme"] - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - incremented_lift = inputs[Dynamic.Mission.LIFT] - incremented_drag = inputs[Dynamic.Mission.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + incremented_lift = inputs[Dynamic.Vehicle.LIFT] + incremented_drag = inputs[Dynamic.Vehicle.DRAG] TAS = inputs[Dynamic.Mission.VELOCITY] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -138,10 +190,10 @@ def compute_partials(self, inputs, J): mu = MU_TAKEOFF - weight = inputs[Dynamic.Mission.MASS] * GRAV_ENGLISH_LBM - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - incremented_lift = inputs[Dynamic.Mission.LIFT] - incremented_drag = inputs[Dynamic.Mission.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * GRAV_ENGLISH_LBM + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + incremented_lift = inputs[Dynamic.Vehicle.LIFT] + incremented_drag = inputs[Dynamic.Vehicle.DRAG] TAS = inputs[Dynamic.Mission.VELOCITY] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -178,7 +230,7 @@ def compute_partials(self, inputs, J): dNF_dIwing = -np.ones(nn) * dTAcF_dIwing dNF_dIwing[normal_force < 0] = 0 - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.THRUST_TOTAL] = ( + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( (dTAlF_dThrust - mu * dNF_dThrust) * GRAV_ENGLISH_GASP / weight ) J[Dynamic.Mission.VELOCITY_RATE, "alpha"] = ( @@ -187,9 +239,12 @@ def compute_partials(self, inputs, J): J[Dynamic.Mission.VELOCITY_RATE, Aircraft.Wing.INCIDENCE] = ( (dTAlF_dIwing - mu * dNF_dIwing) * GRAV_ENGLISH_GASP / weight ) - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.DRAG] = -GRAV_ENGLISH_GASP / weight - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.MASS] = ( - GRAV_ENGLISH_GASP * GRAV_ENGLISH_LBM + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.DRAG] = ( + -GRAV_ENGLISH_GASP / weight + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.MASS] = ( + GRAV_ENGLISH_GASP + * GRAV_ENGLISH_LBM * ( weight * (-np.sin(gamma) - mu * dNF_dWeight) - ( @@ -201,21 +256,25 @@ def compute_partials(self, inputs, J): ) / weight**2 ) - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = - \ - np.cos(gamma) * GRAV_ENGLISH_GASP - J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.LIFT] = GRAV_ENGLISH_GASP * \ - (-mu * dNF_dLift) / weight + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -np.cos(gamma) * GRAV_ENGLISH_GASP + ) + J[Dynamic.Mission.VELOCITY_RATE, Dynamic.Vehicle.LIFT] = ( + GRAV_ENGLISH_GASP * (-mu * dNF_dLift) / weight + ) J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = np.sin(gamma) - J[Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE] = TAS * np.cos(gamma) + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + TAS * np.cos(gamma) + ) J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = np.cos(gamma) - J[Dynamic.Mission.DISTANCE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -TAS * np.sin(gamma) + ) - J["normal_force", Dynamic.Mission.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM - J["normal_force", Dynamic.Mission.LIFT] = dNF_dLift - J["normal_force", Dynamic.Mission.THRUST_TOTAL] = dNF_dThrust + J["normal_force", Dynamic.Vehicle.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM + J["normal_force", Dynamic.Vehicle.LIFT] = dNF_dLift + J["normal_force", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = dNF_dThrust J["normal_force", "alpha"] = dNF_dAlpha J["normal_force", Aircraft.Wing.INCIDENCE] = dNF_dIwing diff --git a/aviary/mission/gasp_based/ode/rotation_ode.py b/aviary/mission/gasp_based/ode/rotation_ode.py index 64f5eaa68..c4158b6b7 100644 --- a/aviary/mission/gasp_based/ode/rotation_ode.py +++ b/aviary/mission/gasp_based/ode/rotation_ode.py @@ -65,8 +65,9 @@ def setup(self): self.set_input_defaults("t_init_flaps", val=47.5, units='s') self.set_input_defaults("t_init_gear", val=37.3, units='s') self.set_input_defaults("alpha", val=np.ones(nn), units="deg") - self.set_input_defaults(Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units="deg") + self.set_input_defaults( + Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units="deg" + ) self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.zeros(nn), units="ft") self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.zeros(nn), units="kn") self.set_input_defaults("t_curr", val=np.zeros(nn), units="s") diff --git a/aviary/mission/gasp_based/ode/taxi_eom.py b/aviary/mission/gasp_based/ode/taxi_eom.py index cd548d7bd..eceb83bd7 100644 --- a/aviary/mission/gasp_based/ode/taxi_eom.py +++ b/aviary/mission/gasp_based/ode/taxi_eom.py @@ -1,8 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input +from aviary.variable_info.functions import add_aviary_input, add_aviary_option from aviary.variable_info.variables import Dynamic, Mission @@ -12,13 +11,11 @@ class TaxiFuelComponent(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Mission.Taxi.DURATION, units='s') def setup(self): self.add_input( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, val=1.0, units="lbm/s", desc="fuel flow rate", @@ -32,7 +29,7 @@ def setup(self): desc="taxi_fuel_consumed", ) self.add_output( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, val=175000.0, units="lbm", desc="mass after taxi", @@ -40,22 +37,30 @@ def setup(self): def setup_partials(self): self.declare_partials( - "taxi_fuel_consumed", [ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL]) - self.declare_partials( - Dynamic.Mission.MASS, Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL) + "taxi_fuel_consumed", + [Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL], + ) self.declare_partials( - Dynamic.Mission.MASS, Mission.Summary.GROSS_MASS, val=1) + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + ) + self.declare_partials(Dynamic.Vehicle.MASS, Mission.Summary.GROSS_MASS, val=1) def compute(self, inputs, outputs): fuelflow, takeoff_mass = inputs.values() - dt_taxi = self.options['aviary_options'].get_val(Mission.Taxi.DURATION, 's') + dt_taxi, _ = self.options[Mission.Taxi.DURATION] outputs["taxi_fuel_consumed"] = -fuelflow * dt_taxi - outputs[Dynamic.Mission.MASS] = takeoff_mass - outputs["taxi_fuel_consumed"] + outputs[Dynamic.Vehicle.MASS] = takeoff_mass - outputs["taxi_fuel_consumed"] def compute_partials(self, inputs, J): - dt_taxi = self.options['aviary_options'].get_val(Mission.Taxi.DURATION, 's') + dt_taxi, _ = self.options[Mission.Taxi.DURATION] - J["taxi_fuel_consumed", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL] = -dt_taxi + J[ + "taxi_fuel_consumed", + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + ] = -dt_taxi - J[Dynamic.Mission.MASS, Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL] = dt_taxi + J[ + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + ] = dt_taxi diff --git a/aviary/mission/gasp_based/ode/taxi_ode.py b/aviary/mission/gasp_based/ode/taxi_ode.py index 0c69e60db..fa593c47a 100644 --- a/aviary/mission/gasp_based/ode/taxi_ode.py +++ b/aviary/mission/gasp_based/ode/taxi_ode.py @@ -1,3 +1,11 @@ +import openmdao.api as om +import numpy as np + +from aviary.subsystems.atmosphere.atmosphere import Atmosphere +from aviary.utils.aviary_values import AviaryValues +from aviary.utils.functions import add_opts2vals, create_opts2vals + +from aviary.variable_info.enums import SpeedType from aviary.mission.gasp_based.ode.base_ode import BaseODE from aviary.mission.gasp_based.ode.params import ParamPort from aviary.mission.gasp_based.ode.taxi_eom import TaxiFuelComponent @@ -5,7 +13,7 @@ from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase from aviary.utils.aviary_values import AviaryValues from aviary.utils.functions import add_opts2vals, create_opts2vals -from aviary.variable_info.variables import Dynamic, Mission +from aviary.variable_info.variables import Aircraft, Dynamic, Mission class TaxiSegment(BaseODE): @@ -17,33 +25,69 @@ def setup(self): self.add_subsystem("params", ParamPort(), promotes=["*"]) + add_opts2vals(self, create_opts2vals([Mission.Taxi.MACH]), options) + + alias_comp = om.ExecComp( + 'alt=airport_alt', + alt={ + 'val': np.zeros(1), + 'units': 'ft', + }, + airport_alt={'val': np.zeros(1), 'units': 'ft'}, + has_diag_partials=True, + ) + + alias_comp.add_expr( + 'mach=taxi_mach', + mach={'val': np.zeros(1), 'units': 'unitless'}, + taxi_mach={'val': np.zeros(1), 'units': 'unitless'}, + ) + + self.add_subsystem( + 'alias_taxi_phase', + alias_comp, + promotes_inputs=[ + ('airport_alt', Mission.Takeoff.AIRPORT_ALTITUDE), + ('taxi_mach', Mission.Taxi.MACH), + ], + promotes_outputs=[ + ('alt', Dynamic.Mission.ALTITUDE), + ('mach', Dynamic.Atmosphere.MACH), + ], + ) + self.add_subsystem( name='atmosphere', - subsys=Atmosphere(num_nodes=1), + subsys=Atmosphere(num_nodes=1, input_speed_type=SpeedType.MACH), promotes=[ '*', - (Dynamic.Mission.ALTITUDE, Mission.Takeoff.AIRPORT_ALTITUDE), ], ) - add_opts2vals(self, create_opts2vals( - [Mission.Taxi.MACH]), options) - for subsystem in core_subsystems: if isinstance(subsystem, PropulsionBuilderBase): system = subsystem.build_mission(num_nodes=1, aviary_inputs=options) - self.add_subsystem(subsystem.name, - system, - promotes_inputs=['*', (Dynamic.Mission.ALTITUDE, Mission.Takeoff.AIRPORT_ALTITUDE), - (Dynamic.Mission.MACH, Mission.Taxi.MACH)], - promotes_outputs=['*']) + self.add_subsystem( + subsystem.name, + system, + promotes_inputs=[ + '*', + (Dynamic.Mission.ALTITUDE, Mission.Takeoff.AIRPORT_ALTITUDE), + (Dynamic.Atmosphere.MACH, Mission.Taxi.MACH), + ], + promotes_outputs=['*'], + ) - self.add_subsystem("taxifuel", TaxiFuelComponent( - aviary_options=options), promotes=["*"]) + self.add_subsystem( + "taxifuel", TaxiFuelComponent(), promotes=["*"] + ) ParamPort.set_default_vals(self) self.set_input_defaults(Mission.Taxi.MACH, 0) # Throttle Idle - self.set_input_defaults('throttle', 0.0) + num_engine_types = len(options.get_val(Aircraft.Engine.NUM_ENGINES)) + self.set_input_defaults( + Dynamic.Vehicle.Propulsion.THROTTLE, np.zeros((1, num_engine_types)) + ) diff --git a/aviary/mission/gasp_based/ode/test/test_accel_eom.py b/aviary/mission/gasp_based/ode/test/test_accel_eom.py index bb3d8c5f4..697038fb5 100644 --- a/aviary/mission/gasp_based/ode/test/test_accel_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_accel_eom.py @@ -24,16 +24,19 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([174878, 174878]), units="lbm" + Dynamic.Vehicle.MASS, np.array([174878, 174878]), units="lbm" ) self.prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([2635.225, 2635.225]), units="lbf" + Dynamic.Vehicle.DRAG, np.array([2635.225, 2635.225]), units="lbf" ) # note: this input value is not provided in the GASP data, so an estimation was made based on another similar data point self.prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([32589, 32589]), units="lbf" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + np.array([32589, 32589]), + units="lbf", ) self.prob.model.set_input_defaults( - Dynamic.Mission.VELOCITY, np.array([252, 252]), units="kn") + Dynamic.Mission.VELOCITY, np.array([252, 252]), units="kn" + ) self.prob.setup(check=False, force_alloc_complex=True) @@ -43,8 +46,9 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [5.51533958, 5.51533958]), tol + self.prob[Dynamic.Mission.VELOCITY_RATE], + np.array([5.51533958, 5.51533958]), + tol, # note: this was finite differenced from GASP. The fd value is: np.array([5.2353365, 5.2353365]) ) assert_near_equal( diff --git a/aviary/mission/gasp_based/ode/test/test_accel_ode.py b/aviary/mission/gasp_based/ode/test/test_accel_ode.py index 4552ad305..39b25f670 100644 --- a/aviary/mission/gasp_based/ode/test/test_accel_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_accel_ode.py @@ -9,7 +9,7 @@ from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic +from aviary.variable_info.variables import Aircraft, Dynamic class AccelerationODETestCase(unittest.TestCase): @@ -21,6 +21,7 @@ def setUp(self): self.prob = om.Problem() aviary_options = get_option_defaults() + aviary_options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) default_mission_subsystems = get_default_mission_subsystems( 'GASP', build_engine_deck(aviary_options)) @@ -35,18 +36,22 @@ def test_accel(self): throttle_climb = 0.956 self.prob.set_val(Dynamic.Mission.ALTITUDE, [500, 500], units="ft") self.prob.set_val( - Dynamic.Mission.THROTTLE, [ - throttle_climb, throttle_climb], units='unitless') + Dynamic.Vehicle.Propulsion.THROTTLE, + [throttle_climb, throttle_climb], + units='unitless', + ) self.prob.set_val(Dynamic.Mission.VELOCITY, [185, 252], units="kn") - self.prob.set_val(Dynamic.Mission.MASS, [174974, 174878], units="lbm") + self.prob.set_val(Dynamic.Vehicle.MASS, [174974, 174878], units="lbm") set_params_for_unit_tests(self.prob) self.prob.run_model() testvals = { - Dynamic.Mission.LIFT: [174974, 174878], - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: [ - -13262.73, -13567.53] # lbm/h + Dynamic.Vehicle.LIFT: [174974, 174878], + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL: [ + -13262.73, + -13567.53, + ], # lbm/h } check_prob_outputs(self.prob, testvals, rtol=1e-6) diff --git a/aviary/mission/gasp_based/ode/test/test_ascent_eom.py b/aviary/mission/gasp_based/ode/test/test_ascent_eom.py index c675b000e..340240369 100644 --- a/aviary/mission/gasp_based/ode/test/test_ascent_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_ascent_eom.py @@ -14,19 +14,23 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem("group", AscentEOM(num_nodes=2), promotes=["*"]) self.prob.model.set_input_defaults( - Dynamic.Mission.MASS, val=175400 * np.ones(2), units="lbm" + Dynamic.Vehicle.MASS, val=175400 * np.ones(2), units="lbm" ) self.prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" ) self.prob.model.set_input_defaults( - Dynamic.Mission.LIFT, val=200 * np.ones(2), units="lbf") + Dynamic.Vehicle.LIFT, val=200 * np.ones(2), units="lbf" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.DRAG, val=10000 * np.ones(2), units="lbf") + Dynamic.Vehicle.DRAG, val=10000 * np.ones(2), units="lbf" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.VELOCITY, val=10 * np.ones(2), units="ft/s") + Dynamic.Mission.VELOCITY, val=10 * np.ones(2), units="ft/s" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(2), units="rad") + Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(2), units="rad" + ) self.prob.model.set_input_defaults(Aircraft.Wing.INCIDENCE, val=0, units="deg") self.prob.model.set_input_defaults("alpha", val=np.zeros(2), units="deg") @@ -38,12 +42,14 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [2.202965, 2.202965]), tol + self.prob[Dynamic.Mission.VELOCITY_RATE], + np.array([2.202965, 2.202965]), + tol, ) assert_near_equal( - self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array( - [-3.216328, -3.216328]), tol + self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], + np.array([-3.216328, -3.216328]), + tol, ) partial_data = self.prob.check_partials(out_stream=None, method="cs") @@ -67,15 +73,17 @@ def test_case1(self): prob = om.Problem() prob.model.add_subsystem("group", AscentEOM(num_nodes=2), promotes=["*"]) prob.model.set_input_defaults( - Dynamic.Mission.MASS, val=175400 * np.ones(2), units="lbm" + Dynamic.Vehicle.MASS, val=175400 * np.ones(2), units="lbm" ) prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" ) prob.model.set_input_defaults( - Dynamic.Mission.LIFT, val=200 * np.ones(2), units="lbf") + Dynamic.Vehicle.LIFT, val=200 * np.ones(2), units="lbf" + ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, val=10000 * np.ones(2), units="lbf") + Dynamic.Vehicle.DRAG, val=10000 * np.ones(2), units="lbf" + ) prob.model.set_input_defaults( Dynamic.Mission.VELOCITY, val=10 * np.ones(2), units="ft/s") prob.model.set_input_defaults( diff --git a/aviary/mission/gasp_based/ode/test/test_ascent_ode.py b/aviary/mission/gasp_based/ode/test/test_ascent_ode.py index d56246aba..ea6c70248 100644 --- a/aviary/mission/gasp_based/ode/test/test_ascent_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_ascent_ode.py @@ -9,7 +9,7 @@ from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic +from aviary.variable_info.variables import Aircraft, Dynamic class AscentODETestCase(unittest.TestCase): @@ -17,6 +17,7 @@ def setUp(self): self.prob = om.Problem() aviary_options = get_option_defaults() + aviary_options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) default_mission_subsystems = get_default_mission_subsystems( 'GASP', build_engine_deck(aviary_options)) @@ -39,14 +40,18 @@ def test_ascent_partials(self): tol = tol = 1e-6 assert_near_equal( - self.prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [641174.75, 641174.75]), tol) + self.prob[Dynamic.Mission.VELOCITY_RATE], + np.array([641174.75, 641174.75]), + tol, + ) assert_near_equal( - self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array( - [2260.644, 2260.644]), tol) + self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], + np.array([2260.644, 2260.644]), + tol, + ) assert_near_equal( - self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array( - [0.0, 0.0]), tol) + self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array([0.0, 0.0]), tol + ) assert_near_equal( self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( [168.781, 168.781]), tol) diff --git a/aviary/mission/gasp_based/ode/test/test_breguet_cruise_eom.py b/aviary/mission/gasp_based/ode/test/test_breguet_cruise_eom.py index b563c2efe..4f79823ee 100644 --- a/aviary/mission/gasp_based/ode/test/test_breguet_cruise_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_breguet_cruise_eom.py @@ -26,7 +26,7 @@ def setUp(self): self.prob.set_val("TAS_cruise", 458.8, units="kn") self.prob.set_val("mass", np.linspace(171481, 171481 - 10000, nn), units="lbm") - self.prob.set_val(Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - + self.prob.set_val(Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - 5870 * np.ones(nn,), units="lbm/h") def test_case1(self): @@ -62,7 +62,13 @@ def setUp(self): self.prob.model.set_input_defaults( "mass", np.linspace(171481, 171481 - 10000, nn), units="lbm") self.prob.model.set_input_defaults( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, -5870 * np.ones(nn,), units="lbm/h") + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + -5870 + * np.ones( + nn, + ), + units="lbm/h", + ) self.prob.setup(check=False, force_alloc_complex=True) @@ -109,7 +115,13 @@ def test_partials(self): prob.model.set_input_defaults( "mass", np.linspace(171481, 171481 - 10000, nn), units="lbm") prob.model.set_input_defaults( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, -5870 * np.ones(nn,), units="lbm/h") + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + -5870 + * np.ones( + nn, + ), + units="lbm/h", + ) prob.setup(check=False, force_alloc_complex=True) partial_data = prob.check_partials(out_stream=None, method="cs") @@ -128,8 +140,14 @@ def setUp(self): self.prob.set_val("TAS_cruise", 458.8, units="kn") self.prob.set_val("mass", np.linspace(171481, 171481 - 10000, nn), units="lbm") - self.prob.set_val(Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - - 5870 * np.ones(nn,), units="lbm/h") + self.prob.set_val( + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + -5870 + * np.ones( + nn, + ), + units="lbm/h", + ) def test_results(self): self.prob.run_model() @@ -138,9 +156,9 @@ def test_results(self): V = self.prob.get_val("TAS_cruise", units="kn") r = self.prob.get_val("cruise_range", units="NM") t = self.prob.get_val("cruise_time", units="h") - fuel_flow = - \ - self.prob.get_val( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/h") + fuel_flow = -self.prob.get_val( + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/h" + ) v_avg = (V[:-1] + V[1:])/2 fuel_flow_avg = (fuel_flow[:-1] + fuel_flow[1:])/2 diff --git a/aviary/mission/gasp_based/ode/test/test_breguet_cruise_ode.py b/aviary/mission/gasp_based/ode/test/test_breguet_cruise_ode.py index c69f465d2..23e79bc82 100644 --- a/aviary/mission/gasp_based/ode/test/test_breguet_cruise_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_breguet_cruise_ode.py @@ -9,7 +9,7 @@ from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic +from aviary.variable_info.variables import Aircraft, Dynamic class CruiseODETestCase(unittest.TestCase): @@ -17,23 +17,26 @@ def setUp(self): self.prob = om.Problem() aviary_options = get_option_defaults() + aviary_options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) default_mission_subsystems = get_default_mission_subsystems( - 'GASP', build_engine_deck(aviary_options)) + 'GASP', build_engine_deck(aviary_options) + ) self.prob.model = BreguetCruiseODESolution( num_nodes=2, aviary_options=aviary_options, - core_subsystems=default_mission_subsystems) + core_subsystems=default_mission_subsystems, + ) self.prob.model.set_input_defaults( - Dynamic.Mission.MACH, np.array([0, 0]), units="unitless" + Dynamic.Atmosphere.MACH, np.array([0, 0]), units="unitless" ) def test_cruise(self): # test partial derivatives self.prob.setup(check=False, force_alloc_complex=True) - self.prob.set_val(Dynamic.Mission.MACH, [0.7, 0.7], units="unitless") + self.prob.set_val(Dynamic.Atmosphere.MACH, [0.7, 0.7], units="unitless") self.prob.set_val("interference_independent_of_shielded_area", 1.89927266) self.prob.set_val("drag_loss_due_to_shielded_wing_area", 68.02065834) @@ -43,20 +46,22 @@ def test_cruise(self): tol = tol = 1e-6 assert_near_equal( - self.prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [1.0, 1.0]), tol) - assert_near_equal( - self.prob[Dynamic.Mission.DISTANCE], np.array( - [0.0, 881.8116]), tol) + self.prob[Dynamic.Mission.VELOCITY_RATE], np.array([1.0, 1.0]), tol + ) assert_near_equal( - self.prob["time"], np.array( - [0, 7906.83]), tol) + self.prob[Dynamic.Mission.DISTANCE], np.array([0.0, 882.5769]), tol + ) + assert_near_equal(self.prob["time"], np.array([0, 7913.69]), tol) assert_near_equal( - self.prob[Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS], np.array( - [3.429719, 4.433518]), tol) + self.prob[Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS], + np.array([3.439203, 4.440962]), + tol, + ) assert_near_equal( - self.prob[Dynamic.Mission.ALTITUDE_RATE_MAX], np.array( - [-17.63194, -16.62814]), tol) + self.prob[Dynamic.Mission.ALTITUDE_RATE_MAX], + np.array([-17.622456, -16.62070]), + tol, + ) partial_data = self.prob.check_partials( out_stream=None, method="cs", excludes=["*USatm*", "*params*", "*aero*"] diff --git a/aviary/mission/gasp_based/ode/test/test_climb_eom.py b/aviary/mission/gasp_based/ode/test/test_climb_eom.py index ec9f04da5..0335b62f8 100644 --- a/aviary/mission/gasp_based/ode/test/test_climb_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_climb_eom.py @@ -21,15 +21,18 @@ def setUp(self): self.prob.model.add_subsystem("group", ClimbRates(num_nodes=2), promotes=["*"]) self.prob.model.set_input_defaults( - Dynamic.Mission.VELOCITY, np.array([459, 459]), units="kn") + Dynamic.Mission.VELOCITY, np.array([459, 459]), units="kn" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([10473, 10473]), units="lbf" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + np.array([10473, 10473]), + units="lbf", ) self.prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([9091.517, 9091.517]), units="lbf" + Dynamic.Vehicle.DRAG, np.array([9091.517, 9091.517]), units="lbf" ) self.prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([171481, 171481]), units="lbm" + Dynamic.Vehicle.MASS, np.array([171481, 171481]), units="lbm" ) self.prob.setup(check=False, force_alloc_complex=True) @@ -40,8 +43,9 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array( - [6.24116612, 6.24116612]), tol + self.prob[Dynamic.Mission.ALTITUDE_RATE], + np.array([6.24116612, 6.24116612]), + tol, ) # note: values from GASP are: np.array([5.9667, 5.9667]) assert_near_equal( self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( @@ -54,8 +58,9 @@ def test_case1(self): tol, ) # note: values from GASP are: np.array([170316.2, 170316.2]) assert_near_equal( - self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE], np.array( - [0.00805627, 0.00805627]), tol + self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE], + np.array([0.00805627, 0.00805627]), + tol, ) # note: values from GASP are:np.array([.0076794487, .0076794487]) partial_data = self.prob.check_partials(out_stream=None, method="cs") @@ -81,13 +86,15 @@ def test_case1(self): prob.model.set_input_defaults( Dynamic.Mission.VELOCITY, np.array([459, 459]), units="kn") prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([10473, 10473]), units="lbf" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + np.array([10473, 10473]), + units="lbf", ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([9091.517, 9091.517]), units="lbf" + Dynamic.Vehicle.DRAG, np.array([9091.517, 9091.517]), units="lbf" ) prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([171481, 171481]), units="lbm" + Dynamic.Vehicle.MASS, np.array([171481, 171481]), units="lbm" ) prob.setup(check=False, force_alloc_complex=True) diff --git a/aviary/mission/gasp_based/ode/test/test_climb_ode.py b/aviary/mission/gasp_based/ode/test/test_climb_ode.py index 8be1742a8..2df625238 100644 --- a/aviary/mission/gasp_based/ode/test/test_climb_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_climb_ode.py @@ -9,6 +9,7 @@ from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.utils.test_utils.IO_test_util import check_prob_outputs +from aviary.variable_info.enums import Verbosity from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Dynamic @@ -22,15 +23,19 @@ def setUp(self): self.prob = om.Problem() aviary_options = get_option_defaults() + aviary_options.set_val('verbosity', Verbosity.QUIET) + aviary_options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) + default_mission_subsystems = get_default_mission_subsystems( - 'GASP', build_engine_deck(aviary_options)) + 'GASP', build_engine_deck(aviary_options) + ) self.sys = self.prob.model = ClimbODE( num_nodes=1, EAS_target=250, mach_cruise=0.8, - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems + aviary_options=aviary_options, + core_subsystems=default_mission_subsystems, ) def test_start_of_climb(self): @@ -41,9 +46,10 @@ def test_start_of_climb(self): throttle_climb = 0.956 self.prob.set_val( - Dynamic.Mission.THROTTLE, throttle_climb, units='unitless') + Dynamic.Vehicle.Propulsion.THROTTLE, throttle_climb, units='unitless' + ) self.prob.set_val(Dynamic.Mission.ALTITUDE, 1000, units="ft") - self.prob.set_val(Dynamic.Mission.MASS, 174845, units="lbm") + self.prob.set_val(Dynamic.Vehicle.MASS, 174845, units="lbm") self.prob.set_val("EAS", 250, units="kn") # slightly greater than zero to help check partials self.prob.set_val(Aircraft.Wing.INCIDENCE, 0.0000001, units="deg") @@ -58,11 +64,12 @@ def test_start_of_climb(self): "alpha": 5.16398, "CL": 0.59766664, "CD": 0.03070836, - Dynamic.Mission.ALTITUDE_RATE: 3414.63 / 60, # ft/s - # TAS (kts -> ft/s) * cos(gamma), 253.6827 * 1.68781 * cos(0.13331060446181708) + Dynamic.Mission.ALTITUDE_RATE: 3414.624 / 60, # ft/s + # TAS (kts -> ft/s) * cos(gamma), 253.6827 * 1.68781 * + # cos(0.13331060446181708) Dynamic.Mission.DISTANCE_RATE: 424.36918705874785, # ft/s - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: -13448.29, # lbm/h - "theta": 0.22343879616956605, # rad (12.8021 deg) + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL: -13448.29, # lbm/h + "theta": 0.22343906, # rad (12.8021 deg) Dynamic.Mission.FLIGHT_PATH_ANGLE: 0.13331060446181708, # rad (7.638135 deg) } check_prob_outputs(self.prob, testvals, rtol=1e-6) @@ -82,10 +89,14 @@ def test_end_of_climb(self): throttle_climb = 0.956 self.prob.set_val( - Dynamic.Mission.THROTTLE, np.array([ - throttle_climb, throttle_climb]), units='unitless') - self.prob.set_val(Dynamic.Mission.ALTITUDE, np.array([11000, 37000]), units="ft") - self.prob.set_val(Dynamic.Mission.MASS, np.array([174149, 171592]), units="lbm") + Dynamic.Vehicle.Propulsion.THROTTLE, + np.array([throttle_climb, throttle_climb]), + units='unitless', + ) + self.prob.set_val( + Dynamic.Mission.ALTITUDE, np.array([11000, 37000]), units="ft" + ) + self.prob.set_val(Dynamic.Vehicle.MASS, np.array([174149, 171592]), units="lbm") self.prob.set_val("EAS", np.array([270, 270]), units="kn") self.prob.set_val("interference_independent_of_shielded_area", 1.89927266) self.prob.set_val("drag_loss_due_to_shielded_wing_area", 68.02065834) @@ -95,16 +106,19 @@ def test_end_of_climb(self): self.prob.run_model() testvals = { - "alpha": [4.05559, 4.08245], - "CL": [0.512629, 0.617725], - "CD": [0.02692764, 0.03311237], - Dynamic.Mission.ALTITUDE_RATE: [3053.754 / 60, 429.665 / 60], # ft/s + "alpha": [4.0557, 4.06615], + "CL": [0.512628, 0.615819], + "CD": [0.02692759, 0.03299578], + Dynamic.Mission.ALTITUDE_RATE: [3053.64 / 60, 430.746 / 60], # ft/s # TAS (kts -> ft/s) * cos(gamma), [319, 459] kts - Dynamic.Mission.DISTANCE_RATE: [536.2835, 774.4118], # ft/s - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: [-11420.05, -6050.26], - "theta": [0.16540479, 0.08049912], # rad ([9.47699, 4.61226] deg), - Dynamic.Mission.FLIGHT_PATH_ANGLE: [0.09462135, 0.00924686], # rad, gamma - Dynamic.Mission.THRUST_TOTAL: [25560.51, 10784.25], + Dynamic.Mission.DISTANCE_RATE: [536.23446, 774.40085], # ft/s + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL: [ + -11419.94, + -6050.26, + ], + "theta": [0.16541191, 0.08023799], # rad ([9.47740, 4.59730] deg), + Dynamic.Mission.FLIGHT_PATH_ANGLE: [0.09462652, 0.00927027], # rad, gamma + Dynamic.Vehicle.Propulsion.THRUST_TOTAL: [25561.393, 10784.245], } check_prob_outputs(self.prob, testvals, 1e-6) diff --git a/aviary/mission/gasp_based/ode/test/test_descent_eom.py b/aviary/mission/gasp_based/ode/test/test_descent_eom.py index 414a6ebc4..baef579ee 100644 --- a/aviary/mission/gasp_based/ode/test/test_descent_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_descent_eom.py @@ -23,14 +23,16 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Dynamic.Mission.VELOCITY, np.array([459, 459]), units="kn") + Dynamic.Mission.VELOCITY, np.array([459, 459]), units="kn" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([452, 452]), units="lbf") + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, np.array([452, 452]), units="lbf" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([7966.927, 7966.927]), units="lbf" + Dynamic.Vehicle.DRAG, np.array([7966.927, 7966.927]), units="lbf" ) # estimated from GASP values self.prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([147661, 147661]), units="lbm" + Dynamic.Vehicle.MASS, np.array([147661, 147661]), units="lbm" ) self.prob.model.set_input_defaults("alpha", np.array([3.2, 3.2]), units="deg") @@ -42,8 +44,9 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array( - [-39.41011217, -39.41011217]), tol + self.prob[Dynamic.Mission.ALTITUDE_RATE], + np.array([-39.41011217, -39.41011217]), + tol, ) # note: values from GASP are: np.array([-39.75, -39.75]) assert_near_equal( self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( @@ -54,10 +57,12 @@ def test_case1(self): self.prob["required_lift"], np.array([147444.58096139, 147444.58096139]), tol, - ) # note: values from GASP are: np.array([146288.8, 146288.8]) (estimated based on GASP values) + # note: values from GASP are: np.array([146288.8, 146288.8]) (estimated based on GASP values) + ) assert_near_equal( - self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE], np.array( - [-0.05089311, -0.05089311]), tol + self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE], + np.array([-0.05089311, -0.05089311]), + tol, ) # note: values from GASP are: np.array([-.0513127, -.0513127]) partial_data = self.prob.check_partials(out_stream=None, method="cs") @@ -85,12 +90,13 @@ def test_case1(self): prob.model.set_input_defaults( Dynamic.Mission.VELOCITY, np.array([459, 459]), units="kn") prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, np.array([452, 452]), units="lbf") + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, np.array([452, 452]), units="lbf" + ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, np.array([7966.927, 7966.927]), units="lbf" + Dynamic.Vehicle.DRAG, np.array([7966.927, 7966.927]), units="lbf" ) prob.model.set_input_defaults( - Dynamic.Mission.MASS, np.array([147661, 147661]), units="lbm" + Dynamic.Vehicle.MASS, np.array([147661, 147661]), units="lbm" ) prob.model.set_input_defaults("alpha", np.array([3.2, 3.2]), units="deg") prob.setup(check=False, force_alloc_complex=True) diff --git a/aviary/mission/gasp_based/ode/test/test_descent_ode.py b/aviary/mission/gasp_based/ode/test/test_descent_ode.py index 1fa46aea7..2b823203a 100644 --- a/aviary/mission/gasp_based/ode/test/test_descent_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_descent_ode.py @@ -26,14 +26,20 @@ def setUp(self): aviary_options = get_option_defaults() default_mission_subsystems = get_default_mission_subsystems( - 'GASP', build_engine_deck(aviary_options)) + 'GASP', build_engine_deck(aviary_options) + ) - self.sys = self.prob.model = DescentODE(num_nodes=1, - mach_cruise=0.8, - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems) + self.sys = self.prob.model = DescentODE( + num_nodes=1, + mach_cruise=0.8, + aviary_options=get_option_defaults(), + core_subsystems=default_mission_subsystems + ) - @unittest.skipIf(version.parse(openmdao.__version__) < version.parse("3.26"), "Skipping due to OpenMDAO version being too low (<3.26)") + @unittest.skipIf( + version.parse(openmdao.__version__) < version.parse("3.26"), + "Skipping due to OpenMDAO version being too low (<3.26)", + ) def test_high_alt(self): # Test descent above 10k ft with Mach under and over the EAS limit self.sys.options["num_nodes"] = 2 @@ -43,10 +49,12 @@ def test_high_alt(self): self.prob.setup(check=False, force_alloc_complex=True) self.prob.set_val( - Dynamic.Mission.THROTTLE, np.array([ - 0, 0]), units='unitless') - self.prob.set_val(Dynamic.Mission.ALTITUDE, np.array([36500, 14500]), units="ft") - self.prob.set_val(Dynamic.Mission.MASS, np.array([147661, 147572]), units="lbm") + Dynamic.Vehicle.Propulsion.THROTTLE, np.array([0, 0]), units='unitless' + ) + self.prob.set_val( + Dynamic.Mission.ALTITUDE, np.array([36500, 14500]), units="ft" + ) + self.prob.set_val(Dynamic.Vehicle.MASS, np.array([147661, 147572]), units="lbm") self.prob.set_val("interference_independent_of_shielded_area", 1.89927266) self.prob.set_val("drag_loss_due_to_shielded_wing_area", 68.02065834) @@ -55,19 +63,21 @@ def test_high_alt(self): self.prob.run_model() testvals = { - "alpha": np.array([3.23388, 1.203234]), - "CL": np.array([0.51849367, 0.25908653]), - "CD": np.array([0.02794324, 0.01862946]), + "alpha": np.array([3.22047, 1.20346]), + "CL": np.array([0.5169255, 0.25908651]), + "CD": np.array([0.02786507, 0.01862951]), # ft/s - Dynamic.Mission.ALTITUDE_RATE: np.array([-2356.7705, -2877.9606]) / 60, + Dynamic.Mission.ALTITUDE_RATE: np.array([-39.28806432, -47.9587925]), # TAS (ft/s) * cos(gamma), [458.67774, 437.62297] kts - Dynamic.Mission.DISTANCE_RATE: [773.1637, 737.0653], # ft/s + Dynamic.Mission.DISTANCE_RATE: [773.1451, 736.9446], # ft/s # lbm/h - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: np.array([-451.0239, -997.1514]), - "EAS": [417.87419406, 590.73344937], # ft/s ([247.58367, 349.99997] kts) - Dynamic.Mission.MACH: [0.8, 0.697266], + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL: np.array( + [-451.02392, -997.0488] + ), + "EAS": [418.50757579, 590.73344999], # ft/s ([247.95894, 349.99997] kts) + Dynamic.Atmosphere.MACH: [0.8, 0.697125], # gamma, rad ([-2.908332, -3.723388] deg) - Dynamic.Mission.FLIGHT_PATH_ANGLE: [-0.05075997, -0.06498538], + Dynamic.Mission.FLIGHT_PATH_ANGLE: [-0.05077223, -0.06498624], } check_prob_outputs(self.prob, testvals, rtol=1e-6) @@ -83,9 +93,9 @@ def test_low_alt(self): self.prob.setup(check=False, force_alloc_complex=True) - self.prob.set_val(Dynamic.Mission.THROTTLE, 0, units='unitless') + self.prob.set_val(Dynamic.Vehicle.Propulsion.THROTTLE, 0, units='unitless') self.prob.set_val(Dynamic.Mission.ALTITUDE, 1500, units="ft") - self.prob.set_val(Dynamic.Mission.MASS, 147410, units="lbm") + self.prob.set_val(Dynamic.Vehicle.MASS, 147410, units="lbm") self.prob.set_val("EAS", 250, units="kn") self.prob.set_val("interference_independent_of_shielded_area", 1.89927266) self.prob.set_val("drag_loss_due_to_shielded_wing_area", 68.02065834) @@ -98,10 +108,10 @@ def test_low_alt(self): "alpha": 4.19956, "CL": 0.507578, "CD": 0.0268404, - Dynamic.Mission.ALTITUDE_RATE: -1138.583 / 60, + Dynamic.Mission.ALTITUDE_RATE: -18.97635475, # TAS (ft/s) * cos(gamma) = 255.5613 * 1.68781 * cos(-0.0440083) - Dynamic.Mission.DISTANCE_RATE: 430.9213, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: -1295.11, + Dynamic.Mission.DISTANCE_RATE: 430.92063193, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL: -1295.11, Dynamic.Mission.FLIGHT_PATH_ANGLE: -0.0440083, # rad (-2.52149 deg) } check_prob_outputs(self.prob, testvals, rtol=1e-6) diff --git a/aviary/mission/gasp_based/ode/test/test_flight_path_eom.py b/aviary/mission/gasp_based/ode/test/test_flight_path_eom.py index 289e353e1..3a8d25203 100644 --- a/aviary/mission/gasp_based/ode/test/test_flight_path_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_flight_path_eom.py @@ -24,8 +24,10 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [-27.10027, -27.10027]), tol) + self.prob[Dynamic.Mission.VELOCITY_RATE], + np.array([-27.10027, -27.10027]), + tol, + ) assert_near_equal( self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( [0.5403023, 0.5403023]), tol) @@ -39,11 +41,15 @@ def test_case1(self): self.prob["load_factor"], np.array( [1.883117, 1.883117]), tol) assert_near_equal( - self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array( - [0.841471, 0.841471]), tol) + self.prob[Dynamic.Mission.ALTITUDE_RATE], + np.array([0.841471, 0.841471]), + tol, + ) assert_near_equal( - self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array( - [15.36423, 15.36423]), tol) + self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], + np.array([15.36423, 15.36423]), + tol, + ) partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) @@ -59,8 +65,10 @@ def test_case2(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [-27.09537, -27.09537]), tol) + self.prob[Dynamic.Mission.VELOCITY_RATE], + np.array([-27.09537, -27.09537]), + tol, + ) assert_near_equal( self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( [0.5403023, 0.5403023]), tol) diff --git a/aviary/mission/gasp_based/ode/test/test_flight_path_ode.py b/aviary/mission/gasp_based/ode/test/test_flight_path_ode.py index e3fb4bec9..e1889e16e 100644 --- a/aviary/mission/gasp_based/ode/test/test_flight_path_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_flight_path_ode.py @@ -10,7 +10,7 @@ from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic +from aviary.variable_info.variables import Aircraft, Dynamic class FlightPathODETestCase(unittest.TestCase): @@ -22,12 +22,16 @@ def setUp(self): self.prob = om.Problem() aviary_options = get_option_defaults() + aviary_options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) default_mission_subsystems = get_default_mission_subsystems( - 'GASP', build_engine_deck(aviary_options)) + 'GASP', build_engine_deck(aviary_options) + ) - self.fp = self.prob.model = FlightPathODE(num_nodes=2, - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems) + self.fp = self.prob.model = FlightPathODE( + num_nodes=2, + aviary_options=get_option_defaults(), + core_subsystems=default_mission_subsystems, + ) def test_case1(self): # ground_roll = False (the aircraft is not confined to the ground) @@ -37,7 +41,7 @@ def test_case1(self): set_params_for_unit_tests(self.prob) self.prob.set_val(Dynamic.Mission.VELOCITY, [100, 100], units="kn") - self.prob.set_val(Dynamic.Mission.MASS, [100000, 100000], units="lbm") + self.prob.set_val(Dynamic.Vehicle.MASS, [100000, 100000], units="lbm") self.prob.set_val(Dynamic.Mission.ALTITUDE, [500, 500], units="ft") self.prob.set_val("interference_independent_of_shielded_area", 1.89927266) self.prob.set_val("drag_loss_due_to_shielded_wing_area", 68.02065834) @@ -58,8 +62,7 @@ def test_case1(self): tol = 1e-6 assert_near_equal( - self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array( - [0, 0]), tol + self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array([0, 0]), tol ) partial_data = self.prob.check_partials( @@ -76,7 +79,7 @@ def test_case2(self): set_params_for_unit_tests(self.prob) self.prob.set_val(Dynamic.Mission.VELOCITY, [100, 100], units="kn") - self.prob.set_val(Dynamic.Mission.MASS, [100000, 100000], units="lbm") + self.prob.set_val(Dynamic.Vehicle.MASS, [100000, 100000], units="lbm") self.prob.set_val(Dynamic.Mission.ALTITUDE, [500, 500], units="ft") self.prob.set_val("interference_independent_of_shielded_area", 1.89927266) self.prob.set_val("drag_loss_due_to_shielded_wing_area", 68.02065834) diff --git a/aviary/mission/gasp_based/ode/test/test_groundroll_eom.py b/aviary/mission/gasp_based/ode/test/test_groundroll_eom.py index a1eaf3a25..30ec303ef 100644 --- a/aviary/mission/gasp_based/ode/test/test_groundroll_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_groundroll_eom.py @@ -16,19 +16,23 @@ def setUp(self): "group", GroundrollEOM(num_nodes=2), promotes=["*"] ) self.prob.model.set_input_defaults( - Dynamic.Mission.MASS, val=175400 * np.ones(2), units="lbm" + Dynamic.Vehicle.MASS, val=175400 * np.ones(2), units="lbm" ) self.prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" ) self.prob.model.set_input_defaults( - Dynamic.Mission.LIFT, val=200 * np.ones(2), units="lbf") + Dynamic.Vehicle.LIFT, val=200 * np.ones(2), units="lbf" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.DRAG, val=10000 * np.ones(2), units="lbf") + Dynamic.Vehicle.DRAG, val=10000 * np.ones(2), units="lbf" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.VELOCITY, val=10 * np.ones(2), units="ft/s") + Dynamic.Mission.VELOCITY, val=10 * np.ones(2), units="ft/s" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(2), units="rad") + Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(2), units="rad" + ) self.prob.model.set_input_defaults(Aircraft.Wing.INCIDENCE, val=0, units="deg") self.prob.model.set_input_defaults("alpha", val=np.zeros(2), units="deg") @@ -40,14 +44,16 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [1.5597, 1.5597]), tol) + self.prob[Dynamic.Mission.VELOCITY_RATE], + np.array([1.5597, 1.5597]), + tol, + ) assert_near_equal( - self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array( - [0.0, 0.0]), tol) + self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array([0.0, 0.0]), tol + ) assert_near_equal( - self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array( - [0.0, 0.0]), tol) + self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array([0.0, 0.0]), tol + ) assert_near_equal( self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( [10.0, 10.0]), tol) @@ -80,15 +86,17 @@ def test_case1(self): "group", GroundrollEOM(num_nodes=2), promotes=["*"] ) prob.model.set_input_defaults( - Dynamic.Mission.MASS, val=175400 * np.ones(2), units="lbm" + Dynamic.Vehicle.MASS, val=175400 * np.ones(2), units="lbm" ) prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" ) prob.model.set_input_defaults( - Dynamic.Mission.LIFT, val=200 * np.ones(2), units="lbf") + Dynamic.Vehicle.LIFT, val=200 * np.ones(2), units="lbf" + ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, val=10000 * np.ones(2), units="lbf") + Dynamic.Vehicle.DRAG, val=10000 * np.ones(2), units="lbf" + ) prob.model.set_input_defaults( Dynamic.Mission.VELOCITY, val=10 * np.ones(2), units="ft/s") prob.model.set_input_defaults( diff --git a/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py b/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py index d7ccbcef4..66bb7c08b 100644 --- a/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py @@ -9,7 +9,7 @@ from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic +from aviary.variable_info.variables import Aircraft, Dynamic class GroundrollODETestCase(unittest.TestCase): @@ -21,12 +21,16 @@ def setUp(self): self.prob = om.Problem() aviary_options = get_option_defaults() + aviary_options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) default_mission_subsystems = get_default_mission_subsystems( - 'GASP', build_engine_deck(aviary_options)) + 'GASP', build_engine_deck(aviary_options) + ) - self.prob.model = GroundrollODE(num_nodes=2, - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems) + self.prob.model = GroundrollODE( + num_nodes=2, + aviary_options=get_option_defaults(), + core_subsystems=default_mission_subsystems, + ) def test_groundroll_partials(self): # Check partial derivatives diff --git a/aviary/mission/gasp_based/ode/test/test_landing_eom.py b/aviary/mission/gasp_based/ode/test/test_landing_eom.py index d82fdaab7..8ae2830df 100644 --- a/aviary/mission/gasp_based/ode/test/test_landing_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_landing_eom.py @@ -8,7 +8,7 @@ from aviary.mission.gasp_based.ode.landing_eom import ( GlideConditionComponent, LandingAltitudeComponent, LandingGroundRollComponent) -from aviary.variable_info.variables import Aircraft, Mission +from aviary.variable_info.variables import Aircraft, Mission, Dynamic class LandingAltTestCase(unittest.TestCase): @@ -55,7 +55,7 @@ def setUp(self): ) self.prob.model.set_input_defaults( - "rho_app", RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3" + Dynamic.Atmosphere.DENSITY, RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3" ) # value from online calculator self.prob.model.set_input_defaults( @@ -137,7 +137,8 @@ def test_case1(self): prob.model.add_subsystem( "group", GlideConditionComponent(), promotes=["*"]) prob.model.set_input_defaults( - "rho_app", RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3") + Dynamic.Atmosphere.DENSITY, RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3" + ) prob.model.set_input_defaults( Mission.Landing.MAXIMUM_SINK_RATE, 900, units="ft/min") prob.model.set_input_defaults("mass", 165279, units="lbm") diff --git a/aviary/mission/gasp_based/ode/test/test_landing_ode.py b/aviary/mission/gasp_based/ode/test/test_landing_ode.py index 08dfe2154..74498ded9 100644 --- a/aviary/mission/gasp_based/ode/test/test_landing_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_landing_ode.py @@ -12,6 +12,7 @@ from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.utils.test_utils.IO_test_util import check_prob_outputs +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Dynamic, Mission @@ -32,6 +33,8 @@ def setUp(self): self.prob.model = LandingSegment( aviary_options=options, core_subsystems=core_subsystems) + setup_model_options(self.prob, options) + @unittest.skipIf(version.parse(openmdao.__version__) < version.parse("3.26"), "Skipping due to OpenMDAO version being too low (<3.26)") def test_dland(self): self.prob.setup(check=False, force_alloc_complex=True) @@ -48,7 +51,7 @@ def test_dland(self): self.prob.set_val(Mission.Landing.TOUCHDOWN_SINK_RATE, 5, units="ft/s") self.prob.set_val(Mission.Landing.BRAKING_DELAY, 1, units="s") self.prob.set_val("mass", 165279, units="lbm") - self.prob.set_val(Dynamic.Mission.THROTTLE, 0.0, units='unitless') + self.prob.set_val(Dynamic.Vehicle.Propulsion.THROTTLE, 0.0, units='unitless') self.prob.run_model() diff --git a/aviary/mission/gasp_based/ode/test/test_rotation_eom.py b/aviary/mission/gasp_based/ode/test/test_rotation_eom.py index 13fdf4c28..ddf48c369 100644 --- a/aviary/mission/gasp_based/ode/test/test_rotation_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_rotation_eom.py @@ -14,19 +14,23 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem("group", RotationEOM(num_nodes=2), promotes=["*"]) self.prob.model.set_input_defaults( - Dynamic.Mission.MASS, val=175400 * np.ones(2), units="lbm" + Dynamic.Vehicle.MASS, val=175400 * np.ones(2), units="lbm" ) self.prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" ) self.prob.model.set_input_defaults( - Dynamic.Mission.LIFT, val=200 * np.ones(2), units="lbf") + Dynamic.Vehicle.LIFT, val=200 * np.ones(2), units="lbf" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.DRAG, val=10000 * np.ones(2), units="lbf") + Dynamic.Vehicle.DRAG, val=10000 * np.ones(2), units="lbf" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.VELOCITY, val=10 * np.ones(2), units="ft/s") + Dynamic.Mission.VELOCITY, val=10 * np.ones(2), units="ft/s" + ) self.prob.model.set_input_defaults( - Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(2), units="rad") + Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(2), units="rad" + ) self.prob.model.set_input_defaults(Aircraft.Wing.INCIDENCE, val=0, units="deg") self.prob.model.set_input_defaults("alpha", val=np.zeros(2), units="deg") @@ -38,14 +42,16 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [1.5597, 1.5597]), tol) + self.prob[Dynamic.Mission.VELOCITY_RATE], + np.array([1.5597, 1.5597]), + tol, + ) assert_near_equal( - self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array( - [0.0, 0.0]), tol) + self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array([0.0, 0.0]), tol + ) assert_near_equal( - self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array( - [0.0, 0.0]), tol) + self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array([0.0, 0.0]), tol + ) assert_near_equal( self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( [10., 10.]), tol) @@ -77,13 +83,17 @@ def test_case1(self): prob = om.Problem() prob.model.add_subsystem("group", RotationEOM(num_nodes=2), promotes=["*"]) prob.model.set_input_defaults( - Dynamic.Mission.MASS, val=175400 * np.ones(2), units="lbm") + Dynamic.Vehicle.MASS, val=175400 * np.ones(2), units="lbm" + ) prob.model.set_input_defaults( - Dynamic.Mission.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf") + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=22000 * np.ones(2), units="lbf" + ) prob.model.set_input_defaults( - Dynamic.Mission.LIFT, val=200 * np.ones(2), units="lbf") + Dynamic.Vehicle.LIFT, val=200 * np.ones(2), units="lbf" + ) prob.model.set_input_defaults( - Dynamic.Mission.DRAG, val=10000 * np.ones(2), units="lbf") + Dynamic.Vehicle.DRAG, val=10000 * np.ones(2), units="lbf" + ) prob.model.set_input_defaults( Dynamic.Mission.VELOCITY, val=10 * np.ones(2), units="ft/s") prob.model.set_input_defaults( diff --git a/aviary/mission/gasp_based/ode/test/test_rotation_ode.py b/aviary/mission/gasp_based/ode/test/test_rotation_ode.py index 602e31945..5fdec7b11 100644 --- a/aviary/mission/gasp_based/ode/test/test_rotation_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_rotation_ode.py @@ -21,6 +21,7 @@ def setUp(self): self.prob = om.Problem() aviary_options = get_option_defaults() + aviary_options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) default_mission_subsystems = get_default_mission_subsystems( 'GASP', build_engine_deck(aviary_options)) @@ -33,7 +34,7 @@ def test_rotation_partials(self): self.prob.setup(check=False, force_alloc_complex=True) self.prob.set_val(Aircraft.Wing.INCIDENCE, 1.5, units="deg") - self.prob.set_val(Dynamic.Mission.MASS, [100000, 100000], units="lbm") + self.prob.set_val(Dynamic.Vehicle.MASS, [100000, 100000], units="lbm") self.prob.set_val("alpha", [1.5, 1.5], units="deg") self.prob.set_val(Dynamic.Mission.VELOCITY, [100, 100], units="kn") self.prob.set_val("t_curr", [1, 2], units="s") @@ -46,14 +47,16 @@ def test_rotation_partials(self): tol = 1e-6 assert_near_equal( - self.prob[Dynamic.Mission.VELOCITY_RATE], np.array( - [13.66655, 13.66655]), tol) + self.prob[Dynamic.Mission.VELOCITY_RATE], + np.array([13.66655, 13.66655]), + tol, + ) assert_near_equal( - self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array( - [0.0, 0.0]), tol) + self.prob[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], np.array([0.0, 0.0]), tol + ) assert_near_equal( - self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array( - [0.0, 0.0]), tol) + self.prob[Dynamic.Mission.ALTITUDE_RATE], np.array([0.0, 0.0]), tol + ) assert_near_equal( self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( [168.781, 168.781]), tol) diff --git a/aviary/mission/gasp_based/ode/test/test_taxi_eom.py b/aviary/mission/gasp_based/ode/test/test_taxi_eom.py index d4f1c968f..0eacbbb6a 100644 --- a/aviary/mission/gasp_based/ode/test/test_taxi_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_taxi_eom.py @@ -6,6 +6,7 @@ from aviary.utils.aviary_values import AviaryValues from aviary.mission.gasp_based.ode.taxi_eom import TaxiFuelComponent +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Dynamic, Mission @@ -15,19 +16,24 @@ class TaxiFuelComponentTestCase(unittest.TestCase): """ def setUp(self): - self.prob = om.Problem(model=om.Group()) + self.prob = om.Problem() aviary_options = AviaryValues() aviary_options.set_val(Mission.Taxi.DURATION, 0.1677, units="h") - self.prob.model.add_subsystem('taxi', TaxiFuelComponent( - aviary_options=aviary_options), promotes=['*']) + self.prob.model.add_subsystem('taxi', TaxiFuelComponent(), + promotes=['*']) + + setup_model_options(self.prob, aviary_options) def test_fuel_consumed(self): self.prob.setup(force_alloc_complex=True) - self.prob.set_val(Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - -1512, units="lbm/h") + self.prob.set_val( + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + -1512, + units="lbm/h", + ) self.prob.set_val(Mission.Summary.GROSS_MASS, 175400.0, units="lbm") self.prob.run_model() diff --git a/aviary/mission/gasp_based/ode/test/test_taxi_ode.py b/aviary/mission/gasp_based/ode/test/test_taxi_ode.py index 0c595da1a..9bbdcb5e9 100644 --- a/aviary/mission/gasp_based/ode/test/test_taxi_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_taxi_ode.py @@ -10,6 +10,7 @@ from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.utils.test_utils.IO_test_util import check_prob_outputs +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Dynamic, Mission @@ -26,12 +27,24 @@ def setUp(self): options = get_option_defaults() options.set_val(Mission.Taxi.DURATION, 0.1677, units="h") default_mission_subsystems = get_default_mission_subsystems( - 'GASP', build_engine_deck(options)) + 'GASP', build_engine_deck(options) + ) self.prob.model = TaxiSegment( - aviary_options=options, core_subsystems=default_mission_subsystems) + aviary_options=options, core_subsystems=default_mission_subsystems + ) + + setup_model_options(self.prob, options) - @unittest.skipIf(version.parse(openmdao.__version__) < version.parse("3.26"), "Skipping due to OpenMDAO version being too low (<3.26)") + self.prob.model.set_input_defaults( + Mission.Takeoff.AIRPORT_ALTITUDE, + 0.0, + ) + + @unittest.skipIf( + version.parse(openmdao.__version__) < version.parse("3.26"), + "Skipping due to OpenMDAO version being too low (<3.26)", + ) def test_taxi(self): self.prob.setup(check=False, force_alloc_complex=True) @@ -40,12 +53,15 @@ def test_taxi(self): self.prob.set_val(Mission.Takeoff.AIRPORT_ALTITUDE, 0, units="ft") self.prob.set_val(Mission.Taxi.MACH, 0.1, units="unitless") self.prob.set_val( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, -1512, units="lbm/h") + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + -1512, + units="lbm/h", + ) self.prob.run_model() testvals = { - Dynamic.Mission.MASS: 175190.3, # lbm + Dynamic.Vehicle.MASS: 175190.3, # lbm } check_prob_outputs(self.prob, testvals, rtol=1e-6) diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/gamma_comp.py b/aviary/mission/gasp_based/ode/unsteady_solved/gamma_comp.py index 84b35f540..07a5f7b91 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/gamma_comp.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/gamma_comp.py @@ -24,8 +24,12 @@ def setup(self): self.add_input("d2h_dr2", shape=nn, units="m/distance_units**2", desc="second derivative of altitude wrt range") - self.add_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, shape=nn, units="rad", - desc="flight path angle") + self.add_output( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + shape=nn, + units="rad", + desc="flight path angle", + ) self.add_output("dgam_dr", shape=nn, units="rad/distance_units", desc="change in flight path angle per unit range traversed") @@ -34,8 +38,9 @@ def setup_partials(self): nn = self.options["num_nodes"] ar = np.arange(nn, dtype=int) - self.declare_partials(of=Dynamic.Mission.FLIGHT_PATH_ANGLE, - wrt="dh_dr", rows=ar, cols=ar) + self.declare_partials( + of=Dynamic.Mission.FLIGHT_PATH_ANGLE, wrt="dh_dr", rows=ar, cols=ar + ) self.declare_partials(of="dgam_dr", wrt=["dh_dr", "d2h_dr2"], rows=ar, cols=ar) def compute(self, inputs, outputs): @@ -49,6 +54,6 @@ def compute_partials(self, inputs, partials): dh_dr = inputs["dh_dr"] d2h_dr2 = inputs["d2h_dr2"] - partials[Dynamic.Mission.FLIGHT_PATH_ANGLE, "dh_dr"] = 1. / (dh_dr**2 + 1) + partials[Dynamic.Mission.FLIGHT_PATH_ANGLE, "dh_dr"] = 1.0 / (dh_dr**2 + 1) partials["dgam_dr", "dh_dr"] = -d2h_dr2 * dh_dr * 2 / (dh_dr**2 + 1)**2 partials["dgam_dr", "d2h_dr2"] = 1. / (dh_dr**2 + 1) diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_gamma_comp.py b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_gamma_comp.py index 6290cbc5e..5de32444d 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_gamma_comp.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_gamma_comp.py @@ -28,10 +28,10 @@ def _test_unsteady_flight_eom(self, ground_roll=False): p.setup(force_alloc_complex=True) p.set_val(Dynamic.Mission.VELOCITY, 250, units="kn") - p.set_val(Dynamic.Mission.MASS, 175_000, units="lbm") - p.set_val(Dynamic.Mission.THRUST_TOTAL, 20_000, units="lbf") - p.set_val(Dynamic.Mission.LIFT, 175_000, units="lbf") - p.set_val(Dynamic.Mission.DRAG, 20_000, units="lbf") + p.set_val(Dynamic.Vehicle.MASS, 175_000, units="lbm") + p.set_val(Dynamic.Vehicle.Propulsion.THRUST_TOTAL, 20_000, units="lbf") + p.set_val(Dynamic.Vehicle.LIFT, 175_000, units="lbf") + p.set_val(Dynamic.Vehicle.DRAG, 20_000, units="lbf") p.set_val(Aircraft.Wing.INCIDENCE, 0.0, units="deg") if not ground_roll: @@ -71,17 +71,25 @@ def _test_unsteady_flight_eom(self, ground_roll=False): assert_near_equal(dgam_dt_approx, np.zeros(nn), tolerance=1.0E-12) p.set_val(Dynamic.Mission.VELOCITY, 250 + 10 * np.random.rand(nn), units="kn") - p.set_val(Dynamic.Mission.MASS, 175_000 + 1000 * np.random.rand(nn), units="lbm") - p.set_val(Dynamic.Mission.THRUST_TOTAL, 20_000 + - 100 * np.random.rand(nn), units="lbf") - p.set_val(Dynamic.Mission.LIFT, 175_000 + 1000 * np.random.rand(nn), units="lbf") - p.set_val(Dynamic.Mission.DRAG, 20_000 + 100 * np.random.rand(nn), units="lbf") + p.set_val( + Dynamic.Vehicle.MASS, 175_000 + 1000 * np.random.rand(nn), units="lbm" + ) + p.set_val( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + 20_000 + 100 * np.random.rand(nn), + units="lbf", + ) + p.set_val( + Dynamic.Vehicle.LIFT, 175_000 + 1000 * np.random.rand(nn), units="lbf" + ) + p.set_val(Dynamic.Vehicle.DRAG, 20_000 + 100 * np.random.rand(nn), units="lbf") p.set_val(Aircraft.Wing.INCIDENCE, np.random.rand(1), units="deg") if not ground_roll: p.set_val("alpha", 5 * np.random.rand(nn), units="deg") - p.set_val(Dynamic.Mission.FLIGHT_PATH_ANGLE, - 5 * np.random.rand(nn), units="deg") + p.set_val( + Dynamic.Mission.FLIGHT_PATH_ANGLE, 5 * np.random.rand(nn), units="deg" + ) p.set_val("dh_dr", 0.1 * np.random.rand(nn), units=None) p.set_val("d2h_dr2", 0.01 * np.random.rand(nn), units="1/m") @@ -100,20 +108,20 @@ def test_gamma_comp(self): nn = 2 p = om.Problem() - p.model.add_subsystem("gamma", - GammaComp(num_nodes=nn), - promotes_inputs=[ - "dh_dr", - "d2h_dr2"], - promotes_outputs=[ - Dynamic.Mission.FLIGHT_PATH_ANGLE, - "dgam_dr"]) + p.model.add_subsystem( + "gamma", + GammaComp(num_nodes=nn), + promotes_inputs=["dh_dr", "d2h_dr2"], + promotes_outputs=[Dynamic.Mission.FLIGHT_PATH_ANGLE, "dgam_dr"], + ) p.setup(force_alloc_complex=True) p.run_model() assert_near_equal( - p[Dynamic.Mission.FLIGHT_PATH_ANGLE], [0.78539816, 0.78539816], - tolerance=1.0E-6) + p[Dynamic.Mission.FLIGHT_PATH_ANGLE], + [0.78539816, 0.78539816], + tolerance=1.0e-6, + ) assert_near_equal( p["dgam_dr"], [0.5, 0.5], tolerance=1.0E-6) diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_alpha_thrust_iter_group.py b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_alpha_thrust_iter_group.py index 2c6653816..1486d307e 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_alpha_thrust_iter_group.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_alpha_thrust_iter_group.py @@ -41,7 +41,6 @@ def _test_unsteady_alpha_thrust_iter_group(self, ground_roll=False): g = UnsteadyControlIterGroup(num_nodes=nn, ground_roll=ground_roll, clean=True, - aviary_options=get_option_defaults(), core_subsystems=[aero]) ig = p.model.add_subsystem("iter_group", @@ -58,9 +57,11 @@ def _test_unsteady_alpha_thrust_iter_group(self, ground_roll=False): p.final_setup() - p.set_val(Dynamic.Mission.SPEED_OF_SOUND, 968.076 * np.ones(nn), units="ft/s") p.set_val( - Dynamic.Mission.DENSITY, 0.000659904 * np.ones(nn), units="slug/ft**3" + Dynamic.Atmosphere.SPEED_OF_SOUND, 968.076 * np.ones(nn), units="ft/s" + ) + p.set_val( + Dynamic.Atmosphere.DENSITY, 0.000659904 * np.ones(nn), units="slug/ft**3" ) p.set_val(Dynamic.Mission.VELOCITY, 487 * np.ones(nn), units="kn") p.set_val("mass", 170_000 * np.ones(nn), units="lbm") @@ -76,11 +77,14 @@ def _test_unsteady_alpha_thrust_iter_group(self, ground_roll=False): p.run_model() - drag = p.model.get_val(Dynamic.Mission.DRAG, units="lbf") - lift = p.model.get_val(Dynamic.Mission.LIFT, units="lbf") + drag = p.model.get_val(Dynamic.Vehicle.DRAG, units="lbf") + lift = p.model.get_val(Dynamic.Vehicle.LIFT, units="lbf") thrust_req = p.model.get_val("thrust_req", units="lbf") - gamma = 0 if ground_roll else p.model.get_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") + gamma = ( + 0 + if ground_roll + else p.model.get_val(Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") + ) weight = p.model.get_val("mass", units="lbm") * GRAV_ENGLISH_LBM iwing = p.model.get_val(Aircraft.Wing.INCIDENCE, units="deg") alpha = iwing if ground_roll else p.model.get_val("alpha", units="deg") diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_flight_conditions.py b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_flight_conditions.py index 3a2fb66c6..575359d02 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_flight_conditions.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_flight_conditions.py @@ -28,10 +28,10 @@ def _test_unsteady_flight_conditions(self, ground_roll=False, input_speed_type=S subsys=Atmosphere(num_nodes=nn, output_dsos_dh=True), promotes_inputs=[Dynamic.Mission.ALTITUDE], promotes_outputs=[ - Dynamic.Mission.DENSITY, - Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Atmosphere.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, "viscosity", "drhos_dh", "dsos_dh", @@ -59,16 +59,16 @@ def _test_unsteady_flight_conditions(self, ground_roll=False, input_speed_type=S p.set_val("dEAS_dr", np.zeros(nn), units="kn/km") else: p.set_val(Dynamic.Mission.ALTITUDE, 37500, units="ft") - p.set_val(Dynamic.Mission.MACH, 0.78, units="unitless") + p.set_val(Dynamic.Atmosphere.MACH, 0.78, units="unitless") p.set_val("dmach_dr", np.zeros(nn), units="unitless/km") p.run_model() - mach = p.get_val(Dynamic.Mission.MACH) + mach = p.get_val(Dynamic.Atmosphere.MACH) eas = p.get_val("EAS") tas = p.get_val(Dynamic.Mission.VELOCITY, units="m/s") - sos = p.get_val(Dynamic.Mission.SPEED_OF_SOUND, units="m/s") - rho = p.get_val(Dynamic.Mission.DENSITY, units="kg/m**3") + sos = p.get_val(Dynamic.Atmosphere.SPEED_OF_SOUND, units="m/s") + rho = p.get_val(Dynamic.Atmosphere.DENSITY, units="kg/m**3") rho_sl = RHO_SEA_LEVEL_METRIC dTAS_dt_approx = p.get_val("dTAS_dt_approx") diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_eom.py b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_eom.py index 30bab8230..fd08c80be 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_eom.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_eom.py @@ -28,9 +28,9 @@ def _test_unsteady_solved_eom(self, ground_roll=False): p.set_val(Dynamic.Mission.VELOCITY, 250, units="kn") p.set_val("mass", 175_000, units="lbm") - p.set_val(Dynamic.Mission.THRUST_TOTAL, 20_000, units="lbf") - p.set_val(Dynamic.Mission.LIFT, 175_000, units="lbf") - p.set_val(Dynamic.Mission.DRAG, 20_000, units="lbf") + p.set_val(Dynamic.Vehicle.Propulsion.THRUST_TOTAL, 20_000, units="lbf") + p.set_val(Dynamic.Vehicle.LIFT, 175_000, units="lbf") + p.set_val(Dynamic.Vehicle.DRAG, 20_000, units="lbf") p.set_val(Aircraft.Wing.INCIDENCE, 0.0, units="deg") if not ground_roll: @@ -71,16 +71,20 @@ def _test_unsteady_solved_eom(self, ground_roll=False): p.set_val(Dynamic.Mission.VELOCITY, 250 + 10 * np.random.rand(nn), units="kn") p.set_val("mass", 175_000 + 1000 * np.random.rand(nn), units="lbm") - p.set_val(Dynamic.Mission.THRUST_TOTAL, 20_000 + - 100 * np.random.rand(nn), units="lbf") - p.set_val(Dynamic.Mission.LIFT, 175_000 + 1000 * np.random.rand(nn), units="lbf") - p.set_val(Dynamic.Mission.DRAG, 20_000 + 100 * np.random.rand(nn), units="lbf") + p.set_val( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + 20_000 + 100 * np.random.rand(nn), + units="lbf", + ) + p.set_val(Dynamic.Vehicle.LIFT, 175_000 + 1000 * np.random.rand(nn), units="lbf") + p.set_val(Dynamic.Vehicle.DRAG, 20_000 + 100 * np.random.rand(nn), units="lbf") p.set_val(Aircraft.Wing.INCIDENCE, np.random.rand(1), units="deg") if not ground_roll: p.set_val("alpha", 5 * np.random.rand(nn), units="deg") - p.set_val(Dynamic.Mission.FLIGHT_PATH_ANGLE, - 5 * np.random.rand(nn), units="deg") + p.set_val( + Dynamic.Mission.FLIGHT_PATH_ANGLE, 5 * np.random.rand(nn), units="deg" + ) p.set_val("dh_dr", 0.1 * np.random.rand(nn), units=None) p.set_val("d2h_dr2", 0.01 * np.random.rand(nn), units="1/m") @@ -121,10 +125,15 @@ def _test_unsteady_solved_eom(self, ground_roll=False): p.set_val(Dynamic.Mission.VELOCITY, 250 + 10 * np.random.rand(nn), units="kn") p.set_val("mass", 175_000 + 1000 * np.random.rand(nn), units="lbm") - p.set_val(Dynamic.Mission.THRUST_TOTAL, 20_000 + - 100 * np.random.rand(nn), units="lbf") - p.set_val(Dynamic.Mission.LIFT, 175_000 + 1000 * np.random.rand(nn), units="lbf") - p.set_val(Dynamic.Mission.DRAG, 20_000 + 100 * np.random.rand(nn), units="lbf") + p.set_val( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + 20_000 + 100 * np.random.rand(nn), + units="lbf", + ) + p.set_val( + Dynamic.Vehicle.LIFT, 175_000 + 1000 * np.random.rand(nn), units="lbf" + ) + p.set_val(Dynamic.Vehicle.DRAG, 20_000 + 100 * np.random.rand(nn), units="lbf") p.set_val(Aircraft.Wing.INCIDENCE, np.random.rand(1), units="deg") if not ground_roll: diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_ode.py b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_ode.py index a873b68c1..194e2f40c 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_ode.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_ode.py @@ -7,8 +7,12 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.mission.gasp_based.ode.params import set_params_for_unit_tests -from aviary.mission.gasp_based.ode.unsteady_solved.unsteady_solved_ode import \ - UnsteadySolvedODE +from aviary.mission.gasp_based.ode.unsteady_solved.unsteady_solved_ode import ( + UnsteadySolvedODE, +) +from aviary.variable_info.options import get_option_defaults +from aviary.variable_info.enums import SpeedType +from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.variable_info.enums import SpeedType @@ -17,29 +21,34 @@ class TestUnsteadySolvedODE(unittest.TestCase): - """ Test the unsteady solved ODE in steady level flight. """ + """Test the unsteady solved ODE in steady level flight.""" - def _test_unsteady_solved_ode(self, ground_roll=False, input_speed_type=SpeedType.MACH, clean=True): + def _test_unsteady_solved_ode( + self, ground_roll=False, input_speed_type=SpeedType.MACH, clean=True + ): nn = 5 p = om.Problem() aviary_options = get_option_defaults() default_mission_subsystems = get_default_mission_subsystems( - 'GASP', build_engine_deck(aviary_options)) + 'GASP', build_engine_deck(aviary_options) + ) - ode = UnsteadySolvedODE(num_nodes=nn, - input_speed_type=input_speed_type, - clean=clean, - ground_roll=ground_roll, - aviary_options=aviary_options, - core_subsystems=default_mission_subsystems) + ode = UnsteadySolvedODE( + num_nodes=nn, + input_speed_type=input_speed_type, + clean=clean, + ground_roll=ground_roll, + aviary_options=aviary_options, + core_subsystems=default_mission_subsystems, + ) p.model.add_subsystem("ode", ode, promotes=["*"]) - p.model.set_input_defaults(Dynamic.Mission.MACH, 0.8 * np.ones(nn)) + p.model.set_input_defaults(Dynamic.Atmosphere.MACH, 0.8 * np.ones(nn)) if ground_roll: - p.model.set_input_defaults(Dynamic.Mission.MACH, 0.1 * np.ones(nn)) + p.model.set_input_defaults(Dynamic.Atmosphere.MACH, 0.1 * np.ones(nn)) ode.set_input_defaults("alpha", np.zeros(nn), units="deg") p.setup(force_alloc_complex=True) @@ -48,9 +57,11 @@ def _test_unsteady_solved_ode(self, ground_roll=False, input_speed_type=SpeedTyp p.final_setup() - p.set_val(Dynamic.Mission.SPEED_OF_SOUND, 968.076 * np.ones(nn), units="ft/s") p.set_val( - Dynamic.Mission.DENSITY, 0.000659904 * np.ones(nn), units="slug/ft**3" + Dynamic.Atmosphere.SPEED_OF_SOUND, 968.076 * np.ones(nn), units="ft/s" + ) + p.set_val( + Dynamic.Atmosphere.DENSITY, 0.000659904 * np.ones(nn), units="slug/ft**3" ) p.set_val("mach", 0.8 * np.ones(nn), units="unitless") p.set_val("mass", 170_000 * np.ones(nn), units="lbm") @@ -65,14 +76,18 @@ def _test_unsteady_solved_ode(self, ground_roll=False, input_speed_type=SpeedTyp p.run_model() - drag = p.model.get_val(Dynamic.Mission.DRAG, units="lbf") - lift = p.model.get_val(Dynamic.Mission.LIFT, units="lbf") + drag = p.model.get_val(Dynamic.Vehicle.DRAG, units="lbf") + lift = p.model.get_val(Dynamic.Vehicle.LIFT, units="lbf") thrust_req = p.model.get_val("thrust_req", units="lbf") - gamma = 0 if ground_roll else p.model.get_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") + gamma = ( + 0 + if ground_roll + else p.model.get_val(Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") + ) weight = p.model.get_val("mass", units="lbm") * GRAV_ENGLISH_LBM fuelflow = p.model.get_val( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/s") + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/s" + ) dmass_dr = p.model.get_val("dmass_dr", units="lbm/ft") dt_dr = p.model.get_val("dt_dr", units="s/ft") tas = p.model.get_val(Dynamic.Mission.VELOCITY, units="ft/s") @@ -86,24 +101,27 @@ def _test_unsteady_solved_ode(self, ground_roll=False, input_speed_type=SpeedTyp s_gamma = np.sin(np.radians(gamma)) # 1. Test that forces balance along the velocity axis - assert_near_equal(drag + thrust_req * s_gamma, - thrust_req * c_alphai, tolerance=1.0E-12) + assert_near_equal( + drag + thrust_req * s_gamma, thrust_req * c_alphai, tolerance=1.0e-12 + ) # 2. Test that forces balance normal to the velocity axis - assert_near_equal(lift + thrust_req * s_alphai, - weight * c_gamma, tolerance=1.0E-12) + assert_near_equal( + lift + thrust_req * s_alphai, weight * c_gamma, tolerance=1.0e-12 + ) # 3. Test that dt_dr is the inverse of true airspeed - assert_near_equal(tas, 1/dt_dr, tolerance=1.0E-12) + assert_near_equal(tas, 1 / dt_dr, tolerance=1.0e-12) # 4. Test that the inverse of dt_dr is true airspeed - assert_near_equal(tas, 1/dt_dr, tolerance=1.0E-12) + assert_near_equal(tas, 1 / dt_dr, tolerance=1.0e-12) # 5. Test that fuelflow (lbf/s) * dt_dr (s/ft) is equal to dmass_dr - assert_near_equal(fuelflow * dt_dr, dmass_dr, tolerance=1.0E-12) + assert_near_equal(fuelflow * dt_dr, dmass_dr, tolerance=1.0e-12) - cpd = p.check_partials(out_stream=None, method="cs", - excludes=["*params*", "*aero*"]) + cpd = p.check_partials( + out_stream=None, method="cs", excludes=["*params*", "*aero*"] + ) # issue #495 # dTAS_dt_approx wrt flight_path_angle | abs | fwd-fd | 1.8689625335382314 # dTAS_dt_approx wrt flight_path_angle | rel | fwd-fd | 1.0 diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_control_iter_group.py b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_control_iter_group.py index 2df7762bd..37a2fcb65 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_control_iter_group.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_control_iter_group.py @@ -21,6 +21,7 @@ def initialize(self): "output and adjusts the TAS rate equation.") self.options.declare("clean", types=bool, default=False, desc="If true then no flaps or gear are included. Useful for high-speed flight phases.") + self.options.declare( 'aviary_options', types=AviaryValues, default=None, desc='collection of Aircraft/Mission specific options' @@ -61,10 +62,15 @@ def setup(self): eom_comp = UnsteadySolvedEOM(num_nodes=nn, ground_roll=ground_roll) - self.add_subsystem("eom", subsys=eom_comp, - promotes_inputs=["*", - (Dynamic.Mission.THRUST_TOTAL, "thrust_req")], - promotes_outputs=["*"]) + self.add_subsystem( + "eom", + subsys=eom_comp, + promotes_inputs=[ + "*", + (Dynamic.Vehicle.Propulsion.THRUST_TOTAL, "thrust_req"), + ], + promotes_outputs=["*"], + ) thrust_alpha_bal = om.BalanceComp() if not self.options['ground_roll']: @@ -97,17 +103,17 @@ def setup(self): # Set common default values for promoted inputs onn = np.ones(nn) self.set_input_defaults( - name=Dynamic.Mission.DENSITY, + name=Dynamic.Atmosphere.DENSITY, val=RHO_SEA_LEVEL_ENGLISH * onn, units="slug/ft**3", ) self.set_input_defaults( - name=Dynamic.Mission.SPEED_OF_SOUND, - val=1116.4 * onn, - units="ft/s") + name=Dynamic.Atmosphere.SPEED_OF_SOUND, val=1116.4 * onn, units="ft/s" + ) if not self.options['ground_roll']: - self.set_input_defaults(name=Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=0.0 * onn, units="rad") + self.set_input_defaults( + name=Dynamic.Mission.FLIGHT_PATH_ANGLE, val=0.0 * onn, units="rad" + ) self.set_input_defaults( name=Dynamic.Mission.VELOCITY, val=250.0 * onn, units="kn" ) diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_eom.py b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_eom.py index 257e12db5..24a86ce07 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_eom.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_eom.py @@ -40,19 +40,27 @@ def setup(self): # is really a mass. This should be resolved with an adapter component that # uses gravity. self.add_input("mass", shape=nn, desc="aircraft mass", units="lbm") - self.add_input(Dynamic.Mission.THRUST_TOTAL, shape=nn, - desc=Dynamic.Mission.THRUST_TOTAL, units="N") - self.add_input(Dynamic.Mission.LIFT, shape=nn, - desc=Dynamic.Mission.LIFT, units="N") - self.add_input(Dynamic.Mission.DRAG, shape=nn, - desc=Dynamic.Mission.DRAG, units="N") + self.add_input( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + shape=nn, + desc=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + units="N", + ) + self.add_input(Dynamic.Vehicle.LIFT, shape=nn, + desc=Dynamic.Vehicle.LIFT, units="N") + self.add_input(Dynamic.Vehicle.DRAG, shape=nn, + desc=Dynamic.Vehicle.DRAG, units="N") add_aviary_input(self, Aircraft.Wing.INCIDENCE, val=0, units="rad") self.add_input("alpha", val=np.zeros( nn), desc="angle of attack", units="rad") if not self.options["ground_roll"]: - self.add_input(Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros( - nn), desc="flight path angle", units="rad") + self.add_input( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + val=np.zeros(nn), + desc="flight path angle", + units="rad", + ) self.add_input("dh_dr", val=np.zeros( nn), desc="d(alt)/d(range)", units="m/distance_units") self.add_input("d2h_dr2", val=np.zeros( @@ -87,19 +95,30 @@ def setup_partials(self): of="dt_dr", wrt=Dynamic.Mission.VELOCITY, rows=ar, cols=ar ) - self.declare_partials(of=["normal_force", "dTAS_dt"], - wrt=[Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, - "mass", Dynamic.Mission.LIFT], - rows=ar, cols=ar) + self.declare_partials( + of=["normal_force", "dTAS_dt"], + wrt=[ + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + "mass", + Dynamic.Vehicle.LIFT, + ], + rows=ar, + cols=ar, + ) self.declare_partials(of="normal_force", wrt="mass", rows=ar, cols=ar, val=LBF_TO_N * GRAV_ENGLISH_LBM) - self.declare_partials(of="normal_force", wrt=Dynamic.Mission.LIFT, + self.declare_partials(of="normal_force", wrt=Dynamic.Vehicle.LIFT, rows=ar, cols=ar, val=-1.0) - self.declare_partials(of="load_factor", wrt=[Dynamic.Mission.LIFT, "mass", Dynamic.Mission.THRUST_TOTAL], - rows=ar, cols=ar) + self.declare_partials( + of="load_factor", + wrt=[Dynamic.Vehicle.LIFT, "mass", Dynamic.Vehicle.Propulsion.THRUST_TOTAL], + rows=ar, + cols=ar, + ) self.declare_partials(of=["dTAS_dt", "normal_force", "load_factor"], wrt=[Aircraft.Wing.INCIDENCE]) @@ -120,33 +139,62 @@ def setup_partials(self): rows=ar, cols=ar) if not ground_roll: - self.declare_partials(of="dt_dr", wrt=Dynamic.Mission.FLIGHT_PATH_ANGLE, - rows=ar, cols=ar) + self.declare_partials( + of="dt_dr", wrt=Dynamic.Mission.FLIGHT_PATH_ANGLE, rows=ar, cols=ar + ) - self.declare_partials(of=["dgam_dt", "dgam_dt_approx"], - wrt=[Dynamic.Mission.LIFT, "mass", Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG, "alpha", Dynamic.Mission.FLIGHT_PATH_ANGLE], - rows=ar, cols=ar) + self.declare_partials( + of=["dgam_dt", "dgam_dt_approx"], + wrt=[ + Dynamic.Vehicle.LIFT, + "mass", + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + "alpha", + Dynamic.Mission.FLIGHT_PATH_ANGLE, + ], + rows=ar, + cols=ar, + ) - self.declare_partials(of=["normal_force", "dTAS_dt"], - wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], - rows=ar, cols=ar) + self.declare_partials( + of=["normal_force", "dTAS_dt"], + wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=ar, + cols=ar, + ) self.declare_partials( of=["dgam_dt"], wrt=[Dynamic.Mission.VELOCITY], rows=ar, cols=ar ) - self.declare_partials(of="load_factor", wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], - rows=ar, cols=ar) + self.declare_partials( + of="load_factor", + wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=ar, + cols=ar, + ) - self.declare_partials(of=["dgam_dt", "dgam_dt_approx"], - wrt=[Dynamic.Mission.LIFT, "mass", - Dynamic.Mission.THRUST_TOTAL, "alpha", Dynamic.Mission.FLIGHT_PATH_ANGLE], - rows=ar, cols=ar) + self.declare_partials( + of=["dgam_dt", "dgam_dt_approx"], + wrt=[ + Dynamic.Vehicle.LIFT, + "mass", + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + "alpha", + Dynamic.Mission.FLIGHT_PATH_ANGLE, + ], + rows=ar, + cols=ar, + ) - self.declare_partials(of="fuselage_pitch", - wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], - rows=ar, cols=ar, val=1.0) + self.declare_partials( + of="fuselage_pitch", + wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=ar, + cols=ar, + val=1.0, + ) self.declare_partials( of=["dgam_dt_approx"], @@ -160,11 +208,11 @@ def setup_partials(self): def compute(self, inputs, outputs): tas = inputs[Dynamic.Mission.VELOCITY] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] # convert to newtons # TODO: change this to use the units conversion weight = inputs["mass"] * GRAV_ENGLISH_LBM * LBF_TO_N - drag = inputs[Dynamic.Mission.DRAG] - lift = inputs[Dynamic.Mission.LIFT] + drag = inputs[Dynamic.Vehicle.DRAG] + lift = inputs[Dynamic.Vehicle.LIFT] alpha = inputs["alpha"] i_wing = inputs[Aircraft.Wing.INCIDENCE] @@ -217,11 +265,11 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, partials): ground_roll = self.options["ground_roll"] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] # convert to newtons # TODO: change this to use the units conversion weight = inputs["mass"] * GRAV_ENGLISH_LBM * LBF_TO_N - drag = inputs[Dynamic.Mission.DRAG] - lift = inputs[Dynamic.Mission.LIFT] + drag = inputs[Dynamic.Vehicle.DRAG] + lift = inputs[Dynamic.Vehicle.LIFT] tas = inputs[Dynamic.Mission.VELOCITY] i_wing = inputs[Aircraft.Wing.INCIDENCE] alpha = inputs["alpha"] @@ -261,22 +309,24 @@ def compute_partials(self, inputs, partials): partials["dt_dr", Dynamic.Mission.VELOCITY] = -cgam / dr_dt**2 - partials["dTAS_dt", Dynamic.Mission.THRUST_TOTAL] = calpha_i / \ - m + salpha_i / m * mu - partials["dTAS_dt", Dynamic.Mission.DRAG] = -1. / m + partials["dTAS_dt", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( + calpha_i / m + salpha_i / m * mu + ) + partials["dTAS_dt", Dynamic.Vehicle.DRAG] = -1. / m partials["dTAS_dt", "mass"] = \ GRAV_ENGLISH_LBM * (LBF_TO_N * (-sgam - mu) / m - _f / (weight/LBF_TO_N * m)) - partials["dTAS_dt", Dynamic.Mission.LIFT] = mu / m + partials["dTAS_dt", Dynamic.Vehicle.LIFT] = mu / m partials["dTAS_dt", "alpha"] = -tsai / m + mu * tcai / m partials["dTAS_dt", Aircraft.Wing.INCIDENCE] = tsai / m - mu * tcai / m - partials["normal_force", Dynamic.Mission.THRUST_TOTAL] = -salpha_i + partials["normal_force", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = -salpha_i - partials["load_factor", Dynamic.Mission.LIFT] = 1 / (weight * cgam) - partials["load_factor", Dynamic.Mission.THRUST_TOTAL] = salpha_i / \ - (weight * cgam) + partials["load_factor", Dynamic.Vehicle.LIFT] = 1 / (weight * cgam) + partials["load_factor", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = salpha_i / ( + weight * cgam + ) partials["load_factor", "mass"] = \ - (lift + tsai) / (weight**2/LBF_TO_N * cgam) * GRAV_ENGLISH_LBM @@ -287,17 +337,22 @@ def compute_partials(self, inputs, partials): partials["load_factor", "alpha"] = tcai / (weight * cgam) if not ground_roll: - partials["dt_dr", Dynamic.Mission.FLIGHT_PATH_ANGLE] = -drdot_dgam / dr_dt**2 + partials["dt_dr", Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -drdot_dgam / dr_dt**2 + ) partials["dTAS_dt", Dynamic.Mission.FLIGHT_PATH_ANGLE] = -weight * cgam / m - partials["dgam_dt", Dynamic.Mission.THRUST_TOTAL] = salpha_i / mtas - partials["dgam_dt", Dynamic.Mission.LIFT] = 1. / mtas + partials["dgam_dt", Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = ( + salpha_i / mtas + ) + partials["dgam_dt", Dynamic.Vehicle.LIFT] = 1. / mtas partials["dgam_dt", "mass"] = \ GRAV_ENGLISH_LBM * (LBF_TO_N*cgam / (mtas) - (tsai + lift + weight*cgam)/(weight**2 / LBF_TO_N/g * tas)) - partials["dgam_dt", Dynamic.Mission.FLIGHT_PATH_ANGLE] = m * \ - tas * weight * sgam / mtas2 + partials["dgam_dt", Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + m * tas * weight * sgam / mtas2 + ) partials["dgam_dt", "alpha"] = m * tas * tcai / mtas2 partials["dgam_dt", Dynamic.Mission.VELOCITY] = ( -m * (tsai + lift - weight * cgam) / mtas2 @@ -311,7 +366,9 @@ def compute_partials(self, inputs, partials): partials["dgam_dt_approx", "dh_dr"] = dr_dt * ddgam_dr_ddh_dr partials["dgam_dt_approx", "d2h_dr2"] = dr_dt * ddgam_dr_dd2h_dr2 partials["dgam_dt_approx", Dynamic.Mission.VELOCITY] = dgam_dr * drdot_dtas - partials["dgam_dt_approx", - Dynamic.Mission.FLIGHT_PATH_ANGLE] = dgam_dr * drdot_dgam + partials["dgam_dt_approx", Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + dgam_dr * drdot_dgam + ) partials["load_factor", Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( - lift + tsai) / (weight * cgam**2) * sgam + (lift + tsai) / (weight * cgam**2) * sgam + ) diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_flight_conditions.py b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_flight_conditions.py index 08c1868ba..af2b8bdea 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_flight_conditions.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_flight_conditions.py @@ -11,7 +11,7 @@ class UnsteadySolvedFlightConditions(om.ExplicitComponent): Cross-compute TAS, EAS, and Mach regardless of the input speed type. Inputs: - Dynamic.Mission.DENSITY : local atmospheric density + Dynamic.Atmosphere.DENSITY : local atmospheric density Dynamic.Mission.SPEED_OF_SOUND : local speed of sound Additional inputs if ground_roll = False: @@ -26,20 +26,20 @@ class UnsteadySolvedFlightConditions(om.ExplicitComponent): dEAS_dr : approximate rate of change of equivalent airspeed per unit range Additional inputs when input_speed_type = SpeedType.MACH: - Dynamic.Mission.MACH : Mach number + Dynamic.Atmosphere.MACH : Mach number dmach_dr : approximate rate of change of Mach number per unit range Outputs always provided: - Dynamic.Mission.DYNAMIC_PRESSURE : dynamic pressure + Dynamic.Atmosphere.DYNAMIC_PRESSURE : dynamic pressure dTAS_dt_approx : approximate time derivative of TAS based on control rates. Additional outputs when input_speed_type = SpeedType.TAS EAS : equivalent airspeed - Dynamic.Mission.MACH : Mach number + Dynamic.Atmosphere.MACH : Mach number Outputs provided when input_speed_type = SpeedType.EAS: TAS : true airspeed - Dynamic.Mission.MACH : Mach number + Dynamic.Atmosphere.MACH : Mach number """ def initialize(self): @@ -62,20 +62,20 @@ def setup(self): ar = np.arange(self.options["num_nodes"]) self.add_input( - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, val=np.zeros(nn), units="kg/m**3", desc="density of air", ) self.add_input( - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.SPEED_OF_SOUND, val=np.zeros(nn), units="m/s", desc="speed of sound", ) self.add_output( - Dynamic.Mission.DYNAMIC_PRESSURE, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, val=np.zeros(nn), units="N/m**2", desc="dynamic pressure", @@ -118,27 +118,27 @@ def setup(self): desc="equivalent air speed", ) self.add_output( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, val=np.zeros(nn), units="unitless", desc="mach number", ) self.declare_partials( - of=Dynamic.Mission.DYNAMIC_PRESSURE, - wrt=[Dynamic.Mission.DENSITY, Dynamic.Mission.VELOCITY], + of=Dynamic.Atmosphere.DYNAMIC_PRESSURE, + wrt=[Dynamic.Atmosphere.DENSITY, Dynamic.Mission.VELOCITY], rows=ar, cols=ar, ) self.declare_partials( - of=Dynamic.Mission.MACH, - wrt=[Dynamic.Mission.SPEED_OF_SOUND, Dynamic.Mission.VELOCITY], + of=Dynamic.Atmosphere.MACH, + wrt=[Dynamic.Atmosphere.SPEED_OF_SOUND, Dynamic.Mission.VELOCITY], rows=ar, cols=ar, ) self.declare_partials( of="EAS", - wrt=[Dynamic.Mission.VELOCITY, Dynamic.Mission.DENSITY], + wrt=[Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.DENSITY], rows=ar, cols=ar, ) @@ -150,9 +150,12 @@ def setup(self): ) if not ground_roll: - self.declare_partials(of="dTAS_dt_approx", - wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], - rows=ar, cols=ar) + self.declare_partials( + of="dTAS_dt_approx", + wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=ar, + cols=ar, + ) elif in_type is SpeedType.EAS: self.add_input( @@ -181,45 +184,52 @@ def setup(self): desc="true air speed", ) self.add_output( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, val=np.zeros(nn), units="unitless", desc="mach number", ) self.declare_partials( - of=Dynamic.Mission.DYNAMIC_PRESSURE, - wrt=[Dynamic.Mission.DENSITY, "EAS"], + of=Dynamic.Atmosphere.DYNAMIC_PRESSURE, + wrt=[Dynamic.Atmosphere.DENSITY, "EAS"], rows=ar, cols=ar, ) self.declare_partials( - of=Dynamic.Mission.MACH, - wrt=[Dynamic.Mission.SPEED_OF_SOUND, "EAS", Dynamic.Mission.DENSITY], + of=Dynamic.Atmosphere.MACH, + wrt=[ + Dynamic.Atmosphere.SPEED_OF_SOUND, + "EAS", + Dynamic.Atmosphere.DENSITY, + ], rows=ar, cols=ar, ) self.declare_partials( of=Dynamic.Mission.VELOCITY, - wrt=[Dynamic.Mission.DENSITY, "EAS"], + wrt=[Dynamic.Atmosphere.DENSITY, "EAS"], rows=ar, cols=ar, ) self.declare_partials( of="dTAS_dt_approx", - wrt=["drho_dh", Dynamic.Mission.DENSITY, "EAS", "dEAS_dr"], + wrt=["drho_dh", Dynamic.Atmosphere.DENSITY, "EAS", "dEAS_dr"], rows=ar, cols=ar, ) if not ground_roll: - self.declare_partials(of="dTAS_dt_approx", - wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], - rows=ar, cols=ar) + self.declare_partials( + of="dTAS_dt_approx", + wrt=[Dynamic.Mission.FLIGHT_PATH_ANGLE], + rows=ar, + cols=ar, + ) else: self.add_input( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, val=np.zeros(nn), units="unitless", desc="mach number", @@ -251,11 +261,11 @@ def setup(self): ) self.declare_partials( - of=Dynamic.Mission.DYNAMIC_PRESSURE, + of=Dynamic.Atmosphere.DYNAMIC_PRESSURE, wrt=[ - Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.MACH, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.DENSITY, ], rows=ar, cols=ar, @@ -263,7 +273,7 @@ def setup(self): self.declare_partials( of=Dynamic.Mission.VELOCITY, - wrt=[Dynamic.Mission.SPEED_OF_SOUND, Dynamic.Mission.MACH], + wrt=[Dynamic.Atmosphere.SPEED_OF_SOUND, Dynamic.Atmosphere.MACH], rows=ar, cols=ar, ) @@ -271,9 +281,9 @@ def setup(self): self.declare_partials( of="EAS", wrt=[ - Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.MACH, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.DENSITY, ], rows=ar, cols=ar, @@ -287,10 +297,10 @@ def compute(self, inputs, outputs): in_type = self.options["input_speed_type"] ground_roll = self.options["ground_roll"] - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] rho_sl = constants.RHO_SEA_LEVEL_METRIC sqrt_rho_rho_sl = np.sqrt(rho / rho_sl) - sos = inputs[Dynamic.Mission.SPEED_OF_SOUND] + sos = inputs[Dynamic.Atmosphere.SPEED_OF_SOUND] cgam = 1.0 if ground_roll else np.cos(inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE]) sgam = 0.0 if ground_roll else np.sin(inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE]) @@ -298,7 +308,7 @@ def compute(self, inputs, outputs): if in_type is SpeedType.TAS: tas = inputs[Dynamic.Mission.VELOCITY] dtas_dr = inputs["dTAS_dr"] - outputs[Dynamic.Mission.MACH] = tas / sos + outputs[Dynamic.Atmosphere.MACH] = tas / sos outputs["EAS"] = tas * sqrt_rho_rho_sl outputs["dTAS_dt_approx"] = dtas_dr * tas * cgam @@ -307,14 +317,14 @@ def compute(self, inputs, outputs): drho_dh = inputs["drho_dh"] deas_dr = inputs["dEAS_dr"] outputs[Dynamic.Mission.VELOCITY] = tas = eas / sqrt_rho_rho_sl - outputs[Dynamic.Mission.MACH] = tas / sos + outputs[Dynamic.Atmosphere.MACH] = tas / sos drho_dt_approx = drho_dh * tas * sgam deas_dt_approx = deas_dr * tas * cgam outputs["dTAS_dt_approx"] = deas_dt_approx * (rho_sl / rho)**1.5 \ - 0.5 * eas * drho_dt_approx * rho_sl**1.5 / rho_sl**2.5 else: - mach = inputs[Dynamic.Mission.MACH] + mach = inputs[Dynamic.Atmosphere.MACH] dmach_dr = inputs["dmach_dr"] outputs[Dynamic.Mission.VELOCITY] = tas = sos * mach outputs["EAS"] = tas * sqrt_rho_rho_sl @@ -323,17 +333,17 @@ def compute(self, inputs, outputs): outputs["dTAS_dt_approx"] = dmach_dt_approx * sos \ + dsos_dt_approx * tas / sos - outputs[Dynamic.Mission.DYNAMIC_PRESSURE] = 0.5 * rho * tas**2 + outputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] = 0.5 * rho * tas**2 def compute_partials(self, inputs, partials): in_type = self.options["input_speed_type"] ground_roll = self.options["ground_roll"] - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] rho_sl = constants.RHO_SEA_LEVEL_METRIC sqrt_rho_rho_sl = np.sqrt(rho / rho_sl) dsqrt_rho_rho_sl_drho = 0.5 / sqrt_rho_rho_sl / rho_sl - sos = inputs[Dynamic.Mission.SPEED_OF_SOUND] + sos = inputs[Dynamic.Atmosphere.SPEED_OF_SOUND] cgam = 1.0 if ground_roll else np.cos(inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE]) sgam = 0.0 if ground_roll else np.sin(inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE]) @@ -344,26 +354,28 @@ def compute_partials(self, inputs, partials): tas = inputs[Dynamic.Mission.VELOCITY] dTAS_dr = inputs["dTAS_dr"] - partials[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.VELOCITY] = ( + partials[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Mission.VELOCITY] = ( rho * TAS ) - partials[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.DENSITY] = ( - 0.5 * TAS**2 - ) + partials[ + Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.DENSITY + ] = (0.5 * TAS**2) - partials[Dynamic.Mission.MACH, Dynamic.Mission.VELOCITY] = 1 / sos - partials[Dynamic.Mission.MACH, - Dynamic.Mission.SPEED_OF_SOUND] = -TAS / sos ** 2 + partials[Dynamic.Atmosphere.MACH, Dynamic.Mission.VELOCITY] = 1 / sos + partials[Dynamic.Atmosphere.MACH, Dynamic.Atmosphere.SPEED_OF_SOUND] = ( + -TAS / sos**2 + ) partials["EAS", Dynamic.Mission.VELOCITY] = sqrt_rho_rho_sl - partials["EAS", Dynamic.Mission.DENSITY] = tas * dsqrt_rho_rho_sl_drho + partials["EAS", Dynamic.Atmosphere.DENSITY] = tas * dsqrt_rho_rho_sl_drho partials["dTAS_dt_approx", "dTAS_dr"] = tas * cgam partials["dTAS_dt_approx", Dynamic.Mission.VELOCITY] = dTAS_dr * cgam if not ground_roll: - partials["dTAS_dt_approx", - Dynamic.Mission.FLIGHT_PATH_ANGLE] = -dTAS_dr * tas * sgam + partials["dTAS_dt_approx", Dynamic.Mission.FLIGHT_PATH_ANGLE] = ( + -dTAS_dr * tas * sgam + ) elif in_type is SpeedType.EAS: EAS = inputs["EAS"] @@ -372,33 +384,38 @@ def compute_partials(self, inputs, partials): dTAS_dRho = -0.5 * EAS * rho_sl**0.5 / rho**1.5 dTAS_dEAS = 1 / sqrt_rho_rho_sl - partials[Dynamic.Mission.DYNAMIC_PRESSURE, "EAS"] = EAS * rho_sl - partials[Dynamic.Mission.MACH, "EAS"] = dTAS_dEAS / sos - partials[Dynamic.Mission.MACH, Dynamic.Mission.DENSITY] = dTAS_dRho / sos - partials[Dynamic.Mission.MACH, - Dynamic.Mission.SPEED_OF_SOUND] = -TAS / sos ** 2 - partials[Dynamic.Mission.VELOCITY, Dynamic.Mission.DENSITY] = dTAS_dRho + partials[Dynamic.Atmosphere.DYNAMIC_PRESSURE, "EAS"] = EAS * rho_sl + partials[Dynamic.Atmosphere.MACH, "EAS"] = dTAS_dEAS / sos + partials[Dynamic.Atmosphere.MACH, Dynamic.Atmosphere.DENSITY] = ( + dTAS_dRho / sos + ) + partials[Dynamic.Atmosphere.MACH, Dynamic.Atmosphere.SPEED_OF_SOUND] = ( + -TAS / sos**2 + ) + partials[Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.DENSITY] = dTAS_dRho partials[Dynamic.Mission.VELOCITY, "EAS"] = dTAS_dEAS partials["dTAS_dt_approx", "dEAS_dr"] = TAS * cgam * (rho_sl / rho)**1.5 partials['dTAS_dt_approx', 'drho_dh'] = -0.5 * \ EAS * TAS * sgam * rho_sl**1.5 / rho_sl**2.5 else: - mach = inputs[Dynamic.Mission.MACH] + mach = inputs[Dynamic.Atmosphere.MACH] TAS = sos * mach - partials[Dynamic.Mission.DYNAMIC_PRESSURE, - Dynamic.Mission.SPEED_OF_SOUND] = rho * sos * mach ** 2 - partials[Dynamic.Mission.DYNAMIC_PRESSURE, - Dynamic.Mission.MACH] = rho * sos ** 2 * mach - partials[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.DENSITY] = ( - 0.5 * sos**2 * mach**2 - ) - partials[Dynamic.Mission.VELOCITY, Dynamic.Mission.SPEED_OF_SOUND] = mach - partials[Dynamic.Mission.VELOCITY, Dynamic.Mission.MACH] = sos - partials["EAS", Dynamic.Mission.SPEED_OF_SOUND] = mach * sqrt_rho_rho_sl - partials["EAS", Dynamic.Mission.MACH] = sos * sqrt_rho_rho_sl - partials["EAS", Dynamic.Mission.DENSITY] = ( + partials[ + Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.SPEED_OF_SOUND + ] = (rho * sos * mach**2) + partials[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.MACH] = ( + rho * sos**2 * mach + ) + partials[ + Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.DENSITY + ] = (0.5 * sos**2 * mach**2) + partials[Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.SPEED_OF_SOUND] = mach + partials[Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.MACH] = sos + partials["EAS", Dynamic.Atmosphere.SPEED_OF_SOUND] = mach * sqrt_rho_rho_sl + partials["EAS", Dynamic.Atmosphere.MACH] = sos * sqrt_rho_rho_sl + partials["EAS", Dynamic.Atmosphere.DENSITY] = ( TAS * (1 / rho_sl) ** 0.5 * 0.5 * rho ** (-0.5) ) partials['dTAS_dt_approx', 'dmach_dr'] = TAS * cgam * sos diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_ode.py b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_ode.py index fcc5c10ce..cffa4259b 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_ode.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_ode.py @@ -95,10 +95,10 @@ def setup(self): subsys=Atmosphere(num_nodes=nn, output_dsos_dh=True), promotes_inputs=[Dynamic.Mission.ALTITUDE], promotes_outputs=[ - Dynamic.Mission.DENSITY, - Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Atmosphere.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, "viscosity", "drhos_dh", "dsos_dh", @@ -132,10 +132,10 @@ def setup(self): throttle_balance_comp = om.BalanceComp() throttle_balance_comp.add_balance( - Dynamic.Mission.THROTTLE, + Dynamic.Vehicle.Propulsion.THROTTLE, units="unitless", val=np.ones(nn) * 0.5, - lhs_name=Dynamic.Mission.THRUST_TOTAL, + lhs_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, rhs_name="thrust_req", eq_units="lbf", normalize=False, @@ -195,7 +195,7 @@ def setup(self): input_list = [ '*', - (Dynamic.Mission.THRUST_TOTAL, "thrust_req"), + (Dynamic.Vehicle.Propulsion.THRUST_TOTAL, "thrust_req"), Dynamic.Mission.VELOCITY, ] control_iter_group.add_subsystem("eom", subsys=eom_comp, @@ -232,38 +232,46 @@ def setup(self): # control_iter_group.nonlinear_solver.linesearch = om.BoundsEnforceLS() control_iter_group.linear_solver = om.DirectSolver(assemble_jac=True) - self.add_subsystem("mass_rate", - om.ExecComp("dmass_dr = fuelflow * dt_dr", - fuelflow={"units": "lbm/s", "shape": nn}, - dt_dr={"units": "s/distance_units", "shape": nn}, - dmass_dr={"units": "lbm/distance_units", - "shape": nn, - "tags": ['dymos.state_rate_source:mass', - 'dymos.state_units:lbm']}, - has_diag_partials=True), - promotes_inputs=[ - ("fuelflow", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL), "dt_dr"], - promotes_outputs=["dmass_dr"]) + self.add_subsystem( + "mass_rate", + om.ExecComp( + "dmass_dr = fuelflow * dt_dr", + fuelflow={"units": "lbm/s", "shape": nn}, + dt_dr={"units": "s/distance_units", "shape": nn}, + dmass_dr={ + "units": "lbm/distance_units", + "shape": nn, + "tags": ['dymos.state_rate_source:mass', 'dymos.state_units:lbm'], + }, + has_diag_partials=True, + ), + promotes_inputs=[ + ("fuelflow", Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL), + "dt_dr", + ], + promotes_outputs=["dmass_dr"], + ) if self.options["include_param_comp"]: ParamPort.set_default_vals(self) onn = np.ones(nn) - self.set_input_defaults(name=Dynamic.Mission.DENSITY, - val=rho_sl * onn, units="slug/ft**3") self.set_input_defaults( - name=Dynamic.Mission.SPEED_OF_SOUND, - val=1116.4 * onn, - units="ft/s") + name=Dynamic.Atmosphere.DENSITY, val=rho_sl * onn, units="slug/ft**3" + ) + self.set_input_defaults( + name=Dynamic.Atmosphere.SPEED_OF_SOUND, val=1116.4 * onn, units="ft/s" + ) if not self.options['ground_roll']: self.set_input_defaults( - name=Dynamic.Mission.FLIGHT_PATH_ANGLE, val=0.0 * onn, units="rad") - self.set_input_defaults(name=Dynamic.Mission.VELOCITY, - val=250. * onn, units="kn") + name=Dynamic.Mission.FLIGHT_PATH_ANGLE, val=0.0 * onn, units="rad" + ) self.set_input_defaults( - name=Dynamic.Mission.ALTITUDE, - val=10000. * onn, - units="ft") + name=Dynamic.Mission.VELOCITY, val=250.0 * onn, units="kn" + ) + self.set_input_defaults( + name=Dynamic.Mission.ALTITUDE, val=10000.0 * onn, units="ft" + ) self.set_input_defaults(name="dh_dr", val=0. * onn, units="ft/distance_units") self.set_input_defaults(name="d2h_dr2", val=0. * onn, units="ft/distance_units**2") diff --git a/aviary/mission/gasp_based/phases/accel_phase.py b/aviary/mission/gasp_based/phases/accel_phase.py index a1dcfa5d5..0bfdbe487 100644 --- a/aviary/mission/gasp_based/phases/accel_phase.py +++ b/aviary/mission/gasp_based/phases/accel_phase.py @@ -64,11 +64,17 @@ def build_phase(self, aviary_options: AviaryValues = None): # Timeseries Outputs phase.add_timeseries_output("EAS", output_name="EAS", units="kn") phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") + Dynamic.Atmosphere.MACH, + output_name=Dynamic.Atmosphere.MACH, + units="unitless", + ) phase.add_timeseries_output("alpha", output_name="alpha", units="deg") phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + units="lbf", + ) phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") return phase diff --git a/aviary/mission/gasp_based/phases/ascent_phase.py b/aviary/mission/gasp_based/phases/ascent_phase.py index 663655411..6352dfccf 100644 --- a/aviary/mission/gasp_based/phases/ascent_phase.py +++ b/aviary/mission/gasp_based/phases/ascent_phase.py @@ -86,11 +86,13 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.add_parameter("t_init_flaps", units="s", static_target=True, opt=False, val=48.21) - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units="lbf" + ) phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output(Dynamic.Atmosphere.MACH) phase.add_timeseries_output("EAS", units="kn") - phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output(Dynamic.Vehicle.LIFT) phase.add_timeseries_output("CL") phase.add_timeseries_output("CD") diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index 0bb6bbed8..279c644a7 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -81,27 +81,41 @@ def build_phase(self, aviary_options: AviaryValues = None): if target_mach: phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc="final", equals=mach_cruise, + Dynamic.Atmosphere.MACH, + loc="final", + equals=mach_cruise, ) # Timeseries Outputs phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") + Dynamic.Atmosphere.MACH, + output_name=Dynamic.Atmosphere.MACH, + units="unitless", + ) phase.add_timeseries_output("EAS", output_name="EAS", units="kn") phase.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/s") + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/s" + ) phase.add_timeseries_output("theta", output_name="theta", units="deg") phase.add_timeseries_output("alpha", output_name="alpha", units="deg") - phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, - output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") + phase.add_timeseries_output( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, + units="deg", + ) phase.add_timeseries_output( "TAS_violation", output_name="TAS_violation", units="kn") phase.add_timeseries_output( - Dynamic.Mission.VELOCITY, output_name=Dynamic.Mission.VELOCITY, units="kn" + Dynamic.Mission.VELOCITY, + output_name=Dynamic.Mission.VELOCITY, + units="kn", ) phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + units="lbf", + ) phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") return phase diff --git a/aviary/mission/gasp_based/phases/cruise_phase.py b/aviary/mission/gasp_based/phases/cruise_phase.py index 44b7704f5..6ccfc8edf 100644 --- a/aviary/mission/gasp_based/phases/cruise_phase.py +++ b/aviary/mission/gasp_based/phases/cruise_phase.py @@ -61,17 +61,17 @@ def build_phase(self, aviary_options: AviaryValues = None): mach_cruise = user_options.get_val('mach_cruise') alt_cruise, alt_units = user_options.get_item('alt_cruise') - phase.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, - val=alt_cruise, units=alt_units) - phase.add_parameter(Dynamic.Mission.MACH, opt=False, - val=mach_cruise) + phase.add_parameter( + Dynamic.Mission.ALTITUDE, opt=False, val=alt_cruise, units=alt_units + ) + phase.add_parameter(Dynamic.Atmosphere.MACH, opt=False, val=mach_cruise) phase.add_parameter("initial_distance", opt=False, val=0.0, units="NM", static_target=True) phase.add_parameter("initial_time", opt=False, val=0.0, units="s", static_target=True) phase.add_timeseries_output("time", units="s", output_name="time") - phase.add_timeseries_output(Dynamic.Mission.MASS, units="lbm") + phase.add_timeseries_output(Dynamic.Vehicle.MASS, units="lbm") phase.add_timeseries_output(Dynamic.Mission.DISTANCE, units="nmi") return phase diff --git a/aviary/mission/gasp_based/phases/descent_phase.py b/aviary/mission/gasp_based/phases/descent_phase.py index 713e2234f..409187456 100644 --- a/aviary/mission/gasp_based/phases/descent_phase.py +++ b/aviary/mission/gasp_based/phases/descent_phase.py @@ -53,18 +53,29 @@ def build_phase(self, aviary_options: AviaryValues = None): # Add timeseries outputs phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") + Dynamic.Atmosphere.MACH, + output_name=Dynamic.Atmosphere.MACH, + units="unitless", + ) phase.add_timeseries_output("EAS", output_name="EAS", units="kn") phase.add_timeseries_output( - Dynamic.Mission.VELOCITY, output_name=Dynamic.Mission.VELOCITY, units="kn" + Dynamic.Mission.VELOCITY, + output_name=Dynamic.Mission.VELOCITY, + units="kn", + ) + phase.add_timeseries_output( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, + units="deg", ) - phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, - output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") phase.add_timeseries_output("alpha", output_name="alpha", units="deg") phase.add_timeseries_output("theta", output_name="theta", units="deg") phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + output_name=Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + units="lbf", + ) phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") return phase diff --git a/aviary/mission/gasp_based/phases/groundroll_phase.py b/aviary/mission/gasp_based/phases/groundroll_phase.py index d954b2c1b..a7d55e510 100644 --- a/aviary/mission/gasp_based/phases/groundroll_phase.py +++ b/aviary/mission/gasp_based/phases/groundroll_phase.py @@ -52,14 +52,14 @@ def build_phase(self, aviary_options: AviaryValues = None): self.add_velocity_state(user_options) phase.add_state( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, fix_initial=fix_initial_mass, input_initial=connect_initial_mass, fix_final=False, lower=mass_lower, upper=mass_upper, units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, ref=mass_ref, defect_ref=mass_defect_ref, ref0=mass_ref0, @@ -88,13 +88,15 @@ def build_phase(self, aviary_options: AviaryValues = None): # phase phase.add_timeseries_output("time", units="s", output_name="time") - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units="lbf" + ) phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output(Dynamic.Atmosphere.MACH) phase.add_timeseries_output("EAS", units="kn") - phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output(Dynamic.Vehicle.LIFT) phase.add_timeseries_output("CL") phase.add_timeseries_output("CD") phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") diff --git a/aviary/mission/gasp_based/phases/rotation_phase.py b/aviary/mission/gasp_based/phases/rotation_phase.py index ebb04888b..8643ea5ec 100644 --- a/aviary/mission/gasp_based/phases/rotation_phase.py +++ b/aviary/mission/gasp_based/phases/rotation_phase.py @@ -97,11 +97,13 @@ def build_phase(self, aviary_options: AviaryValues = None): ) # Add timeseries outputs - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output( + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units="lbf" + ) phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output(Dynamic.Atmosphere.MACH) phase.add_timeseries_output("EAS", units="kn") - phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output(Dynamic.Vehicle.LIFT) phase.add_timeseries_output("CL") phase.add_timeseries_output("CD") phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") diff --git a/aviary/mission/gasp_based/phases/test/test_v_rotate_comp.py b/aviary/mission/gasp_based/phases/test/test_v_rotate_comp.py index f166d8a7a..3378792b4 100644 --- a/aviary/mission/gasp_based/phases/test/test_v_rotate_comp.py +++ b/aviary/mission/gasp_based/phases/test/test_v_rotate_comp.py @@ -25,7 +25,7 @@ def test_partials(self): prob.set_val("dVR", val=5, units="kn") prob.set_val(Aircraft.Wing.AREA, val=1370, units="ft**2") prob.set_val( - Dynamic.Mission.DENSITY, val=RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3" + Dynamic.Atmosphere.DENSITY, val=RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3" ) prob.set_val("CL_max", val=2.1886, units="unitless") prob.set_val("mass", val=175_000, units="lbm") @@ -59,7 +59,7 @@ def test_partials(self): prob.set_val("dVR", val=5, units="kn") prob.set_val(Aircraft.Wing.AREA, val=1370, units="ft**2") prob.set_val( - Dynamic.Mission.DENSITY, val=RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3" + Dynamic.Atmosphere.DENSITY, val=RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3" ) prob.set_val("CL_max", val=2.1886, units="unitless") prob.set_val("mass", val=175_000, units="lbm") diff --git a/aviary/mission/gasp_based/phases/time_integration_phases.py b/aviary/mission/gasp_based/phases/time_integration_phases.py index ca8a10f39..7b5e5d0b8 100644 --- a/aviary/mission/gasp_based/phases/time_integration_phases.py +++ b/aviary/mission/gasp_based/phases/time_integration_phases.py @@ -32,14 +32,15 @@ def __init__( problem_name=phase_name, outputs=["normal_force"], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, Dynamic.Mission.VELOCITY, ], # state_units=['lbm','nmi','ft','ft/s'], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, **simupy_args, ) @@ -66,14 +67,15 @@ def __init__( problem_name=phase_name, outputs=["normal_force", "alpha"], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, Dynamic.Mission.VELOCITY, ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, **simupy_args, ) @@ -108,8 +110,11 @@ def __init__( ): controls = None super().__init__( - AscentODE(analysis_scheme=AnalysisScheme.SHOOTING, - alpha_mode=alpha_mode, **ode_args), + AscentODE( + analysis_scheme=AnalysisScheme.SHOOTING, + alpha_mode=alpha_mode, + **ode_args, + ), problem_name=phase_name, outputs=[ "load_factor", @@ -118,7 +123,7 @@ def __init__( "alpha", ], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, Dynamic.Mission.VELOCITY, @@ -127,7 +132,8 @@ def __init__( ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, controls=controls, **simupy_args, ) @@ -365,14 +371,15 @@ def __init__( problem_name=phase_name, outputs=["EAS", "mach", "alpha"], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, Dynamic.Mission.VELOCITY, ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, **simupy_args, ) @@ -424,24 +431,26 @@ def __init__( "mach", "EAS", Dynamic.Mission.VELOCITY, - Dynamic.Mission.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, "drag", Dynamic.Mission.ALTITUDE_RATE, ], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, **simupy_args, ) self.phase_name = phase_name - self.add_trigger(Dynamic.Mission.ALTITUDE, "alt_trigger", - units=self.alt_trigger_units) + self.add_trigger( + Dynamic.Mission.ALTITUDE, "alt_trigger", units=self.alt_trigger_units + ) self.add_trigger(self.speed_trigger_name, "speed_trigger", units="speed_trigger_units") @@ -481,25 +490,26 @@ def __init__( "lift", "EAS", Dynamic.Mission.VELOCITY, - Dynamic.Mission.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, "drag", Dynamic.Mission.ALTITUDE_RATE, ], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, Dynamic.Mission.VELOCITY, ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, **simupy_args, ) self.phase_name = phase_name self.add_trigger(Dynamic.Mission.DISTANCE, "distance_trigger") - self.add_trigger(Dynamic.Mission.MASS, 'mass_trigger') + self.add_trigger(Dynamic.Vehicle.MASS, 'mass_trigger') class SGMDescent(SimuPyProblem): @@ -544,23 +554,25 @@ def __init__( "lift", "EAS", Dynamic.Mission.VELOCITY, - Dynamic.Mission.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, "drag", Dynamic.Mission.ALTITUDE_RATE, ], states=[ - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Vehicle.MASS: Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL + }, **simupy_args, ) self.phase_name = phase_name - self.add_trigger(Dynamic.Mission.ALTITUDE, "alt_trigger", - units=self.alt_trigger_units) + self.add_trigger( + Dynamic.Mission.ALTITUDE, "alt_trigger", units=self.alt_trigger_units + ) self.add_trigger(self.speed_trigger_name, "speed_trigger", units=self.speed_trigger_units) diff --git a/aviary/mission/gasp_based/phases/v_rotate_comp.py b/aviary/mission/gasp_based/phases/v_rotate_comp.py index 2c2b991be..a96a8ad0f 100644 --- a/aviary/mission/gasp_based/phases/v_rotate_comp.py +++ b/aviary/mission/gasp_based/phases/v_rotate_comp.py @@ -13,10 +13,10 @@ class VRotateComp(om.ExplicitComponent): def setup(self): # Temporarily set this to shape (1, 1) to avoid OpenMDAO bug - add_aviary_input(self, Dynamic.Mission.MASS, shape=(1, 1), units="lbm") + add_aviary_input(self, Dynamic.Vehicle.MASS, shape=(1, 1), units="lbm") add_aviary_input( self, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, shape=(1,), units="slug/ft**3", val=RHO_SEA_LEVEL_ENGLISH, @@ -39,8 +39,8 @@ def setup(self): self.declare_partials( of="Vrot", wrt=[ - Dynamic.Mission.MASS, - Dynamic.Mission.DENSITY, + Dynamic.Vehicle.MASS, + Dynamic.Atmosphere.DENSITY, Aircraft.Wing.AREA, "CL_max", ], @@ -56,7 +56,7 @@ def compute_partials(self, inputs, partials, discrete_inputs=None): K = 0.5 * ((2 * mass * GRAV_ENGLISH_LBM) / (rho * wing_area * CL_max)) ** 0.5 - partials["Vrot", Dynamic.Mission.MASS] = K / mass - partials["Vrot", Dynamic.Mission.DENSITY] = -K / rho + partials["Vrot", Dynamic.Vehicle.MASS] = K / mass + partials["Vrot", Dynamic.Atmosphere.DENSITY] = -K / rho partials["Vrot", Aircraft.Wing.AREA] = -K / wing_area partials["Vrot", "CL_max"] = -K / CL_max diff --git a/aviary/mission/gasp_based/test/test_idle_descent_estimation.py b/aviary/mission/gasp_based/test/test_idle_descent_estimation.py index be6910d58..7fc63fb5e 100644 --- a/aviary/mission/gasp_based/test/test_idle_descent_estimation.py +++ b/aviary/mission/gasp_based/test/test_idle_descent_estimation.py @@ -27,7 +27,9 @@ def setUp(self): aviary_inputs, _ = create_vehicle(input_deck) aviary_inputs.set_val(Settings.VERBOSITY, 0) aviary_inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, val=28690, units="lbf") - aviary_inputs.set_val(Dynamic.Mission.THROTTLE, val=0, units="unitless") + aviary_inputs.set_val( + Dynamic.Vehicle.Propulsion.THROTTLE, val=0, units="unitless" + ) engine = build_engine_deck(aviary_options=aviary_inputs) preprocess_propulsion(aviary_inputs, engine) @@ -76,8 +78,8 @@ def test_subproblem(self): warnings.filterwarnings('default', category=UserWarning) # Values obtained by running idle_descent_estimation - assert_near_equal(prob.get_val('descent_range', 'NM'), 98.38026813, self.tol) - assert_near_equal(prob.get_val('descent_fuel', 'lbm'), 250.84809336, self.tol) + assert_near_equal(prob.get_val('descent_range', 'NM'), 98.3445738, self.tol) + assert_near_equal(prob.get_val('descent_fuel', 'lbm'), 250.79875356, self.tol) # TODO: check_partials() call results in runtime error: Jacobian in 'ODE_group' is not full rank. # partial_data = prob.check_partials(out_stream=None, method="cs") diff --git a/aviary/mission/ode/altitude_rate.py b/aviary/mission/ode/altitude_rate.py index 30c045c1d..5b7b285ef 100644 --- a/aviary/mission/ode/altitude_rate.py +++ b/aviary/mission/ode/altitude_rate.py @@ -16,17 +16,30 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - self.add_input(Dynamic.Mission.SPECIFIC_ENERGY_RATE, val=np.ones( - nn), desc='current specific power', units='m/s') - self.add_input(Dynamic.Mission.VELOCITY_RATE, val=np.ones( - nn), desc='current acceleration', units='m/s**2') + self.add_input( + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + val=np.ones(nn), + desc='current specific power', + units='m/s', + ) + self.add_input( + Dynamic.Mission.VELOCITY_RATE, + val=np.ones(nn), + desc='current acceleration', + units='m/s**2', + ) self.add_input( Dynamic.Mission.VELOCITY, val=np.ones(nn), desc='current velocity', - units='m/s') - self.add_output(Dynamic.Mission.ALTITUDE_RATE, val=np.ones( - nn), desc='current climb rate', units='m/s') + units='m/s', + ) + self.add_output( + Dynamic.Mission.ALTITUDE_RATE, + val=np.ones(nn), + desc='current climb rate', + units='m/s', + ) def compute(self, inputs, outputs): gravity = constants.GRAV_METRIC_FLOPS @@ -34,23 +47,32 @@ def compute(self, inputs, outputs): acceleration = inputs[Dynamic.Mission.VELOCITY_RATE] velocity = inputs[Dynamic.Mission.VELOCITY] - outputs[Dynamic.Mission.ALTITUDE_RATE] = \ + outputs[Dynamic.Mission.ALTITUDE_RATE] = ( specific_power - (velocity * acceleration) / gravity + ) def setup_partials(self): arange = np.arange(self.options['num_nodes']) - self.declare_partials(Dynamic.Mission.ALTITUDE_RATE, - [Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.VELOCITY], - rows=arange, - cols=arange, - val=1) + self.declare_partials( + Dynamic.Mission.ALTITUDE_RATE, + [ + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.VELOCITY_RATE, + Dynamic.Mission.VELOCITY, + ], + rows=arange, + cols=arange, + val=1, + ) def compute_partials(self, inputs, J): gravity = constants.GRAV_METRIC_FLOPS acceleration = inputs[Dynamic.Mission.VELOCITY_RATE] velocity = inputs[Dynamic.Mission.VELOCITY] - J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY_RATE] = -velocity / gravity - J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = -acceleration / gravity + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY_RATE] = ( + -velocity / gravity + ) + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = ( + -acceleration / gravity + ) diff --git a/aviary/mission/ode/specific_energy_rate.py b/aviary/mission/ode/specific_energy_rate.py index 41002d0df..2046a8e5e 100644 --- a/aviary/mission/ode/specific_energy_rate.py +++ b/aviary/mission/ode/specific_energy_rate.py @@ -20,50 +20,68 @@ def setup(self): Dynamic.Mission.VELOCITY, val=np.ones(nn), desc='current velocity', - units='m/s') + units='m/s', + ) self.add_input( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, val=np.ones(nn), desc='current mass', units='kg') - self.add_input(Dynamic.Mission.THRUST_TOTAL, val=np.ones(nn), + self.add_input(Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=np.ones(nn), desc='current thrust', units='N') self.add_input( - Dynamic.Mission.DRAG, + Dynamic.Vehicle.DRAG, val=np.ones(nn), desc='current drag', units='N') - self.add_output(Dynamic.Mission.SPECIFIC_ENERGY_RATE, val=np.ones( - nn), desc='current specific power', units='m/s') + self.add_output( + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + val=np.ones(nn), + desc='current specific power', + units='m/s', + ) def compute(self, inputs, outputs): velocity = inputs[Dynamic.Mission.VELOCITY] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] - weight = inputs[Dynamic.Mission.MASS] * gravity - outputs[Dynamic.Mission.SPECIFIC_ENERGY_RATE] = velocity * \ - (thrust - drag) / weight + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * gravity + outputs[Dynamic.Mission.SPECIFIC_ENERGY_RATE] = ( + velocity * (thrust - drag) / weight + ) def setup_partials(self): arange = np.arange(self.options['num_nodes']) - self.declare_partials(Dynamic.Mission.SPECIFIC_ENERGY_RATE, - [Dynamic.Mission.VELOCITY, - Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.DRAG], - rows=arange, - cols=arange) + self.declare_partials( + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + [ + Dynamic.Mission.VELOCITY, + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.DRAG, + ], + rows=arange, + cols=arange, + ) def compute_partials(self, inputs, J): velocity = inputs[Dynamic.Mission.VELOCITY] - thrust = inputs[Dynamic.Mission.THRUST_TOTAL] - drag = inputs[Dynamic.Mission.DRAG] - weight = inputs[Dynamic.Mission.MASS] * gravity + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] + drag = inputs[Dynamic.Vehicle.DRAG] + weight = inputs[Dynamic.Vehicle.MASS] * gravity - J[Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.VELOCITY] = (thrust - drag) / weight - J[Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.THRUST_TOTAL] = velocity / weight - J[Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.DRAG] = -velocity / weight - J[Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.MASS] = -gravity\ - * velocity * (thrust - drag) / (weight)**2 + J[Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.VELOCITY] = ( + thrust - drag + ) / weight + J[ + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + ] = ( + velocity / weight + ) + J[Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Vehicle.DRAG] = ( + -velocity / weight + ) + J[Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Vehicle.MASS] = ( + -gravity * velocity * (thrust - drag) / (weight) ** 2 + ) diff --git a/aviary/mission/ode/test/test_altitude_rate.py b/aviary/mission/ode/test/test_altitude_rate.py index e6d33d548..20c43fc26 100644 --- a/aviary/mission/ode/test/test_altitude_rate.py +++ b/aviary/mission/ode/test/test_altitude_rate.py @@ -27,15 +27,19 @@ def setUp(self): def test_case1(self): - do_validation_test(self.prob, - 'full_mission_test_data', - input_validation_data=data, - output_validation_data=data, - input_keys=[Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.VELOCITY, - Dynamic.Mission.VELOCITY_RATE], - output_keys=Dynamic.Mission.ALTITUDE_RATE, - tol=1e-9) + do_validation_test( + self.prob, + 'full_mission_test_data', + input_validation_data=data, + output_validation_data=data, + input_keys=[ + Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.VELOCITY, + Dynamic.Mission.VELOCITY_RATE, + ], + output_keys=Dynamic.Mission.ALTITUDE_RATE, + tol=1e-9, + ) def test_IO(self): assert_match_varnames(self.prob.model) diff --git a/aviary/mission/ode/test/test_specific_energy_rate.py b/aviary/mission/ode/test/test_specific_energy_rate.py index 3618e4c29..103860b48 100644 --- a/aviary/mission/ode/test/test_specific_energy_rate.py +++ b/aviary/mission/ode/test/test_specific_energy_rate.py @@ -27,16 +27,20 @@ def setUp(self): def test_case1(self): - do_validation_test(self.prob, - 'full_mission_test_data', - input_validation_data=data, - output_validation_data=data, - input_keys=[Dynamic.Mission.DRAG, - Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.VELOCITY], - output_keys=Dynamic.Mission.SPECIFIC_ENERGY_RATE, - tol=1e-12) + do_validation_test( + self.prob, + 'full_mission_test_data', + input_validation_data=data, + output_validation_data=data, + input_keys=[ + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.MASS, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Mission.VELOCITY, + ], + output_keys=Dynamic.Mission.SPECIFIC_ENERGY_RATE, + tol=1e-12, + ) def test_IO(self): assert_match_varnames(self.prob.model) diff --git a/aviary/mission/phase_builder_base.py b/aviary/mission/phase_builder_base.py index 11375cee4..c468db885 100644 --- a/aviary/mission/phase_builder_base.py +++ b/aviary/mission/phase_builder_base.py @@ -483,14 +483,14 @@ def add_mass_state(self, user_options): mass_ref0 = user_options.get_val('mass_ref0', units='lbm') mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') self.phase.add_state( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, fix_initial=user_options.get_val('fix_initial'), fix_final=False, lower=mass_lower, upper=mass_upper, units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, + rate_source=Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Vehicle.MASS, ref=mass_ref, ref0=mass_ref0, defect_ref=mass_defect_ref, diff --git a/aviary/mission/test/__init__.py b/aviary/mission/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/mission/test/test_external_mission.py b/aviary/mission/test/test_external_mission.py new file mode 100644 index 000000000..e2f8eca85 --- /dev/null +++ b/aviary/mission/test/test_external_mission.py @@ -0,0 +1,135 @@ +""" +Test for some features when using an external subsystem in the mission. +""" +from copy import deepcopy +import unittest + +import numpy as np +import openmdao.api as om +from openmdao.utils.assert_utils import assert_near_equal + +from aviary.interface.methods_for_level2 import AviaryProblem + +from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase +from aviary.utils.csv_data_file import read_data_file +from aviary.interface.default_phase_info.height_energy import phase_info +from aviary.variable_info.variables import Aircraft + + +# The drag-polar-generating component reads this in, instead of computing the polars. +polar_file = "subsystems/aerodynamics/gasp_based/data/large_single_aisle_1_aero_free_reduced_alpha.txt" + +phase_info = deepcopy(phase_info) + +phase_info['pre_mission']['include_takeoff'] = False +phase_info['post_mission']['include_landing'] = False +phase_info.pop('climb') +phase_info.pop('descent') + + +class TestSolvedAero(unittest.TestCase): + + def test_mission_solver(self): + + local_phase_info = deepcopy(phase_info) + local_phase_info['cruise']['external_subsystems'] = [ + SolverBuilder(name='solve_me')] + + prob = AviaryProblem() + + prob.load_inputs( + "subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv", local_phase_info) + + # Preprocess inputs + prob.check_and_preprocess_inputs() + + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + + prob.link_phases() + + prob.setup() + + prob.set_initial_guesses() + + prob.run_model() + + self.assertTrue(hasattr( + prob.model.traj.phases.cruise.rhs_all.solver_sub.external_subsystems, + "solve_me" + )) + + def test_no_mission_solver(self): + + local_phase_info = deepcopy(phase_info) + local_phase_info['cruise']['external_subsystems'] = [ + NoSolverBuilder(name='do_not_solve_me')] + + prob = AviaryProblem() + + prob.load_inputs( + "subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv", + local_phase_info + ) + + # Preprocess inputs + prob.check_and_preprocess_inputs() + + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + + prob.link_phases() + + prob.setup() + + prob.set_initial_guesses() + + prob.run_model() + + self.assertTrue(hasattr( + prob.model.traj.phases.cruise.rhs_all.external_subsystems, + "do_not_solve_me" + )) + + +class ExternNoSolve(om.ExplicitComponent): + """ + This component should not have a solver above it. + """ + + def setup(self): + self.add_input(Aircraft.Wing.AREA, 1.0, units='ft**2') + self.add_output("stuff", 1.0, units='ft**2') + + def compute(self, inputs, outputs): + pass + + +class NoSolverBuilder(SubsystemBuilderBase): + """ + Mission only. No solver. + """ + + def needs_mission_solver(self, aviary_options): + return False + + def build_mission(self, num_nodes, aviary_inputs): + return ExternNoSolve() + + +class SolverBuilder(SubsystemBuilderBase): + """ + Mission only. No solver. + """ + + def needs_mission_solver(self, aviary_options): + return True + + def build_mission(self, num_nodes, aviary_inputs): + return ExternNoSolve() + + +if __name__ == "__main__": + unittest.main() diff --git a/aviary/mission/twodof_phase.py b/aviary/mission/twodof_phase.py index 21a96954d..15f2068f1 100644 --- a/aviary/mission/twodof_phase.py +++ b/aviary/mission/twodof_phase.py @@ -79,7 +79,7 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.add_timeseries_output("EAS", units="kn") phase.add_timeseries_output(Dynamic.Mission.VELOCITY, units="kn") - phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output(Dynamic.Vehicle.LIFT) return phase diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index 4b4d66971..a3452f39d 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -20,10 +20,10 @@ from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.aviary_values import AviaryValues from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems, get_default_mission_subsystems -from aviary.utils.preprocessors import preprocess_options from aviary.utils.functions import get_path from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings from aviary.variable_info.enums import EquationsOfMotion, LegacyCode +# from aviary.utils.preprocessors import preprocess_options N3CC = {} inputs = N3CC['inputs'] = AviaryValues() @@ -62,15 +62,20 @@ # Crew and Payload # --------------------------- +inputs.set_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, 20) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, 16) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, 154, units='unitless') +inputs.set_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, 118) +inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 20) +inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 16) +inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 154, units='unitless') +inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 118) + inputs.set_val(Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 35.0, 'lbm') inputs.set_val(Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, 0.0) inputs.set_val(Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER, 1.0) inputs.set_val(Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 20) -inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 16) inputs.set_val(Aircraft.CrewPayload.MISC_CARGO, 0., 'lbm') -inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 154, units='unitless') -inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 118) inputs.set_val(Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER, 1.) inputs.set_val(Aircraft.CrewPayload.MASS_PER_PASSENGER, 165., 'lbm') inputs.set_val(Aircraft.CrewPayload.WING_CARGO, 0., 'lbm') @@ -241,7 +246,7 @@ inputs.set_val(Aircraft.Wing.AREA, 1220.0, 'ft**2') inputs.set_val(Aircraft.Wing.ASPECT_RATIO, 11.5587605382765) inputs.set_val(Aircraft.Wing.ASPECT_RATIO_REF, 11.5587605382765) -inputs.set_val(Aircraft.Wing.BENDING_MASS_SCALER, 1.0) +inputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, 1.0) inputs.set_val( Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, np.array( @@ -426,8 +431,8 @@ outputs.set_val(Aircraft.VerticalTail.FINENESS, 0.1000) outputs.set_val(Aircraft.VerticalTail.MASS, 1175.0, 'lbm') -outputs.set_val(Aircraft.Wing.BENDING_FACTOR, 11.9602) -outputs.set_val(Aircraft.Wing.BENDING_MASS, 5410.5, 'lbm') +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 11.9602) +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 5410.5, 'lbm') outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 10.27, 'ft') outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 0.333 * 1220, 'ft**2') outputs.set_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 0.960516) @@ -442,7 +447,9 @@ # Create engine model engine = build_engine_deck(aviary_options=inputs) -preprocess_options(inputs, engine_models=engine) +# Calls to preprocess_options() in this location should be avoided because they +# # will trigger when get_flops_inputs() is imported +# preprocess_options(inputs, engine_models=engine) # build subsystems default_premission_subsystems = get_default_premission_subsystems('FLOPS', engine) @@ -452,29 +459,44 @@ takeoff_trajectory_builder = TakeoffTrajectory('detailed_takeoff') # region - takeoff aero -takeoff_subsystem_options = {'core_aerodynamics': - {'method': 'low_speed', - 'ground_altitude': 0., # units='m' - 'angles_of_attack': [ - 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, - 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, - 12.0, 13.0, 14.0, 15.0], # units='deg' - 'lift_coefficients': [ - 0.5178, 0.6, 0.75, 0.85, 0.95, 1.05, - 1.15, 1.25, 1.35, 1.5, 1.6, 1.7, - 1.8, 1.85, 1.9, 1.95], - 'drag_coefficients': [ - 0.0674, 0.065, 0.065, 0.07, 0.072, 0.076, - 0.084, 0.09, 0.10, 0.11, 0.12, 0.13, - 0.15, 0.16, 0.18, 0.20], - 'lift_coefficient_factor': 1., - 'drag_coefficient_factor': 1.}} - -takeoff_subsystem_options_spoilers = {'core_aerodynamics': - {**takeoff_subsystem_options['core_aerodynamics'], - 'use_spoilers': True, - 'spoiler_drag_coefficient': inputs.get_val(Mission.Takeoff.SPOILER_DRAG_COEFFICIENT), - 'spoiler_lift_coefficient': inputs.get_val(Mission.Takeoff.SPOILER_LIFT_COEFFICIENT)}} +# block auto-formatting of tables +# autopep8: off +# fmt: off +takeoff_subsystem_options = { + 'core_aerodynamics': { + 'method': 'low_speed', + 'ground_altitude': 0.0, # units='m' + 'angles_of_attack': [ + 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, + 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, + ], # units='deg' + 'lift_coefficients': [ + 0.5178, 0.6, 0.75, 0.85, 0.95, 1.05, 1.15, 1.25, + 1.35, 1.5, 1.6, 1.7, 1.8, 1.85, 1.9, 1.95, + ], + 'drag_coefficients': [ + 0.0674, 0.065, 0.065, 0.07, 0.072, 0.076, 0.084, 0.09, + 0.10, 0.11, 0.12, 0.13, 0.15, 0.16, 0.18, 0.20, + ], + 'lift_coefficient_factor': 1.0, + 'drag_coefficient_factor': 1.0, + } +} +# autopep8: on +# fmt: on + +takeoff_subsystem_options_spoilers = { + 'core_aerodynamics': { + **takeoff_subsystem_options['core_aerodynamics'], + 'use_spoilers': True, + 'spoiler_drag_coefficient': inputs.get_val( + Mission.Takeoff.SPOILER_DRAG_COEFFICIENT + ), + 'spoiler_lift_coefficient': inputs.get_val( + Mission.Takeoff.SPOILER_LIFT_COEFFICIENT + ), + } +} # endregion - takeoff aero @@ -589,7 +611,8 @@ takeoff_liftoff_initial_guesses.set_val('throttle', 1.) takeoff_liftoff_initial_guesses.set_val('altitude', [0, 35.0], 'ft') takeoff_liftoff_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, [0, 6.0], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [0, 6.0], 'deg' +) takeoff_liftoff_initial_guesses.set_val('angle_of_attack', 8.117, 'deg') takeoff_liftoff_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -632,7 +655,8 @@ takeoff_mic_p2_initial_guesses.set_val('throttle', 1.) takeoff_mic_p2_initial_guesses.set_val('altitude', [35, 985.0], 'ft') takeoff_mic_p2_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, [7.0, 10.0], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [7.0, 10.0], 'deg' +) takeoff_mic_p2_initial_guesses.set_val('angle_of_attack', 8.117, 'deg') takeoff_mic_p2_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -687,7 +711,8 @@ takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val('altitude', [985, 2500.0], 'ft') takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, [11.0, 10.0], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [11.0, 10.0], 'deg' +) takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val('angle_of_attack', 5.0, 'deg') @@ -742,7 +767,8 @@ takeoff_engine_cutback_initial_guesses.set_val('altitude', [2500.0, 2600.0], 'ft') takeoff_engine_cutback_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, [10.0, 10.0], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [10.0, 10.0], 'deg' +) takeoff_engine_cutback_initial_guesses.set_val('angle_of_attack', 5.0, 'deg') takeoff_engine_cutback_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -803,7 +829,8 @@ 'altitude', [2600, 2700.0], 'ft') takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, 2.29, 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, 2.29, 'deg' +) takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val('angle_of_attack', 5.0, 'deg') takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val( @@ -850,7 +877,8 @@ takeoff_mic_p1_to_climb_initial_guesses.set_val('throttle', cutback_throttle) takeoff_mic_p1_to_climb_initial_guesses.set_val('altitude', [2700, 3200.0], 'ft') takeoff_mic_p1_to_climb_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, 2.29, 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, 2.29, 'deg' +) takeoff_mic_p1_to_climb_initial_guesses.set_val('angle_of_attack', 5.0, 'deg') takeoff_mic_p1_to_climb_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -876,14 +904,15 @@ detailed_takeoff.set_val(Dynamic.Mission.ALTITUDE, [0.00, 0.00, 0.64, 27.98], 'ft') velocity = np.array([4.74, 157.58, 160.99, 166.68]) detailed_takeoff.set_val(Dynamic.Mission.VELOCITY, velocity, 'kn') -detailed_takeoff.set_val(Dynamic.Mission.MACH, [0.007, 0.2342, 0.2393, 0.2477]) +detailed_takeoff.set_val(Dynamic.Atmosphere.MACH, [0.007, 0.2342, 0.2393, 0.2477]) detailed_takeoff.set_val( - Dynamic.Mission.THRUST_TOTAL, [44038.8, 34103.4, 33929.0, 33638.2], 'lbf') + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, [44038.8, 34103.4, 33929.0, 33638.2], 'lbf') detailed_takeoff.set_val('angle_of_attack', [0.000, 3.600, 8.117, 8.117], 'deg') -detailed_takeoff.set_val(Dynamic.Mission.FLIGHT_PATH_ANGLE, [ - 0.000, 0.000, 0.612, 4.096], 'deg') +detailed_takeoff.set_val( + Dynamic.Mission.FLIGHT_PATH_ANGLE, [0.000, 0.000, 0.612, 4.096], 'deg' +) # missing from the default FLOPS output generated by hand # RANGE_RATE = VELOCITY * cos(flight_path_angle) @@ -901,7 +930,7 @@ # NOTE FLOPS output is based on "constant" takeoff mass - assume gross weight # - currently neglecting taxi -detailed_takeoff.set_val(Dynamic.Mission.MASS, [ +detailed_takeoff.set_val(Dynamic.Vehicle.MASS, [ 129734., 129734., 129734., 129734.], 'lbm') lift_coeff = np.array([0.5580, 0.9803, 1.4831, 1.3952]) @@ -915,10 +944,10 @@ RHV2 = 0.5 * rho * v * v * S lift = RHV2 * lift_coeff # N -detailed_takeoff.set_val(Dynamic.Mission.LIFT, lift, 'N') +detailed_takeoff.set_val(Dynamic.Vehicle.LIFT, lift, 'N') drag = RHV2 * drag_coeff # N -detailed_takeoff.set_val(Dynamic.Mission.DRAG, drag, 'N') +detailed_takeoff.set_val(Dynamic.Vehicle.DRAG, drag, 'N') def _split_aviary_values(aviary_values, slicing): @@ -1043,7 +1072,8 @@ def _split_aviary_values(aviary_values, slicing): balanced_liftoff_initial_guesses.set_val('throttle', engine_out_throttle) balanced_liftoff_initial_guesses.set_val('altitude', [0., 35.], 'ft') balanced_liftoff_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, [0., 5.], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [0.0, 5.0], 'deg' +) balanced_liftoff_initial_guesses.set_val('angle_of_attack', 8.117, 'deg') balanced_liftoff_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -1151,105 +1181,127 @@ def _split_aviary_values(aviary_values, slicing): detailed_landing = AviaryValues() -values = np.array([ - -4.08, -4.08, -3.92, -3.76, -3.59, -3.43, -3.27, -3.1, -2.94, -2.78, - -2.61, -2.45, -2.29, -2.12, -1.96, -1.8, -1.63, -1.47, -1.31, -1.14, - -0.98, -0.82, -0.65, -0.49, -0.33, -0.16, 0, 0.16, 0.33, 0.49, - 0.65, 0.82, 0.98, 1.14, 1.31, 1.47, 1.63, 1.8, 1.96, 2.12, - 2.29, 2.45, 2.61, 2.78, 2.94, 3.1, 3.13, 3.92, 4.97, 5.68, - 5.93, 6.97, 7.97, 8.97, 9.97, 10.97, 11.97, 12.97, 13.97, 14.97, - 15.97, 16.97, 17.97, 18.97, 19.97, 20.97, 21.97, 22.97, 23.97, 24.49]) +# block auto-formatting of tables +# autopep8: off +# fmt: off +values = np.array( + [ + -4.08, -4.08, -3.92, -3.76, -3.59, -3.43, -3.27, -3.1, -2.94, -2.78, -2.61, + -2.45, -2.29, -2.12, -1.96, -1.8, -1.63, -1.47, -1.31, -1.14, -0.98, -0.82, + -0.65, -0.49, -0.33, -0.16, 0, 0.16, 0.33, 0.49, 0.65, 0.82, 0.98, 1.14, 1.31, + 1.47, 1.63, 1.8, 1.96, 2.12, 2.29, 2.45, 2.61, 2.78, 2.94, 3.1, 3.13, 3.92, 4.97, + 5.68, 5.93, 6.97, 7.97, 8.97, 9.97, 10.97, 11.97, 12.97, 13.97, 14.97, 15.97, + 16.97, 17.97, 18.97, 19.97, 20.97, 21.97, 22.97, 23.97, 24.49 + ] +) base = values[0] values = values - base detailed_landing.set_val('time', values, 's') -values = np.array([ - -954.08, -954.06, -915.89, -877.73, -839.57, -801.41, -763.25, -725.08, - -686.92, -648.76, -610.6, -572.43, -534.27, -496.11, -457.95, -419.78, - -381.62, -343.46, -305.3, -267.14, -228.97, -190.81, -152.65, -114.49, - -76.32, -38.16, 0, 38.16, 76.32, 114.49, 152.65, 190.81, - 228.97, 267.14, 305.3, 343.46, 381.62, 419.78, 457.95, 496.11, - 534.27, 572.43, 610.6, 648.76, 686.92, 725.08, 731.46, 917.22, - 1160.47, 1324.21, 1381.29, 1610.61, 1817.53, 2010.56, 2190, 2356.17, - 2509.36, 2649.84, 2777.85, 2893.6, 2997.28, 3089.05, 3169.07, 3237.45, - 3294.31, 3339.73, 3373.78, 3396.51, 3407.96, 3409.47]) +values = np.array( + [ + -954.08, -954.06, -915.89, -877.73, -839.57, -801.41, -763.25, -725.08, -686.92, + -648.76, -610.6, -572.43, -534.27, -496.11, -457.95, -419.78, -381.62, -343.46, + -305.3, -267.14, -228.97, -190.81, -152.65, -114.49, -76.32, -38.16, 0, 38.16, + 76.32, 114.49, 152.65, 190.81, 228.97, 267.14, 305.3, 343.46, 381.62, 419.78, + 457.95, 496.11, 534.27, 572.43, 610.6, 648.76, 686.92, 725.08, 731.46, 917.22, + 1160.47, 1324.21, 1381.29, 1610.61, 1817.53, 2010.56, 2190, 2356.17, + 2509.36, 2649.84, 2777.85, 2893.6, 2997.28, 3089.05, 3169.07, 3237.45, + 3294.31, 3339.73, 3373.78, 3396.51, 3407.96, 3409.47 + ] +) +# autopep8: on +# fmt: on base = values[0] values = values - base detailed_landing.set_val(Dynamic.Mission.DISTANCE, values, 'ft') +# block auto-formatting of tables +# autopep8: off +# fmt: off detailed_landing.set_val( Dynamic.Mission.ALTITUDE, [ - 100, 100, 98, 96, 94, 92, 90, 88, 86, 84, - 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, - 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, - 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, - 22, 20, 18, 16, 14, 12, 11.67, 2.49, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - 'ft') + 100, 100, 98, 96, 94, 92, 90, 88, 86, 84, 80, 78, 76, 74, 72, 70, 68, 66, 64, 62, + 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, + 20, 18, 16, 14, 12, 11.67, 2.49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + ], + 'ft', +) detailed_landing.set_val( Dynamic.Mission.VELOCITY, - np.array([ - 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, - 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, - 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, - 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, - 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.6, 137.18, 136.12, - 134.43, 126.69, 118.46, 110.31, 102.35, 94.58, 86.97, 79.52, 72.19, 64.99, - 57.88, 50.88, 43.95, 37.09, 30.29, 23.54, 16.82, 10.12, 3.45, 0]), - 'kn') + np.array( + [ + 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, + 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, + 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, + 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, + 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, + 138.65, 138.65, 138.60, 137.18, 136.12, 134.43, 126.69, 118.46, 110.31, + 102.35, 94.58, 86.97, 79.52, 72.19, 64.99, 57.88, 50.88, 43.95, 37.09, + 30.29, 23.54, 16.82, 10.12, 3.45, 0 + ] + ), + 'kn', +) detailed_landing.set_val( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, [ 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, - 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.206, 0.2039, 0.2023, + 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2060, 0.2039, 0.2023, 0.1998, 0.1883, 0.1761, 0.1639, 0.1521, 0.1406, 0.1293, 0.1182, 0.1073, 0.0966, - 0.086, 0.0756, 0.0653, 0.0551, 0.045, 0.035, 0.025, 0.015, 0.0051, 0]) + 0.086, 0.0756, 0.0653, 0.0551, 0.045, 0.035, 0.025, 0.015, 0.0051, 0, + ], +) detailed_landing.set_val( - Dynamic.Mission.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, [ - 7614, 7614, 7607.7, 7601, 7593.9, 7586.4, 7578.5, 7570.2, 7561.3, 7551.8, - 7541.8, 7531.1, 7519.7, 7507.6, 7494.6, 7480.6, 7465.7, 7449.7, 7432.5, 7414, - 7394, 7372.3, 7348.9, 7323.5, 7295.9, 7265.8, 7233, 7197.1, 7157.7, 7114.3, + 7614.0, 7614.0, 7607.7, 7601.0, 7593.9, 7586.4, 7578.5, 7570.2, 7561.3, 7551.8, + 7541.8, 7531.1, 7519.7, 7507.6, 7494.6, 7480.6, 7465.7, 7449.7, 7432.5, 7414.0, + 7394.0, 7372.3, 7348.9, 7323.5, 7295.9, 7265.8, 7233.0, 7197.1, 7157.7, 7114.3, 7066.6, 7013.8, 6955.3, 6890.2, 6817.7, 6736.7, 6645.8, 6543.5, 6428.2, 6297.6, - 6149.5, 5980.9, 5788.7, 5569.3, 5318.5, 5032, 4980.3, 4102, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - 'lbf') + 6149.5, 5980.9, 5788.7, 5569.3, 5318.5, 5032.0, 4980.3, 4102, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + 'lbf', +) detailed_landing.set_val( 'angle_of_attack', [ - 5.231, 5.231, 5.231, 5.23, 5.23, 5.23, 5.23, 5.23, 5.229, 5.229, - 5.229, 5.229, 5.228, 5.228, 5.227, 5.227, 5.227, 5.226, 5.226, 5.225, - 5.224, 5.224, 5.223, 5.222, 5.221, 5.22, 5.219, 5.218, 5.217, 5.215, - 5.214, 5.212, 5.21, 5.207, 5.204, 5.201, 5.197, 5.193, 5.187, 5.181, - 5.173, 5.163, 5.151, 5.136, 5.117, 5.091, 5.086, 6.834, 5.585, 4.023, - 3.473, 1.185, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + 5.231, 5.231, 5.231, 5.23, 5.23, 5.23, 5.23, 5.23, 5.229, 5.229, 5.229, 5.229, + 5.228, 5.228, 5.227, 5.227, 5.227, 5.226, 5.226, 5.225, 5.224, 5.224, 5.223, + 5.222, 5.221, 5.22, 5.219, 5.218, 5.217, 5.215, 5.214, 5.212, 5.21, 5.207, 5.204, + 5.201, 5.197, 5.193, 5.187, 5.181, 5.173, 5.163, 5.151, 5.136, 5.117, 5.091, + 5.086, 6.834, 5.585, 4.023, 3.473, 1.185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ], 'deg') # glide slope == flight path angle? detailed_landing.set_val( Dynamic.Mission.FLIGHT_PATH_ANGLE, - np.array([ - -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, - -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, - -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, - -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, - -3, -3, -3, -3, -3, -3, -3, -2.47, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - 'deg') + np.array( + [ + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, + -3, -3, -3, -3, -3, -3, -3, -3, -3, -2.47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] + ), + 'deg', +) +# autopep8: on +# fmt: on # missing from the default FLOPS output generated by script # RANGE_RATE = VELOCITY * cos(flight_path_angle) @@ -1270,26 +1322,37 @@ def _split_aviary_values(aviary_values, slicing): detailed_landing_mass = 106292. # units='lbm' detailed_landing.set_val( - Dynamic.Mission.MASS, np.full(velocity.shape, detailed_landing_mass), 'lbm') + Dynamic.Vehicle.MASS, np.full(velocity.shape, detailed_landing_mass), 'lbm') +# block auto-formatting of tables +# autopep8: off +# fmt: off # lift/drag is calculated very close to landing altitude (sea level, in this case)... -lift_coeff = np.array([ - 1.4091, 1.4091, 1.4091, 1.4091, 1.4092, 1.4092, 1.4092, 1.4092, 1.4092, 1.4092, - 1.4092, 1.4092, 1.4092, 1.4093, 1.4093, 1.4093, 1.4093, 1.4093, 1.4094, 1.4094, - 1.4094, 1.4094, 1.4095, 1.4095, 1.4095, 1.4096, 1.4096, 1.4096, 1.4097, 1.4097, - 1.4098, 1.4099, 1.4099, 1.41, 1.4101, 1.4102, 1.4103, 1.4105, 1.4106, 1.4108, - 1.4109, 1.4112, 1.4114, 1.4117, 1.412, 1.4124, 1.4124, 1.6667, 1.595, 1.397, - 0.5237, 0.2338, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, - 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046]) - -drag_coeff = np.array([ - 0.1731, 0.1731, 0.173, 0.173, 0.1729, 0.1728, 0.1727, 0.1726, 0.1724, 0.1723, - 0.1722, 0.1721, 0.1719, 0.1718, 0.1716, 0.1714, 0.1712, 0.171, 0.1708, 0.1705, - 0.1703, 0.17, 0.1697, 0.1694, 0.169, 0.1686, 0.1682, 0.1677, 0.1672, 0.1666, - 0.166, 0.1653, 0.1646, 0.1637, 0.1628, 0.1618, 0.1606, 0.1592, 0.1577, 0.1561, - 0.1541, 0.1519, 0.1495, 0.1466, 0.1434, 0.1396, 0.139, 0.13, 0.1207, 0.1099, - 0.1922, 0.1827, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, - 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785]) +lift_coeff = np.array( + [ + 1.4091, 1.4091, 1.4091, 1.4091, 1.4092, 1.4092, 1.4092, 1.4092, 1.4092, 1.4092, + 1.4092, 1.4092, 1.4092, 1.4093, 1.4093, 1.4093, 1.4093, 1.4093, 1.4094, 1.4094, + 1.4094, 1.4094, 1.4095, 1.4095, 1.4095, 1.4096, 1.4096, 1.4096, 1.4097, 1.4097, + 1.4098, 1.4099, 1.4099, 1.41, 1.4101, 1.4102, 1.4103, 1.4105, 1.4106, 1.4108, + 1.4109, 1.4112, 1.4114, 1.4117, 1.412, 1.4124, 1.4124, 1.6667, 1.595, 1.397, + 0.5237, 0.2338, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, + 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046, 0.046 + ] +) + +drag_coeff = np.array( + [ + 0.1731, 0.1731, 0.173, 0.173, 0.1729, 0.1728, 0.1727, 0.1726, 0.1724, 0.1723, + 0.1722, 0.1721, 0.1719, 0.1718, 0.1716, 0.1714, 0.1712, 0.171, 0.1708, 0.1705, + 0.1703, 0.17, 0.1697, 0.1694, 0.169, 0.1686, 0.1682, 0.1677, 0.1672, 0.1666, + 0.166, 0.1653, 0.1646, 0.1637, 0.1628, 0.1618, 0.1606, 0.1592, 0.1577, 0.1561, + 0.1541, 0.1519, 0.1495, 0.1466, 0.1434, 0.1396, 0.139, 0.13, 0.1207, 0.1099, + 0.1922, 0.1827, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, + 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785 + ] +) +# autopep8: on +# fmt: on S = inputs.get_val(Aircraft.Wing.AREA, 'm**2') v = detailed_landing.get_val(Dynamic.Mission.VELOCITY, 'm/s') @@ -1299,10 +1362,10 @@ def _split_aviary_values(aviary_values, slicing): RHV2 = 0.5 * rho * v * v * S lift = RHV2 * lift_coeff # N -detailed_landing.set_val(Dynamic.Mission.LIFT, lift, 'N') +detailed_landing.set_val(Dynamic.Vehicle.LIFT, lift, 'N') drag = RHV2 * drag_coeff # N -detailed_landing.set_val(Dynamic.Mission.DRAG, drag, 'N') +detailed_landing.set_val(Dynamic.Vehicle.DRAG, drag, 'N') # Flops variable APRANG apr_angle = -3.0 # deg @@ -1343,7 +1406,8 @@ def _split_aviary_values(aviary_values, slicing): landing_approach_to_mic_p3_initial_guesses.set_val('altitude', [600., 394.], 'ft') landing_approach_to_mic_p3_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg' +) landing_approach_to_mic_p3_initial_guesses.set_val('angle_of_attack', 5.25, 'deg') @@ -1394,7 +1458,8 @@ def _split_aviary_values(aviary_values, slicing): landing_mic_p3_to_obstacle_initial_guesses.set_val('altitude', [394., 50.], 'ft') landing_mic_p3_to_obstacle_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg' +) landing_mic_p3_to_obstacle_initial_guesses.set_val('angle_of_attack', 5.25, 'deg') @@ -1432,7 +1497,8 @@ def _split_aviary_values(aviary_values, slicing): landing_obstacle_initial_guesses.set_val('altitude', [50., 15.], 'ft') landing_obstacle_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg' +) landing_obstacle_initial_guesses.set_val('angle_of_attack', 5.2, 'deg') @@ -1473,7 +1539,8 @@ def _split_aviary_values(aviary_values, slicing): landing_flare_initial_guesses.set_val('throttle', [throttle, throttle*4/7]) landing_flare_initial_guesses.set_val('altitude', [15., 0.], 'ft') landing_flare_initial_guesses.set_val( - Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, 0.], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, 0.0], 'deg' +) landing_flare_initial_guesses.set_val('angle_of_attack', [5.2, 7.5], 'deg') landing_flare_builder = LandingFlareToTouchdown( diff --git a/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv b/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv index 5a9b874c6..17d699c42 100644 --- a/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv +++ b/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv @@ -10,16 +10,16 @@ aircraft:canard:laminar_flow_lower,0,unitless aircraft:canard:laminar_flow_upper,0,unitless aircraft:canard:mass_scaler,1,unitless aircraft:crew_and_payload:baggage_mass_per_passenger,35,lbm +aircraft:crew_and_payload:design:num_business_class,20,unitless +aircraft:crew_and_payload:design:num_first_class,16,unitless +aircraft:crew_and_payload:design:num_tourist_class,118,unitless aircraft:crew_and_payload:flight_crew_mass_scaler,1,unitless aircraft:crew_and_payload:mass_per_passenger,165,lbm aircraft:crew_and_payload:misc_cargo,0,lbm aircraft:crew_and_payload:non_flight_crew_mass_scaler,1,unitless -aircraft:crew_and_payload:num_business_class,20,unitless -aircraft:crew_and_payload:num_first_class,16,unitless aircraft:crew_and_payload:num_flight_attendants,-1,unitless aircraft:crew_and_payload:num_flight_crew,-1,unitless aircraft:crew_and_payload:num_galley_crew,-1,unitless -aircraft:crew_and_payload:num_tourist_class,118,unitless aircraft:crew_and_payload:passenger_service_mass_scaler,1,unitless aircraft:crew_and_payload:wing_cargo,0,lbm aircraft:design:base_area,0,ft**2 @@ -46,6 +46,7 @@ aircraft:engine:num_fuselage_engines,0,unitless aircraft:engine:num_wing_engines,2,unitless aircraft:engine:reference_mass,6293.8,lbm aircraft:engine:reference_sls_thrust,22200.5,lbf +aircraft:engine:scale_factor,0.99997747798473,unitless aircraft:engine:scaled_sls_thrust,22200,0,0,0,0,0,lbf aircraft:engine:subsonic_fuel_flow_scaler,1,unitless aircraft:engine:supersonic_fuel_flow_scaler,1,unitless @@ -115,7 +116,7 @@ aircraft:wing:airfoil_technology,1.6,unitless aircraft:wing:area,1220,1,0,0,0,0,ft**2 aircraft:wing:aspect_ratio,11.5587605382765,1,0,0,0,0,unitless aircraft:wing:aspect_ratio_reference,11.5587605382765,unitless -aircraft:wing:bending_mass_scaler,1,unitless +aircraft:wing:BENDING_MATERIAL_MASS_SCALER,1,unitless aircraft:wing:bwb_aft_body_mass_scaler,1,unitless aircraft:wing:chord_per_semispan,0.273522534166506,0.204274849507037,0.0888152947868224,0.0725353313595661,unitless aircraft:wing:composite_fraction,0.33333,unitless diff --git a/aviary/models/engines/turboshaft_4465hp.deck b/aviary/models/engines/turboshaft_4465hp.deck index 23f1ddba8..568d62045 100644 --- a/aviary/models/engines/turboshaft_4465hp.deck +++ b/aviary/models/engines/turboshaft_4465hp.deck @@ -1,4 +1,4 @@ -# GASP_TS-derived engine deck converted from turboshaft_4465hp.eng +# GASP-derived turboshaft engine deck converted from turboshaft_4465hp.eng # t4max: 50.0 # t4cruise: 45.0 # t4climb: 50.0 @@ -13,2179 +13,1771 @@ # sls_corrected_airflow: 30.5 Mach_Number, Altitude (ft), Throttle, Shaft_Power_Corrected (hp), Tailpipe_Thrust (lbf), Fuel_Flow (lb/h) - 0.0, 0.0, 26.0, 794.3999999999999, 618.3999999999999, 1035.8999999999999 - 0.05, 0.0, 26.0, 794.7000000000002, 563.7, 1033.8000000000002 - 0.1, 0.0, 26.0, 794.3, 508.8000000000001, 1027.5000000000007 -0.15000000000000002, 0.0, 26.0, 793.2000000000002, 454.1000000000001, 1016.8 - 0.2, 0.0, 26.0, 791.4, 399.60000000000025, 1001.9999999999999 - 0.25, 0.0, 26.0, 788.1000000000004, 345.4, 983.1000000000009 -0.30000000000000004, 0.0, 26.0, 784.1000000000001, 292.0, 960.5 -0.35000000000000003, 0.0, 26.0, 779.4999999999995, 239.9999999999999, 934.2999999999998 - 0.4, 0.0, 26.0, 773.8999999999988, 189.10000000000008, 904.8000000000008 - 0.45, 0.0, 26.0, 766.7000000000006, 139.39999999999992, 872.3999999999997 - 0.5, 0.0, 26.0, 758.8000000000015, 91.2, 837.2999999999996 - 0.55, 0.0, 26.0, 751.100000000003, 44.80000000000016, 799.6999999999994 - 0.6000000000000001, 0.0, 26.0, 744.5000000000052, 0.5000000000005871, 759.7999999999993 - 0.65, 0.0, 26.0, 739.9000000000082, -41.399999999998585, 717.7999999999993 - 0.7000000000000001, 0.0, 26.0, 738.2000000000118, -80.59999999999746, 673.8999999999996 - 0.75, 0.0, 26.0, 740.3000000000164, -116.79999999999583, 628.3000000000001 - 0.8, 0.0, 26.0, 747.100000000022, -149.69999999999374, 581.200000000001 - 0.0, 0.0, 28.0, 1191.5999999999997, 651.7, 1194.4999999999995 - 0.05, 0.0, 28.0, 1192.0999999999997, 597.0999999999993, 1192.4999999999975 - 0.1, 0.0, 28.0, 1191.5000000000005, 542.3999999999995, 1185.899999999994 -0.15000000000000002, 0.0, 28.0, 1189.7999999999984, 487.79999999999933, 1174.899999999999 - 0.2, 0.0, 28.0, 1186.9999999999964, 433.59999999999894, 1159.5000000000023 - 0.25, 0.0, 28.0, 1182.2000000000012, 379.69999999999965, 1139.7999999999952 -0.30000000000000004, 0.0, 28.0, 1176.0999999999988, 326.6000000000004, 1116.1999999999994 -0.35000000000000003, 0.0, 28.0, 1169.1999999999994, 274.8000000000004, 1088.9000000000017 - 0.4, 0.0, 28.0, 1160.6999999999969, 224.30000000000058, 1058.000000000005 - 0.45, 0.0, 28.0, 1150.100000000001, 174.8999999999994, 1023.900000000005 - 0.5, 0.0, 28.0, 1138.2000000000016, 127.0999999999993, 987.0000000000101 - 0.55, 0.0, 28.0, 1125.8000000000018, 81.39999999999979, 947.7000000000164 - 0.6000000000000001, 0.0, 28.0, 1113.700000000002, 38.30000000000135, 906.4000000000234 - 0.65, 0.0, 28.0, 1102.7000000000025, -1.6999999999956197, 863.5000000000305 - 0.7000000000000001, 0.0, 28.0, 1093.6000000000015, -38.099999999990914, 819.4000000000376 - 0.75, 0.0, 28.0, 1087.2000000000007, -70.39999999998402, 774.5000000000434 - 0.8, 0.0, 28.0, 1084.2999999999981, -98.09999999997468, 729.2000000000479 - 0.0, 0.0, 30.0, 1588.8999999999996, 684.8000000000001, 1353.7999999999993 - 0.05, 0.0, 30.0, 1589.4999999999993, 630.3999999999978, 1351.7999999999934 - 0.1, 0.0, 30.0, 1588.7000000000019, 575.8999999999962, 1345.0999999999865 -0.15000000000000002, 0.0, 30.0, 1586.4999999999966, 521.499999999999, 1333.6999999999996 - 0.2, 0.0, 30.0, 1582.5999999999922, 467.4999999999981, 1317.8000000000077 - 0.25, 0.0, 30.0, 1576.1999999999996, 413.69999999999874, 1297.1999999999828 -0.30000000000000004, 0.0, 30.0, 1568.1999999999978, 360.90000000000094, 1272.6000000000001 -0.35000000000000003, 0.0, 30.0, 1558.9999999999955, 309.4000000000007, 1244.0000000000045 - 0.4, 0.0, 30.0, 1547.699999999982, 259.2000000000002, 1211.8000000000125 - 0.45, 0.0, 30.0, 1533.6000000000042, 210.0999999999986, 1175.9000000000117 - 0.5, 0.0, 30.0, 1517.600000000001, 162.4999999999988, 1136.900000000023 - 0.55, 0.0, 30.0, 1500.5999999999913, 116.80000000000094, 1095.4000000000356 - 0.6000000000000001, 0.0, 30.0, 1483.4999999999702, 73.40000000000593, 1052.0000000000464 - 0.65, 0.0, 30.0, 1467.1999999999348, 32.7000000000148, 1007.3000000000532 - 0.7000000000000001, 0.0, 30.0, 1452.599999999881, -4.8999999999716835, 961.9000000000542 - 0.75, 0.0, 30.0, 1440.5999999998055, -38.999999999952564, 916.400000000046 - 0.8, 0.0, 30.0, 1432.0999999997046, -69.19999999992686, 871.400000000027 - 0.0, 0.0, 32.0, 1986.100000000001, 717.6999999999996, 1513.600000000001 - 0.05, 0.0, 32.0, 1986.9000000000042, 663.4000000000009, 1511.6000000000063 - 0.1, 0.0, 32.0, 1985.9000000000055, 609.1000000000029, 1504.7000000000212 -0.15000000000000002, 0.0, 32.0, 1983.0999999999956, 554.9000000000004, 1492.9999999999945 - 0.2, 0.0, 32.0, 1978.299999999995, 501.10000000000264, 1476.5999999999874 - 0.25, 0.0, 32.0, 1970.200000000027, 447.4999999999964, 1455.2000000000214 -0.30000000000000004, 0.0, 32.0, 1960.1999999999966, 394.9000000000022, 1429.5000000000084 -0.35000000000000003, 0.0, 32.0, 1948.699999999988, 343.7999999999993, 1399.8000000000038 - 0.4, 0.0, 32.0, 1934.599999999947, 293.8999999999996, 1366.1000000000142 - 0.45, 0.0, 32.0, 1916.9000000000524, 245.00000000000563, 1328.4000000000326 - 0.5, 0.0, 32.0, 1897.0000000001098, 198.20000000001303, 1288.8000000000757 - 0.55, 0.0, 32.0, 1876.3000000001823, 154.60000000002424, 1249.4000000001347 - 0.6000000000000001, 0.0, 32.0, 1856.2000000002672, 115.30000000003959, 1212.30000000021 - 0.65, 0.0, 32.0, 1838.1000000003596, 81.40000000005975, 1179.6000000003005 - 0.7000000000000001, 0.0, 32.0, 1823.4000000004567, 54.00000000008495, 1153.4000000004041 - 0.75, 0.0, 32.0, 1813.5000000005543, 34.20000000011595, 1135.8000000005218 - 0.8, 0.0, 32.0, 1809.8000000006484, 23.100000000153102, 1128.9000000006508 - 0.0, 0.0, 34.0, 2383.2999999999993, 750.4000000000004, 1674.2 - 0.05, 0.0, 34.0, 2384.199999999992, 696.2999999999997, 1672.300000000002 - 0.1, 0.0, 34.0, 2383.099999999966, 642.0999999999981, 1665.200000000004 -0.15000000000000002, 0.0, 34.0, 2379.5999999999967, 588.0999999999991, 1653.1000000000013 - 0.2, 0.0, 34.0, 2373.9999999999945, 534.4999999999957, 1636.200000000012 - 0.25, 0.0, 34.0, 2364.299999999955, 481.19999999999845, 1614.1000000000063 -0.30000000000000004, 0.0, 34.0, 2352.200000000006, 428.9000000000019, 1587.3999999999999 -0.35000000000000003, 0.0, 34.0, 2338.5000000000023, 378.0000000000026, 1556.5000000000073 - 0.4, 0.0, 34.0, 2321.600000000001, 328.400000000007, 1521.6000000000197 - 0.45, 0.0, 34.0, 2300.300000000006, 280.50000000000574, 1483.8000000000052 - 0.5, 0.0, 34.0, 2276.4000000000196, 234.20000000001184, 1442.9000000000074 - 0.55, 0.0, 34.0, 2251.700000000041, 189.40000000001965, 1398.700000000003 - 0.6000000000000001, 0.0, 34.0, 2228.0000000000755, 146.00000000002862, 1350.9999999999866 - 0.65, 0.0, 34.0, 2207.100000000123, 103.90000000003882, 1299.5999999999538 - 0.7000000000000001, 0.0, 34.0, 2190.800000000187, 63.000000000049226, 1244.2999999999001 - 0.75, 0.0, 34.0, 2180.90000000027, 23.20000000005996, 1184.8999999998196 - 0.8, 0.0, 34.0, 2179.200000000373, -15.59999999992965, 1121.1999999997092 - 0.0, 0.0, 36.0, 2780.500000000001, 785.0000000000003, 1842.099999999999 - 0.05, 0.0, 36.0, 2781.5999999999995, 731.0999999999974, 1840.1999999999955 - 0.1, 0.0, 36.0, 2780.200000000006, 676.9999999999911, 1832.999999999994 -0.15000000000000002, 0.0, 36.0, 2776.1999999999857, 623.2000000000028, 1820.3999999999862 - 0.2, 0.0, 36.0, 2769.5999999999817, 569.8000000000047, 1802.6999999999653 - 0.25, 0.0, 36.0, 2758.400000000019, 516.5999999999946, 1779.5000000000075 -0.30000000000000004, 0.0, 36.0, 2744.3000000000065, 464.40000000000106, 1751.4000000000015 -0.35000000000000003, 0.0, 36.0, 2728.200000000007, 414.1000000000014, 1720.300000000005 - 0.4, 0.0, 36.0, 2708.5000000000246, 365.20000000000385, 1684.8000000000018 - 0.45, 0.0, 36.0, 2683.6000000000604, 317.400000000008, 1644.9000000000265 - 0.5, 0.0, 36.0, 2655.8000000000998, 271.3000000000183, 1601.6000000000483 - 0.55, 0.0, 36.0, 2627.40000000013, 227.5000000000315, 1555.9000000000656 - 0.6000000000000001, 0.0, 36.0, 2600.700000000137, 186.60000000004715, 1508.8000000000682 - 0.65, 0.0, 36.0, 2578.0000000001087, 149.20000000006468, 1461.3000000000482 - 0.7000000000000001, 0.0, 36.0, 2561.6000000000345, 115.90000000008331, 1414.3999999999967 - 0.75, 0.0, 36.0, 2553.7999999998992, 87.30000000010247, 1369.0999999999046 - 0.8, 0.0, 36.0, 2556.8999999996936, 64.00000000012136, 1326.3999999997632 - 0.0, 0.0, 38.0, 3177.6999999999985, 820.3, 2013.2000000000007 - 0.05, 0.0, 38.0, 3178.999999999995, 766.4000000000009, 2011.3000000000038 - 0.1, 0.0, 38.0, 3177.399999999991, 712.5000000000006, 2003.800000000018 -0.15000000000000002, 0.0, 38.0, 3172.799999999992, 658.7999999999964, 1990.899999999992 - 0.2, 0.0, 38.0, 3165.2999999999884, 605.6999999999906, 1972.8999999999737 - 0.25, 0.0, 38.0, 3152.3999999999733, 552.9999999999947, 1949.6000000000051 -0.30000000000000004, 0.0, 38.0, 3136.300000000012, 501.3000000000025, 1921.40000000001 -0.35000000000000003, 0.0, 38.0, 3117.9000000000324, 451.20000000000147, 1888.800000000004 - 0.4, 0.0, 38.0, 3095.500000000084, 402.7000000000048, 1851.7000000000137 - 0.45, 0.0, 38.0, 3067.000000000039, 355.0000000000085, 1809.7000000000405 - 0.5, 0.0, 38.0, 3035.2000000000885, 309.5000000000235, 1765.0000000000925 - 0.55, 0.0, 38.0, 3002.900000000154, 267.6000000000488, 1719.8000000001648 - 0.6000000000000001, 0.0, 38.0, 2972.9000000002357, 230.70000000008724, 1676.3000000002592 - 0.65, 0.0, 38.0, 2948.0000000003306, 200.20000000014124, 1636.7000000003732 - 0.7000000000000001, 0.0, 38.0, 2931.0000000004366, 177.50000000021322, 1603.2000000005073 - 0.75, 0.0, 38.0, 2924.7000000005523, 164.0000000003058, 1578.000000000662 - 0.8, 0.0, 38.0, 2931.9000000006763, 161.10000000042135, 1563.3000000008367 - 0.0, 0.0, 40.0, 3574.9000000000005, 855.4999999999987, 2185.7999999999993 - 0.05, 0.0, 40.0, 3576.3000000000106, 801.6999999999987, 2184.000000000001 - 0.1, 0.0, 40.0, 3574.5000000000277, 748.1000000000004, 2176.699999999999 -0.15000000000000002, 0.0, 40.0, 3569.400000000006, 694.7000000000066, 2163.9000000000137 - 0.2, 0.0, 40.0, 3561.0000000000164, 642.0000000000198, 2145.600000000041 - 0.25, 0.0, 40.0, 3546.4000000000606, 589.4999999999928, 2121.200000000043 -0.30000000000000004, 0.0, 40.0, 3528.3999999999974, 537.9999999999978, 2091.8999999999924 -0.35000000000000003, 0.0, 40.0, 3507.6999999999994, 488.19999999999754, 2057.9000000000037 - 0.4, 0.0, 40.0, 3482.300000000003, 439.89999999999156, 2019.3000000000188 - 0.45, 0.0, 40.0, 3450.399999999949, 392.9000000000062, 1976.4999999999807 - 0.5, 0.0, 40.0, 3414.5999999998758, 347.70000000001437, 1930.0999999999738 - 0.55, 0.0, 40.0, 3377.4999999997526, 304.8000000000261, 1880.69999999998 - 0.6000000000000001, 0.0, 40.0, 3341.6999999995714, 264.7000000000414, 1828.900000000006 - 0.65, 0.0, 40.0, 3309.79999999932, 227.9000000000601, 1775.3000000000607 - 0.7000000000000001, 0.0, 40.0, 3284.3999999989837, 194.9000000000819, 1720.5000000001526 - 0.75, 0.0, 40.0, 3268.099999998551, 166.20000000010737, 1665.1000000002898 - 0.8, 0.0, 40.0, 3263.4999999980128, 142.30000000013598, 1609.700000000479 - 0.0, 0.0, 42.0, 3798.0720000000024, 875.2782857142853, 2283.190285714286 - 0.05, 0.0, 42.0, 3799.5371428571525, 821.5680000000007, 2281.459428571425 - 0.1, 0.0, 42.0, 3797.654857142873, 768.0862857142888, 2274.138857142845 -0.15000000000000002, 0.0, 42.0, 3792.300571428572, 714.8657142857145, 2261.2485714285663 - 0.2, 0.0, 42.0, 3783.4702857142884, 662.3085714285754, 2242.7314285714187 - 0.25, 0.0, 42.0, 3768.107428571425, 609.8942857142835, 2217.779428571414 -0.30000000000000004, 0.0, 42.0, 3749.2005714285697, 558.5085714285731, 2187.8091428571415 -0.35000000000000003, 0.0, 42.0, 3727.3782857142837, 508.95314285714204, 2153.3948571428546 - 0.4, 0.0, 42.0, 3700.5217142857246, 460.9017142857136, 2114.331428571431 - 0.45, 0.0, 42.0, 3666.8017142857066, 414.2360000000001, 2070.9297142857076 - 0.5, 0.0, 42.0, 3628.9405714285504, 369.25600000000026, 2023.5525714285661 - 0.55, 0.0, 42.0, 3589.66057142853, 326.26171428571485, 1972.5628571428542 - 0.6000000000000001, 0.0, 42.0, 3551.683999999926, 285.5531428571436, 1918.3234285714323 - 0.65, 0.0, 42.0, 3517.733142857028, 247.43028571428658, 1861.1971428571542 - 0.7000000000000001, 0.0, 42.0, 3490.5302857141164, 212.19314285714373, 1801.5468571428787 - 0.75, 0.0, 42.0, 3472.797714285481, 180.14171428571498, 1739.7354285714625 - 0.8, 0.0, 42.0, 3467.257714285403, 151.5760000000003, 1676.125714285762 - 0.0, 0.0, 44.0, 3922.952000000004, 886.341142857142, 2338.2131428571433 - 0.05, 0.0, 44.0, 3924.448571428588, 832.7080000000001, 2336.5137142857066 - 0.1, 0.0, 44.0, 3922.5034285714564, 779.229142857147, 2329.027428571406 -0.15000000000000002, 0.0, 44.0, 3916.9462857142858, 726.102857142858, 2315.8942857142756 - 0.2, 0.0, 44.0, 3907.8331428571446, 673.5342857142958, 2297.145714285699 - 0.25, 0.0, 44.0, 3891.9817142857214, 621.1371428571389, 2271.8937142856967 -0.30000000000000004, 0.0, 44.0, 3872.3862857142844, 569.8142857142893, 2241.4405714285717 -0.35000000000000003, 0.0, 44.0, 3849.8411428571385, 520.4445714285696, 2207.043428571425 - 0.4, 0.0, 44.0, 3822.178857142878, 472.6388571428555, 2167.96571428572 - 0.45, 0.0, 44.0, 3787.2988571428464, 426.05600000000055, 2123.946857142843 - 0.5, 0.0, 44.0, 3748.2262857142546, 381.21600000000245, 2075.898285714275 - 0.55, 0.0, 44.0, 3707.986285714229, 338.6388571428631, 2024.7314285714333 - 0.6000000000000001, 0.0, 44.0, 3669.603999999906, 298.84457142858287, 1971.3577142857475 - 0.65, 0.0, 44.0, 3636.1045714284332, 262.3531428571625, 1916.6885714286482 - 0.7000000000000001, 0.0, 44.0, 3610.51314285695, 229.68457142860188, 1861.6354285715677 - 0.75, 0.0, 44.0, 3595.8548571426036, 201.35885714290197, 1807.1097142859367 - 0.8, 0.0, 44.0, 3595.1548571425315, 177.89600000006257, 1754.0228571431858 - 0.0, 0.0, 46.0, 4066.411199999998, 898.8888, 2400.8423999999995 - 0.05, 0.0, 46.0, 4067.9040000000005, 845.3103999999973, 2399.1103999999937 - 0.1, 0.0, 46.0, 4065.7584000000097, 791.8023999999932, 2391.42319999998 -0.15000000000000002, 0.0, 46.0, 4059.713600000006, 738.7287999999996, 2377.928799999996 - 0.2, 0.0, 46.0, 4049.93040000002, 686.1359999999979, 2358.7471999999843 - 0.25, 0.0, 46.0, 4032.6207999999756, 633.7560000000003, 2332.9552000000035 -0.30000000000000004, 0.0, 46.0, 4011.0344000000005, 582.4928000000006, 2301.8015999999975 -0.35000000000000003, 0.0, 46.0, 3986.7007999999896, 533.2288, 2266.931999999988 - 0.4, 0.0, 46.0, 3957.2919999999767, 485.5728000000009, 2227.315199999967 - 0.45, 0.0, 46.0, 3920.2888000000107, 438.9608, 2182.2727999999975 - 0.5, 0.0, 46.0, 3878.9584000000186, 394.1552000000022, 2133.162399999998 - 0.55, 0.0, 46.0, 3836.5680000000334, 351.9184000000067, 2081.341600000003 - 0.6000000000000001, 0.0, 46.0, 3796.3848000000553, 313.0128000000148, 2028.168000000018 - 0.65, 0.0, 46.0, 3761.676000000088, 278.2008000000278, 1974.9992000000434 - 0.7000000000000001, 0.0, 46.0, 3735.7088000001313, 248.24480000004607, 1923.192800000083 - 0.75, 0.0, 46.0, 3721.750400000186, 223.90720000007113, 1874.106400000141 - 0.8, 0.0, 46.0, 3723.0680000002553, 205.95040000010377, 1829.0976000002192 - 0.0, 0.0, 48.0, 4263.050399999998, 916.1335999999998, 2486.788799999999 - 0.05, 0.0, 48.0, 4264.508000000001, 862.5927999999951, 2484.9727999999873 - 0.1, 0.0, 48.0, 4261.984800000016, 809.0727999999885, 2477.090399999966 -0.15000000000000002, 0.0, 48.0, 4255.115200000006, 756.0375999999991, 2463.1575999999936 - 0.2, 0.0, 48.0, 4244.164800000027, 703.4719999999961, 2443.3343999999784 - 0.25, 0.0, 48.0, 4224.345599999962, 651.1320000000009, 2416.662400000004 -0.30000000000000004, 0.0, 48.0, 4199.4368, 599.9456000000005, 2384.5111999999954 -0.35000000000000003, 0.0, 48.0, 4172.157599999983, 550.7216000000002, 2348.491999999979 - 0.4, 0.0, 48.0, 4139.86799999996, 503.10960000000176, 2307.610399999941 - 0.45, 0.0, 48.0, 4099.56160000002, 456.4455999999999, 2261.101599999999 - 0.5, 0.0, 48.0, 4054.6448000000455, 411.5944000000027, 2210.400800000002 - 0.55, 0.0, 48.0, 4008.5240000000895, 369.42080000000914, 2156.943200000013 - 0.6000000000000001, 0.0, 48.0, 3964.6056000001518, 330.7896000000209, 2102.1640000000357 - 0.65, 0.0, 48.0, 3926.2960000002395, 296.56560000004004, 2047.4984000000763 - 0.7000000000000001, 0.0, 48.0, 3897.001600000358, 267.6136000000677, 1994.3816000001375 - 0.75, 0.0, 48.0, 3880.1288000005084, 244.79840000010572, 1944.2488000002259 - 0.8, 0.0, 48.0, 3879.0840000006974, 228.9848000001556, 1898.5352000003447 - 0.0, 0.0, 50.0, 4465.199999999999, 934.2999999999996, 2577.499999999998 - 0.05, 0.0, 50.0, 4466.5999999999985, 880.7999999999923, 2575.599999999979 - 0.1, 0.0, 50.0, 4463.600000000023, 827.2999999999823, 2567.4999999999477 -0.15000000000000002, 0.0, 50.0, 4455.800000000005, 774.2999999999989, 2553.0999999999917 - 0.2, 0.0, 50.0, 4443.500000000032, 721.7999999999943, 2532.5999999999704 - 0.25, 0.0, 50.0, 4421.199999999948, 669.5000000000016, 2505.0000000000027 -0.30000000000000004, 0.0, 50.0, 4393.100000000003, 618.4000000000002, 2471.7999999999906 -0.35000000000000003, 0.0, 50.0, 4362.9999999999745, 569.2, 2434.4999999999677 - 0.4, 0.0, 50.0, 4327.899999999938, 521.6000000000031, 2392.1999999999075 - 0.45, 0.0, 50.0, 4284.300000000036, 474.89999999999986, 2344.1000000000026 - 0.5, 0.0, 50.0, 4235.800000000087, 430.0000000000032, 2291.7000000000094 - 0.55, 0.0, 50.0, 4186.00000000017, 387.8000000000115, 2236.500000000026 - 0.6000000000000001, 0.0, 50.0, 4138.500000000296, 349.20000000002756, 2180.000000000062 - 0.65, 0.0, 50.0, 4096.900000000471, 315.1000000000537, 2123.7000000001217 - 0.7000000000000001, 0.0, 50.0, 4064.8000000007037, 286.4000000000919, 2069.1000000002136 - 0.75, 0.0, 50.0, 4045.8000000010043, 264.00000000014484, 2017.7000000003432 - 0.8, 0.0, 50.0, 4043.5000000013792, 248.8000000002147, 1971.0000000005175 - 0.0, 0.0, 52.0, 4666.325599999999, 953.1063999999992, 2671.5551999999975 - 0.05, 0.0, 52.0, 4667.651999999996, 899.663199999989, 2669.6031999999695 - 0.1, 0.0, 52.0, 4664.095200000032, 846.2471999999749, 2661.269599999926 -0.15000000000000002, 0.0, 52.0, 4655.3488, 793.2983999999989, 2646.4183999999896 - 0.2, 0.0, 52.0, 4641.619200000037, 740.9279999999914, 2625.2895999999632 - 0.25, 0.0, 52.0, 4617.366399999934, 688.6680000000026, 2596.809600000001 -0.30000000000000004, 0.0, 52.0, 4586.923200000007, 637.6703999999995, 2562.5927999999853 -0.35000000000000003, 0.0, 52.0, 4554.722399999964, 588.5104000000002, 2524.059999999955 - 0.4, 0.0, 52.0, 4517.38799999991, 540.9224000000046, 2480.373599999864 - 0.45, 0.0, 52.0, 4470.990400000056, 494.2663999999998, 2430.6984000000084 - 0.5, 0.0, 52.0, 4419.435200000138, 449.36560000000367, 2376.631200000018 - 0.55, 0.0, 52.0, 4366.628000000279, 407.0432000000141, 2319.768800000045 - 0.6000000000000001, 0.0, 52.0, 4316.474400000491, 368.1224000000347, 2261.708000000096 - 0.65, 0.0, 52.0, 4272.880000000786, 333.4264000000686, 2204.045600000183 - 0.7000000000000001, 0.0, 52.0, 4239.750400001183, 303.77840000011895, 2148.378400000314 - 0.75, 0.0, 52.0, 4220.99120000169, 280.0016000001889, 2096.3032000005005 - 0.8, 0.0, 52.0, 4220.508000002326, 262.9192000002819, 2049.4168000007503 - 0.0, 0.0, 54.0, 4859.8928000000005, 972.271199999999, 2767.533599999997 - 0.05, 0.0, 54.0, 4861.135999999992, 918.9135999999847, 2765.5935999999565 - 0.1, 0.0, 54.0, 4856.961600000038, 865.6775999999657, 2757.0167999998985 -0.15000000000000002, 0.0, 54.0, 4847.342399999992, 812.815199999999, 2741.7751999999878 - 0.2, 0.0, 54.0, 4832.205600000043, 760.6639999999884, 2720.1487999999586 - 0.25, 0.0, 54.0, 4807.027199999915, 708.4440000000043, 2690.932799999998 -0.30000000000000004, 0.0, 54.0, 4775.805600000008, 657.571199999999, 2655.814399999979 -0.35000000000000003, 0.0, 54.0, 4742.819199999957, 608.4992, 2616.275999999939 - 0.4, 0.0, 54.0, 4704.331999999879, 560.9552000000065, 2571.4207999998116 - 0.45, 0.0, 54.0, 4656.119200000081, 514.4872, 2520.3272000000156 - 0.5, 0.0, 54.0, 4602.561600000207, 469.68480000000454, 2464.765600000031 - 0.55, 0.0, 54.0, 4548.040000000422, 427.1376000000172, 2406.506400000068 - 0.6000000000000001, 0.0, 54.0, 4496.935200000743, 387.43520000004287, 2347.32000000014 - 0.65, 0.0, 54.0, 4453.6280000011975, 351.1672000000856, 2288.9768000002614 - 0.7000000000000001, 0.0, 54.0, 4422.499200001804, 318.92320000014945, 2233.2472000004436 - 0.75, 0.0, 54.0, 4407.929600002586, 291.2928000002387, 2181.901600000703 - 0.8, 0.0, 54.0, 4414.300000003563, 268.86560000035735, 2136.7104000010518 - 0.0, 0.0, 56.0, 5039.367200000003, 991.5127999999985, 2864.014399999996 - 0.05, 0.0, 56.0, 5040.523999999988, 938.2823999999794, 2862.18239999994 - 0.1, 0.0, 56.0, 5035.690400000044, 885.3543999999548, 2853.3591999998666 -0.15000000000000002, 0.0, 56.0, 5025.36159999998, 832.6327999999992, 2837.832799999988 - 0.2, 0.0, 56.0, 5008.942400000046, 780.8159999999848, 2815.9231999999533 - 0.25, 0.0, 56.0, 4984.364799999892, 728.6360000000066, 2786.2111999999943 -0.30000000000000004, 0.0, 56.0, 4954.646400000012, 677.9167999999981, 2750.3895999999704 -0.35000000000000003, 0.0, 56.0, 4922.784799999945, 629.0127999999999, 2710.2519999999204 - 0.4, 0.0, 56.0, 4884.7319999998435, 581.5768000000088, 2664.6311999997515 - 0.45, 0.0, 56.0, 4836.172800000113, 535.5048000000004, 2612.4168000000263 - 0.5, 0.0, 56.0, 4782.190400000292, 490.95120000000554, 2555.674400000049 - 0.55, 0.0, 56.0, 4727.868000000596, 448.07040000002087, 2496.4696000000977 - 0.6000000000000001, 0.0, 56.0, 4678.288800001058, 407.0168000000521, 2436.8680000001946 - 0.65, 0.0, 56.0, 4638.536000001708, 367.9448000001046, 2378.9352000003582 - 0.7000000000000001, 0.0, 56.0, 4613.692800002582, 331.00880000018356, 2324.736800000606 - 0.75, 0.0, 56.0, 4608.842400003708, 296.3632000002943, 2276.338400000958 - 0.8, 0.0, 56.0, 4629.068000005118, 264.1624000004422, 2235.805600001432 - 0.0, 5000.0, 26.0, 889.3999999999999, 671.3999999999999, 1101.3999999999999 - 0.05, 5000.0, 26.0, 889.6000000000004, 614.6, 1099.3000000000004 - 0.1, 5000.0, 26.0, 889.0000000000015, 557.5000000000002, 1092.8000000000009 -0.15000000000000002, 5000.0, 26.0, 886.8999999999999, 500.6000000000001, 1081.4000000000005 - 0.2, 5000.0, 26.0, 884.0999999999996, 443.90000000000003, 1066.0000000000007 - 0.25, 5000.0, 26.0, 879.5000000000009, 387.6000000000001, 1046.3000000000006 -0.30000000000000004, 5000.0, 26.0, 873.8000000000001, 332.1, 1022.5000000000003 -0.35000000000000003, 5000.0, 26.0, 867.8999999999999, 277.9999999999999, 995.2999999999998 - 0.4, 5000.0, 26.0, 860.8999999999996, 225.19999999999987, 964.8999999999996 - 0.45, 5000.0, 26.0, 852.2999999999992, 173.69999999999973, 931.3000000000001 - 0.5, 5000.0, 26.0, 842.499999999998, 123.69999999999924, 895.0 - 0.55, 5000.0, 26.0, 831.8999999999961, 75.39999999999847, 856.5 - 0.6000000000000001, 5000.0, 26.0, 820.8999999999936, 28.999999999997407, 816.3000000000002 - 0.65, 5000.0, 26.0, 809.8999999999904, -15.300000000003926, 774.9000000000003 - 0.7000000000000001, 5000.0, 26.0, 799.2999999999864, -57.30000000000565, 732.8000000000008 - 0.75, 5000.0, 26.0, 789.4999999999815, -96.80000000000771, 690.5000000000016 - 0.8, 5000.0, 26.0, 780.8999999999758, -133.60000000001025, 648.5000000000026 - 0.0, 5000.0, 28.0, 1334.1, 709.4000000000001, 1276.9000000000005 - 0.05, 5000.0, 28.0, 1334.3, 652.600000000001, 1274.6000000000006 - 0.1, 5000.0, 28.0, 1333.4000000000005, 595.8000000000034, 1267.800000000004 -0.15000000000000002, 5000.0, 28.0, 1330.399999999998, 539.0999999999999, 1256.1999999999987 - 0.2, 5000.0, 28.0, 1326.0999999999967, 482.69999999999953, 1239.8999999999962 - 0.25, 5000.0, 28.0, 1319.3000000000015, 426.5999999999988, 1219.1000000000035 -0.30000000000000004, 5000.0, 28.0, 1310.7000000000012, 371.30000000000007, 1194.1000000000017 -0.35000000000000003, 5000.0, 28.0, 1301.8000000000047, 317.6000000000011, 1165.4999999999982 - 0.4, 5000.0, 28.0, 1291.400000000011, 265.1000000000026, 1133.3999999999946 - 0.45, 5000.0, 28.0, 1278.3999999999967, 213.80000000000052, 1097.8000000000095 - 0.5, 5000.0, 28.0, 1263.7999999999824, 164.49999999999994, 1060.1000000000172 - 0.55, 5000.0, 28.0, 1248.5999999999558, 117.99999999999854, 1021.7000000000273 - 0.6000000000000001, 5000.0, 28.0, 1233.7999999999122, 75.099999999996, 984.0000000000391 - 0.65, 5000.0, 28.0, 1220.3999999998478, 36.599999999992164, 948.400000000052 - 0.7000000000000001, 5000.0, 28.0, 1209.3999999997584, 3.299999999986767, 916.3000000000667 - 0.75, 5000.0, 28.0, 1201.7999999996393, -24.0000000000205, 889.1000000000821 - 0.8, 5000.0, 28.0, 1198.5999999994885, -44.50000000002988, 868.2000000000982 - 0.0, 5000.0, 30.0, 1778.8000000000004, 747.2000000000003, 1453.0000000000018 - 0.05, 5000.0, 30.0, 1779.0999999999979, 690.7000000000019, 1450.8000000000025 - 0.1, 5000.0, 30.0, 1777.899999999997, 634.0000000000047, 1443.800000000009 -0.15000000000000002, 5000.0, 30.0, 1773.8999999999965, 577.3999999999993, 1431.5999999999972 - 0.2, 5000.0, 30.0, 1768.09999999999, 521.1999999999996, 1414.5999999999974 - 0.25, 5000.0, 30.0, 1758.9999999999973, 465.29999999999666, 1392.6999999999957 -0.30000000000000004, 5000.0, 30.0, 1747.8000000000036, 410.20000000000033, 1366.2000000000057 -0.35000000000000003, 5000.0, 30.0, 1735.700000000011, 356.8000000000029, 1336.1999999999985 - 0.4, 5000.0, 30.0, 1721.8000000000252, 304.80000000000706, 1302.8999999999926 - 0.45, 5000.0, 30.0, 1704.3999999999824, 254.5000000000039, 1267.0000000000318 - 0.5, 5000.0, 30.0, 1685.199999999936, 205.90000000000433, 1228.3000000000616 - 0.55, 5000.0, 30.0, 1665.8999999998473, 159.0000000000029, 1186.600000000099 - 0.6000000000000001, 5000.0, 30.0, 1648.1999999997042, 113.79999999999895, 1141.7000000001447 - 0.65, 5000.0, 30.0, 1633.7999999994947, 70.29999999999177, 1093.4000000001977 - 0.7000000000000001, 5000.0, 30.0, 1624.399999999207, 28.499999999980787, 1041.5000000002565 - 0.75, 5000.0, 30.0, 1621.699999998828, -11.600000000034981, 985.8000000003217 - 0.8, 5000.0, 30.0, 1627.399999998345, -50.00000000005599, 926.1000000003925 - 0.0, 5000.0, 32.0, 2223.3999999999987, 784.8000000000002, 1629.7999999999997 - 0.05, 5000.0, 32.0, 2223.900000000005, 728.3999999999988, 1627.6000000000022 - 0.1, 5000.0, 32.0, 2222.300000000032, 671.8999999999932, 1620.5000000000032 -0.15000000000000002, 5000.0, 32.0, 2217.399999999995, 615.499999999996, 1607.7000000000046 - 0.2, 5000.0, 32.0, 2210.1999999999684, 559.4999999999877, 1590.0000000000196 - 0.25, 5000.0, 32.0, 2198.6999999999875, 503.6999999999985, 1566.7999999999743 -0.30000000000000004, 5000.0, 32.0, 2184.700000000002, 449.2000000000004, 1539.9000000000033 -0.35000000000000003, 5000.0, 32.0, 2169.6000000000145, 396.5000000000004, 1509.8000000000006 - 0.4, 5000.0, 32.0, 2152.3000000000407, 345.3000000000017, 1475.9999999999952 - 0.45, 5000.0, 32.0, 2130.6000000000295, 295.20000000000374, 1437.9999999999986 - 0.5, 5000.0, 32.0, 2106.4000000000447, 247.00000000000506, 1396.9999999999957 - 0.55, 5000.0, 32.0, 2081.600000000049, 201.5000000000045, 1354.1999999999891 - 0.6000000000000001, 5000.0, 32.0, 2058.100000000035, 159.5000000000013, 1310.7999999999774 - 0.65, 5000.0, 32.0, 2037.7999999999925, 121.79999999999454, 1267.9999999999586 - 0.7000000000000001, 5000.0, 32.0, 2022.599999999913, 89.19999999998285, 1226.9999999999316 - 0.75, 5000.0, 32.0, 2014.3999999997889, 62.49999999996572, 1188.9999999998931 - 0.8, 5000.0, 32.0, 2015.099999999612, 42.499999999941565, 1155.199999999843 - 0.0, 5000.0, 34.0, 2668.1, 822.2999999999998, 1807.6999999999998 - 0.05, 5000.0, 34.0, 2668.7000000000035, 765.8999999999959, 1805.5999999999967 - 0.1, 5000.0, 34.0, 2666.9000000000055, 709.5999999999892, 1798.099999999987 -0.15000000000000002, 5000.0, 34.0, 2660.799999999998, 653.5999999999992, 1785.4 - 0.2, 5000.0, 34.0, 2652.1999999999857, 598.1000000000003, 1767.8999999999944 - 0.25, 5000.0, 34.0, 2638.4999999999955, 542.8999999999983, 1744.700000000022 -0.30000000000000004, 5000.0, 34.0, 2621.600000000003, 488.70000000000095, 1716.8999999999971 -0.35000000000000003, 5000.0, 34.0, 2603.5999999999854, 436.300000000002, 1685.2999999999913 - 0.4, 5000.0, 34.0, 2582.699999999959, 385.40000000000697, 1649.5999999999601 - 0.45, 5000.0, 34.0, 2556.700000000042, 335.7000000000041, 1609.8000000000136 - 0.5, 5000.0, 34.0, 2527.700000000062, 287.8000000000047, 1566.8000000000197 - 0.55, 5000.0, 34.0, 2497.8000000000643, 242.3000000000015, 1521.5000000000139 - 0.6000000000000001, 5000.0, 34.0, 2469.1000000000377, 199.79999999999222, 1474.7999999999881 - 0.65, 5000.0, 34.0, 2443.699999999969, 160.8999999999749, 1427.5999999999335 - 0.7000000000000001, 5000.0, 34.0, 2423.6999999998466, 126.19999999994727, 1380.7999999998428 - 0.75, 5000.0, 34.0, 2411.199999999661, 96.29999999990719, 1335.2999999997057 - 0.8, 5000.0, 34.0, 2408.2999999993963, 71.79999999985246, 1291.9999999995161 - 0.0, 5000.0, 36.0, 3112.8, 862.1999999999997, 1994.6000000000017 - 0.05, 5000.0, 36.0, 3113.499999999998, 806.0999999999967, 1992.6000000000008 - 0.1, 5000.0, 36.0, 3111.300000000007, 749.8999999999895, 1985.2999999999984 -0.15000000000000002, 5000.0, 36.0, 3104.299999999984, 693.9999999999997, 1971.8999999999946 - 0.2, 5000.0, 36.0, 3094.1999999999375, 638.6999999999967, 1953.2999999999784 - 0.25, 5000.0, 36.0, 3078.200000000006, 583.6000000000073, 1928.6999999999796 -0.30000000000000004, 5000.0, 36.0, 3058.5000000000236, 529.6000000000008, 1899.3000000000125 -0.35000000000000003, 5000.0, 36.0, 3037.5000000000073, 477.3999999999997, 1865.9000000000108 - 0.4, 5000.0, 36.0, 3013.2000000000353, 426.799999999999, 1828.8000000000156 - 0.45, 5000.0, 36.0, 2982.8000000000447, 377.40000000000566, 1786.8000000000086 - 0.5, 5000.0, 36.0, 2949.000000000104, 329.80000000001155, 1741.4000000000092 - 0.55, 5000.0, 36.0, 2914.500000000179, 284.6000000000189, 1694.0999999999929 - 0.6000000000000001, 5000.0, 36.0, 2882.000000000266, 242.40000000002726, 1646.399999999951 - 0.65, 5000.0, 36.0, 2854.2000000003595, 203.80000000003648, 1599.7999999998729 - 0.7000000000000001, 5000.0, 36.0, 2833.8000000004577, 169.40000000004574, 1555.799999999749 - 0.75, 5000.0, 36.0, 2823.5000000005525, 139.80000000005504, 1515.8999999995704 - 0.8, 5000.0, 36.0, 2826.000000000639, 115.60000000006342, 1481.5999999993257 - 0.0, 5000.0, 38.0, 3557.5000000000023, 902.9000000000009, 2185.9000000000015 - 0.05, 5000.0, 38.0, 3558.2000000000053, 846.9000000000011, 2183.9000000000165 - 0.1, 5000.0, 38.0, 3555.7000000000094, 791.0000000000016, 2176.3000000000575 -0.15000000000000002, 5000.0, 38.0, 3547.700000000015, 735.2999999999942, 2162.2999999999984 - 0.2, 5000.0, 38.0, 3536.2000000000503, 680.0999999999866, 2142.9000000000024 - 0.25, 5000.0, 38.0, 3517.8999999999855, 625.2000000000011, 2117.100000000016 -0.30000000000000004, 5000.0, 38.0, 3495.40000000001, 571.6000000000023, 2086.5999999999985 -0.35000000000000003, 5000.0, 38.0, 3471.5000000000173, 519.7999999999987, 2052.1999999999925 - 0.4, 5000.0, 38.0, 3443.6000000000554, 469.59999999999604, 2013.499999999989 - 0.45, 5000.0, 38.0, 3409.0000000000414, 420.5000000000035, 1969.5000000000175 - 0.5, 5000.0, 38.0, 3370.300000000086, 373.30000000000666, 1921.8000000000318 - 0.55, 5000.0, 38.0, 3330.100000000133, 328.80000000000956, 1872.0000000000455 - 0.6000000000000001, 5000.0, 38.0, 3291.000000000171, 287.80000000001144, 1821.7000000000553 - 0.65, 5000.0, 38.0, 3255.6000000001904, 251.10000000001185, 1772.500000000057 - 0.7000000000000001, 5000.0, 38.0, 3226.5000000001824, 219.50000000000998, 1726.0000000000468 - 0.75, 5000.0, 38.0, 3206.3000000001352, 193.80000000000518, 1683.8000000000222 - 0.8, 5000.0, 38.0, 3197.6000000000386, 174.7999999999967, 1647.4999999999782 - 0.0, 5000.0, 40.0, 4002.1999999999944, 943.3999999999988, 2377.8 - 0.05, 5000.0, 40.0, 4002.999999999997, 887.4999999999983, 2375.8000000000143 - 0.1, 5000.0, 40.0, 4000.2999999999993, 831.7999999999965, 2368.0000000000427 -0.15000000000000002, 5000.0, 40.0, 3991.2000000000303, 776.4000000000046, 2354.1999999999966 - 0.2, 5000.0, 40.0, 3978.300000000092, 721.6000000000138, 2334.0999999999963 - 0.25, 5000.0, 40.0, 3957.600000000038, 667.0000000000048, 2307.6999999999857 -0.30000000000000004, 5000.0, 40.0, 3932.2999999999943, 613.5999999999992, 2276.0000000000014 -0.35000000000000003, 5000.0, 40.0, 3905.4000000000137, 562.1999999999967, 2240.1000000000013 - 0.4, 5000.0, 40.0, 3874.1000000000536, 512.3999999999902, 2199.700000000006 - 0.45, 5000.0, 40.0, 3835.1000000000436, 463.60000000000286, 2153.8000000000106 - 0.5, 5000.0, 40.0, 3791.5000000001223, 416.7000000000046, 2103.8000000000447 - 0.55, 5000.0, 40.0, 3746.400000000256, 372.6000000000075, 2051.10000000011 - 0.6000000000000001, 5000.0, 40.0, 3702.9000000004603, 332.20000000001266, 1997.1000000002166 - 0.65, 5000.0, 40.0, 3664.1000000007493, 296.4000000000208, 1943.200000000376 - 0.7000000000000001, 5000.0, 40.0, 3633.1000000011363, 266.1000000000327, 1890.8000000005964 - 0.75, 5000.0, 40.0, 3613.0000000016353, 242.20000000004927, 1841.3000000008892 - 0.8, 5000.0, 40.0, 3606.900000002263, 225.60000000007128, 1796.1000000012639 - 0.0, 5000.0, 42.0, 4252.814285714287, 966.3125714285716, 2486.596 - 0.05, 5000.0, 42.0, 4253.683428571426, 910.5022857142882, 2484.6691428571444 - 0.1, 5000.0, 42.0, 4250.895999999973, 854.8514285714348, 2476.6691428571467 -0.15000000000000002, 5000.0, 42.0, 4241.228000000004, 799.6308571428572, 2462.8480000000027 - 0.2, 5000.0, 42.0, 4227.624000000026, 745.0388571428615, 2442.5142857143 - 0.25, 5000.0, 42.0, 4205.762285714297, 690.5857142857113, 2415.6399999999803 -0.30000000000000004, 5000.0, 42.0, 4178.917142857152, 637.3039999999997, 2383.2531428571424 -0.35000000000000003, 5000.0, 42.0, 4150.467428571426, 586.1199999999977, 2346.621142857133 - 0.4, 5000.0, 42.0, 4117.335428571429, 536.5279999999932, 2305.252571428543 - 0.45, 5000.0, 42.0, 4075.9971428571416, 487.91142857142825, 2258.285714285695 - 0.5, 5000.0, 42.0, 4029.854285714292, 441.23142857142983, 2207.0839999999603 - 0.55, 5000.0, 42.0, 3982.308571428589, 397.44914285714697, 2153.010857142785 - 0.6000000000000001, 5000.0, 42.0, 3936.7617142857493, 357.5257142857232, 2097.4297142855976 - 0.65, 5000.0, 42.0, 3896.615428571486, 322.4222857143016, 2041.7039999998224 - 0.7000000000000001, 5000.0, 42.0, 3865.27142857151, 293.10000000002503, 1987.1971428568866 - 0.75, 5000.0, 42.0, 3846.131428571539, 270.5200000000369, 1935.2725714282155 - 0.8, 5000.0, 42.0, 3842.5971428572866, 255.6434285714798, 1887.2937142852363 - 0.0, 5000.0, 44.0, 4392.5771428571425, 979.1782857142856, 2548.0960000000005 - 0.05, 5000.0, 44.0, 4393.477714285705, 923.4451428571472, 2546.260571428572 - 0.1, 5000.0, 44.0, 4390.535999999959, 867.7657142857265, 2538.0605714285725 -0.15000000000000002, 5000.0, 44.0, 4380.568000000013, 812.6394285714288, 2524.0280000000057 - 0.2, 5000.0, 44.0, 4366.524000000057, 758.1274285714361, 2503.6571428571697 - 0.25, 5000.0, 44.0, 4344.045142857173, 703.7228571428527, 2476.3199999999647 -0.30000000000000004, 5000.0, 44.0, 4316.228571428592, 650.5039999999999, 2443.464571428575 -0.35000000000000003, 5000.0, 44.0, 4286.881714285712, 599.3999999999958, 2406.4525714285533 - 0.4, 5000.0, 44.0, 4252.589714285717, 549.8879999999883, 2364.4582857142327 - 0.45, 5000.0, 44.0, 4209.868571428575, 501.3657142857142, 2316.8028571428276 - 0.5, 5000.0, 44.0, 4162.277142857168, 454.8257142857177, 2264.9239999999436 - 0.55, 5000.0, 44.0, 4113.3742857143525, 411.26057142858264, 2210.2594285713376 - 0.6000000000000001, 5000.0, 44.0, 4066.7188571429856, 371.66285714288114, 2154.2468571427253 - 0.65, 5000.0, 44.0, 4025.869714285932, 337.0251428571861, 2098.323999999821 - 0.7000000000000001, 5000.0, 44.0, 3994.3857142860475, 308.34000000006984, 2043.9285714283387 - 0.75, 5000.0, 44.0, 3975.8257142861953, 286.6000000001051, 1992.4982857139955 - 0.8, 5000.0, 44.0, 3973.748571429236, 272.79771428586406, 1945.4708571425058 - 0.0, 5000.0, 46.0, 4549.907999999997, 993.4679999999992, 2616.6967999999974 - 0.05, 5000.0, 46.0, 4550.772799999993, 937.7863999999995, 2614.872799999997 - 0.1, 5000.0, 46.0, 4547.20639999999, 882.1103999999964, 2606.4727999999886 -0.15000000000000002, 5000.0, 46.0, 4536.743200000002, 827.0336000000023, 2592.0464000000034 - 0.2, 5000.0, 46.0, 4521.7152000000115, 772.5536000000072, 2571.379199999999 - 0.25, 5000.0, 46.0, 4497.9184000000305, 718.1751999999892, 2543.3775999999866 -0.30000000000000004, 5000.0, 46.0, 4468.493600000002, 664.9935999999988, 2509.7656000000006 -0.35000000000000003, 5000.0, 46.0, 4437.5039999999835, 613.8703999999998, 2472.034399999989 - 0.4, 5000.0, 46.0, 4401.111199999951, 564.3936000000014, 2429.113599999973 - 0.45, 5000.0, 46.0, 4356.031199999997, 515.8983999999978, 2380.3855999999837 - 0.5, 5000.0, 46.0, 4305.893600000012, 469.3863999999965, 2327.416799999966 - 0.55, 5000.0, 46.0, 4254.328000000051, 425.859199999996, 2271.773599999942 - 0.6000000000000001, 5000.0, 46.0, 4204.964000000129, 386.31839999999715, 2215.0223999999184 - 0.65, 5000.0, 46.0, 4161.4312000002565, 351.7656000000006, 2158.729599999896 - 0.7000000000000001, 5000.0, 46.0, 4127.359200000445, 323.20240000000723, 2104.461599999879 - 0.75, 5000.0, 46.0, 4106.377600000704, 301.63040000001786, 2053.78479999987 - 0.8, 5000.0, 46.0, 4102.116000001048, 288.0512000000331, 2008.2655999998708 - 0.0, 5000.0, 48.0, 4762.855999999996, 1012.7919999999986, 2709.617599999996 - 0.05, 5000.0, 48.0, 4763.633599999985, 957.1447999999989, 2707.713599999995 - 0.1, 5000.0, 48.0, 4759.016799999973, 901.540799999993, 2699.113599999979 -0.15000000000000002, 5000.0, 48.0, 4747.798400000002, 846.4992000000034, 2684.164800000004 - 0.2, 5000.0, 48.0, 4731.18640000001, 792.0512000000111, 2662.8584 - 0.25, 5000.0, 48.0, 4705.228800000038, 737.7103999999805, 2633.975199999982 -0.30000000000000004, 5000.0, 48.0, 4673.4072, 684.563199999998, 2599.235199999998 -0.35000000000000003, 5000.0, 48.0, 4639.831999999975, 633.3807999999995, 2560.304799999984 - 0.4, 5000.0, 48.0, 4600.218399999918, 583.9392000000015, 2516.023199999963 - 0.45, 5000.0, 48.0, 4551.522400000001, 535.436799999997, 2465.6911999999775 - 0.5, 5000.0, 48.0, 4497.407200000029, 488.8727999999944, 2411.00959999995 - 0.55, 5000.0, 48.0, 4441.536000000103, 445.2463999999928, 2353.67919999992 - 0.6000000000000001, 5000.0, 48.0, 4387.572000000239, 405.5567999999925, 2295.400799999892 - 0.65, 5000.0, 48.0, 4339.178400000461, 370.80319999999494, 2237.87519999987 - 0.7000000000000001, 5000.0, 48.0, 4300.018400000786, 341.984800000001, 2182.8031999998616 - 0.75, 5000.0, 48.0, 4273.755200001236, 320.1008000000111, 2131.885599999872 - 0.8, 5000.0, 48.0, 4264.052000001828, 306.1504000000269, 2086.823199999904 - 0.0, 5000.0, 50.0, 4979.099999999995, 1032.8999999999978, 2806.899999999994 - 0.05, 5000.0, 50.0, 4979.799999999974, 977.2999999999981, 2804.8999999999924 - 0.1, 5000.0, 50.0, 4974.1999999999525, 921.7999999999882, 2796.0999999999653 -0.15000000000000002, 5000.0, 50.0, 4962.299999999995, 866.8000000000046, 2780.6000000000063 - 0.2, 5000.0, 50.0, 4944.200000000009, 812.4000000000163, 2758.6000000000004 - 0.25, 5000.0, 50.0, 4916.200000000045, 758.0999999999698, 2728.799999999976 -0.30000000000000004, 5000.0, 50.0, 4882.099999999998, 704.999999999997, 2692.899999999991 -0.35000000000000003, 5000.0, 50.0, 4845.99999999996, 653.799999999999, 2652.6999999999775 - 0.4, 5000.0, 50.0, 4803.299999999868, 604.4000000000012, 2606.9999999999545 - 0.45, 5000.0, 50.0, 4751.1000000000095, 555.8999999999959, 2554.999999999969 - 0.5, 5000.0, 50.0, 4693.100000000058, 509.29999999999234, 2498.4999999999363 - 0.55, 5000.0, 50.0, 4633.0000000001755, 465.59999999998894, 2439.299999999902 - 0.6000000000000001, 5000.0, 50.0, 4574.500000000388, 425.7999999999868, 2379.199999999875 - 0.65, 5000.0, 50.0, 4521.300000000733, 390.899999999987, 2319.9999999998645 - 0.7000000000000001, 5000.0, 50.0, 4477.100000001231, 361.89999999999065, 2263.499999999879 - 0.75, 5000.0, 50.0, 4445.60000000192, 339.7999999999984, 2211.499999999929 - 0.8, 5000.0, 50.0, 4430.500000002824, 325.60000000001185, 2165.8000000000197 - 0.0, 5000.0, 52.0, 5191.5039999999935, 1053.4719999999968, 2907.174399999992 - 0.05, 5000.0, 52.0, 5192.174399999962, 997.9511999999969, 2905.09439999999 - 0.1, 5000.0, 52.0, 5185.927199999931, 942.5871999999828, 2896.094399999947 -0.15000000000000002, 5000.0, 52.0, 5173.553599999989, 887.6608000000064, 2880.091200000009 - 0.2, 5000.0, 52.0, 5154.381600000003, 833.3568000000234, 2857.445599999999 - 0.25, 5000.0, 52.0, 5124.867200000052, 779.1135999999565, 2826.7767999999724 -0.30000000000000004, 5000.0, 52.0, 5088.984799999995, 726.0927999999959, 2789.812799999983 -0.35000000000000003, 5000.0, 52.0, 5050.823999999941, 674.9871999999989, 2748.407199999972 - 0.4, 5000.0, 52.0, 5005.709599999809, 625.6608000000008, 2701.352799999947 - 0.45, 5000.0, 52.0, 4950.661600000024, 577.2111999999953, 2647.780799999963 - 0.5, 5000.0, 52.0, 4889.464800000102, 530.6551999999901, 2589.510399999926 - 0.55, 5000.0, 52.0, 4825.904000000273, 487.0095999999849, 2528.360799999893 - 0.6000000000000001, 5000.0, 52.0, 4763.764000000584, 447.29119999998, 2466.151199999877 - 0.65, 5000.0, 52.0, 4706.829600001072, 412.51679999997685, 2404.7007999998928 - 0.7000000000000001, 5000.0, 52.0, 4658.885600001782, 383.70319999997616, 2345.8287999999525 - 0.75, 5000.0, 52.0, 4623.716800002756, 361.8671999999792, 2291.3544000000693 - 0.8, 5000.0, 52.0, 4605.10800000403, 348.0255999999869, 2243.096800000256 - 0.0, 5000.0, 54.0, 5392.9319999999925, 1074.1879999999958, 3009.07119999999 - 0.05, 5000.0, 54.0, 5393.659199999947, 1018.7975999999954, 3006.9591999999843 - 0.1, 5000.0, 54.0, 5387.369599999905, 963.6015999999762, 2997.7591999999217 -0.15000000000000002, 5000.0, 54.0, 5374.864799999981, 908.8064000000084, 2981.377600000009 - 0.2, 5000.0, 54.0, 5355.356799999995, 854.6784000000317, 2958.2367999999956 - 0.25, 5000.0, 54.0, 5325.265600000061, 800.520799999941, 2926.8303999999684 -0.30000000000000004, 5000.0, 54.0, 5288.474399999994, 747.6303999999952, 2889.02639999997 -0.35000000000000003, 5000.0, 54.0, 5249.119999999916, 696.801599999999, 2846.6135999999665 - 0.4, 5000.0, 54.0, 5202.800799999734, 647.6064000000005, 2798.390399999943 - 0.45, 5000.0, 54.0, 5146.104800000048, 599.2935999999946, 2743.502399999959 - 0.5, 5000.0, 54.0, 5082.994400000158, 552.9255999999885, 2683.663199999922 - 0.55, 5000.0, 54.0, 5017.432000000399, 509.56479999998095, 2620.5863999998965 - 0.6000000000000001, 5000.0, 54.0, 4953.380000000821, 470.2735999999727, 2555.985599999906 - 0.65, 5000.0, 54.0, 4894.800800001483, 436.11439999996475, 2491.574399999966 - 0.7000000000000001, 5000.0, 54.0, 4845.6568000024345, 408.14959999995807, 2429.0664000000975 - 0.75, 5000.0, 54.0, 4809.910400003736, 387.4415999999534, 2370.1752000003185 - 0.8, 5000.0, 54.0, 4791.524000005438, 375.0527999999516, 2316.614400000648 - 0.0, 5000.0, 56.0, 5576.2479999999905, 1094.7279999999944, 3111.220799999988 - 0.05, 5000.0, 56.0, 5577.156799999931, 1039.538399999994, 3109.1567999999784 - 0.1, 5000.0, 56.0, 5571.6983999998765, 984.5423999999679, 3099.756799999892 -0.15000000000000002, 5000.0, 56.0, 5559.5391999999665, 929.961600000011, 3083.1984000000093 - 0.2, 5000.0, 56.0, 5540.751199999983, 876.1216000000421, 3059.8151999999886 - 0.25, 5000.0, 56.0, 5511.430400000067, 822.0911999999231, 3027.8855999999673 -0.30000000000000004, 5000.0, 56.0, 5474.981599999989, 769.401599999994, 2989.593599999954 -0.35000000000000003, 5000.0, 56.0, 5435.703999999888, 719.1023999999987, 2946.5063999999593 - 0.4, 5000.0, 56.0, 5389.927199999644, 670.1216000000001, 2897.42159999994 - 0.45, 5000.0, 56.0, 5333.32720000008, 622.0703999999947, 2841.6335999999574 - 0.5, 5000.0, 56.0, 5270.181600000232, 576.0983999999875, 2780.580799999925 - 0.55, 5000.0, 56.0, 5204.768000000555, 533.3551999999775, 2715.7015999999194 - 0.6000000000000001, 5000.0, 56.0, 5141.364000001109, 494.990399999965, 2648.4343999999687 - 0.65, 5000.0, 56.0, 5084.247200001965, 462.1535999999511, 2580.217600000099 - 0.7000000000000001, 5000.0, 56.0, 5037.695200003194, 435.99439999993604, 2512.489600000334 - 0.75, 5000.0, 56.0, 5005.98560000486, 417.6623999999205, 2446.6888000007034 - 0.8, 5000.0, 56.0, 4993.396000007036, 408.307199999905, 2384.2536000012315 - 0.0, 10000.0, 26.0, 1121.9999999999998, 814.8999999999999, 1262.2999999999997 - 0.05, 10000.0, 26.0, 1122.2, 753.6000000000003, 1260.2 - 0.1, 10000.0, 26.0, 1121.099999999999, 692.4000000000004, 1253.3 -0.15000000000000002, 10000.0, 26.0, 1118.9, 631.5000000000003, 1241.7000000000003 - 0.2, 10000.0, 26.0, 1115.4000000000003, 571.2000000000008, 1225.6000000000006 - 0.25, 10000.0, 26.0, 1108.8000000000006, 511.0000000000005, 1204.4 -0.30000000000000004, 10000.0, 26.0, 1100.7999999999995, 451.79999999999995, 1179.0999999999997 -0.35000000000000003, 10000.0, 26.0, 1092.2999999999995, 394.39999999999975, 1150.2999999999995 - 0.4, 10000.0, 26.0, 1082.2999999999977, 338.39999999999964, 1117.8999999999992 - 0.45, 10000.0, 26.0, 1070.3999999999994, 283.5000000000001, 1082.0999999999983 - 0.5, 10000.0, 26.0, 1057.1000000000008, 230.5, 1043.599999999999 - 0.55, 10000.0, 26.0, 1042.6000000000001, 179.29999999999998, 1002.6000000000007 - 0.6000000000000001, 10000.0, 26.0, 1027.0999999999997, 130.0999999999999, 959.4999999999998 - 0.65, 10000.0, 26.0, 1008.7999999999988, 83.40000000000003, 916.5999999999998 - 0.7000000000000001, 10000.0, 26.0, 988.9999999999976, 39.09999999999999, 872.7999999999997 - 0.75, 10000.0, 26.0, 968.9999999999952, -2.9000000000003356, 826.9999999999994 - 0.8, 10000.0, 26.0, 950.0999999999913, -42.700000000001296, 778.0999999999987 - 0.0, 10000.0, 28.0, 1682.9000000000005, 866.3999999999999, 1477.6999999999996 - 0.05, 10000.0, 28.0, 1683.3000000000013, 805.3, 1475.6999999999991 - 0.1, 10000.0, 28.0, 1681.8000000000025, 744.3999999999999, 1468.6 -0.15000000000000002, 10000.0, 28.0, 1678.2999999999968, 683.7999999999988, 1456.5999999999979 - 0.2, 10000.0, 28.0, 1672.9999999999945, 623.8999999999962, 1439.9999999999986 - 0.25, 10000.0, 28.0, 1663.2999999999952, 563.9999999999945, 1417.69999999999 -0.30000000000000004, 10000.0, 28.0, 1651.2000000000003, 505.3000000000004, 1391.000000000001 -0.35000000000000003, 10000.0, 28.0, 1638.4000000000037, 448.50000000000074, 1360.5000000000018 - 0.4, 10000.0, 28.0, 1623.4000000000092, 393.0000000000019, 1326.4000000000076 - 0.45, 10000.0, 28.0, 1605.4999999999905, 338.80000000000246, 1288.5000000000105 - 0.5, 10000.0, 28.0, 1585.599999999999, 286.39999999999924, 1247.6000000000024 - 0.55, 10000.0, 28.0, 1564.0000000000055, 236.00000000000037, 1204.000000000004 - 0.6000000000000001, 10000.0, 28.0, 1540.6000000000006, 187.7, 1158.1999999999998 - 0.65, 10000.0, 28.0, 1513.2000000000055, 141.39999999999966, 1111.7999999999972 - 0.7000000000000001, 10000.0, 28.0, 1483.4000000000121, 97.49999999999858, 1063.8999999999926 - 0.75, 10000.0, 28.0, 1452.8000000000206, 56.39999999999629, 1013.5999999999852 - 0.8, 10000.0, 28.0, 1423.0000000000284, 18.499999999992284, 959.9999999999756 - 0.0, 10000.0, 30.0, 2244.000000000002, 917.4, 1693.5999999999992 - 0.05, 10000.0, 30.0, 2244.3000000000025, 856.4999999999984, 1691.6000000000001 - 0.1, 10000.0, 30.0, 2242.300000000005, 795.7999999999945, 1684.3000000000056 -0.15000000000000002, 10000.0, 30.0, 2237.7999999999925, 735.4999999999965, 1672.0999999999974 - 0.2, 10000.0, 30.0, 2230.699999999989, 675.9999999999893, 1654.8000000000072 - 0.25, 10000.0, 30.0, 2217.699999999972, 616.5999999999831, 1631.4999999999766 -0.30000000000000004, 10000.0, 30.0, 2201.7000000000035, 558.3000000000019, 1603.4000000000003 -0.35000000000000003, 10000.0, 30.0, 2184.500000000013, 502.00000000000455, 1571.7000000000041 - 0.4, 10000.0, 30.0, 2164.600000000028, 447.3000000000116, 1535.8000000000147 - 0.45, 10000.0, 30.0, 2140.6999999999834, 393.6000000000079, 1495.700000000027 - 0.5, 10000.0, 30.0, 2114.0999999999926, 341.9000000000003, 1452.5000000000134 - 0.55, 10000.0, 30.0, 2085.4000000000074, 292.2000000000006, 1406.4000000000149 - 0.6000000000000001, 10000.0, 30.0, 2054.100000000003, 244.70000000000005, 1357.900000000001 - 0.65, 10000.0, 30.0, 2017.6000000000108, 198.8999999999989, 1307.8999999999996 - 0.7000000000000001, 10000.0, 30.0, 1977.9000000000206, 155.39999999999577, 1256.0999999999956 - 0.75, 10000.0, 30.0, 1937.0000000000239, 114.79999999999015, 1202.1999999999873 - 0.8, 10000.0, 30.0, 1896.9000000000165, 77.69999999998123, 1145.8999999999755 - 0.0, 10000.0, 32.0, 2804.8999999999987, 968.4000000000002, 1911.200000000001 - 0.05, 10000.0, 32.0, 2805.499999999996, 907.6999999999973, 1909.2000000000041 - 0.1, 10000.0, 32.0, 2802.899999999985, 847.199999999995, 1901.800000000008 -0.15000000000000002, 10000.0, 32.0, 2797.199999999987, 787.2999999999975, 1889.2000000000014 - 0.2, 10000.0, 32.0, 2788.299999999961, 728.0999999999955, 1871.4000000000187 - 0.25, 10000.0, 32.0, 2772.0000000000373, 669.1000000000006, 1846.9000000000046 -0.30000000000000004, 10000.0, 32.0, 2752.0000000000086, 611.2000000000019, 1817.300000000006 -0.35000000000000003, 10000.0, 32.0, 2730.699999999993, 555.3000000000033, 1783.9000000000074 - 0.4, 10000.0, 32.0, 2705.6999999999575, 501.1000000000083, 1746.4000000000153 - 0.45, 10000.0, 32.0, 2675.90000000002, 448.1000000000125, 1704.2000000000453 - 0.5, 10000.0, 32.0, 2642.7999999999893, 397.0000000000046, 1658.600000000018 - 0.55, 10000.0, 32.0, 2606.600000000016, 348.0000000000107, 1610.0000000000307 - 0.6000000000000001, 10000.0, 32.0, 2567.7000000000003, 301.30000000000024, 1558.9000000000055 - 0.65, 10000.0, 32.0, 2521.9999999999905, 255.90000000000026, 1505.000000000005 - 0.7000000000000001, 10000.0, 32.0, 2472.3999999999705, 212.69999999999823, 1449.2000000000062 - 0.75, 10000.0, 32.0, 2421.7999999999365, 172.5999999999939, 1392.4000000000126 - 0.8, 10000.0, 32.0, 2373.0999999998844, 136.4999999999861, 1335.500000000029 - 0.0, 10000.0, 34.0, 3365.899999999997, 1019.2000000000002, 2129.8 - 0.05, 10000.0, 34.0, 3366.4999999999977, 958.4999999999984, 2127.9999999999945 - 0.1, 10000.0, 34.0, 3363.400000000002, 898.2999999999928, 2120.4999999999827 -0.15000000000000002, 10000.0, 34.0, 3356.6999999999957, 838.7, 2107.399999999981 - 0.2, 10000.0, 34.0, 3346.0999999999854, 779.9000000000004, 2088.999999999939 - 0.25, 10000.0, 34.0, 3326.3999999999915, 721.0999999999908, 2063.3000000000034 -0.30000000000000004, 10000.0, 34.0, 3302.40000000003, 663.7000000000037, 2032.5000000000036 -0.35000000000000003, 10000.0, 34.0, 3276.8000000000075, 608.3999999999988, 1997.699999999999 - 0.4, 10000.0, 34.0, 3247.0000000000114, 554.7999999999929, 1958.400000000004 - 0.45, 10000.0, 34.0, 3211.0, 502.6000000000112, 1914.6000000000029 - 0.5, 10000.0, 34.0, 3171.3000000000443, 452.2000000000056, 1866.8000000000281 - 0.55, 10000.0, 34.0, 3128.000000000024, 403.6999999999965, 1815.1999999999946 - 0.6000000000000001, 10000.0, 34.0, 3081.200000000004, 357.9, 1761.6999999999973 - 0.65, 10000.0, 34.0, 3026.3999999999987, 312.7999999999965, 1703.8999999999803 - 0.7000000000000001, 10000.0, 34.0, 2966.899999999968, 269.99999999998926, 1643.9999999999427 - 0.75, 10000.0, 34.0, 2905.9999999998986, 231.09999999997763, 1584.199999999879 - 0.8, 10000.0, 34.0, 2846.9999999997767, 197.69999999996048, 1526.6999999997836 - 0.0, 10000.0, 36.0, 3926.900000000005, 1071.8000000000018, 2355.8000000000006 - 0.05, 10000.0, 36.0, 3927.6999999999907, 1011.3999999999996, 2353.900000000007 - 0.1, 10000.0, 36.0, 3924.099999999962, 951.299999999996, 2346.3000000000293 -0.15000000000000002, 10000.0, 36.0, 3916.0999999999967, 891.9999999999985, 2332.799999999998 - 0.2, 10000.0, 36.0, 3903.6999999999935, 833.6000000000054, 2313.6999999999975 - 0.25, 10000.0, 36.0, 3880.799999999999, 775.1999999999941, 2286.8999999999905 -0.30000000000000004, 10000.0, 36.0, 3852.9, 718.1000000000035, 2254.4000000000115 -0.35000000000000003, 10000.0, 36.0, 3822.900000000017, 663.3000000000029, 2217.9999999999955 - 0.4, 10000.0, 36.0, 3788.2000000000103, 610.1000000000084, 2176.69999999999 - 0.45, 10000.0, 36.0, 3746.2000000000417, 558.2000000000107, 2130.1000000000467 - 0.5, 10000.0, 36.0, 3699.900000000006, 508.3000000000059, 2079.5000000000136 - 0.55, 10000.0, 36.0, 3649.4000000000683, 460.59999999999997, 2025.3 - 0.6000000000000001, 10000.0, 36.0, 3594.700000000011, 415.30000000000194, 1968.399999999987 - 0.65, 10000.0, 36.0, 3530.7000000000185, 370.60000000000673, 1906.999999999947 - 0.7000000000000001, 10000.0, 36.0, 3461.5000000000027, 328.00000000001444, 1842.7999999998792 - 0.75, 10000.0, 36.0, 3391.1999999999402, 289.0000000000268, 1777.4999999997817 - 0.8, 10000.0, 36.0, 3323.8999999998096, 255.10000000004425, 1712.7999999996516 - 0.0, 10000.0, 38.0, 4487.900000000003, 1126.2999999999984, 2588.8999999999996 - 0.05, 10000.0, 38.0, 4488.70000000002, 1065.9999999999975, 2587.2000000000025 - 0.1, 10000.0, 38.0, 4484.600000000045, 1006.1999999999955, 2579.3000000000097 -0.15000000000000002, 10000.0, 38.0, 4475.499999999992, 947.1999999999925, 2565.5999999999954 - 0.2, 10000.0, 38.0, 4461.30000000001, 889.1999999999794, 2545.8999999999796 - 0.25, 10000.0, 38.0, 4435.299999999985, 831.1999999999887, 2517.8999999999523 -0.30000000000000004, 10000.0, 38.0, 4403.200000000018, 774.499999999999, 2483.900000000001 -0.35000000000000003, 10000.0, 38.0, 4369.100000000019, 720.2000000000031, 2446.00000000001 - 0.4, 10000.0, 38.0, 4329.3, 667.8000000000079, 2403.0000000000273 - 0.45, 10000.0, 38.0, 4281.300000000142, 616.5000000000093, 2354.399999999996 - 0.5, 10000.0, 38.0, 4228.39999999997, 567.3000000000048, 2301.3000000000306 - 0.55, 10000.0, 38.0, 4170.59999999997, 520.3000000000054, 2244.7000000000517 - 0.6000000000000001, 10000.0, 38.0, 4108.200000000019, 475.69999999999686, 2184.8999999999855 - 0.65, 10000.0, 38.0, 4035.100000000027, 431.4999999999858, 2119.5999999999494 - 0.7000000000000001, 10000.0, 38.0, 3955.9000000000055, 389.2999999999638, 2051.29999999989 - 0.75, 10000.0, 38.0, 3875.1999999999343, 350.69999999992757, 1982.49999999981 - 0.8, 10000.0, 38.0, 3797.599999999791, 317.2999999998736, 1915.6999999997065 - 0.0, 10000.0, 40.0, 5048.899999999998, 1181.0, 2824.3999999999965 - 0.05, 10000.0, 40.0, 5049.799999999994, 1120.9000000000042, 2822.5999999999985 - 0.1, 10000.0, 40.0, 5045.200000000003, 1061.3000000000125, 2814.6000000000017 -0.15000000000000002, 10000.0, 40.0, 5035.000000000034, 1002.6000000000054, 2800.4000000000156 - 0.2, 10000.0, 40.0, 5019.00000000009, 945.0000000000168, 2780.4000000000437 - 0.25, 10000.0, 40.0, 4989.7000000000335, 887.0999999999974, 2751.099999999979 -0.30000000000000004, 10000.0, 40.0, 4953.7000000000035, 831.0000000000001, 2716.0000000000036 -0.35000000000000003, 10000.0, 40.0, 4915.2, 777.3000000000013, 2676.600000000004 - 0.4, 10000.0, 40.0, 4870.400000000013, 725.500000000003, 2631.700000000023 - 0.45, 10000.0, 40.0, 4816.600000000032, 674.7000000000002, 2580.9000000000087 - 0.5, 10000.0, 40.0, 4756.899999999926, 626.200000000003, 2525.399999999999 - 0.55, 10000.0, 40.0, 4692.00000000004, 580.1000000000063, 2466.3000000000325 - 0.6000000000000001, 10000.0, 40.0, 4621.900000000005, 536.2000000000004, 2403.6999999999925 - 0.65, 10000.0, 40.0, 4539.500000000015, 492.50000000000205, 2334.5999999999844 - 0.7000000000000001, 10000.0, 40.0, 4450.3000000000375, 450.60000000000474, 2262.099999999973 - 0.75, 10000.0, 40.0, 4359.80000000007, 412.1000000000081, 2189.299999999961 - 0.8, 10000.0, 40.0, 4273.500000000116, 378.6000000000113, 2119.2999999999447 - 0.0, 10000.0, 42.0, 5369.339428571428, 1212.1582857142855, 2959.351999999999 - 0.05, 10000.0, 42.0, 5370.272000000004, 1152.1399999999983, 2957.494857142854 - 0.1, 10000.0, 42.0, 5365.426285714286, 1092.6542857142804, 2949.2908571428484 -0.15000000000000002, 10000.0, 42.0, 5354.653714285712, 1034.0645714285697, 2934.670285714286 - 0.2, 10000.0, 42.0, 5337.733714285725, 976.6359999999968, 2914.098857142852 - 0.25, 10000.0, 42.0, 5306.431999999984, 918.9074285714361, 2884.1657142856957 -0.30000000000000004, 10000.0, 42.0, 5268.006857142857, 863.0605714285714, 2848.3714285714277 -0.35000000000000003, 10000.0, 42.0, 5226.857142857138, 809.7074285714272, 2808.1342857142854 - 0.4, 10000.0, 42.0, 5179.052571428571, 758.2502857142815, 2762.217714285721 - 0.45, 10000.0, 42.0, 5121.676571428543, 707.7971428571328, 2710.143999999971 - 0.5, 10000.0, 42.0, 5058.004571428514, 659.7011428571462, 2653.353714285705 - 0.55, 10000.0, 42.0, 4988.7777142857085, 614.0217142857181, 2592.787999999999 - 0.6000000000000001, 10000.0, 42.0, 4914.137714285733, 570.5502857142865, 2528.579428571436 - 0.65, 10000.0, 42.0, 4826.608571428629, 527.1560000000028, 2457.445142857165 - 0.7000000000000001, 10000.0, 42.0, 4731.915428571553, 485.610285714291, 2382.8611428571876 - 0.75, 10000.0, 42.0, 4635.783428571652, 447.68457142857994, 2308.3034285715025 - 0.8, 10000.0, 42.0, 4543.937714286082, 415.1502857142977, 2237.248000000112 - 0.0, 10000.0, 44.0, 5545.653714285712, 1229.4411428571425, 3035.331999999998 - 0.05, 10000.0, 44.0, 5546.5720000000065, 1169.4399999999982, 3033.443428571422 - 0.1, 10000.0, 44.0, 5541.569142857143, 1110.0171428571364, 3024.9794285714142 -0.15000000000000002, 10000.0, 44.0, 5530.450857142859, 1051.430285714282, 3009.973142857142 - 0.2, 10000.0, 44.0, 5513.010857142885, 994.0359999999911, 2988.667428571416 - 0.25, 10000.0, 44.0, 5480.671999999987, 936.5217142857279, 2958.462857142824 -0.30000000000000004, 10000.0, 44.0, 5440.9754285714325, 880.7262857142866, 2922.1857142857184 -0.35000000000000003, 10000.0, 44.0, 5398.48857142856, 827.5617142857124, 2881.477142857144 - 0.4, 10000.0, 44.0, 5349.158285714294, 776.2931428571355, 2835.054857142874 - 0.45, 10000.0, 44.0, 5289.822285714233, 726.0885714285541, 2782.2439999999397 - 0.5, 10000.0, 44.0, 5224.150285714197, 678.2125714285801, 2724.790857142849 - 0.55, 10000.0, 44.0, 5152.554857142842, 632.6788571428621, 2663.34799999999 - 0.6000000000000001, 10000.0, 44.0, 5075.49485714289, 589.4731428571451, 2598.2137142857287 - 0.65, 10000.0, 44.0, 4985.134285714386, 546.236000000007, 2525.976571428618 - 0.7000000000000001, 10000.0, 44.0, 4887.389714285944, 505.01314285715677, 2450.3925714286665 - 0.75, 10000.0, 44.0, 4788.1777142861465, 467.85028571430826, 2375.2177142858754 - 0.8, 10000.0, 44.0, 4693.414857143587, 436.79314285717567, 2304.2080000002484 - 0.0, 10000.0, 46.0, 5721.667199999998, 1247.2167999999995, 3114.342399999999 - 0.05, 10000.0, 46.0, 5722.548799999993, 1187.2552000000028, 3112.422399999987 - 0.1, 10000.0, 46.0, 5717.199999999958, 1127.8952000000081, 3103.7303999999594 -0.15000000000000002, 10000.0, 46.0, 5705.499199999995, 1069.3272000000002, 3088.3000000000006 - 0.2, 10000.0, 46.0, 5687.161600000011, 1011.9640000000002, 3066.2663999999886 - 0.25, 10000.0, 46.0, 5654.46399999998, 954.6799999999889, 3035.7135999999937 -0.30000000000000004, 10000.0, 46.0, 5614.526400000004, 898.9616000000004, 2998.899199999995 -0.35000000000000003, 10000.0, 46.0, 5571.716799999977, 845.9727999999993, 2957.6743999999926 - 0.4, 10000.0, 46.0, 5521.9647999999215, 794.9119999999962, 2910.759199999978 - 0.45, 10000.0, 46.0, 5461.776000000007, 744.9463999999954, 2857.2207999999882 - 0.5, 10000.0, 46.0, 5395.198400000011, 697.2807999999976, 2799.0631999999982 - 0.55, 10000.0, 46.0, 5322.3992000000335, 651.959999999999, 2736.7175999999868 - 0.6000000000000001, 10000.0, 46.0, 5243.853599999988, 609.0391999999999, 2670.64159999999 - 0.65, 10000.0, 46.0, 5149.893599999957, 565.8439999999995, 2596.8887999999724 - 0.7000000000000001, 10000.0, 46.0, 5048.108799999895, 524.7295999999998, 2519.7063999999564 - 0.75, 10000.0, 46.0, 4946.088799999796, 488.0511999999994, 2443.3415999999525 - 0.8, 10000.0, 46.0, 4851.423199999644, 458.1639999999989, 2372.041599999971 - 0.0, 10000.0, 48.0, 5946.4263999999985, 1270.449599999999, 3217.5327999999995 - 0.05, 10000.0, 48.0, 5947.265599999985, 1210.5704000000046, 3215.5727999999776 - 0.1, 10000.0, 48.0, 5941.327999999926, 1151.2904000000128, 3206.692799999931 -0.15000000000000002, 10000.0, 48.0, 5928.670399999991, 1092.7984, 3190.783999999996 - 0.2, 10000.0, 48.0, 5908.875200000028, 1035.5120000000006, 3168.0767999999703 - 0.25, 10000.0, 48.0, 5876.115999999971, 978.4439999999819, 3136.927199999986 -0.30000000000000004, 10000.0, 48.0, 5836.448800000003, 922.8912000000001, 3099.3983999999896 -0.35000000000000003, 10000.0, 48.0, 5793.753599999962, 870.1095999999983, 3057.4287999999897 - 0.4, 10000.0, 48.0, 5744.025599999883, 819.3079999999936, 3009.786399999969 - 0.45, 10000.0, 48.0, 5683.384000000027, 769.5927999999924, 2955.27759999998 - 0.5, 10000.0, 48.0, 5616.160800000016, 722.177599999995, 2896.0783999999976 - 0.55, 10000.0, 48.0, 5542.486400000049, 677.2039999999977, 2832.5271999999754 - 0.6000000000000001, 10000.0, 48.0, 5462.49519999998, 634.6223999999991, 2765.175199999983 - 0.65, 10000.0, 48.0, 5363.487199999935, 591.4119999999979, 2689.169599999951 - 0.7000000000000001, 10000.0, 48.0, 5255.973599999848, 550.2031999999964, 2609.4087999999215 - 0.75, 10000.0, 48.0, 5150.465599999701, 513.6263999999941, 2530.791199999912 - 0.8, 10000.0, 48.0, 5057.474399999483, 484.31199999999075, 2458.2151999999396 - 0.0, 10000.0, 50.0, 6174.199999999997, 1294.6999999999987, 3325.1999999999994 - 0.05, 10000.0, 50.0, 6174.9999999999745, 1234.9000000000074, 3323.1999999999653 - 0.1, 10000.0, 50.0, 6168.399999999882, 1175.7000000000198, 3314.099999999893 -0.15000000000000002, 10000.0, 50.0, 6154.599999999991, 1117.2999999999993, 3297.6999999999903 - 0.2, 10000.0, 50.0, 6133.200000000053, 1060.1000000000029, 3274.299999999943 - 0.25, 10000.0, 50.0, 6100.199999999964, 1003.1999999999736, 3242.3999999999783 -0.30000000000000004, 10000.0, 50.0, 6060.400000000004, 947.8, 3203.9999999999836 -0.35000000000000003, 10000.0, 50.0, 6017.399999999947, 895.1999999999973, 3161.0999999999863 - 0.4, 10000.0, 50.0, 5967.199999999839, 844.5999999999902, 3112.499999999959 - 0.45, 10000.0, 50.0, 5905.60000000006, 795.0999999999883, 3056.799999999968 - 0.5, 10000.0, 50.0, 5837.200000000023, 747.8999999999913, 2996.299999999997 - 0.55, 10000.0, 50.0, 5762.100000000065, 703.1999999999969, 2931.299999999959 - 0.6000000000000001, 10000.0, 50.0, 5680.09999999997, 660.8999999999979, 2862.3999999999737 - 0.65, 10000.0, 50.0, 5576.29999999991, 617.6999999999953, 2784.099999999923 - 0.7000000000000001, 10000.0, 50.0, 5463.3999999997895, 576.3999999999915, 2701.699999999875 - 0.75, 10000.0, 50.0, 5354.099999999589, 539.7999999999861, 2620.4999999998554 - 0.8, 10000.0, 50.0, 5261.09999999929, 510.6999999999796, 2545.7999999998933 - 0.0, 10000.0, 52.0, 6406.645599999997, 1320.2303999999983, 3438.0671999999995 - 0.05, 10000.0, 52.0, 6407.422399999964, 1260.493600000011, 3436.02719999995 - 0.1, 10000.0, 52.0, 6400.143999999829, 1201.3736000000279, 3426.643199999846 -0.15000000000000002, 10000.0, 52.0, 6385.041599999987, 1143.0816000000002, 3409.751999999981 - 0.2, 10000.0, 52.0, 6362.004800000084, 1085.9840000000063, 3385.627199999906 - 0.25, 10000.0, 52.0, 6328.155999999967, 1029.1719999999643, 3352.7847999999703 -0.30000000000000004, 10000.0, 52.0, 6287.103200000005, 973.8927999999993, 3313.305599999978 -0.35000000000000003, 10000.0, 52.0, 6242.66239999993, 921.4423999999962, 3269.2191999999836 - 0.4, 10000.0, 52.0, 6190.69439999979, 870.9479999999863, 3219.309599999951 - 0.45, 10000.0, 52.0, 6126.824000000101, 821.6151999999828, 3162.082399999953 - 0.5, 10000.0, 52.0, 6055.903200000031, 774.5823999999869, 3099.913599999998 - 0.55, 10000.0, 52.0, 5977.969600000089, 730.0119999999965, 3033.112799999939 - 0.6000000000000001, 10000.0, 52.0, 5892.648799999961, 687.8975999999966, 2962.2647999999604 - 0.65, 10000.0, 52.0, 5784.8247999998775, 644.8039999999918, 2881.8143999998874 - 0.7000000000000001, 10000.0, 52.0, 5667.546399999718, 603.524799999985, 2796.983199999814 - 0.75, 10000.0, 52.0, 5553.862399999456, 566.853599999976, 2712.992799999782 - 0.8, 10000.0, 52.0, 5456.821599999062, 537.5839999999655, 2635.064799999829 - 0.0, 10000.0, 54.0, 6645.420799999996, 1347.3031999999978, 3556.8575999999994 - 0.05, 10000.0, 54.0, 6646.203199999948, 1287.6008000000143, 3554.7775999999303 - 0.1, 10000.0, 54.0, 6638.287999999763, 1228.5608000000382, 3545.0135999997865 -0.15000000000000002, 10000.0, 54.0, 6621.748799999988, 1170.392800000001, 3527.6439999999707 - 0.2, 10000.0, 54.0, 6597.158400000133, 1113.4200000000126, 3502.7495999998587 - 0.25, 10000.0, 54.0, 6561.423999999976, 1056.5839999999546, 3468.734399999965 -0.30000000000000004, 10000.0, 54.0, 6517.281600000005, 1001.3743999999984, 3427.91679999997 -0.35000000000000003, 10000.0, 54.0, 6469.547199999913, 949.0351999999947, 3382.3175999999803 - 0.4, 10000.0, 54.0, 6413.715199999738, 898.5119999999823, 3330.6247999999437 - 0.45, 10000.0, 54.0, 6345.456000000153, 849.2855999999755, 3271.419199999933 - 0.5, 10000.0, 54.0, 6269.857600000039, 802.3591999999818, 3207.1048000000014 - 0.55, 10000.0, 54.0, 6186.824800000117, 757.7039999999969, 3138.042399999915 - 0.6000000000000001, 10000.0, 54.0, 6096.122399999946, 715.640799999995, 3064.718399999947 - 0.65, 10000.0, 54.0, 5985.554399999841, 672.8199999999872, 2982.447199999843 - 0.7000000000000001, 10000.0, 54.0, 5865.571199999638, 631.7823999999769, 2895.6615999997393 - 0.75, 10000.0, 54.0, 5746.6231999993015, 595.0687999999637, 2808.79439999969 - 0.8, 10000.0, 54.0, 5639.160799998793, 565.2199999999494, 2726.2783999997473 - 0.0, 10000.0, 56.0, 6892.183199999994, 1376.1807999999971, 3682.2943999999998 - 0.05, 10000.0, 56.0, 6893.012799999931, 1316.471200000019, 3680.174399999907 - 0.1, 10000.0, 56.0, 6884.559999999685, 1257.5112000000504, 3669.9023999997166 -0.15000000000000002, 10000.0, 56.0, 6866.475199999988, 1199.4832000000026, 3652.0799999999567 - 0.2, 10000.0, 56.0, 6840.529600000194, 1142.664000000022, 3626.3583999997986 - 0.25, 10000.0, 56.0, 6801.443999999999, 1085.6599999999435, 3590.901599999959 -0.30000000000000004, 10000.0, 56.0, 6751.658400000009, 1030.449599999997, 3548.4351999999626 -0.35000000000000003, 10000.0, 56.0, 6698.060799999895, 978.1767999999928, 3500.9263999999785 - 0.4, 10000.0, 56.0, 6635.46879999968, 927.4519999999779, 3446.8551999999377 - 0.45, 10000.0, 56.0, 6559.896000000214, 878.2583999999666, 3385.1047999999087 - 0.5, 10000.0, 56.0, 6476.650400000052, 831.3647999999755, 3318.0592000000074 - 0.55, 10000.0, 56.0, 6385.395200000151, 786.3399999999982, 3246.165599999887 - 0.6000000000000001, 10000.0, 56.0, 6286.501599999929, 744.1551999999929, 3169.709599999931 - 0.65, 10000.0, 56.0, 6174.981599999797, 701.8439999999816, 3086.1327999997898 - 0.7000000000000001, 10000.0, 56.0, 6054.632799999543, 661.3775999999666, 2998.1383999996497 - 0.75, 10000.0, 56.0, 5929.25279999912, 624.7271999999493, 2908.429599999578 - 0.8, 10000.0, 56.0, 5802.639199998482, 593.8639999999311, 2819.7095999996454 - 0.0, 15000.0, 26.0, 1231.4999999999934, 884.1999999999911, 1375.3000000000052 - 0.05, 15000.0, 26.0, 1239.299999999997, 824.599999999995, 1372.2000000000028 - 0.1, 15000.0, 26.0, 1242.099999999999, 763.2999999999976, 1363.8000000000009 -0.15000000000000002, 15000.0, 26.0, 1240.7999999999997, 700.9999999999991, 1350.4 - 0.2, 15000.0, 26.0, 1236.2999999999997, 638.3999999999999, 1332.2999999999997 - 0.25, 15000.0, 26.0, 1229.5, 576.2, 1309.8000000000002 -0.30000000000000004, 15000.0, 26.0, 1221.3000000000004, 515.0999999999998, 1283.2 -0.35000000000000003, 15000.0, 26.0, 1212.5999999999997, 455.7999999999999, 1252.8 - 0.4, 15000.0, 26.0, 1202.1999999999996, 397.99999999999994, 1218.9 - 0.45, 15000.0, 26.0, 1189.6999999999991, 341.2999999999998, 1180.9999999999982 - 0.5, 15000.0, 26.0, 1174.7999999999988, 286.4000000000001, 1140.1000000000004 - 0.55, 15000.0, 26.0, 1157.3000000000004, 233.30000000000015, 1096.0000000000025 - 0.6000000000000001, 15000.0, 26.0, 1138.2999999999995, 182.39999999999986, 1050.0 - 0.65, 15000.0, 26.0, 1118.199999999999, 133.79999999999976, 1002.4999999999995 - 0.7000000000000001, 15000.0, 26.0, 1096.7999999999984, 87.5999999999993, 953.6999999999985 - 0.75, 15000.0, 26.0, 1073.8999999999978, 43.89999999999827, 903.799999999996 - 0.8, 15000.0, 26.0, 1049.2999999999972, 2.7999999999962597, 852.9999999999918 - 0.0, 15000.0, 28.0, 1845.2999999999683, 936.0999999999684, 1599.799999999946 - 0.05, 15000.0, 28.0, 1857.4999999999802, 878.9999999999816, 1600.4999999999734 - 0.1, 15000.0, 28.0, 1862.1999999999907, 819.3999999999908, 1594.299999999989 -0.15000000000000002, 15000.0, 28.0, 1860.6999999999973, 758.1999999999967, 1581.799999999997 - 0.2, 15000.0, 28.0, 1854.2999999999993, 696.2999999999997, 1563.5999999999995 - 0.25, 15000.0, 28.0, 1844.2999999999954, 634.6000000000003, 1540.2999999999997 -0.30000000000000004, 15000.0, 28.0, 1832.0000000000014, 574.0000000000005, 1512.4999999999993 -0.35000000000000003, 15000.0, 28.0, 1818.7000000000014, 515.4000000000009, 1480.8000000000018 - 0.4, 15000.0, 28.0, 1803.3000000000034, 458.30000000000115, 1445.100000000005 - 0.45, 15000.0, 28.0, 1784.3000000000145, 402.4000000000025, 1405.4000000000015 - 0.5, 15000.0, 28.0, 1762.2999999999943, 348.3000000000014, 1362.1999999999985 - 0.55, 15000.0, 28.0, 1735.7999999999986, 296.1000000000017, 1315.5000000000102 - 0.6000000000000001, 15000.0, 28.0, 1707.4999999999975, 246.09999999999985, 1266.4000000000003 - 0.65, 15000.0, 28.0, 1677.299999999996, 198.49999999999997, 1215.600000000003 - 0.7000000000000001, 15000.0, 28.0, 1645.2999999999952, 153.2000000000002, 1163.3000000000095 - 0.75, 15000.0, 28.0, 1611.599999999996, 110.10000000000034, 1109.7000000000223 - 0.8, 15000.0, 28.0, 1576.3000000000002, 69.10000000000036, 1055.000000000044 - 0.0, 15000.0, 30.0, 2465.5999999997866, 993.0999999999193, 1820.3999999998093 - 0.05, 15000.0, 30.0, 2479.699999999888, 935.9999999999544, 1827.6999999999039 - 0.1, 15000.0, 30.0, 2484.4999999999527, 876.4999999999782, 1825.2999999999615 -0.15000000000000002, 15000.0, 30.0, 2481.599999999988, 815.4999999999928, 1814.3999999999899 - 0.2, 15000.0, 30.0, 2472.599999999999, 753.8999999999996, 1796.1999999999996 - 0.25, 15000.0, 30.0, 2459.0999999999904, 692.6000000000005, 1771.8999999999999 -0.30000000000000004, 15000.0, 30.0, 2442.700000000006, 632.5000000000022, 1742.6999999999987 -0.35000000000000003, 15000.0, 30.0, 2425.0000000000014, 574.5000000000028, 1709.8000000000043 - 0.4, 15000.0, 30.0, 2404.400000000004, 518.3000000000048, 1672.9000000000135 - 0.45, 15000.0, 30.0, 2379.1000000000404, 463.2000000000075, 1631.2000000000023 - 0.5, 15000.0, 30.0, 2349.6000000000013, 410.0000000000053, 1585.7999999999995 - 0.55, 15000.0, 30.0, 2314.4999999999955, 358.6000000000043, 1536.2000000000264 - 0.6000000000000001, 15000.0, 30.0, 2276.5999999999967, 309.50000000000017, 1484.2000000000005 - 0.65, 15000.0, 30.0, 2236.2999999999965, 262.60000000000036, 1429.900000000005 - 0.7000000000000001, 15000.0, 30.0, 2193.7000000000075, 218.29999999999995, 1374.1000000000195 - 0.75, 15000.0, 30.0, 2148.9000000000287, 176.9999999999987, 1317.600000000049 - 0.8, 15000.0, 30.0, 2102.0000000000673, 139.099999999996, 1261.2000000000985 - 0.0, 15000.0, 32.0, 3070.3999999999896, 1050.999999999959, 2057.8999999998896 - 0.05, 15000.0, 32.0, 3093.2999999999865, 993.4999999999733, 2064.1999999999266 - 0.1, 15000.0, 32.0, 3102.6999999999903, 933.7999999999855, 2060.9999999999604 -0.15000000000000002, 15000.0, 32.0, 3100.9999999999955, 872.7999999999953, 2049.3999999999864 - 0.2, 15000.0, 32.0, 3090.5999999999995, 811.4000000000004, 2030.5000000000014 - 0.25, 15000.0, 32.0, 3073.8999999999983, 750.5000000000001, 2005.4000000000026 -0.30000000000000004, 15000.0, 32.0, 3053.3000000000025, 690.9999999999985, 1975.20000000001 -0.35000000000000003, 15000.0, 32.0, 3031.1999999999853, 633.799999999999, 1941.0000000000111 - 0.4, 15000.0, 32.0, 3005.4999999999573, 578.0999999999952, 1902.3000000000384 - 0.45, 15000.0, 32.0, 2974.000000000015, 523.8000000000079, 1858.8000000000377 - 0.5, 15000.0, 32.0, 2937.0999999999644, 471.40000000000333, 1811.0000000000111 - 0.55, 15000.0, 32.0, 2893.200000000062, 420.69999999999783, 1758.5000000000275 - 0.6000000000000001, 15000.0, 32.0, 2845.799999999996, 372.29999999999956, 1703.1999999999935 - 0.65, 15000.0, 32.0, 2795.3999999999746, 326.3999999999976, 1645.6999999999646 - 0.7000000000000001, 15000.0, 32.0, 2742.0999999999385, 282.8999999999945, 1586.2999999999108 - 0.75, 15000.0, 32.0, 2685.9999999998913, 241.69999999999118, 1525.2999999998287 - 0.8, 15000.0, 32.0, 2627.1999999998334, 202.69999999998748, 1462.9999999997149 - 0.0, 15000.0, 34.0, 3700.500000000119, 1104.3999999999803, 2296.099999999792 - 0.05, 15000.0, 34.0, 3720.500000000043, 1048.3999999999883, 2302.1999999998884 - 0.1, 15000.0, 34.0, 3727.0000000000036, 989.7999999999946, 2298.599999999951 -0.15000000000000002, 15000.0, 34.0, 3722.299999999992, 929.5999999999987, 2286.399999999986 - 0.2, 15000.0, 34.0, 3708.6999999999975, 868.7999999999998, 2266.7 - 0.25, 15000.0, 34.0, 3688.500000000011, 808.3999999999975, 2240.5999999999995 -0.30000000000000004, 15000.0, 34.0, 3664.000000000012, 749.4000000000009, 2209.200000000005 -0.35000000000000003, 15000.0, 34.0, 3637.500000000005, 692.7999999999969, 2173.599999999999 - 0.4, 15000.0, 34.0, 3606.5999999999813, 637.8999999999854, 2133.5999999999835 - 0.45, 15000.0, 34.0, 3568.7999999999925, 584.3000000000116, 2088.1000000000154 - 0.5, 15000.0, 34.0, 3524.4999999999804, 532.7000000000016, 2038.000000000021 - 0.55, 15000.0, 34.0, 3471.8000000000343, 482.8000000000065, 1982.7999999999934 - 0.6000000000000001, 15000.0, 34.0, 3414.8999999999833, 435.2000000000006, 1924.4999999999957 - 0.65, 15000.0, 34.0, 3354.4999999999727, 390.1000000000029, 1863.5000000000045 - 0.7000000000000001, 15000.0, 34.0, 3290.399999999983, 347.50000000000756, 1800.500000000035 - 0.75, 15000.0, 34.0, 3222.400000000026, 307.400000000016, 1736.2000000000955 - 0.8, 15000.0, 34.0, 3150.300000000119, 269.800000000029, 1671.3000000001969 - 0.0, 15000.0, 36.0, 4312.89999999986, 1156.0999999999253, 2537.7999999998397 - 0.05, 15000.0, 36.0, 4338.199999999933, 1103.499999999959, 2545.5999999999067 - 0.1, 15000.0, 36.0, 4347.099999999976, 1047.0999999999813, 2542.699999999954 -0.15000000000000002, 15000.0, 36.0, 4342.399999999994, 988.1999999999946, 2530.3999999999864 - 0.2, 15000.0, 36.0, 4326.900000000001, 928.1000000000004, 2510.0000000000036 - 0.25, 15000.0, 36.0, 4303.399999999998, 868.100000000001, 2482.8000000000084 -0.30000000000000004, 15000.0, 36.0, 4274.700000000011, 809.5000000000056, 2450.100000000021 -0.35000000000000003, 15000.0, 36.0, 4243.600000000032, 753.6000000000024, 2413.1999999999857 - 0.4, 15000.0, 36.0, 4207.50000000006, 699.4000000000054, 2371.299999999957 - 0.45, 15000.0, 36.0, 4163.50000000006, 646.50000000001, 2323.9000000000137 - 0.5, 15000.0, 36.0, 4111.999999999978, 595.5000000000041, 2271.000000000022 - 0.55, 15000.0, 36.0, 4050.5000000000045, 546.2000000000025, 2212.7000000000075 - 0.6000000000000001, 15000.0, 36.0, 3984.1000000000045, 499.20000000000124, 2150.6999999999907 - 0.65, 15000.0, 36.0, 3913.600000000023, 454.8000000000038, 2085.899999999964 - 0.7000000000000001, 15000.0, 36.0, 3838.800000000095, 412.90000000001186, 2019.099999999922 - 0.75, 15000.0, 36.0, 3759.5000000002574, 373.4000000000287, 1951.0999999998637 - 0.8, 15000.0, 36.0, 3675.500000000545, 336.20000000005797, 1882.6999999997915 - 0.0, 15000.0, 38.0, 4919.19999999985, 1218.8999999999473, 2778.199999999837 - 0.05, 15000.0, 38.0, 4952.799999999873, 1165.3999999999614, 2792.199999999927 - 0.1, 15000.0, 38.0, 4965.899999999921, 1108.5999999999776, 2792.999999999975 -0.15000000000000002, 15000.0, 38.0, 4962.0999999999685, 1049.6999999999914, 2782.3999999999933 - 0.2, 15000.0, 38.0, 4945.000000000002, 989.9000000000005, 2762.1999999999966 - 0.25, 15000.0, 38.0, 4918.2000000000035, 930.4000000000007, 2734.199999999999 -0.30000000000000004, 15000.0, 38.0, 4885.300000000011, 872.4000000000012, 2700.200000000017 -0.35000000000000003, 15000.0, 38.0, 4849.89999999999, 817.1000000000023, 2662.000000000006 - 0.4, 15000.0, 38.0, 4808.599999999972, 763.7000000000013, 2618.5000000000164 - 0.45, 15000.0, 38.0, 4758.300000000009, 711.6000000000201, 2569.1000000000354 - 0.5, 15000.0, 38.0, 4699.300000000061, 661.400000000005, 2514.1000000000354 - 0.55, 15000.0, 38.0, 4628.999999999999, 612.8000000000155, 2452.4999999999995 - 0.6000000000000001, 15000.0, 38.0, 4553.200000000002, 566.8000000000013, 2387.400000000006 - 0.65, 15000.0, 38.0, 4472.69999999999, 523.2000000000046, 2319.5000000000205 - 0.7000000000000001, 15000.0, 38.0, 4387.299999999957, 482.30000000001246, 2248.8000000000397 - 0.75, 15000.0, 38.0, 4296.799999999892, 444.4000000000265, 2175.3000000000698 - 0.8, 15000.0, 38.0, 4200.999999999786, 409.80000000004867, 2099.00000000011 - 0.0, 15000.0, 40.0, 5536.000000000075, 1286.6999999999873, 3042.9999999999577 - 0.05, 15000.0, 40.0, 5573.000000000046, 1230.2999999999934, 3052.9999999999777 - 0.1, 15000.0, 40.0, 5587.200000000024, 1171.6999999999962, 3050.999999999989 -0.15000000000000002, 15000.0, 40.0, 5582.600000000005, 1111.8999999999978, 3038.4999999999955 - 0.2, 15000.0, 40.0, 5563.1999999999925, 1051.899999999999, 3016.999999999999 - 0.25, 15000.0, 40.0, 5532.999999999983, 992.700000000001, 2988.000000000002 -0.30000000000000004, 15000.0, 40.0, 5495.999999999997, 935.2999999999981, 2953.000000000012 -0.35000000000000003, 15000.0, 40.0, 5456.199999999981, 880.6999999999936, 2913.4999999999986 - 0.4, 15000.0, 40.0, 5409.699999999943, 828.1999999999821, 2868.8000000000056 - 0.45, 15000.0, 40.0, 5353.100000000098, 776.899999999997, 2817.200000000044 - 0.5, 15000.0, 40.0, 5286.799999999995, 727.3999999999978, 2759.799999999956 - 0.55, 15000.0, 40.0, 5207.700000000001, 679.7000000000069, 2695.299999999985 - 0.6000000000000001, 15000.0, 40.0, 5122.4000000000015, 634.3999999999974, 2627.2000000000094 - 0.65, 15000.0, 40.0, 5031.8000000000375, 591.7999999999894, 2555.700000000038 - 0.7000000000000001, 15000.0, 40.0, 4935.700000000113, 551.6999999999747, 2481.400000000086 - 0.75, 15000.0, 40.0, 4833.900000000233, 513.8999999999512, 2404.900000000159 - 0.8, 15000.0, 40.0, 4726.200000000402, 478.1999999999177, 2326.8000000002585 - 0.0, 15000.0, 42.0, 5894.917142857293, 1325.1942857142812, 3191.828571428538 - 0.05, 15000.0, 42.0, 5930.8811428572135, 1267.7657142857086, 3203.362285714262 - 0.1, 15000.0, 42.0, 5943.880571428597, 1208.5234285714241, 3201.948571428556 -0.15000000000000002, 15000.0, 42.0, 5937.8880000000045, 1148.3942857142836, 3189.270285714279 - 0.2, 15000.0, 42.0, 5916.8759999999975, 1088.305142857143, 3167.010285714286 - 0.25, 15000.0, 42.0, 5884.817142857137, 1029.1828571428587, 3136.851428571433 -0.30000000000000004, 15000.0, 42.0, 5845.684000000015, 971.9542857142842, 3100.4765714285804 -0.35000000000000003, 15000.0, 42.0, 5803.449142857134, 917.5462857142838, 3059.568571428571 - 0.4, 15000.0, 42.0, 5754.105714285685, 865.2954285714229, 3013.3177142857153 - 0.45, 15000.0, 42.0, 5694.053714285671, 814.2199999999917, 2959.835999999987 - 0.5, 15000.0, 42.0, 5623.517142857109, 765.038285714279, 2900.5422857142703 - 0.55, 15000.0, 42.0, 5539.113142857136, 717.7954285714259, 2834.433714285703 - 0.6000000000000001, 15000.0, 42.0, 5448.109142857159, 672.9971428571438, 2764.5742857142995 - 0.65, 15000.0, 42.0, 5351.469714285756, 630.9074285714318, 2691.053714285754 - 0.7000000000000001, 15000.0, 42.0, 5248.9994285714965, 591.3297142857195, 2614.7371428572164 - 0.75, 15000.0, 42.0, 5140.50285714295, 554.0674285714351, 2536.4897142858263 - 0.8, 15000.0, 42.0, 5025.784571428686, 518.9240000000054, 2457.1765714287217 - 0.0, 15000.0, 44.0, 6096.44857142881, 1345.4971428571446, 3272.994285714213 - 0.05, 15000.0, 44.0, 6129.732571428681, 1288.482857142852, 3288.6651428570876 - 0.1, 15000.0, 44.0, 6140.746285714322, 1229.4977142857083, 3289.434285714251 -0.15000000000000002, 15000.0, 44.0, 6133.2680000000055, 1169.4971428571396, 3277.393142857127 - 0.2, 15000.0, 44.0, 6111.075999999997, 1109.4365714285716, 3254.633142857144 - 0.25, 15000.0, 44.0, 6077.948571428567, 1050.2714285714321, 3223.2457142857256 -0.30000000000000004, 15000.0, 44.0, 6037.664000000037, 992.9571428571413, 3185.3222857143046 -0.35000000000000003, 15000.0, 44.0, 5994.000571428554, 938.449142857139, 3142.9542857142847 - 0.4, 15000.0, 44.0, 5943.022857142802, 886.0697142857038, 3094.954857142859 - 0.45, 15000.0, 44.0, 5880.990857142777, 834.8799999999842, 3039.775999999976 - 0.5, 15000.0, 44.0, 5808.068571428527, 785.7811428571315, 2978.9051428571083 - 0.55, 15000.0, 44.0, 5720.944571428542, 738.7297142857082, 2911.9308571428223 - 0.6000000000000001, 15000.0, 44.0, 5627.000571428604, 694.2885714285736, 2841.03714285717 - 0.65, 15000.0, 44.0, 5527.186857142933, 652.4217142857206, 2766.4308571429347 - 0.7000000000000001, 15000.0, 44.0, 5421.3537142858395, 613.1868571428666, 2689.028571428719 - 0.75, 15000.0, 44.0, 5309.351428571605, 576.6417142857251, 2609.7468571430886 - 0.8, 15000.0, 44.0, 5191.030285714511, 542.8440000000081, 2529.502285714616 - 0.0, 15000.0, 46.0, 6290.805599999711, 1363.729599999995, 3359.2095999999237 - 0.05, 15000.0, 46.0, 6323.630399999844, 1308.0736000000006, 3376.665599999961 - 0.1, 15000.0, 46.0, 6333.903199999929, 1249.9472000000028, 3378.187199999981 -0.15000000000000002, 15000.0, 46.0, 6325.419199999976, 1190.4112000000018, 3366.0663999999924 - 0.2, 15000.0, 46.0, 6301.973599999998, 1130.5264000000002, 3342.5951999999975 - 0.25, 15000.0, 46.0, 6267.361599999999, 1071.3535999999988, 3310.0656000000045 -0.30000000000000004, 15000.0, 46.0, 6225.378400000012, 1013.9535999999991, 3270.7696000000105 -0.35000000000000003, 15000.0, 46.0, 6179.819199999972, 959.3871999999965, 3226.999199999991 - 0.4, 15000.0, 46.0, 6126.624799999937, 906.9175999999906, 3177.29599999997 - 0.45, 15000.0, 46.0, 6061.947199999943, 855.6296000000003, 3120.4103999999443 - 0.5, 15000.0, 46.0, 5986.792800000008, 806.6008000000066, 3058.061599999969 - 0.55, 15000.0, 46.0, 5898.782399999986, 759.7600000000025, 2990.2087999999762 - 0.6000000000000001, 15000.0, 46.0, 5803.741599999973, 715.6183999999982, 2918.3160000000016 - 0.65, 15000.0, 46.0, 5702.401599999911, 674.0127999999967, 2842.6720000000173 - 0.7000000000000001, 15000.0, 46.0, 5594.767199999808, 635.1111999999958, 2764.2288000000476 - 0.75, 15000.0, 46.0, 5480.843199999666, 599.0815999999965, 2683.938400000099 - 0.8, 15000.0, 46.0, 5360.634399999468, 566.0919999999987, 2602.752800000178 - 0.0, 15000.0, 48.0, 6528.771199999519, 1385.9991999999752, 3474.3791999998894 - 0.05, 15000.0, 48.0, 6565.076799999741, 1332.2871999999934, 3490.363199999942 - 0.1, 15000.0, 48.0, 6576.854399999883, 1275.402400000001, 3490.6543999999717 -0.15000000000000002, 15000.0, 48.0, 6568.270399999964, 1216.5624000000025, 3477.456799999986 - 0.2, 15000.0, 48.0, 6543.491199999997, 1156.9848000000006, 3452.974399999996 - 0.25, 15000.0, 48.0, 6506.683199999997, 1097.8871999999983, 3419.411200000009 -0.30000000000000004, 15000.0, 48.0, 6462.01280000002, 1040.487199999998, 3378.971200000014 -0.35000000000000003, 15000.0, 48.0, 6413.646399999961, 986.0023999999931, 3333.8583999999814 - 0.4, 15000.0, 48.0, 6357.1495999999015, 933.6111999999812, 3282.559999999943 - 0.45, 15000.0, 48.0, 6288.546399999911, 882.3592000000009, 3223.8847999999184 - 0.5, 15000.0, 48.0, 6210.585599999995, 833.4576000000097, 3159.9951999999525 - 0.55, 15000.0, 48.0, 6122.44879999998, 786.9160000000031, 3090.909599999964 - 0.6000000000000001, 15000.0, 48.0, 6027.011199999953, 743.0367999999975, 3017.712000000006 - 0.65, 15000.0, 48.0, 5924.619199999856, 701.8095999999952, 2940.6760000000327 - 0.7000000000000001, 15000.0, 48.0, 5815.546399999703, 663.2583999999939, 2860.817600000086 - 0.75, 15000.0, 48.0, 5700.066399999483, 627.4071999999932, 2779.152800000173 - 0.8, 15000.0, 48.0, 5578.45279999918, 594.2799999999941, 2696.6976000003006 - 0.0, 15000.0, 50.0, 6761.699999999236, 1408.399999999948, 3593.5999999998494 - 0.05, 15000.0, 50.0, 6804.999999999589, 1356.9999999999811, 3607.9999999999213 - 0.1, 15000.0, 50.0, 6820.4999999998145, 1301.599999999998, 3606.999999999961 -0.15000000000000002, 15000.0, 50.0, 6812.999999999942, 1243.600000000003, 3592.6999999999803 - 0.2, 15000.0, 50.0, 6787.299999999996, 1184.400000000001, 3567.199999999994 - 0.25, 15000.0, 50.0, 6748.199999999997, 1125.3999999999971, 3532.6000000000163 -0.30000000000000004, 15000.0, 50.0, 6700.500000000035, 1067.9999999999964, 3491.000000000017 -0.35000000000000003, 15000.0, 50.0, 6648.999999999941, 1013.5999999999881, 3444.4999999999704 - 0.4, 15000.0, 50.0, 6588.899999999859, 961.2999999999682, 3391.5999999999094 - 0.45, 15000.0, 50.0, 6515.999999999878, 910.1000000000014, 3331.0999999998885 - 0.5, 15000.0, 50.0, 6434.899999999978, 861.3000000000139, 3265.4999999999345 - 0.55, 15000.0, 50.0, 6345.999999999977, 815.0000000000043, 3194.8999999999496 - 0.6000000000000001, 15000.0, 50.0, 6249.49999999993, 771.2999999999964, 3120.1000000000104 - 0.65, 15000.0, 50.0, 6145.399999999792, 730.3999999999937, 3041.400000000052 - 0.7000000000000001, 15000.0, 50.0, 6034.299999999572, 692.0999999999915, 2959.800000000134 - 0.75, 15000.0, 50.0, 5916.799999999257, 656.1999999999891, 2876.3000000002635 - 0.8, 15000.0, 50.0, 5793.49999999883, 622.4999999999868, 2791.9000000004485 - 0.0, 15000.0, 52.0, 6990.660799998834, 1432.0327999999142, 3716.3727999998036 - 0.05, 15000.0, 52.0, 7045.115199999377, 1383.0247999999667, 3730.196799999899 - 0.1, 15000.0, 52.0, 7067.041599999726, 1329.1735999999942, 3728.5295999999503 -0.15000000000000002, 15000.0, 52.0, 7062.161599999916, 1272.0616000000025, 3713.447199999973 - 0.2, 15000.0, 52.0, 7036.196799999994, 1213.271200000001, 3687.0255999999913 - 0.25, 15000.0, 52.0, 6994.868799999998, 1154.3847999999962, 3651.340800000025 -0.30000000000000004, 15000.0, 52.0, 6943.899200000052, 1096.984799999994, 3608.4688000000197 -0.35000000000000003, 15000.0, 52.0, 6889.009599999918, 1042.6535999999817, 3560.485599999956 - 0.4, 15000.0, 52.0, 6825.14639999981, 990.4447999999502, 3505.9519999998693 - 0.45, 15000.0, 52.0, 6747.72559999984, 939.312800000002, 3443.5791999998537 - 0.5, 15000.0, 52.0, 6662.910399999952, 890.5824000000197, 3375.9647999999133 - 0.55, 15000.0, 52.0, 6571.3751999999795, 844.4280000000059, 3303.4343999999323 - 0.6000000000000001, 15000.0, 52.0, 6471.892799999902, 800.8111999999952, 3226.5680000000157 - 0.65, 15000.0, 52.0, 6364.276799999713, 760.1423999999919, 3145.7720000000777 - 0.7000000000000001, 15000.0, 52.0, 6249.485599999416, 721.9495999999882, 3061.9184000001924 - 0.75, 15000.0, 52.0, 6128.477599998993, 685.7607999999835, 2975.8792000003714 - 0.8, 15000.0, 52.0, 6002.2111999984145, 651.1039999999767, 2888.5264000006214 - 0.0, 15000.0, 54.0, 7216.722399998288, 1457.9983999998756, 3842.198399999754 - 0.05, 15000.0, 54.0, 7287.137599999092, 1411.1743999999499, 3857.5743999998776 - 0.1, 15000.0, 54.0, 7318.680799999604, 1358.756799999989, 3856.548799999939 -0.15000000000000002, 15000.0, 54.0, 7318.308799999881, 1302.4848000000022, 3841.3495999999664 - 0.2, 15000.0, 54.0, 7292.978399999991, 1244.097600000001, 3814.2047999999877 - 0.25, 15000.0, 54.0, 7249.646399999994, 1185.3343999999952, 3777.3424000000327 -0.30000000000000004, 15000.0, 54.0, 7195.2696000000715, 1127.934399999992, 3732.9904000000215 -0.35000000000000003, 15000.0, 54.0, 7136.804799999894, 1073.6367999999725, 3683.37679999994 - 0.4, 15000.0, 54.0, 7069.159199999752, 1021.5063999999273, 3627.1519999998236 - 0.45, 15000.0, 54.0, 6987.140799999796, 970.4584000000021, 3562.8455999998137 - 0.5, 15000.0, 54.0, 6897.791199999921, 921.7592000000271, 3492.7783999998915 - 0.55, 15000.0, 54.0, 6800.513599999991, 875.6160000000087, 3417.767199999917 - 0.6000000000000001, 15000.0, 54.0, 6694.874399999873, 831.9735999999945, 3338.2040000000225 - 0.65, 15000.0, 54.0, 6580.782399999628, 791.3951999999904, 3254.720000000107 - 0.7000000000000001, 15000.0, 54.0, 6459.560799999243, 753.1207999999854, 3167.9152000002628 - 0.75, 15000.0, 54.0, 6332.53279999869, 716.3903999999771, 3078.3896000004966 - 0.8, 15000.0, 54.0, 6201.021599997941, 680.4439999999635, 2986.7432000008175 - 0.0, 15000.0, 56.0, 7440.953599997575, 1487.3975999998322, 3970.5775999997013 - 0.05, 15000.0, 56.0, 7532.782399998721, 1442.261599999932, 3990.7535999998568 - 0.1, 15000.0, 56.0, 7577.619199999441, 1390.9831999999838, 3992.3631999999297 -0.15000000000000002, 15000.0, 56.0, 7583.995199999834, 1335.4072000000021, 3978.0583999999594 - 0.2, 15000.0, 56.0, 7560.441599999987, 1277.378400000001, 3950.4911999999845 - 0.25, 15000.0, 56.0, 7515.4895999999935, 1218.741599999994, 3912.3136000000436 -0.30000000000000004, 15000.0, 56.0, 7457.670400000102, 1161.3415999999877, 3866.177600000024 -0.35000000000000003, 15000.0, 56.0, 7395.515199999866, 1107.023199999962, 3814.735199999921 - 0.4, 15000.0, 56.0, 7324.2087999996875, 1054.9455999998981, 3756.7359999997725 - 0.45, 15000.0, 56.0, 7237.66319999975, 1003.9976000000019, 3690.4223999997716 - 0.5, 15000.0, 56.0, 7142.716799999883, 955.2848000000364, 3617.329599999869 - 0.55, 15000.0, 56.0, 7035.354400000008, 908.9800000000129, 3539.1527999998993 - 0.6000000000000001, 15000.0, 56.0, 6919.129599999838, 865.1903999999931, 3456.09600000003 - 0.65, 15000.0, 56.0, 6794.449599999528, 824.5167999999885, 3369.1720000001424 - 0.7000000000000001, 15000.0, 56.0, 6662.983199999042, 785.9271999999818, 3278.532800000342 - 0.75, 15000.0, 56.0, 6526.399199998348, 748.389599999969, 3184.3304000006383 - 0.8, 15000.0, 56.0, 6386.366399997405, 710.8719999999465, 3086.7168000010347 - 0.0, 20000.0, 26.0, 1005.0999999999442, -179.8000000000082, -972.099999999996 - 0.05, 20000.0, 26.0, 1106.39999999996, 68.79999999999444, -301.19999999999766 - 0.1, 20000.0, 26.0, 1185.399999999973, 254.6999999999964, 228.7000000000013 -0.15000000000000002, 20000.0, 26.0, 1244.3999999999828, 385.0999999999981, 633.0000000000009 - 0.2, 20000.0, 26.0, 1285.6999999999898, 467.199999999999, 927.1000000000003 - 0.25, 20000.0, 26.0, 1311.599999999995, 508.1999999999997, 1126.4 -0.30000000000000004, 20000.0, 26.0, 1324.3999999999976, 515.3, 1246.3 -0.35000000000000003, 20000.0, 26.0, 1326.3999999999994, 495.70000000000005, 1302.2 - 0.4, 20000.0, 26.0, 1319.9, 456.6, 1309.5 - 0.45, 20000.0, 26.0, 1307.2, 405.19999999999993, 1283.6000000000001 - 0.5, 20000.0, 26.0, 1290.6000000000001, 348.7, 1239.9000000000003 - 0.55, 20000.0, 26.0, 1272.4000000000024, 294.3000000000004, 1193.8000000000009 - 0.6000000000000001, 20000.0, 26.0, 1252.4999999999995, 242.19999999999976, 1145.4999999999993 - 0.65, 20000.0, 26.0, 1231.1999999999991, 192.39999999999958, 1095.3999999999985 - 0.7000000000000001, 20000.0, 26.0, 1206.3, 144.69999999999987, 1043.4999999999995 - 0.75, 20000.0, 26.0, 1179.5000000000002, 99.60000000000001, 990.4999999999994 - 0.8, 20000.0, 26.0, 1151.1, 56.90000000000004, 936.8999999999988 - 0.0, 20000.0, 28.0, 1499.400000000155, 58.29999999996068, -409.499999999999 - 0.05, 20000.0, 28.0, 1653.6000000001154, 258.49999999997067, 174.7000000000039 - 0.1, 20000.0, 28.0, 1773.9000000000829, 405.89999999997883, 635.3000000000055 -0.15000000000000002, 20000.0, 28.0, 1863.8000000000561, 506.5999999999858, 985.7000000000063 - 0.2, 20000.0, 28.0, 1926.800000000035, 566.699999999991, 1239.3000000000052 - 0.25, 20000.0, 28.0, 1966.400000000019, 592.2999999999951, 1409.5000000000043 -0.30000000000000004, 20000.0, 28.0, 1986.100000000008, 589.4999999999977, 1509.7000000000028 -0.35000000000000003, 20000.0, 28.0, 1989.400000000002, 564.3999999999994, 1553.300000000002 - 0.4, 20000.0, 28.0, 1979.7999999999997, 523.1000000000001, 1553.7000000000003 - 0.45, 20000.0, 28.0, 1960.800000000001, 471.7000000000001, 1524.2999999999997 - 0.5, 20000.0, 28.0, 1935.9000000000065, 416.2999999999994, 1478.5000000000002 - 0.55, 20000.0, 28.0, 1908.6000000000147, 363.00000000000165, 1429.7000000000007 - 0.6000000000000001, 20000.0, 28.0, 1878.900000000001, 311.8999999999993, 1378.6000000000017 - 0.65, 20000.0, 28.0, 1846.6999999999978, 263.2999999999973, 1325.5999999999988 - 0.7000000000000001, 20000.0, 28.0, 1809.6000000000029, 216.79999999999967, 1269.8 - 0.75, 20000.0, 28.0, 1769.3000000000038, 172.6999999999994, 1212.700000000002 - 0.8, 20000.0, 28.0, 1726.6999999999996, 131.19999999999857, 1154.9000000000037 - 0.0, 20000.0, 30.0, 1993.7000000003677, 236.59999999991925, 148.1999999999089 - 0.05, 20000.0, 30.0, 2200.8000000002758, 405.2999999999379, 648.2999999999498 - 0.1, 20000.0, 30.0, 2362.4000000001984, 527.5999999999539, 1041.499999999978 -0.15000000000000002, 20000.0, 30.0, 2483.2000000001344, 608.8999999999676, 1339.2999999999959 - 0.2, 20000.0, 30.0, 2567.9000000000833, 654.5999999999785, 1553.2000000000046 - 0.25, 20000.0, 30.0, 2621.2000000000453, 670.0999999999875, 1694.700000000008 -0.30000000000000004, 20000.0, 30.0, 2647.8000000000193, 660.799999999994, 1775.3000000000065 -0.35000000000000003, 20000.0, 30.0, 2652.400000000004, 632.0999999999984, 1806.5000000000034 - 0.4, 20000.0, 30.0, 2639.699999999999, 589.4000000000007, 1799.8000000000009 - 0.45, 20000.0, 30.0, 2614.400000000004, 538.1000000000007, 1766.700000000001 - 0.5, 20000.0, 30.0, 2581.200000000018, 483.5999999999992, 1718.7000000000062 - 0.55, 20000.0, 30.0, 2544.8000000000293, 431.3000000000053, 1667.3000000000022 - 0.6000000000000001, 20000.0, 30.0, 2505.3000000000084, 381.3999999999982, 1613.600000000007 - 0.65, 20000.0, 30.0, 2462.3000000000093, 333.8999999999911, 1557.4000000000058 - 0.7000000000000001, 20000.0, 30.0, 2412.7000000000053, 288.399999999999, 1497.9999999999989 - 0.75, 20000.0, 30.0, 2359.000000000007, 245.39999999999836, 1436.7000000000012 - 0.8, 20000.0, 30.0, 2302.399999999991, 205.09999999999587, 1374.8000000000025 - 0.0, 20000.0, 32.0, 2524.3999999997613, 414.79999999957806, 704.8999999990343 - 0.05, 20000.0, 32.0, 2774.5999999998685, 551.9999999996978, 1122.6999999993177 - 0.1, 20000.0, 32.0, 2969.599999999941, 649.1999999997931, 1449.6999999995398 -0.15000000000000002, 20000.0, 32.0, 3115.0999999999854, 711.0999999998659, 1695.5999999997084 - 0.2, 20000.0, 32.0, 3216.8000000000075, 742.3999999999195, 1870.0999999998303 - 0.25, 20000.0, 32.0, 3280.4000000000137, 747.7999999999568, 1982.8999999999126 -0.30000000000000004, 20000.0, 32.0, 3311.6000000000117, 731.9999999999808, 2043.6999999999628 -0.35000000000000003, 20000.0, 32.0, 3316.1000000000045, 699.6999999999941, 2062.19999999999 - 0.4, 20000.0, 32.0, 3299.5999999999985, 655.5999999999995, 2048.0999999999995 - 0.45, 20000.0, 32.0, 3267.8000000000015, 604.3999999999997, 2011.1 - 0.5, 20000.0, 32.0, 3226.400000000018, 550.7999999999982, 1960.899999999999 - 0.55, 20000.0, 32.0, 3181.1000000000245, 499.500000000012, 1907.1999999999969 - 0.6000000000000001, 20000.0, 32.0, 3131.5000000000055, 450.6000000000005, 1850.4000000000067 - 0.65, 20000.0, 32.0, 3077.899999999995, 404.1000000000018, 1791.1000000000167 - 0.7000000000000001, 20000.0, 32.0, 3015.899999999993, 359.7000000000004, 1727.8999999999985 - 0.75, 20000.0, 32.0, 2948.7999999999843, 317.9000000000018, 1662.8 - 0.8, 20000.0, 32.0, 2877.9999999999704, 278.5000000000004, 1596.3000000000106 - 0.0, 20000.0, 34.0, 3035.199999999369, 576.599999999807, 1189.9999999984575 - 0.05, 20000.0, 34.0, 3333.7999999995004, 686.7999999998589, 1545.1999999989152 - 0.1, 20000.0, 34.0, 3566.4999999996157, 762.4999999999006, 1821.8999999992723 -0.15000000000000002, 20000.0, 34.0, 3740.099999999717, 807.7999999999333, 2028.3999999995408 - 0.2, 20000.0, 34.0, 3861.3999999998023, 826.7999999999581, 2172.9999999997344 - 0.25, 20000.0, 34.0, 3937.1999999998734, 823.5999999999764, 2263.999999999864 -0.30000000000000004, 20000.0, 34.0, 3974.2999999999283, 802.2999999999888, 2309.699999999942 -0.35000000000000003, 20000.0, 34.0, 3979.4999999999704, 766.9999999999966, 2318.3999999999833 - 0.4, 20000.0, 34.0, 3959.599999999997, 721.8000000000011, 2298.3999999999983 - 0.45, 20000.0, 34.0, 3921.40000000001, 670.8000000000031, 2257.9999999999995 - 0.5, 20000.0, 34.0, 3871.70000000001, 618.1000000000041, 2205.5 - 0.55, 20000.0, 34.0, 3817.3000000000893, 567.7999999999964, 2149.2000000000053 - 0.6000000000000001, 20000.0, 34.0, 3757.7999999999834, 519.8999999999997, 2089.6000000000076 - 0.65, 20000.0, 34.0, 3693.5999999999267, 474.4999999999986, 2027.3000000000156 - 0.7000000000000001, 20000.0, 34.0, 3619.000000000014, 431.0999999999968, 1960.3000000000043 - 0.75, 20000.0, 34.0, 3538.5000000000496, 389.9999999999918, 1890.7000000000203 - 0.8, 20000.0, 34.0, 3453.5000000001037, 351.89999999998366, 1820.2000000000428 - 0.0, 20000.0, 36.0, 3553.4999999979827, 724.3999999991906, 1687.499999999159 - 0.05, 20000.0, 36.0, 3897.79999999865, 811.9999999994433, 1978.999999999422 - 0.1, 20000.0, 36.0, 4166.19999999915, 869.6999999996369, 2204.3999999996245 -0.15000000000000002, 20000.0, 36.0, 4366.499999999508, 901.0999999997791, 2370.599999999772 - 0.2, 20000.0, 36.0, 4506.499999999746, 909.7999999998779, 2484.4999999998754 - 0.25, 20000.0, 36.0, 4593.999999999889, 899.3999999999414, 2552.9999999999413 -0.30000000000000004, 20000.0, 36.0, 4636.799999999964, 873.4999999999774, 2582.99999999998 -0.35000000000000003, 20000.0, 36.0, 4642.699999999993, 835.6999999999936, 2581.399999999997 - 0.4, 20000.0, 36.0, 4619.5, 789.5999999999985, 2555.1000000000035 - 0.45, 20000.0, 36.0, 4575.000000000013, 738.7999999999998, 2511.0000000000064 - 0.5, 20000.0, 36.0, 4517.00000000005, 686.9000000000052, 2456.0000000000146 - 0.55, 20000.0, 36.0, 4453.30000000002, 637.5000000000103, 2396.999999999963 - 0.6000000000000001, 20000.0, 36.0, 4384.199999999981, 590.3999999999977, 2334.4000000000037 - 0.65, 20000.0, 36.0, 4309.199999999932, 545.8999999999965, 2268.4000000000046 - 0.7000000000000001, 20000.0, 36.0, 4222.299999999992, 503.1000000000008, 2196.8999999999946 - 0.75, 20000.0, 36.0, 4128.300000000007, 463.1000000000031, 2123.3999999999933 - 0.8, 20000.0, 36.0, 4029.1000000000327, 426.0000000000039, 2048.3999999999915 - 0.0, 20000.0, 38.0, 4047.799999998764, 902.5000000000281, 2282.5999999976952 - 0.05, 20000.0, 38.0, 4444.999999999165, 959.6000000000246, 2485.5999999983915 - 0.1, 20000.0, 38.0, 4754.699999999465, 993.1000000000199, 2640.0999999989294 -0.15000000000000002, 20000.0, 38.0, 4985.899999999675, 1005.9000000000144, 2750.99999999933 - 0.2, 20000.0, 38.0, 5147.599999999816, 1000.9000000000087, 2823.1999999996133 - 0.25, 20000.0, 38.0, 5248.799999999903, 981.0000000000036, 2861.5999999998025 -0.30000000000000004, 20000.0, 38.0, 5298.4999999999545, 949.0999999999999, 2871.0999999999153 -0.35000000000000003, 20000.0, 38.0, 5305.69999999998, 908.0999999999988, 2856.599999999974 - 0.4, 20000.0, 38.0, 5279.4, 860.9000000000002, 2822.999999999998 - 0.45, 20000.0, 38.0, 5228.60000000003, 810.4000000000055, 2775.200000000009 - 0.5, 20000.0, 38.0, 5162.300000000085, 759.5000000000152, 2718.100000000029 - 0.55, 20000.0, 38.0, 5089.500000000036, 711.1000000000041, 2656.6000000000354 - 0.6000000000000001, 20000.0, 38.0, 5010.400000000011, 665.100000000002, 2591.100000000006 - 0.65, 20000.0, 38.0, 4924.800000000025, 621.8000000000065, 2521.99999999999 - 0.7000000000000001, 20000.0, 38.0, 4825.299999999981, 580.2999999999962, 2447.0999999999945 - 0.75, 20000.0, 38.0, 4717.99999999996, 541.3999999999933, 2369.499999999979 - 0.8, 20000.0, 38.0, 4604.699999999901, 505.19999999998845, 2289.699999999941 - 0.0, 20000.0, 40.0, 4558.599999998213, 1013.7000000002164, 2889.6999999998075 - 0.05, 20000.0, 40.0, 5004.199999998734, 1059.9000000001495, 3002.399999999782 - 0.1, 20000.0, 40.0, 5351.599999999146, 1084.6000000000981, 3084.399999999789 -0.15000000000000002, 20000.0, 40.0, 5610.899999999465, 1090.500000000061, 3138.599999999819 - 0.2, 20000.0, 40.0, 5792.199999999696, 1080.3000000000352, 3167.8999999998628 - 0.25, 20000.0, 40.0, 5905.599999999857, 1056.7000000000187, 3175.1999999999107 -0.30000000000000004, 20000.0, 40.0, 5961.199999999953, 1022.4000000000092, 3163.3999999999564 -0.35000000000000003, 20000.0, 40.0, 5969.0999999999985, 980.1000000000039, 3135.3999999999883 - 0.4, 20000.0, 40.0, 5939.400000000004, 932.5000000000005, 3094.099999999998 - 0.45, 20000.0, 40.0, 5882.199999999979, 882.2999999999971, 3042.3999999999774 - 0.5, 20000.0, 40.0, 5807.599999999935, 832.1999999999914, 2983.1999999999166 - 0.55, 20000.0, 40.0, 5725.700000000126, 784.9000000000196, 2919.4000000000224 - 0.6000000000000001, 20000.0, 40.0, 5636.700000000023, 740.1000000000043, 2851.100000000011 - 0.65, 20000.0, 40.0, 5540.400000000042, 697.8000000000127, 2778.700000000005 - 0.7000000000000001, 20000.0, 40.0, 5428.599999999991, 657.5999999999975, 2700.799999999995 - 0.75, 20000.0, 40.0, 5307.799999999969, 619.5999999999923, 2618.49999999999 - 0.8, 20000.0, 40.0, 5180.199999999955, 584.1999999999842, 2533.599999999981 - 0.0, 20000.0, 42.0, 4843.655428571438, 1055.781142857111, 3050.746285714762 - 0.05, 20000.0, 42.0, 5319.062285714257, 1102.126285714259, 3166.3811428574527 - 0.1, 20000.0, 42.0, 5689.7377142856685, 1126.9245714285498, 3250.2691428573294 -0.15000000000000002, 20000.0, 42.0, 5966.458857142813, 1132.8879999999838, 3305.4188571429568 - 0.2, 20000.0, 42.0, 6160.002857142823, 1122.7285714285606, 3334.8388571428995 - 0.25, 20000.0, 42.0, 6281.146857142841, 1099.1582857142796, 3341.5377142857255 -0.30000000000000004, 20000.0, 42.0, 6340.667999999997, 1064.8891428571403, 3328.523999999998 -0.35000000000000003, 20000.0, 42.0, 6349.343428571432, 1022.6331428571428, 3298.8062857142804 - 0.4, 20000.0, 42.0, 6317.950285714288, 975.1022857142859, 3255.3931428571423 - 0.45, 20000.0, 42.0, 6257.265714285695, 925.0085714285698, 3201.2931428571464 - 0.5, 20000.0, 42.0, 6178.066857142799, 875.0639999999937, 3139.5148571428567 - 0.55, 20000.0, 42.0, 6091.1308571428135, 827.9805714285656, 3073.0668571428637 - 0.6000000000000001, 20000.0, 42.0, 5996.593142857138, 783.454285714289, 3002.0245714285684 - 0.65, 20000.0, 42.0, 5894.298857142844, 741.505142857155, 2926.9468571428497 - 0.7000000000000001, 20000.0, 42.0, 5775.149714285731, 701.7868571428565, 2846.4885714285792 - 0.75, 20000.0, 42.0, 5646.232000000031, 664.2725714285705, 2761.4828571428798 - 0.8, 20000.0, 42.0, 5510.153714285759, 629.4194285714284, 2673.9337142857607 - 0.0, 20000.0, 44.0, 4996.649714286513, 1058.9125714285788, 2962.8291428588177 - 0.05, 20000.0, 44.0, 5489.325142857627, 1111.2491428571377, 3131.912571429708 - 0.1, 20000.0, 44.0, 5873.494857143123, 1140.8702857142741, 3258.020571429297 -0.15000000000000002, 20000.0, 44.0, 6160.327428571556, 1150.6079999999865, 3345.4074285718552 - 0.2, 20000.0, 44.0, 6360.991428571477, 1143.2942857142732, 3398.3274285716498 - 0.25, 20000.0, 44.0, 6486.655428571444, 1121.7611428571342, 3421.0348571429504 -0.30000000000000004, 20000.0, 44.0, 6548.4880000000085, 1088.8405714285675, 3417.7840000000247 -0.35000000000000003, 20000.0, 44.0, 6557.657714285726, 1047.3645714285706, 3392.8291428571415 - 0.4, 20000.0, 44.0, 6525.333142857148, 1000.1651428571432, 3350.4245714285703 - 0.45, 20000.0, 44.0, 6462.682857142827, 950.0742857142837, 3294.824571428578 - 0.5, 20000.0, 44.0, 6380.875428571324, 899.923999999991, 3230.2834285714375 - 0.55, 20000.0, 44.0, 6291.079428571333, 852.5462857142722, 3161.05542857143 - 0.6000000000000001, 20000.0, 44.0, 6193.384571428569, 807.7571428571495, 3087.3502857142826 - 0.65, 20000.0, 44.0, 6087.727428571416, 765.756571428595, 3009.95542857142 - 0.7000000000000001, 20000.0, 44.0, 5964.666857142878, 726.035428571427, 2927.2742857142975 - 0.75, 20000.0, 44.0, 5831.552000000042, 688.7582857142826, 2840.791428571465 - 0.8, 20000.0, 44.0, 5691.070857142921, 654.2937142857113, 2752.0508571429345 - 0.0, 20000.0, 46.0, 5169.605600002497, 1073.749600000052, 2931.046400000766 - 0.05, 20000.0, 46.0, 5672.192800001668, 1128.4488000000244, 3136.948000000519 - 0.1, 20000.0, 46.0, 6063.965600001045, 1160.035200000007, 3292.092000000332 -0.15000000000000002, 20000.0, 46.0, 6356.304800000598, 1171.371199999998, 3401.5880000001966 - 0.2, 20000.0, 46.0, 6560.591200000301, 1165.3191999999956, 3470.5456000001022 - 0.25, 20000.0, 46.0, 6688.205600000124, 1144.7415999999964, 3504.074400000045 -0.30000000000000004, 20000.0, 46.0, 6750.528800000034, 1112.5007999999993, 3507.2840000000133 -0.35000000000000003, 20000.0, 46.0, 6758.941600000002, 1071.4592000000007, 3485.284000000001 - 0.4, 20000.0, 46.0, 6724.824800000002, 1024.4792000000004, 3443.183999999999 - 0.45, 20000.0, 46.0, 6659.5592000000015, 974.4231999999953, 3386.093599999999 - 0.5, 20000.0, 46.0, 6574.525599999973, 924.1535999999832, 3319.1223999999947 - 0.55, 20000.0, 46.0, 6481.104799999988, 876.5328000000027, 3247.379999999995 - 0.6000000000000001, 20000.0, 46.0, 6379.58399999998, 831.5351999999978, 3171.1527999999976 - 0.65, 20000.0, 46.0, 6270.048799999944, 789.4479999999937, 3091.4344000000046 - 0.7000000000000001, 20000.0, 46.0, 6144.852799999988, 749.7559999999979, 3006.827999999995 - 0.75, 20000.0, 46.0, 6010.113599999974, 712.7447999999963, 2919.082399999988 - 0.8, 20000.0, 46.0, 5867.386399999943, 678.6751999999939, 2829.2207999999837 - 0.0, 20000.0, 48.0, 5397.8672000045635, 1109.9752000001365, 3044.4808000015146 - 0.05, 20000.0, 48.0, 5909.93760000307, 1162.4856000000757, 3252.272000001029 - 0.1, 20000.0, 48.0, 6308.819200001942, 1192.4144000000351, 3408.6720000006612 -0.15000000000000002, 20000.0, 48.0, 6606.093600001129, 1202.5544000000114, 3518.8400000003926 - 0.2, 20000.0, 48.0, 6813.342400000581, 1195.6984000000002, 3587.935200000208 - 0.25, 20000.0, 48.0, 6942.147200000243, 1174.6391999999971, 3621.116800000093 -0.30000000000000004, 20000.0, 48.0, 7004.089600000071, 1142.1695999999993, 3623.5440000000294 -0.35000000000000003, 20000.0, 48.0, 7010.751200000009, 1101.0824000000014, 3600.3760000000034 - 0.4, 20000.0, 48.0, 6973.713600000004, 1054.1704000000007, 3556.771999999998 - 0.45, 20000.0, 48.0, 6904.558400000006, 1004.2263999999922, 3497.8911999999978 - 0.5, 20000.0, 48.0, 6814.867199999965, 954.0431999999731, 3428.8927999999873 - 0.55, 20000.0, 48.0, 6716.22159999996, 906.4136000000022, 3354.9359999999947 - 0.6000000000000001, 20000.0, 48.0, 6609.291999999968, 861.450399999996, 3276.309599999994 - 0.65, 20000.0, 48.0, 6494.361599999901, 819.3679999999896, 3194.104800000001 - 0.7000000000000001, 20000.0, 48.0, 6367.4415999999865, 779.8879999999971, 3107.6959999999917 - 0.75, 20000.0, 48.0, 6232.075199999963, 743.225599999994, 3018.3847999999803 - 0.8, 20000.0, 48.0, 6087.684799999924, 709.5823999999909, 2926.8735999999676 - 0.0, 20000.0, 50.0, 5600.100000007005, 1136.3000000002728, 3176.2000000024345 - 0.05, 20000.0, 50.0, 6129.900000004725, 1189.7000000001613, 3381.5000000016544 - 0.1, 20000.0, 50.0, 6542.300000003, 1220.4000000000844, 3535.700000001062 -0.15000000000000002, 20000.0, 50.0, 6849.300000001754, 1231.2000000000369, 3643.900000000631 - 0.2, 20000.0, 50.0, 7062.900000000908, 1224.9000000000108, 3711.200000000335 - 0.25, 20000.0, 50.0, 7195.100000000388, 1204.300000000001, 3742.70000000015 -0.30000000000000004, 20000.0, 50.0, 7257.900000000114, 1172.2000000000007, 3743.5000000000496 -0.35000000000000003, 20000.0, 50.0, 7263.300000000014, 1131.4000000000024, 3718.7000000000066 - 0.4, 20000.0, 50.0, 7223.300000000006, 1084.7000000000007, 3673.3999999999974 - 0.45, 20000.0, 50.0, 7149.900000000014, 1034.899999999989, 3612.699999999995 - 0.5, 20000.0, 50.0, 7055.099999999962, 984.7999999999603, 3541.6999999999757 - 0.55, 20000.0, 50.0, 6950.899999999918, 937.2000000000022, 3465.499999999996 - 0.6000000000000001, 20000.0, 50.0, 6838.199999999953, 892.2999999999936, 3384.499999999989 - 0.65, 20000.0, 50.0, 6717.499999999845, 850.1999999999838, 3299.6999999999916 - 0.7000000000000001, 20000.0, 50.0, 6588.199999999982, 810.8999999999957, 3211.2999999999874 - 0.75, 20000.0, 50.0, 6451.399999999955, 774.4999999999918, 3120.099999999966 - 0.8, 20000.0, 50.0, 6304.699999999901, 741.1999999999881, 3026.599999999941 - 0.0, 20000.0, 52.0, 5753.308800009661, 1141.9208000004678, 3307.2792000035097 - 0.05, 20000.0, 52.0, 6316.886400006525, 1202.6424000002855, 3511.8320000023823 - 0.1, 20000.0, 52.0, 6755.364800004147, 1239.1856000001583, 3665.240000001527 -0.15000000000000002, 20000.0, 52.0, 7081.578400002427, 1254.517600000076, 3772.576000000906 - 0.2, 20000.0, 52.0, 7308.361600001259, 1251.6056000000294, 3838.912800000481 - 0.25, 20000.0, 52.0, 7448.548800000537, 1233.4168000000086, 3869.323200000215 -0.30000000000000004, 20000.0, 52.0, 7514.974400000158, 1202.9184000000032, 3868.88000000007 -0.35000000000000003, 20000.0, 52.0, 7520.472800000014, 1163.0776000000046, 3842.6560000000104 - 0.4, 20000.0, 52.0, 7477.878400000007, 1116.8616000000013, 3795.723999999997 - 0.45, 20000.0, 52.0, 7400.025600000026, 1067.2375999999847, 3733.156799999991 - 0.5, 20000.0, 52.0, 7299.748799999968, 1017.1727999999448, 3660.0271999999586 - 0.55, 20000.0, 52.0, 7189.882399999861, 969.6344000000026, 3581.4080000000017 - 0.6000000000000001, 20000.0, 52.0, 7071.203999999933, 924.813599999991, 3498.002399999984 - 0.65, 20000.0, 52.0, 6944.430399999777, 882.6799999999768, 3410.447199999981 - 0.7000000000000001, 20000.0, 52.0, 6810.87839999998, 843.4959999999946, 3319.623999999982 - 0.75, 20000.0, 52.0, 6670.148799999947, 807.2143999999901, 3225.943199999949 - 0.8, 20000.0, 52.0, 6519.091199999882, 774.1295999999859, 3129.910399999902 - 0.0, 20000.0, 54.0, 5834.498400012377, 1116.0344000007303, 3418.7936000047257 - 0.05, 20000.0, 54.0, 6455.70320000836, 1193.8632000004554, 3630.4680000032035 - 0.1, 20000.0, 54.0, 6938.970400005313, 1243.9648000002603, 3789.3560000020484 -0.15000000000000002, 20000.0, 54.0, 7298.583200003108, 1269.7168000001325, 3900.676000001213 - 0.2, 20000.0, 54.0, 7548.824800001609, 1274.4968000000567, 3969.646400000641 - 0.25, 20000.0, 54.0, 7703.978400000683, 1261.6824000000204, 4001.4856000002865 -0.30000000000000004, 20000.0, 54.0, 7778.327200000197, 1234.651200000008, 4001.4120000000935 -0.35000000000000003, 20000.0, 54.0, 7786.154400000015, 1196.7808000000068, 3974.644000000015 - 0.4, 20000.0, 54.0, 7741.74320000001, 1151.4488000000017, 3926.399999999996 - 0.45, 20000.0, 54.0, 7659.376800000043, 1102.0327999999795, 3861.8983999999864 - 0.5, 20000.0, 54.0, 7553.33839999998, 1051.9103999999268, 3786.357599999938 - 0.55, 20000.0, 54.0, 7437.91119999979, 1004.4592000000039, 3704.996000000012 - 0.6000000000000001, 20000.0, 54.0, 7313.199999999915, 959.7207999999881, 3619.0951999999747 - 0.65, 20000.0, 54.0, 7180.119199999699, 917.5439999999683, 3528.5735999999615 - 0.7000000000000001, 20000.0, 54.0, 7039.227199999974, 878.3799999999934, 3434.651999999975 - 0.75, 20000.0, 54.0, 6890.382399999937, 842.0151999999883, 3337.629599999923 - 0.8, 20000.0, 54.0, 6731.517599999856, 808.9727999999849, 3238.315199999847 - 0.0, 20000.0, 56.0, 5820.673600014989, 1047.8376000010703, 3491.8184000060664 - 0.05, 20000.0, 56.0, 6531.156800010113, 1155.9128000006763, 3724.6080000041047 - 0.1, 20000.0, 56.0, 7084.07360000642, 1229.9312000003956, 3900.112000002621 -0.15000000000000002, 20000.0, 56.0, 7495.968800003748, 1274.0072000002078, 4024.008000001547 - 0.2, 20000.0, 56.0, 7783.387200001932, 1292.2552000000942, 4101.973600000815 - 0.25, 20000.0, 56.0, 7962.87360000081, 1288.7896000000362, 4139.686400000362 -0.30000000000000004, 20000.0, 56.0, 8050.972800000225, 1267.7248000000143, 4142.824000000118 -0.35000000000000003, 20000.0, 56.0, 8064.229600000013, 1233.1752000000095, 4117.0640000000185 - 0.4, 20000.0, 56.0, 8019.188800000013, 1189.2552000000023, 4068.083999999995 - 0.45, 20000.0, 56.0, 7932.395200000065, 1140.0791999999738, 4001.561599999981 - 0.5, 20000.0, 56.0, 7820.393600000004, 1089.761599999906, 3923.1743999999117 - 0.55, 20000.0, 56.0, 7699.728799999704, 1042.416800000006, 3838.600000000028 - 0.6000000000000001, 20000.0, 56.0, 7569.083999999894, 997.7511999999844, 3750.056799999966 - 0.65, 20000.0, 56.0, 7429.5327999996025, 955.5279999999585, 3656.3063999999376 - 0.7000000000000001, 20000.0, 56.0, 7276.99679999997, 916.2559999999921, 3558.3679999999663 - 0.75, 20000.0, 56.0, 7114.161599999928, 879.5487999999874, 3456.8743999998906 - 0.8, 20000.0, 56.0, 6942.6383999998325, 846.3311999999856, 3353.3247999997748 - 0.0, 25000.0, 26.0, 1454.9999999999484, 1019.3999999999954, 1480.0999999997996 - 0.05, 25000.0, 26.0, 1470.3999999999637, 948.9999999999962, 1485.3999999998584 - 0.1, 25000.0, 26.0, 1480.599999999976, 879.8999999999971, 1484.1999999999043 -0.15000000000000002, 25000.0, 26.0, 1485.999999999985, 812.2999999999979, 1477.099999999939 - 0.2, 25000.0, 26.0, 1486.9999999999914, 746.3999999999986, 1464.6999999999641 - 0.25, 25000.0, 26.0, 1483.9999999999957, 682.3999999999992, 1447.599999999981 -0.30000000000000004, 25000.0, 26.0, 1477.399999999998, 620.4999999999995, 1426.399999999992 -0.35000000000000003, 25000.0, 26.0, 1467.5999999999995, 560.9, 1401.6999999999975 - 0.4, 25000.0, 26.0, 1455.0, 503.8, 1374.1 - 0.45, 25000.0, 26.0, 1440.0000000000005, 449.3999999999999, 1344.2000000000007 - 0.5, 25000.0, 26.0, 1423.0000000000007, 397.89999999999964, 1312.6000000000008 - 0.55, 25000.0, 26.0, 1404.4000000000003, 349.49999999999994, 1279.9000000000012 - 0.6000000000000001, 25000.0, 26.0, 1384.0, 304.7, 1246.5999999999995 - 0.65, 25000.0, 26.0, 1361.4000000000008, 263.1000000000003, 1211.9999999999984 - 0.7000000000000001, 25000.0, 26.0, 1334.1, 213.69999999999993, 1155.8999999999996 - 0.75, 25000.0, 26.0, 1305.0999999999995, 166.90000000000015, 1099.1 - 0.8, 25000.0, 26.0, 1274.5999999999985, 123.2000000000004, 1042.9000000000005 - 0.0, 25000.0, 28.0, 2278.299999999715, 1094.6999999998795, 1873.4999999997287 - 0.05, 25000.0, 28.0, 2273.6999999997906, 1024.4999999999134, 1847.5999999998128 - 0.1, 25000.0, 28.0, 2267.1999999998516, 955.5999999999411, 1821.3999999998762 -0.15000000000000002, 25000.0, 28.0, 2258.6999999999007, 888.1999999999621, 1794.6999999999232 - 0.2, 25000.0, 28.0, 2248.099999999939, 822.4999999999774, 1767.2999999999565 - 0.25, 25000.0, 28.0, 2235.2999999999656, 758.6999999999877, 1738.9999999999777 -0.30000000000000004, 25000.0, 28.0, 2220.199999999984, 696.9999999999942, 1709.599999999991 -0.35000000000000003, 25000.0, 28.0, 2202.699999999995, 637.5999999999984, 1678.8999999999971 - 0.4, 25000.0, 28.0, 2182.6999999999994, 580.7, 1646.7000000000007 - 0.45, 25000.0, 28.0, 2160.0999999999976, 526.5000000000007, 1612.8000000000036 - 0.5, 25000.0, 28.0, 2134.7999999999934, 475.2000000000012, 1577.000000000008 - 0.55, 25000.0, 28.0, 2106.700000000014, 427.0000000000018, 1539.1000000000079 - 0.6000000000000001, 25000.0, 28.0, 2075.6999999999985, 382.2999999999994, 1500.6999999999962 - 0.65, 25000.0, 28.0, 2042.2000000000032, 340.79999999999836, 1460.3999999999892 - 0.7000000000000001, 25000.0, 28.0, 2001.200000000002, 292.80000000000007, 1401.0999999999976 - 0.75, 25000.0, 28.0, 1957.7000000000046, 247.70000000000056, 1341.0999999999956 - 0.8, 25000.0, 28.0, 1911.900000000004, 205.4000000000019, 1280.4999999999918 - 0.0, 25000.0, 30.0, 3040.799999999219, 1180.799999999564, 2124.2999999987683 - 0.05, 25000.0, 30.0, 3033.1999999994314, 1107.2999999996928, 2109.39999999915 - 0.1, 25000.0, 30.0, 3023.4999999996016, 1035.8999999997932, 2091.2999999994413 -0.15000000000000002, 25000.0, 30.0, 3011.4999999997362, 966.6999999998686, 2070.099999999656 - 0.2, 25000.0, 30.0, 2996.9999999998377, 899.7999999999233, 2045.8999999998052 - 0.25, 25000.0, 30.0, 2979.7999999999092, 835.2999999999602, 2018.7999999999022 -0.30000000000000004, 25000.0, 30.0, 2959.699999999957, 773.299999999983, 1988.8999999999592 -0.35000000000000003, 25000.0, 30.0, 2936.499999999985, 713.8999999999953, 1956.2999999999884 - 0.4, 25000.0, 30.0, 2909.999999999998, 657.2000000000003, 1921.1000000000015 - 0.45, 25000.0, 30.0, 2880.0, 603.3000000000014, 1883.400000000012 - 0.5, 25000.0, 30.0, 2846.299999999994, 552.3000000000028, 1843.3000000000306 - 0.55, 25000.0, 30.0, 2808.7000000000344, 504.30000000000587, 1800.9000000000221 - 0.6000000000000001, 25000.0, 30.0, 2767.6999999999966, 459.79999999999825, 1757.09999999999 - 0.65, 25000.0, 30.0, 2722.800000000008, 418.3999999999948, 1711.3999999999728 - 0.7000000000000001, 25000.0, 30.0, 2668.200000000005, 371.8999999999996, 1648.7999999999927 - 0.75, 25000.0, 30.0, 2610.100000000011, 328.1000000000009, 1584.5999999999874 - 0.8, 25000.0, 30.0, 2549.200000000011, 287.50000000000364, 1520.3999999999812 - 0.0, 25000.0, 32.0, 3745.299999999083, 1266.6999999997893, 2485.0999999995415 - 0.05, 25000.0, 32.0, 3752.49999999933, 1189.899999999847, 2449.8999999996854 - 0.1, 25000.0, 32.0, 3753.399999999525, 1115.999999999894, 2415.2999999997933 -0.15000000000000002, 25000.0, 32.0, 3748.199999999674, 1044.99999999993, 2380.8999999998705 - 0.2, 25000.0, 32.0, 3737.0999999997866, 976.8999999999573, 2346.299999999923 - 0.25, 25000.0, 32.0, 3720.2999999998688, 911.6999999999771, 2311.0999999999553 -0.30000000000000004, 25000.0, 32.0, 3697.999999999927, 849.3999999999895, 2274.8999999999746 -0.35000000000000003, 25000.0, 32.0, 3670.399999999968, 789.9999999999972, 2237.299999999987 - 0.4, 25000.0, 32.0, 3637.699999999999, 733.5000000000002, 2197.899999999997 - 0.45, 25000.0, 32.0, 3600.1000000000267, 679.9000000000007, 2156.3000000000106 - 0.5, 25000.0, 32.0, 3557.800000000058, 629.1999999999988, 2112.1000000000354 - 0.55, 25000.0, 32.0, 3510.9999999999977, 581.4000000000095, 2064.9000000000065 - 0.6000000000000001, 25000.0, 32.0, 3459.6999999999957, 537.0999999999992, 2015.900000000005 - 0.65, 25000.0, 32.0, 3403.599999999991, 495.9999999999917, 1964.900000000015 - 0.7000000000000001, 25000.0, 32.0, 3335.2999999999856, 450.39999999999907, 1898.2999999999981 - 0.75, 25000.0, 32.0, 3262.6999999999543, 408.39999999999856, 1831.30000000001 - 0.8, 25000.0, 32.0, 3186.4999999999013, 369.39999999999765, 1763.1000000000288 - 0.0, 25000.0, 34.0, 4545.299999997396, 1284.5999999996125, 2619.8000000001202 - 0.05, 25000.0, 34.0, 4539.599999998129, 1224.1999999997247, 2629.600000000122 - 0.1, 25000.0, 34.0, 4529.2999999987105, 1163.2999999998128, 2630.100000000109 -0.15000000000000002, 25000.0, 34.0, 4514.2999999991625, 1102.29999999988, 2622.0000000000873 - 0.2, 25000.0, 34.0, 4494.499999999497, 1041.5999999999285, 2606.000000000061 - 0.25, 25000.0, 34.0, 4469.799999999732, 981.5999999999617, 2582.8000000000343 -0.30000000000000004, 25000.0, 34.0, 4440.099999999881, 922.6999999999824, 2553.100000000012 -0.35000000000000003, 25000.0, 34.0, 4405.299999999963, 865.2999999999945, 2517.6 - 0.4, 25000.0, 34.0, 4365.299999999996, 809.8000000000004, 2477.000000000002 - 0.45, 25000.0, 34.0, 4319.9999999999945, 756.6000000000035, 2432.0000000000227 - 0.5, 25000.0, 34.0, 4269.29999999997, 706.1000000000066, 2383.3000000000657 - 0.55, 25000.0, 34.0, 4213.100000000103, 658.7000000000023, 2331.6000000000163 - 0.6000000000000001, 25000.0, 34.0, 4151.700000000002, 614.4999999999986, 2277.500000000001 - 0.65, 25000.0, 34.0, 4084.199999999999, 573.3999999999971, 2220.7999999999847 - 0.7000000000000001, 25000.0, 34.0, 4002.4999999999973, 529.7999999999972, 2151.799999999994 - 0.75, 25000.0, 34.0, 3915.3999999999724, 488.9999999999934, 2080.7999999999815 - 0.8, 25000.0, 34.0, 3823.7999999999156, 451.09999999998695, 2008.1999999999596 - 0.0, 25000.0, 36.0, 5200.299999996687, 1386.8999999996997, 2950.400000000227 - 0.05, 25000.0, 36.0, 5222.899999997663, 1318.7999999997667, 2949.8000000001707 - 0.1, 25000.0, 36.0, 5233.999999998426, 1251.8999999998252, 2941.800000000121 -0.15000000000000002, 25000.0, 36.0, 5234.199999998997, 1186.3999999998748, 2926.80000000008 - 0.2, 25000.0, 36.0, 5224.099999999409, 1122.4999999999154, 2905.200000000048 - 0.25, 25000.0, 36.0, 5204.2999999996855, 1060.3999999999487, 2877.4000000000246 -0.30000000000000004, 25000.0, 36.0, 5175.39999999986, 1000.2999999999731, 2843.800000000009 -0.35000000000000003, 25000.0, 36.0, 5137.999999999957, 942.3999999999902, 2804.800000000001 - 0.4, 25000.0, 36.0, 5092.700000000005, 886.8999999999991, 2760.8000000000006 - 0.45, 25000.0, 36.0, 5040.100000000032, 834.0000000000003, 2712.200000000007 - 0.5, 25000.0, 36.0, 4980.8000000000675, 783.899999999994, 2659.400000000022 - 0.55, 25000.0, 36.0, 4915.400000000029, 736.8000000000192, 2602.800000000043 - 0.6000000000000001, 25000.0, 36.0, 4843.399999999994, 692.8000000000033, 2543.4999999999923 - 0.65, 25000.0, 36.0, 4764.99999999998, 652.6000000000051, 2482.799999999981 - 0.7000000000000001, 25000.0, 36.0, 4669.400000000001, 609.9999999999991, 2410.100000000002 - 0.75, 25000.0, 36.0, 4567.800000000037, 570.2999999999942, 2334.8000000000025 - 0.8, 25000.0, 36.0, 4461.10000000011, 533.499999999984, 2257.4999999999955 - 0.0, 25000.0, 38.0, 6179.599999998828, 1476.8999999993048, 3390.8999999997313 - 0.05, 25000.0, 38.0, 6137.499999999119, 1405.6999999995166, 3354.799999999818 - 0.1, 25000.0, 38.0, 6096.599999999359, 1336.49999999968, 3317.999999999882 -0.15000000000000002, 25000.0, 38.0, 6055.899999999557, 1269.3999999998014, 3280.0999999999267 - 0.2, 25000.0, 38.0, 6014.399999999714, 1204.4999999998868, 3240.699999999956 - 0.25, 25000.0, 38.0, 5971.099999999834, 1141.8999999999432, 3199.3999999999746 -0.30000000000000004, 25000.0, 38.0, 5924.999999999919, 1081.699999999976, 3155.7999999999856 -0.35000000000000003, 25000.0, 38.0, 5875.09999999997, 1023.9999999999931, 3109.499999999996 - 0.4, 25000.0, 38.0, 5820.399999999995, 968.8999999999997, 3060.100000000005 - 0.45, 25000.0, 38.0, 5759.899999999995, 916.5000000000026, 3007.2000000000203 - 0.5, 25000.0, 38.0, 5692.59999999997, 866.9000000000085, 2950.400000000044 - 0.55, 25000.0, 38.0, 5617.500000000001, 820.2000000000104, 2889.300000000063 - 0.6000000000000001, 25000.0, 38.0, 5535.400000000016, 776.8999999999985, 2825.499999999998 - 0.65, 25000.0, 38.0, 5445.600000000083, 736.8999999999974, 2759.099999999982 - 0.7000000000000001, 25000.0, 38.0, 5336.5999999999985, 695.5999999999977, 2682.2999999999965 - 0.75, 25000.0, 38.0, 5220.399999999995, 657.1999999999964, 2602.699999999995 - 0.8, 25000.0, 38.0, 5098.399999999977, 621.5999999999931, 2521.299999999995 - 0.0, 25000.0, 40.0, 6774.100000001599, 1477.2999999995213, 3427.5000000001737 - 0.05, 25000.0, 40.0, 6777.300000001191, 1431.1999999996553, 3478.000000000095 - 0.1, 25000.0, 40.0, 6771.30000000085, 1381.4999999997615, 3507.900000000041 -0.15000000000000002, 25000.0, 40.0, 6756.2000000005755, 1328.999999999844, 3519.2000000000085 - 0.2, 25000.0, 40.0, 6732.1000000003605, 1274.4999999999059, 3513.8999999999933 - 0.25, 25000.0, 40.0, 6699.100000000202, 1218.7999999999495, 3493.9999999999886 -0.30000000000000004, 25000.0, 40.0, 6657.300000000092, 1162.6999999999775, 3461.4999999999923 -0.35000000000000003, 25000.0, 40.0, 6606.800000000024, 1106.9999999999932, 3418.3999999999974 - 0.4, 25000.0, 40.0, 6547.699999999996, 1052.5000000000002, 3366.7000000000003 - 0.45, 25000.0, 40.0, 6480.099999999998, 1000.0000000000008, 3308.3999999999965 - 0.5, 25000.0, 40.0, 6404.100000000028, 950.2999999999971, 3245.4999999999814 - 0.55, 25000.0, 40.0, 6319.80000000016, 904.2000000000176, 3179.9999999999845 - 0.6000000000000001, 25000.0, 40.0, 6227.400000000023, 861.2000000000024, 3111.100000000017 - 0.65, 25000.0, 40.0, 6126.40000000009, 821.3000000000078, 3038.200000000074 - 0.7000000000000001, 25000.0, 40.0, 6003.499999999999, 781.2000000000024, 2957.8999999999955 - 0.75, 25000.0, 40.0, 5873.000000000003, 744.1000000000058, 2874.3999999999915 - 0.8, 25000.0, 40.0, 5735.699999999997, 709.800000000007, 2788.5999999999844 - 0.0, 25000.0, 42.0, 7201.338857143723, 1531.8771428571938, 3623.85314285827 - 0.05, 25000.0, 42.0, 7205.9742857148285, 1483.7662857143125, 3672.2222857150814 - 0.1, 25000.0, 42.0, 7200.592571428879, 1432.57200000001, 3700.2308571433914 -0.15000000000000002, 25000.0, 42.0, 7185.327428571578, 1379.0297142857141, 3709.804000000335 - 0.2, 25000.0, 42.0, 7160.3125714286225, 1323.8748571428516, 3702.866857143047 - 0.25, 25000.0, 42.0, 7125.681714285716, 1267.8428571428503, 3681.344571428665 -0.30000000000000004, 25000.0, 42.0, 7081.568571428556, 1211.669142857137, 3647.162285714319 -0.35000000000000003, 25000.0, 42.0, 7028.10685714285, 1156.08914285714, 3602.2451428571476 - 0.4, 25000.0, 42.0, 6965.430285714287, 1101.838285714286, 3548.5182857142845 - 0.45, 25000.0, 42.0, 6893.672571428577, 1049.6520000000028, 3487.9068571428634 - 0.5, 25000.0, 42.0, 6812.967428571416, 1000.2657142857178, 3422.3360000000207 - 0.55, 25000.0, 42.0, 6723.448571428582, 954.4148571428586, 3353.730857142858 - 0.6000000000000001, 25000.0, 42.0, 6625.392571428571, 911.5131428571457, 3281.2645714285695 - 0.65, 25000.0, 42.0, 6518.05942857144, 871.5240000000081, 3204.2394285714313 - 0.7000000000000001, 25000.0, 42.0, 6387.5434285714555, 831.6040000000007, 3120.2634285714416 - 0.75, 25000.0, 42.0, 6248.869714285774, 794.7125714285745, 3033.0422857143094 - 0.8, 25000.0, 42.0, 6102.97542857153, 760.6862857142926, 2943.3862857143095 - 0.0, 25000.0, 44.0, 7515.267428573812, 1612.0485714287408, 3889.6645714312112 - 0.05, 25000.0, 44.0, 7498.117142858703, 1547.6891428572442, 3890.3251428590083 - 0.1, 25000.0, 44.0, 7475.1782857152275, 1483.972000000053, 3881.239428572684 -0.15000000000000002, 25000.0, 44.0, 7446.061714286227, 1421.1668571428775, 3862.9840000007894 - 0.2, 25000.0, 44.0, 7410.378285714515, 1359.5434285714298, 3836.135428571882 - 0.25, 25000.0, 44.0, 7367.738857142927, 1299.3714285714204, 3801.270285714508 -0.30000000000000004, 25000.0, 44.0, 7317.754285714288, 1240.9205714285629, 3758.965142857226 -0.35000000000000003, 25000.0, 44.0, 7260.035428571417, 1184.4605714285656, 3709.7965714285865 - 0.4, 25000.0, 44.0, 7194.193142857149, 1130.2611428571436, 3654.34114285714 - 0.45, 25000.0, 44.0, 7119.838285714304, 1078.5920000000062, 3593.1754285714424 - 0.5, 25000.0, 44.0, 7036.581714285719, 1029.7228571428648, 3526.876000000044 - 0.55, 25000.0, 44.0, 6944.034285714296, 983.9234285714305, 3456.019428571424 - 0.6000000000000001, 25000.0, 44.0, 6842.878285714283, 941.0245714285761, 3380.990285714283 - 0.65, 25000.0, 44.0, 6731.9337142857285, 900.884000000014, 3301.373714285718 - 0.7000000000000001, 25000.0, 44.0, 6597.277714285766, 860.5640000000012, 3213.737714285736 - 0.75, 25000.0, 44.0, 6453.926857142969, 823.2582857142911, 3123.0051428571774 - 0.8, 25000.0, 44.0, 6303.269714285897, 788.9091428571545, 3029.909142857169 - 0.0, 25000.0, 46.0, 7781.253599999968, 1670.7576000000292, 4065.1528000006115 - 0.05, 25000.0, 46.0, 7753.888799999919, 1596.3480000000088, 4043.9128000004284 - 0.1, 25000.0, 46.0, 7722.371999999904, 1524.8983999999964, 4017.819200000287 -0.15000000000000002, 25000.0, 46.0, 7686.098399999908, 1456.3887999999902, 3986.804000000181 - 0.2, 25000.0, 46.0, 7644.463199999928, 1390.799199999989, 3950.7992000001054 - 0.25, 25000.0, 46.0, 7596.861599999954, 1328.1095999999907, 3909.736800000056 -0.30000000000000004, 25000.0, 46.0, 7542.688799999979, 1268.2999999999943, 3863.5488000000246 -0.35000000000000003, 25000.0, 46.0, 7481.339999999995, 1211.3503999999978, 3812.167200000008 - 0.4, 25000.0, 46.0, 7412.210400000001, 1157.2407999999998, 3755.5240000000003 - 0.45, 25000.0, 46.0, 7334.695199999984, 1105.9511999999988, 3693.5511999999962 - 0.5, 25000.0, 46.0, 7248.189599999935, 1057.4615999999926, 3626.180799999988 - 0.55, 25000.0, 46.0, 7152.088800000006, 1011.7519999999979, 3553.3448000000185 - 0.6000000000000001, 25000.0, 46.0, 7047.215200000018, 968.9295999999969, 3476.0184000000013 - 0.65, 25000.0, 46.0, 6932.150400000042, 928.7879999999915, 3394.168800000013 - 0.7000000000000001, 25000.0, 46.0, 6792.506399999961, 888.1607999999969, 3303.269599999996 - 0.75, 25000.0, 46.0, 6644.0047999999015, 850.5399999999938, 3209.364799999998 - 0.8, 25000.0, 46.0, 6488.021599999819, 815.9351999999893, 3113.1296000000057 - 0.0, 25000.0, 48.0, 8041.831200000129, 1697.8952000001418, 4129.50960000108 - 0.05, 25000.0, 48.0, 8022.317599999999, 1624.9440000000818, 4127.097600000756 - 0.1, 25000.0, 48.0, 7996.259999999931, 1554.66480000004, 4115.570400000506 -0.15000000000000002, 25000.0, 48.0, 7963.300799999905, 1487.0736000000131, 4095.3440000003193 - 0.2, 25000.0, 48.0, 7923.082399999916, 1422.1863999999987, 4066.8344000001857 - 0.25, 25000.0, 48.0, 7875.247199999942, 1360.0191999999931, 4030.457600000098 -0.30000000000000004, 25000.0, 48.0, 7819.437599999977, 1300.5879999999934, 3986.629600000043 -0.35000000000000003, 25000.0, 48.0, 7755.2959999999985, 1243.908799999997, 3935.766400000014 - 0.4, 25000.0, 48.0, 7682.464800000002, 1189.9975999999997, 3878.284 - 0.45, 25000.0, 48.0, 7600.586399999967, 1138.8703999999989, 3814.5983999999926 - 0.5, 25000.0, 48.0, 7509.303199999883, 1090.5431999999914, 3745.125599999981 - 0.55, 25000.0, 48.0, 7408.257600000019, 1045.0319999999956, 3670.281600000026 - 0.6000000000000001, 25000.0, 48.0, 7298.046400000026, 1002.4031999999945, 3590.6007999999993 - 0.65, 25000.0, 48.0, 7177.292800000061, 962.4519999999857, 3506.369600000017 - 0.7000000000000001, 25000.0, 48.0, 7030.520799999938, 921.8175999999955, 3412.6071999999936 - 0.75, 25000.0, 48.0, 6875.105599999839, 884.195999999989, 3315.8015999999934 - 0.8, 25000.0, 48.0, 6711.87919999971, 849.5983999999813, 3216.5872000000036 - 0.0, 25000.0, 50.0, 8316.700000000581, 1720.3000000002658, 4200.9000000017 - 0.05, 25000.0, 50.0, 8301.30000000027, 1650.500000000162, 4216.50000000119 - 0.1, 25000.0, 50.0, 8277.700000000077, 1582.7000000000874, 4218.800000000796 -0.15000000000000002, 25000.0, 50.0, 8245.699999999973, 1517.0000000000382, 4208.700000000499 - 0.2, 25000.0, 50.0, 8205.09999999994, 1453.5000000000089, 4187.10000000029 - 0.25, 25000.0, 50.0, 8155.6999999999525, 1392.2999999999956, 4154.900000000149 -0.30000000000000004, 25000.0, 50.0, 8097.299999999982, 1333.4999999999923, 4113.000000000064 -0.35000000000000003, 25000.0, 50.0, 8029.700000000007, 1277.1999999999953, 4062.3000000000193 - 0.4, 25000.0, 50.0, 7952.700000000003, 1223.4999999999995, 4003.6999999999994 - 0.45, 25000.0, 50.0, 7866.099999999945, 1172.5, 3938.0999999999894 - 0.5, 25000.0, 50.0, 7769.69999999981, 1124.2999999999925, 3866.3999999999733 - 0.55, 25000.0, 50.0, 7663.300000000044, 1078.9999999999927, 3789.5000000000337 - 0.6000000000000001, 25000.0, 50.0, 7547.300000000036, 1036.599999999992, 3707.499999999996 - 0.65, 25000.0, 50.0, 7420.400000000085, 996.8999999999791, 3620.900000000017 - 0.7000000000000001, 25000.0, 50.0, 7266.099999999911, 956.2999999999932, 3524.2999999999893 - 0.75, 25000.0, 50.0, 7103.399999999762, 918.6999999999824, 3424.5999999999854 - 0.8, 25000.0, 50.0, 6932.699999999577, 884.0999999999691, 3322.3999999999965 - 0.0, 25000.0, 52.0, 8636.976800001472, 1746.3368000003827, 4328.002400002502 - 0.05, 25000.0, 52.0, 8614.298400000844, 1679.1280000002369, 4347.486400001748 - 0.1, 25000.0, 52.0, 8584.164000000417, 1613.375200000131, 4352.461600001163 -0.15000000000000002, 25000.0, 52.0, 8546.243200000163, 1549.246400000059, 4343.9600000007285 - 0.2, 25000.0, 52.0, 8500.20560000004, 1486.909600000016, 4323.013600000417 - 0.25, 25000.0, 52.0, 8445.720799999994, 1426.5327999999952, 4290.654400000215 -0.30000000000000004, 25000.0, 52.0, 8382.458400000007, 1368.2839999999894, 4247.914400000091 -0.35000000000000003, 25000.0, 52.0, 8310.088000000018, 1312.3311999999926, 4195.8256000000265 - 0.4, 25000.0, 52.0, 8228.279200000003, 1258.8423999999995, 4135.419999999998 - 0.45, 25000.0, 52.0, 8136.701599999915, 1207.9856000000025, 4067.729599999985 - 0.5, 25000.0, 52.0, 8035.024799999715, 1159.928799999996, 3993.7863999999636 - 0.55, 25000.0, 52.0, 7922.918400000076, 1114.8399999999897, 3914.622400000041 - 0.6000000000000001, 25000.0, 52.0, 7800.761600000048, 1072.6847999999893, 3830.223199999992 - 0.65, 25000.0, 52.0, 7667.283200000119, 1033.251999999971, 3741.094400000014 - 0.7000000000000001, 25000.0, 52.0, 7505.279199999876, 992.7023999999905, 3641.496799999984 - 0.75, 25000.0, 52.0, 7334.974399999665, 955.1079999999736, 3538.7423999999733 - 0.8, 25000.0, 52.0, 7156.736799999417, 920.4575999999523, 3433.3967999999795 - 0.0, 25000.0, 54.0, 9033.778400002962, 1784.3704000004773, 4559.495200003516 - 0.05, 25000.0, 54.0, 8984.775200001823, 1716.9400000002943, 4555.423200002449 - 0.1, 25000.0, 54.0, 8933.124000001031, 1651.061600000162, 4541.508800001626 -0.15000000000000002, 25000.0, 54.0, 8877.877600000518, 1586.8912000000719, 4518.212000001013 - 0.2, 25000.0, 54.0, 8818.088800000225, 1524.5848000000178, 4485.992800000578 - 0.25, 25000.0, 54.0, 8752.81040000009, 1464.2983999999906, 4445.311200000293 -0.30000000000000004, 25000.0, 54.0, 8681.095200000047, 1406.1879999999837, 4396.627200000121 -0.35000000000000003, 25000.0, 54.0, 8601.996000000041, 1350.4095999999893, 4340.400800000035 - 0.4, 25000.0, 54.0, 8514.565600000005, 1297.1191999999994, 4277.091999999997 - 0.45, 25000.0, 54.0, 8417.856799999878, 1246.4728000000066, 4207.16079999998 - 0.5, 25000.0, 54.0, 8310.922399999594, 1198.6264000000026, 4131.067199999953 - 0.55, 25000.0, 54.0, 8192.815200000121, 1153.735999999985, 4049.271200000048 - 0.6000000000000001, 25000.0, 54.0, 8064.216800000061, 1111.822399999987, 3962.2775999999844 - 0.65, 25000.0, 54.0, 7923.753600000161, 1072.627999999964, 3870.287200000008 - 0.7000000000000001, 25000.0, 54.0, 7754.093599999835, 1032.1191999999867, 3767.3463999999753 - 0.75, 25000.0, 54.0, 7575.915199999557, 994.4759999999615, 3661.211199999954 - 0.8, 25000.0, 54.0, 7390.24239999923, 959.6887999999296, 3552.4063999999516 - 0.0, 25000.0, 56.0, 9538.221600005198, 1842.7656000005304, 4944.056800004766 - 0.05, 25000.0, 56.0, 9436.192800003319, 1770.0480000003226, 4875.676800003313 - 0.1, 25000.0, 56.0, 9342.05200000198, 1700.1304000001721, 4810.895200002192 -0.15000000000000002, 25000.0, 56.0, 9253.550400001082, 1633.0128000000707, 4748.54400000136 - 0.2, 25000.0, 56.0, 9168.439200000532, 1568.69520000001, 4687.4552000007725 - 0.25, 25000.0, 56.0, 9084.469600000248, 1507.1775999999804, 4626.460800000387 -0.30000000000000004, 25000.0, 56.0, 8999.392800000123, 1448.459999999975, 4564.392800000156 -0.35000000000000003, 25000.0, 56.0, 8910.960000000074, 1392.5423999999844, 4500.083200000041 - 0.4, 25000.0, 56.0, 8816.922400000007, 1339.4247999999993, 4432.363999999996 - 0.45, 25000.0, 56.0, 8715.031199999825, 1289.1072000000122, 4360.067199999977 - 0.5, 25000.0, 56.0, 8603.037599999443, 1241.5896000000143, 4282.024799999939 - 0.55, 25000.0, 56.0, 8478.692800000177, 1196.871999999981, 4197.068800000053 - 0.6000000000000001, 25000.0, 56.0, 8343.45120000008, 1155.177599999984, 4107.170399999974 - 0.65, 25000.0, 56.0, 8195.622400000208, 1116.1479999999563, 4011.812799999999 - 0.7000000000000001, 25000.0, 56.0, 8018.578399999787, 1075.6447999999816, 3904.9975999999638 - 0.75, 25000.0, 56.0, 7832.3087999994295, 1037.8599999999465, 3794.9887999999273 - 0.8, 25000.0, 56.0, 7639.469599999018, 1002.8111999999, 3682.2575999999103 - 0.0, 30000.0, 26.0, 1587.7999999999893, 1074.6999999999748, 1549.299999999925 - 0.05, 30000.0, 26.0, 1607.3999999999937, 1006.499999999982, 1558.1999999999473 - 0.1, 30000.0, 26.0, 1620.5999999999967, 938.6999999999878, 1559.3999999999648 -0.15000000000000002, 30000.0, 26.0, 1627.8999999999987, 871.5999999999921, 1553.599999999978 - 0.2, 30000.0, 26.0, 1629.7999999999997, 805.4999999999953, 1541.4999999999875 - 0.25, 30000.0, 26.0, 1626.8000000000002, 740.6999999999975, 1523.7999999999938 -0.30000000000000004, 30000.0, 26.0, 1619.4000000000003, 677.499999999999, 1501.1999999999973 -0.35000000000000003, 30000.0, 26.0, 1608.1000000000001, 616.1999999999997, 1474.3999999999992 - 0.4, 30000.0, 26.0, 1593.4, 557.1, 1444.1 - 0.45, 30000.0, 26.0, 1575.8000000000004, 500.5, 1411.0 - 0.5, 30000.0, 26.0, 1555.8000000000009, 446.69999999999993, 1375.8 - 0.55, 30000.0, 26.0, 1533.9000000000008, 396.0000000000004, 1339.2000000000007 - 0.6000000000000001, 30000.0, 26.0, 1509.4, 348.4999999999999, 1301.2000000000005 - 0.65, 30000.0, 26.0, 1483.199999999999, 304.70000000000005, 1262.4000000000012 - 0.7000000000000001, 30000.0, 26.0, 1455.0, 264.99999999999983, 1224.5000000000002 - 0.75, 30000.0, 26.0, 1424.8999999999999, 229.8999999999998, 1187.8000000000002 - 0.8, 30000.0, 26.0, 1393.0999999999995, 199.89999999999964, 1153.4 - 0.0, 30000.0, 28.0, 2577.699999999213, 1142.3999999998246, 1948.0000000003222 - 0.05, 30000.0, 28.0, 2551.49999999945, 1079.099999999876, 1932.7000000002267 - 0.1, 30000.0, 28.0, 2527.299999999633, 1015.2999999999162, 1914.3000000001516 -0.15000000000000002, 30000.0, 28.0, 2504.49999999977, 951.3999999999465, 1892.9000000000947 - 0.2, 30000.0, 28.0, 2482.4999999998668, 887.7999999999686, 1868.6000000000545 - 0.25, 30000.0, 28.0, 2460.6999999999307, 824.8999999999833, 1841.5000000000277 -0.30000000000000004, 30000.0, 28.0, 2438.4999999999704, 763.0999999999925, 1811.7000000000112 -0.35000000000000003, 30000.0, 28.0, 2415.29999999999, 702.7999999999972, 1779.300000000003 - 0.4, 30000.0, 28.0, 2390.5, 644.3999999999997, 1744.400000000001 - 0.45, 30000.0, 28.0, 2363.5000000000045, 588.300000000001, 1707.1000000000022 - 0.5, 30000.0, 28.0, 2333.700000000011, 534.900000000002, 1667.5000000000027 - 0.55, 30000.0, 28.0, 2300.500000000009, 484.6000000000037, 1625.6999999999994 - 0.6000000000000001, 30000.0, 28.0, 2264.2000000000003, 437.50000000000006, 1581.900000000003 - 0.65, 30000.0, 28.0, 2224.600000000006, 394.1000000000001, 1538.000000000003 - 0.7000000000000001, 30000.0, 28.0, 2182.3000000000006, 354.7000000000002, 1493.600000000002 - 0.75, 30000.0, 28.0, 2137.1999999999985, 319.60000000000144, 1450.3000000000043 - 0.8, 30000.0, 28.0, 2089.6999999999935, 289.500000000003, 1408.8000000000045 - 0.0, 30000.0, 30.0, 3346.7999999986814, 1253.799999999447, 2131.4000000006454 - 0.05, 30000.0, 30.0, 3338.3999999990897, 1182.8999999996108, 2153.7000000004614 - 0.1, 30000.0, 30.0, 3326.8999999994, 1113.1999999997383, 2164.600000000316 -0.15000000000000002, 30000.0, 30.0, 3312.199999999628, 1044.8999999998339, 2165.100000000203 - 0.2, 30000.0, 30.0, 3294.1999999997865, 978.1999999999024, 2156.20000000012 - 0.25, 30000.0, 30.0, 3272.799999999889, 913.2999999999483, 2138.900000000062 -0.30000000000000004, 30000.0, 30.0, 3247.8999999999514, 850.3999999999766, 2114.2000000000253 -0.35000000000000003, 30000.0, 30.0, 3219.399999999983, 789.699999999992, 2083.100000000007 - 0.4, 30000.0, 30.0, 3187.1999999999994, 731.3999999999991, 2046.6000000000026 - 0.45, 30000.0, 30.0, 3151.200000000014, 675.7000000000023, 2005.7000000000075 - 0.5, 30000.0, 30.0, 3111.300000000041, 622.8000000000069, 1961.4000000000187 - 0.55, 30000.0, 30.0, 3067.400000000038, 572.9000000000085, 1914.6999999999998 - 0.6000000000000001, 30000.0, 30.0, 3019.0000000000095, 526.3000000000012, 1866.1000000000095 - 0.65, 30000.0, 30.0, 2966.2000000000376, 483.20000000000147, 1815.9000000000085 - 0.7000000000000001, 30000.0, 30.0, 2909.6999999999953, 444.10000000000053, 1765.6000000000056 - 0.75, 30000.0, 30.0, 2849.7999999999915, 409.30000000000354, 1715.400000000016 - 0.8, 30000.0, 30.0, 2786.2999999999847, 378.80000000000797, 1666.4000000000203 - 0.0, 30000.0, 32.0, 4046.699999999955, 1324.400000000169, 2579.499999998938 - 0.05, 30000.0, 32.0, 4074.899999999916, 1257.6000000001118, 2566.0999999992223 - 0.1, 30000.0, 32.0, 4091.199999999899, 1191.2000000000673, 2547.999999999454 -0.15000000000000002, 30000.0, 32.0, 4096.399999999897, 1125.5000000000352, 2525.399999999637 - 0.2, 30000.0, 32.0, 4091.299999999907, 1060.8000000000136, 2498.4999999997767 - 0.25, 30000.0, 32.0, 4076.699999999927, 997.4000000000016, 2467.4999999998777 -0.30000000000000004, 30000.0, 32.0, 4053.399999999951, 935.5999999999959, 2432.5999999999453 -0.35000000000000003, 30000.0, 32.0, 4022.1999999999757, 875.6999999999963, 2393.9999999999845 - 0.4, 30000.0, 32.0, 3983.899999999997, 818.0000000000001, 2351.8999999999983 - 0.45, 30000.0, 32.0, 3939.3000000000116, 762.8000000000062, 2306.4999999999927 - 0.5, 30000.0, 32.0, 3889.200000000014, 710.4000000000132, 2257.999999999972 - 0.55, 30000.0, 32.0, 3834.4000000000387, 661.1000000000118, 2206.60000000001 - 0.6000000000000001, 30000.0, 32.0, 3773.899999999983, 614.5999999999995, 2151.699999999997 - 0.65, 30000.0, 32.0, 3707.7999999999215, 572.2000000000019, 2096.3999999999837 - 0.7000000000000001, 30000.0, 32.0, 3637.2999999999693, 533.5000000000038, 2040.4000000000024 - 0.75, 30000.0, 32.0, 3562.0999999999185, 498.700000000012, 1983.3000000000247 - 0.8, 30000.0, 32.0, 3482.8999999998223, 467.9000000000236, 1926.6000000000683 - 0.0, 30000.0, 34.0, 4934.5999999973865, 1431.000000000178, 2947.7999999993012 - 0.05, 30000.0, 34.0, 4945.799999998146, 1357.5000000001237, 2920.1999999995073 - 0.1, 30000.0, 34.0, 4947.499999998739, 1286.0000000000807, 2890.5999999996675 -0.15000000000000002, 30000.0, 34.0, 4940.099999999187, 1216.6000000000492, 2858.7999999997874 - 0.2, 30000.0, 34.0, 4923.999999999512, 1149.4000000000262, 2824.599999999873 - 0.25, 30000.0, 34.0, 4899.599999999736, 1084.5000000000118, 2787.79999999993 -0.30000000000000004, 30000.0, 34.0, 4867.299999999877, 1022.0000000000036, 2748.1999999999675 -0.35000000000000003, 30000.0, 34.0, 4827.499999999959, 962.0000000000003, 2705.5999999999885 - 0.4, 30000.0, 34.0, 4780.600000000001, 904.6000000000005, 2659.800000000002 - 0.45, 30000.0, 34.0, 4727.000000000025, 849.9000000000025, 2610.6000000000136 - 0.5, 30000.0, 34.0, 4667.100000000053, 798.0000000000057, 2557.8000000000284 - 0.55, 30000.0, 34.0, 4601.300000000055, 749.0000000000072, 2501.2000000000317 - 0.6000000000000001, 30000.0, 34.0, 4528.400000000022, 703.3999999999979, 2441.800000000004 - 0.65, 30000.0, 34.0, 4449.500000000066, 661.4999999999881, 2381.099999999997 - 0.7000000000000001, 30000.0, 34.0, 4364.599999999989, 623.0999999999985, 2318.2999999999984 - 0.75, 30000.0, 34.0, 4274.699999999954, 588.2999999999934, 2254.6999999999734 - 0.8, 30000.0, 34.0, 4179.399999999887, 557.4999999999814, 2190.599999999913 - 0.0, 30000.0, 36.0, 5728.000000000285, 1447.6999999999337, 2984.199999998774 - 0.05, 30000.0, 36.0, 5749.8000000002285, 1395.1999999999523, 3042.3999999991433 - 0.1, 30000.0, 36.0, 5758.600000000174, 1339.9999999999666, 3079.29999999943 -0.15000000000000002, 30000.0, 36.0, 5755.100000000121, 1282.7999999999768, 3096.9999999996426 - 0.2, 30000.0, 36.0, 5740.000000000074, 1224.2999999999845, 3097.5999999997935 - 0.25, 30000.0, 36.0, 5714.000000000036, 1165.19999999999, 3083.1999999998925 -0.30000000000000004, 30000.0, 36.0, 5677.800000000008, 1106.1999999999941, 3055.8999999999546 -0.35000000000000003, 30000.0, 36.0, 5632.099999999996, 1047.9999999999973, 3017.7999999999856 - 0.4, 30000.0, 36.0, 5577.5999999999985, 991.3000000000011, 2971.0000000000005 - 0.45, 30000.0, 36.0, 5515.000000000019, 936.8000000000055, 2917.6000000000095 - 0.5, 30000.0, 36.0, 5445.000000000064, 885.2000000000113, 2859.700000000022 - 0.55, 30000.0, 36.0, 5368.300000000053, 837.2000000000046, 2799.400000000028 - 0.6000000000000001, 30000.0, 36.0, 5283.200000000008, 792.3999999999996, 2735.7000000000094 - 0.65, 30000.0, 36.0, 5190.800000000018, 750.800000000003, 2668.700000000013 - 0.7000000000000001, 30000.0, 36.0, 5092.199999999991, 712.6999999999987, 2600.099999999993 - 0.75, 30000.0, 36.0, 4987.0000000000355, 678.2999999999993, 2529.7000000000044 - 0.8, 30000.0, 36.0, 4876.000000000127, 647.6, 2458.5000000000296 - 0.0, 30000.0, 38.0, 6611.4999999956635, 1658.5999999995806, 3733.2000000005555 - 0.05, 30000.0, 38.0, 6617.199999996998, 1571.0999999997098, 3674.700000000362 - 0.1, 30000.0, 38.0, 6612.199999998024, 1488.499999999809, 3619.1000000002186 -0.15000000000000002, 30000.0, 38.0, 6596.799999998783, 1410.5999999998814, 3565.6000000001195 - 0.2, 30000.0, 38.0, 6571.299999999316, 1337.199999999932, 3513.400000000056 - 0.25, 30000.0, 38.0, 6535.999999999666, 1268.0999999999651, 3461.7000000000194 -0.30000000000000004, 30000.0, 38.0, 6491.199999999871, 1203.099999999985, 3409.700000000004 -0.35000000000000003, 30000.0, 38.0, 6437.199999999969, 1141.9999999999939, 3356.5999999999995 - 0.4, 30000.0, 38.0, 6374.300000000005, 1084.5999999999985, 3301.6000000000004 - 0.45, 30000.0, 38.0, 6302.800000000017, 1030.7000000000016, 3243.899999999998 - 0.5, 30000.0, 38.0, 6223.000000000046, 980.100000000007, 3182.699999999982 - 0.55, 30000.0, 38.0, 6135.2000000000735, 932.5999999999977, 3117.1999999999857 - 0.6000000000000001, 30000.0, 38.0, 6038.100000000012, 888.2000000000058, 3047.3000000000125 - 0.65, 30000.0, 38.0, 5932.400000000043, 847.3000000000072, 2974.7000000000153 - 0.7000000000000001, 30000.0, 38.0, 5819.599999999999, 809.2999999999932, 2899.000000000002 - 0.75, 30000.0, 38.0, 5699.400000000033, 774.9999999999859, 2821.6999999999966 - 0.8, 30000.0, 38.0, 5572.600000000122, 744.3999999999743, 2742.9999999999636 - 0.0, 30000.0, 40.0, 7535.400000000952, 1639.5000000003574, 3802.2000000005596 - 0.05, 30000.0, 40.0, 7513.300000000715, 1583.6000000002516, 3826.2000000003773 - 0.1, 30000.0, 40.0, 7485.300000000515, 1526.3000000001698, 3835.600000000238 -0.15000000000000002, 30000.0, 40.0, 7451.000000000353, 1468.100000000108, 3831.5000000001364 - 0.2, 30000.0, 40.0, 7410.000000000224, 1409.500000000064, 3815.0000000000664 - 0.25, 30000.0, 40.0, 7361.900000000124, 1351.0000000000339, 3787.200000000023 -0.30000000000000004, 30000.0, 40.0, 7306.300000000056, 1293.1000000000156, 3749.2000000000016 -0.35000000000000003, 30000.0, 40.0, 7242.800000000016, 1236.3000000000054, 3702.0999999999963 - 0.4, 30000.0, 40.0, 7170.999999999996, 1181.1000000000004, 3647.0 - 0.45, 30000.0, 40.0, 7090.499999999998, 1127.9999999999977, 3585.0000000000086 - 0.5, 30000.0, 40.0, 7000.9000000000215, 1077.4999999999943, 3517.200000000018 - 0.55, 30000.0, 40.0, 6901.800000000202, 1030.1000000000163, 3444.70000000003 - 0.6000000000000001, 30000.0, 40.0, 6792.599999999982, 985.2999999999995, 3366.5999999999935 - 0.65, 30000.0, 40.0, 6673.999999999963, 943.8000000000064, 3285.199999999985 - 0.7000000000000001, 30000.0, 40.0, 6547.000000000017, 906.1000000000039, 3202.3999999999983 - 0.75, 30000.0, 40.0, 6411.90000000006, 872.200000000006, 3117.899999999978 - 0.8, 30000.0, 40.0, 6269.100000000107, 841.500000000005, 3031.3999999999432 - 0.0, 30000.0, 42.0, 8005.990285715036, 1673.2474285716232, 3948.437142857921 - 0.05, 30000.0, 42.0, 7985.145142857598, 1622.9342857144159, 3990.0468571433676 - 0.1, 30000.0, 42.0, 7957.532000000242, 1570.200000000082, 4013.237714286026 -0.15000000000000002, 30000.0, 42.0, 7922.7782857143875, 1515.6548571429043, 4019.493714285886 - 0.2, 30000.0, 42.0, 7880.511428571448, 1459.9091428571674, 4010.298857142938 - 0.25, 30000.0, 42.0, 7830.358857142836, 1403.5731428571528, 3987.13714285717 -0.30000000000000004, 30000.0, 42.0, 7771.947999999975, 1347.2571428571462, 3951.492571428575 -0.35000000000000003, 30000.0, 42.0, 7704.906285714271, 1291.5714285714287, 3904.8491428571397 - 0.4, 30000.0, 42.0, 7628.861142857143, 1237.1262857142856, 3848.690857142856 - 0.45, 30000.0, 42.0, 7543.440000000008, 1184.5319999999995, 3784.501714285713 - 0.5, 30000.0, 42.0, 7448.270285714279, 1134.3988571428533, 3713.765714285701 - 0.55, 30000.0, 42.0, 7342.979428571434, 1087.3371428571372, 3637.966857142841 - 0.6000000000000001, 30000.0, 42.0, 7227.0005714285835, 1042.8874285714319, 3556.457142857151 - 0.65, 30000.0, 42.0, 7101.120000000055, 1001.6154285714383, 3471.247428571451 - 0.7000000000000001, 30000.0, 42.0, 6966.170285714314, 964.2091428571446, 3384.349714285726 - 0.75, 30000.0, 42.0, 6822.594285714351, 930.4034285714331, 3295.165714285756 - 0.8, 30000.0, 42.0, 6670.848571428687, 899.5817142857236, 3203.6674285715258 - 0.0, 30000.0, 44.0, 8214.073142859635, 1737.461714286159, 4137.528571430464 - 0.05, 30000.0, 44.0, 8208.216571430181, 1677.3771428574441, 4158.575428572685 - 0.1, 30000.0, 44.0, 8192.07200000096, 1616.9600000001933, 4165.394857143638 -0.15000000000000002, 30000.0, 44.0, 8165.64114285765, 1556.5834285715432, 4158.970857143299 - 0.2, 30000.0, 44.0, 8128.925714285927, 1496.6205714286325, 4140.287428571644 - 0.25, 30000.0, 44.0, 8081.92742857148, 1437.444571428599, 4110.328571428653 -0.30000000000000004, 30000.0, 44.0, 8024.6479999999865, 1379.4285714285809, 4070.0782857143013 -0.35000000000000003, 30000.0, 44.0, 7957.08914285712, 1322.9457142857161, 4020.520571428566 - 0.4, 30000.0, 44.0, 7879.252571428573, 1268.369142857143, 3962.639428571426 - 0.45, 30000.0, 44.0, 7791.14000000002, 1216.071999999999, 3897.418857142859 - 0.5, 30000.0, 44.0, 7692.753142857138, 1166.4274285714228, 3825.8428571428403 - 0.55, 30000.0, 44.0, 7584.093714285688, 1119.808571428556, 3748.8954285713894 - 0.6000000000000001, 30000.0, 44.0, 7464.266285714311, 1076.1017142857208, 3666.72857142859 - 0.65, 30000.0, 44.0, 7334.240000000122, 1035.509714285733, 3580.5817142857536 - 0.7000000000000001, 30000.0, 44.0, 7194.873142857193, 998.380571428573, 3491.4068571428784 - 0.75, 30000.0, 44.0, 7046.477142857264, 964.5177142857187, 3399.1828571429387 - 0.8, 30000.0, 44.0, 6889.794285714496, 933.6188571428669, 3304.501714285903 - 0.0, 30000.0, 46.0, 8447.301600000092, 1800.6648000001267, 4315.3656 - 0.05, 30000.0, 46.0, 8445.921600000001, 1730.664800000082, 4317.977599999974 - 0.1, 30000.0, 46.0, 8432.85839999995, 1662.436800000049, 4309.990399999962 -0.15000000000000002, 30000.0, 46.0, 8408.235199999925, 1596.1136000000251, 4291.961599999959 - 0.2, 30000.0, 46.0, 8372.175199999921, 1531.828000000011, 4264.448799999964 - 0.25, 30000.0, 46.0, 8324.801599999939, 1469.7128000000018, 4228.009599999973 -0.30000000000000004, 30000.0, 46.0, 8266.237599999959, 1409.9007999999988, 4183.201599999981 -0.35000000000000003, 30000.0, 46.0, 8196.606399999982, 1352.524799999998, 4130.582399999993 - 0.4, 30000.0, 46.0, 8116.031200000005, 1297.7175999999995, 4070.7096000000006 - 0.45, 30000.0, 46.0, 8024.635200000016, 1245.6120000000008, 4004.1408000000047 - 0.5, 30000.0, 46.0, 7922.541600000007, 1196.3408000000006, 3931.4336000000017 - 0.55, 30000.0, 46.0, 7809.873600000028, 1150.0368000000044, 3853.145600000005 - 0.6000000000000001, 30000.0, 46.0, 7685.423199999985, 1106.8999999999967, 3769.9951999999976 - 0.65, 30000.0, 46.0, 7550.5663999999515, 1066.8567999999893, 3682.5720000000065 - 0.7000000000000001, 30000.0, 46.0, 7406.174399999981, 1029.9631999999979, 3591.2031999999986 - 0.75, 30000.0, 46.0, 7252.4111999999795, 996.1327999999958, 3496.380799999999 - 0.8, 30000.0, 46.0, 7090.157600000024, 965.3359999999917, 3398.9488000000015 - 0.0, 30000.0, 48.0, 8799.627200001054, 1849.573600000298, 4467.291200000452 - 0.05, 30000.0, 48.0, 8785.815200000641, 1775.6096000001992, 4466.731200000284 - 0.1, 30000.0, 48.0, 8762.304800000347, 1704.293600000125, 4455.86880000016 -0.15000000000000002, 30000.0, 48.0, 8728.92640000015, 1635.6552000000713, 4435.215200000077 - 0.2, 30000.0, 48.0, 8685.51040000003, 1569.7240000000345, 4405.281600000025 - 0.25, 30000.0, 48.0, 8631.887199999976, 1506.5296000000126, 4366.579199999999 -0.30000000000000004, 30000.0, 48.0, 8567.887199999966, 1446.1016000000016, 4319.619199999991 -0.35000000000000003, 30000.0, 48.0, 8493.340799999982, 1388.469599999998, 4264.912799999993 - 0.4, 30000.0, 48.0, 8408.078400000006, 1333.6631999999995, 4202.971200000001 - 0.45, 30000.0, 48.0, 8311.930400000023, 1281.7120000000018, 4134.305600000006 - 0.5, 30000.0, 48.0, 8204.727200000014, 1232.6456000000023, 4059.4271999999996 - 0.55, 30000.0, 48.0, 8086.299200000051, 1186.4936000000089, 3978.847200000004 - 0.6000000000000001, 30000.0, 48.0, 7955.3743999999815, 1143.6039999999957, 3893.3903999999957 - 0.65, 30000.0, 48.0, 7813.852799999946, 1103.8095999999841, 3803.3280000000104 - 0.7000000000000001, 30000.0, 48.0, 7662.532799999965, 1067.114399999996, 3709.2224000000006 - 0.75, 30000.0, 48.0, 7501.522399999964, 1033.4735999999912, 3611.701600000002 - 0.8, 30000.0, 48.0, 7331.615200000043, 1002.9559999999844, 3511.3616000000075 - 0.0, 30000.0, 50.0, 9171.300000002611, 1889.1000000005297, 4618.100000001108 - 0.05, 30000.0, 50.0, 9139.600000001694, 1814.1000000003587, 4615.600000000735 - 0.1, 30000.0, 50.0, 9101.30000000102, 1742.0000000002287, 4602.800000000455 -0.15000000000000002, 30000.0, 50.0, 9055.80000000054, 1672.8000000001334, 4580.200000000255 - 0.2, 30000.0, 50.0, 9002.500000000233, 1606.500000000068, 4548.300000000124 - 0.25, 30000.0, 50.0, 8940.80000000006, 1543.1000000000267, 4507.600000000046 -0.30000000000000004, 30000.0, 50.0, 8870.099999999984, 1482.6000000000056, 4458.600000000007 -0.35000000000000003, 30000.0, 50.0, 8789.799999999981, 1424.9999999999984, 4401.7999999999965 - 0.4, 30000.0, 50.0, 8699.300000000008, 1370.2999999999988, 4337.700000000001 - 0.45, 30000.0, 50.0, 8598.000000000038, 1318.500000000003, 4266.800000000006 - 0.5, 30000.0, 50.0, 8485.30000000003, 1269.6000000000056, 4189.599999999999 - 0.55, 30000.0, 50.0, 8360.600000000073, 1223.6000000000151, 4106.599999999999 - 0.6000000000000001, 30000.0, 50.0, 8222.899999999983, 1180.8999999999942, 4018.5999999999917 - 0.65, 30000.0, 50.0, 8074.3999999999505, 1141.2999999999777, 3925.700000000014 - 0.7000000000000001, 30000.0, 50.0, 7915.7999999999465, 1104.7999999999934, 3828.800000000001 - 0.75, 30000.0, 50.0, 7747.199999999949, 1071.399999999985, 3728.6000000000067 - 0.8, 30000.0, 50.0, 7569.300000000063, 1041.1999999999748, 3625.400000000015 - 0.0, 30000.0, 52.0, 9559.420800004911, 1915.0584000008214, 4772.860800001987 - 0.05, 30000.0, 52.0, 9506.90480000327, 1843.48640000056, 4769.204800001343 - 0.1, 30000.0, 52.0, 9451.495200002035, 1774.1224000003594, 4755.091200000855 -0.15000000000000002, 30000.0, 52.0, 9392.08160000115, 1707.048800000212, 4731.0248000005 - 0.2, 30000.0, 52.0, 9327.553600000561, 1642.3480000001098, 4697.510400000261 - 0.25, 30000.0, 52.0, 9256.800800000203, 1580.1024000000455, 4655.052800000112 -0.30000000000000004, 30000.0, 52.0, 9178.712800000032, 1520.3944000000113, 4604.156800000032 -0.35000000000000003, 30000.0, 52.0, 9092.179199999986, 1463.3063999999977, 4545.327200000003 - 0.4, 30000.0, 52.0, 8996.089600000014, 1408.9207999999983, 4479.068800000001 - 0.45, 30000.0, 52.0, 8889.333600000055, 1357.3200000000052, 4405.886400000005 - 0.5, 30000.0, 52.0, 8770.800800000054, 1308.58640000001, 4326.284799999996 - 0.55, 30000.0, 52.0, 8639.380800000105, 1262.802400000024, 4240.768799999995 - 0.6000000000000001, 30000.0, 52.0, 8494.841599999992, 1220.2919999999935, 4150.033599999987 - 0.65, 30000.0, 52.0, 8339.235199999968, 1180.8703999999705, 4054.1680000000188 - 0.7000000000000001, 30000.0, 52.0, 8173.131199999924, 1144.58159999999, 3954.3456000000037 - 0.75, 30000.0, 52.0, 7996.701599999924, 1111.4543999999769, 3851.274400000012 - 0.8, 30000.0, 52.0, 7810.616800000081, 1081.5399999999618, 3745.0704000000246 - 0.0, 30000.0, 54.0, 9961.090400008101, 1923.2632000011731, 4936.642400003106 - 0.05, 30000.0, 54.0, 9887.358400005476, 1861.119200000802, 4932.166400002121 - 0.1, 30000.0, 54.0, 9814.541600003478, 1799.2272000005169, 4917.049600001369 -0.15000000000000002, 30000.0, 54.0, 9740.996800002027, 1737.902400000306, 4891.79840000082 - 0.2, 30000.0, 54.0, 9665.080800001037, 1677.4600000001603, 4856.919200000441 - 0.25, 30000.0, 54.0, 9585.150400000422, 1618.2152000000674, 4812.918400000201 -0.30000000000000004, 30000.0, 54.0, 9499.562400000104, 1560.483200000017, 4760.302400000067 -0.35000000000000003, 30000.0, 54.0, 9406.673599999993, 1504.5791999999974, 4699.577600000012 - 0.4, 30000.0, 54.0, 9304.840800000013, 1450.8183999999976, 4631.250400000002 - 0.45, 30000.0, 54.0, 9192.420800000076, 1399.5160000000078, 4555.827200000006 - 0.5, 30000.0, 54.0, 9067.7704000001, 1350.987200000016, 4473.814399999993 - 0.55, 30000.0, 54.0, 8929.246400000142, 1305.5472000000348, 4385.71839999999 - 0.6000000000000001, 30000.0, 54.0, 8778.040800000002, 1263.2839999999915, 4292.100799999984 - 0.65, 30000.0, 54.0, 8615.385599999996, 1224.0631999999619, 4193.212000000022 - 0.7000000000000001, 30000.0, 54.0, 8441.681599999893, 1188.020799999986, 4090.2688000000044 - 0.75, 30000.0, 54.0, 8257.284799999898, 1155.1791999999668, 3983.9232000000184 - 0.8, 30000.0, 54.0, 8062.9704000001, 1125.4479999999473, 3874.3792000000367 - 0.0, 30000.0, 56.0, 10373.409600012339, 1909.528800001583, 5114.513600004485 - 0.05, 30000.0, 56.0, 10280.58960000842, 1864.3488000010839, 5109.105600003083 - 0.1, 30000.0, 56.0, 10192.09040000542, 1815.8808000006998, 5092.982400002011 -0.15000000000000002, 30000.0, 56.0, 10105.771200003219, 1764.861600000416, 5066.629600001219 - 0.2, 30000.0, 56.0, 10019.491200001696, 1712.0280000002185, 5030.532800000668 - 0.25, 30000.0, 56.0, 9931.109600000736, 1658.1168000000923, 4985.177600000315 -0.30000000000000004, 30000.0, 56.0, 9838.485600000213, 1603.864800000023, 4931.049600000115 -0.35000000000000003, 30000.0, 56.0, 9739.478400000016, 1550.0087999999957, 4868.634400000026 - 0.4, 30000.0, 56.0, 9631.947200000019, 1497.2855999999967, 4798.417600000003 - 0.45, 30000.0, 56.0, 9513.751200000106, 1446.4320000000105, 4720.884800000005 - 0.5, 30000.0, 56.0, 9382.74960000016, 1398.1848000000232, 4636.521599999991 - 0.55, 30000.0, 56.0, 9236.801600000186, 1353.2808000000482, 4545.813599999983 - 0.6000000000000001, 30000.0, 56.0, 9079.339200000022, 1311.3799999999899, 4449.211199999981 - 0.65, 30000.0, 56.0, 8909.878400000047, 1272.420799999953, 4347.312000000028 - 0.7000000000000001, 30000.0, 56.0, 8728.60639999986, 1236.679199999981, 4240.979200000008 - 0.75, 30000.0, 56.0, 8536.207199999859, 1204.1167999999561, 4130.744800000023 - 0.8, 30000.0, 56.0, 8333.765600000115, 1174.3959999999308, 4017.3328000000497 - 0.0, 35000.0, 26.0, 1860.4999999998781, 1134.3999999999799, 1545.4999999998604 - 0.05, 35000.0, 26.0, 1839.8999999999116, 1055.4999999999857, 1573.4999999999002 - 0.1, 35000.0, 26.0, 1822.0999999999385, 980.2999999999904, 1590.6999999999316 -0.15000000000000002, 35000.0, 26.0, 1806.4999999999595, 908.6999999999938, 1598.0999999999558 - 0.2, 35000.0, 26.0, 1792.4999999999754, 840.5999999999964, 1596.6999999999734 - 0.25, 35000.0, 26.0, 1779.4999999999866, 775.8999999999982, 1587.4999999999857 -0.30000000000000004, 35000.0, 26.0, 1766.8999999999937, 714.4999999999991, 1571.4999999999936 -0.35000000000000003, 35000.0, 26.0, 1754.099999999998, 656.2999999999998, 1549.699999999998 - 0.4, 35000.0, 26.0, 1740.5, 601.2, 1523.1 - 0.45, 35000.0, 26.0, 1725.5, 549.1, 1492.7000000000003 - 0.5, 35000.0, 26.0, 1708.499999999999, 499.9, 1459.5000000000005 - 0.55, 35000.0, 26.0, 1688.8999999999992, 453.50000000000057, 1424.500000000001 - 0.6000000000000001, 35000.0, 26.0, 1663.8000000000002, 407.3999999999999, 1385.3999999999999 - 0.65, 35000.0, 26.0, 1632.900000000002, 361.50000000000006, 1343.0999999999983 - 0.7000000000000001, 35000.0, 26.0, 1600.0, 319.39999999999986, 1300.8 - 0.75, 35000.0, 26.0, 1565.1000000000004, 281.49999999999994, 1258.8000000000004 - 0.8, 35000.0, 26.0, 1528.2000000000012, 248.2000000000001, 1218.200000000001 - 0.0, 35000.0, 28.0, 2646.6999999994337, 1179.499999999923, 1909.3999999996133 - 0.05, 35000.0, 28.0, 2656.8999999995813, 1114.6999999999477, 1930.6999999997274 - 0.1, 35000.0, 28.0, 2662.6999999997015, 1050.5999999999663, 1941.9999999998163 -0.15000000000000002, 35000.0, 28.0, 2664.199999999797, 987.4999999999794, 1944.199999999884 - 0.2, 35000.0, 28.0, 2661.4999999998713, 925.6999999999883, 1938.1999999999327 - 0.25, 35000.0, 28.0, 2654.699999999926, 865.4999999999941, 1924.899999999966 -0.30000000000000004, 35000.0, 28.0, 2643.899999999963, 807.1999999999972, 1905.1999999999862 -0.35000000000000003, 35000.0, 28.0, 2629.199999999987, 751.0999999999989, 1879.9999999999961 - 0.4, 35000.0, 28.0, 2610.699999999999, 697.5000000000002, 1850.1999999999998 - 0.45, 35000.0, 28.0, 2588.5000000000014, 646.700000000002, 1816.6999999999991 - 0.5, 35000.0, 28.0, 2562.699999999996, 599.0000000000051, 1780.3999999999978 - 0.55, 35000.0, 28.0, 2533.40000000001, 554.7000000000041, 1742.2000000000169 - 0.6000000000000001, 35000.0, 28.0, 2495.5000000000014, 510.1000000000005, 1698.899999999999 - 0.65, 35000.0, 28.0, 2449.5000000000095, 464.5000000000012, 1650.1999999999987 - 0.7000000000000001, 35000.0, 28.0, 2399.6999999999994, 423.00000000000034, 1601.4000000000003 - 0.75, 35000.0, 28.0, 2347.499999999999, 385.50000000000165, 1552.0000000000034 - 0.8, 35000.0, 28.0, 2292.200000000004, 351.900000000004, 1503.1000000000101 - 0.0, 35000.0, 30.0, 3462.499999998352, 1306.499999999773, 2426.999999998648 - 0.05, 35000.0, 30.0, 3493.799999998788, 1230.7999999998467, 2396.3999999990688 - 0.1, 35000.0, 30.0, 3515.799999999142, 1158.399999999902, 2366.499999999392 -0.15000000000000002, 35000.0, 30.0, 3528.999999999421, 1089.2999999999413, 2336.899999999629 - 0.2, 35000.0, 30.0, 3533.8999999996345, 1023.4999999999671, 2307.199999999794 - 0.25, 35000.0, 30.0, 3530.9999999997904, 960.9999999999835, 2276.9999999999004 -0.30000000000000004, 35000.0, 30.0, 3520.7999999998983, 901.7999999999921, 2245.899999999961 -0.35000000000000003, 35000.0, 30.0, 3503.7999999999643, 845.8999999999972, 2213.49999999999 - 0.4, 35000.0, 30.0, 3480.4999999999973, 793.3000000000004, 2179.4 - 0.45, 35000.0, 30.0, 3451.400000000006, 744.0000000000051, 2143.2000000000035 - 0.5, 35000.0, 30.0, 3416.9999999999986, 698.0000000000143, 2104.500000000016 - 0.55, 35000.0, 30.0, 3377.800000000043, 655.3000000000116, 2062.9000000000547 - 0.6000000000000001, 35000.0, 30.0, 3327.6000000000045, 611.9000000000013, 2014.5999999999997 - 0.65, 35000.0, 30.0, 3265.700000000031, 567.200000000002, 1960.3999999999976 - 0.7000000000000001, 35000.0, 30.0, 3199.7999999999993, 526.1999999999999, 1904.2999999999945 - 0.75, 35000.0, 30.0, 3129.9000000000065, 488.70000000000266, 1847.7999999999977 - 0.8, 35000.0, 30.0, 3056.300000000028, 455.2000000000091, 1790.8000000000047 - 0.0, 35000.0, 32.0, 4472.699999998527, 1341.9999999994682, 2586.4999999985885 - 0.05, 35000.0, 32.0, 4470.399999998946, 1282.1999999996144, 2608.2999999990197 - 0.1, 35000.0, 32.0, 4465.1999999992795, 1222.4999999997315, 2619.399999999354 -0.15000000000000002, 35000.0, 32.0, 4456.699999999534, 1163.2999999998235, 2620.699999999601 - 0.2, 35000.0, 32.0, 4444.49999999972, 1104.9999999998931, 2613.0999999997753 - 0.25, 35000.0, 32.0, 4428.199999999852, 1047.999999999943, 2597.4999999998895 -0.30000000000000004, 35000.0, 32.0, 4407.399999999934, 992.6999999999754, 2574.7999999999565 -0.35000000000000003, 35000.0, 32.0, 4381.69999999998, 939.4999999999934, 2545.8999999999896 - 0.4, 35000.0, 32.0, 4350.700000000001, 888.7999999999992, 2511.7000000000007 - 0.45, 35000.0, 32.0, 4314.000000000006, 840.9999999999957, 2473.100000000003 - 0.5, 35000.0, 32.0, 4271.200000000004, 796.4999999999858, 2431.000000000011 - 0.55, 35000.0, 32.0, 4221.899999999968, 755.7000000000103, 2386.299999999966 - 0.6000000000000001, 35000.0, 32.0, 4159.300000000017, 713.9000000000005, 2334.2999999999984 - 0.65, 35000.0, 32.0, 4082.300000000032, 669.5999999999979, 2273.399999999983 - 0.7000000000000001, 35000.0, 32.0, 3999.7999999999856, 628.7999999999979, 2210.299999999994 - 0.75, 35000.0, 32.0, 3912.1999999999653, 591.6999999999978, 2146.399999999986 - 0.8, 35000.0, 32.0, 3820.0999999998994, 558.400000000001, 2081.7999999999674 - 0.0, 35000.0, 34.0, 5314.899999996407, 1525.0999999996734, 3099.3999999973057 - 0.05, 35000.0, 34.0, 5327.299999997423, 1439.2999999997676, 3073.8999999980924 - 0.1, 35000.0, 34.0, 5332.999999998226, 1359.099999999842, 3047.0999999987075 -0.15000000000000002, 35000.0, 34.0, 5331.899999998844, 1284.299999999898, 3018.799999999172 - 0.2, 35000.0, 34.0, 5323.899999999298, 1214.6999999999387, 2988.7999999995077 - 0.25, 35000.0, 34.0, 5308.899999999618, 1150.0999999999672, 2956.899999999735 -0.30000000000000004, 35000.0, 34.0, 5286.799999999824, 1090.299999999984, 2922.8999999998778 -0.35000000000000003, 35000.0, 34.0, 5257.499999999943, 1035.0999999999945, 2886.599999999958 - 0.4, 35000.0, 34.0, 5220.899999999998, 984.2999999999994, 2847.799999999995 - 0.45, 35000.0, 34.0, 5176.900000000013, 937.7000000000019, 2806.3000000000125 - 0.5, 35000.0, 34.0, 5125.400000000017, 895.1000000000043, 2761.9000000000315 - 0.55, 35000.0, 34.0, 5066.300000000096, 856.3000000000052, 2714.400000000019 - 0.6000000000000001, 35000.0, 34.0, 4991.399999999993, 815.6000000000008, 2657.000000000009 - 0.65, 35000.0, 34.0, 4898.599999999959, 771.6999999999952, 2589.9000000000033 - 0.7000000000000001, 35000.0, 34.0, 4799.799999999972, 731.3999999999995, 2520.000000000005 - 0.75, 35000.0, 34.0, 4694.999999999933, 694.6000000000014, 2448.8000000000147 - 0.8, 35000.0, 34.0, 4584.1999999998825, 661.6000000000024, 2376.7000000000335 - 0.0, 35000.0, 36.0, 6140.699999998994, 1569.3999999997231, 3342.499999998407 - 0.05, 35000.0, 36.0, 6172.299999999443, 1495.1999999998102, 3343.9999999989122 - 0.1, 35000.0, 36.0, 6192.4999999997435, 1424.6999999998754, 3338.8999999992966 -0.15000000000000002, 35000.0, 36.0, 6201.599999999921, 1357.8999999999241, 3327.4999999995766 - 0.2, 35000.0, 36.0, 6199.900000000008, 1294.7999999999581, 3310.09999999977 - 0.25, 35000.0, 36.0, 6187.700000000031, 1235.399999999979, 3286.999999999892 -0.30000000000000004, 35000.0, 36.0, 6165.300000000021, 1179.6999999999916, 3258.4999999999613 -0.35000000000000003, 35000.0, 36.0, 6133.0, 1127.6999999999969, 3224.8999999999924 - 0.4, 35000.0, 36.0, 6091.099999999998, 1079.3999999999994, 3186.500000000004 - 0.45, 35000.0, 36.0, 6039.900000000043, 1034.8000000000009, 3143.600000000012 - 0.5, 35000.0, 36.0, 5979.700000000166, 993.9000000000038, 3096.5000000000323 - 0.55, 35000.0, 36.0, 5910.800000000018, 956.6999999999982, 3045.5000000000637 - 0.6000000000000001, 35000.0, 36.0, 5823.100000000008, 917.099999999993, 2983.399999999981 - 0.65, 35000.0, 36.0, 5715.200000000004, 873.799999999988, 2909.6999999999302 - 0.7000000000000001, 35000.0, 36.0, 5599.799999999981, 834.199999999998, 2833.999999999987 - 0.75, 35000.0, 36.0, 5477.299999999948, 797.8999999999977, 2755.399999999964 - 0.8, 35000.0, 36.0, 5348.299999999879, 765.2000000000007, 2675.7999999999124 - 0.0, 35000.0, 38.0, 7175.399999999354, 1721.900000000009, 3713.0999999989745 - 0.05, 35000.0, 38.0, 7167.199999999515, 1633.6000000000142, 3722.2999999992676 - 0.1, 35000.0, 38.0, 7155.099999999643, 1551.9000000000142, 3721.4999999994993 -0.15000000000000002, 35000.0, 38.0, 7138.399999999748, 1476.5000000000111, 3711.4999999996785 - 0.2, 35000.0, 38.0, 7116.39999999983, 1407.1000000000063, 3693.0999999998103 - 0.25, 35000.0, 38.0, 7088.399999999894, 1343.4000000000012, 3667.0999999999026 -0.30000000000000004, 35000.0, 38.0, 7053.699999999942, 1285.0999999999976, 3634.2999999999606 -0.35000000000000003, 35000.0, 38.0, 7011.599999999979, 1231.899999999997, 3595.4999999999905 - 0.4, 35000.0, 38.0, 6961.40000000001, 1183.500000000001, 3551.5000000000005 - 0.45, 35000.0, 38.0, 6902.400000000037, 1139.6000000000108, 3503.0999999999963 - 0.5, 35000.0, 38.0, 6833.900000000062, 1099.9000000000285, 3451.0999999999835 - 0.55, 35000.0, 38.0, 6755.200000000072, 1064.0999999999985, 3396.300000000068 - 0.6000000000000001, 35000.0, 38.0, 6655.200000000003, 1025.9000000000017, 3329.3999999999933 - 0.65, 35000.0, 38.0, 6531.499999999962, 983.3000000000014, 3249.0999999999735 - 0.7000000000000001, 35000.0, 38.0, 6399.7999999999865, 944.0000000000002, 3165.4999999999895 - 0.75, 35000.0, 38.0, 6259.700000000037, 908.2000000000018, 3079.799999999976 - 0.8, 35000.0, 38.0, 6112.400000000117, 875.899999999998, 2992.099999999943 - 0.0, 35000.0, 40.0, 8001.200000002285, 1705.9000000002864, 3886.30000000061 - 0.05, 35000.0, 40.0, 8012.20000000163, 1651.800000000201, 3957.4000000004644 - 0.1, 35000.0, 40.0, 8014.600000001109, 1597.4000000001347, 4005.8000000003403 -0.15000000000000002, 35000.0, 40.0, 8008.10000000072, 1543.2000000000853, 4033.6000000002405 - 0.2, 35000.0, 40.0, 7992.400000000436, 1489.7000000000505, 4042.9000000001597 - 0.25, 35000.0, 40.0, 7967.200000000238, 1437.400000000027, 4035.800000000097 -0.30000000000000004, 35000.0, 40.0, 7932.200000000108, 1386.8000000000127, 4014.400000000049 -0.35000000000000003, 35000.0, 40.0, 7887.100000000033, 1338.4000000000049, 3980.8000000000175 - 0.4, 35000.0, 40.0, 7831.599999999993, 1292.7000000000007, 3937.100000000001 - 0.45, 35000.0, 40.0, 7765.3999999999705, 1250.1999999999973, 3885.3999999999955 - 0.5, 35000.0, 40.0, 7688.1999999999425, 1211.3999999999933, 3827.800000000001 - 0.55, 35000.0, 40.0, 7599.700000000093, 1176.8000000000009, 3766.4000000000597 - 0.6000000000000001, 35000.0, 40.0, 7486.900000000014, 1139.1000000000047, 3692.399999999998 - 0.65, 35000.0, 40.0, 7348.100000000084, 1096.8000000000154, 3603.7999999999884 - 0.7000000000000001, 35000.0, 40.0, 7199.499999999986, 1057.6000000000017, 3511.0999999999913 - 0.75, 35000.0, 40.0, 7042.3999999999505, 1021.5000000000006, 3415.6999999999675 - 0.8, 35000.0, 40.0, 6876.399999999898, 988.5000000000006, 3317.199999999918 - 0.0, 35000.0, 42.0, 8413.310857143115, 1739.1531428573096, 4151.494857142577 - 0.05, 35000.0, 42.0, 8453.65314285734, 1692.6057142858167, 4211.559428571177 - 0.1, 35000.0, 42.0, 8478.786857143004, 1644.3017142857702, 4251.2331428569305 -0.15000000000000002, 35000.0, 42.0, 8489.108571428673, 1594.9165714285964, 4272.282857142688 - 0.2, 35000.0, 42.0, 8485.01485714292, 1545.1257142857212, 4276.475428571305 - 0.25, 35000.0, 42.0, 8466.90228571432, 1495.6045714285688, 4265.577714285634 -0.30000000000000004, 35000.0, 42.0, 8435.167428571436, 1447.028571428567, 4241.35657142853 -0.35000000000000003, 35000.0, 42.0, 8390.206857142855, 1400.07314285714, 4205.578857142842 - 0.4, 35000.0, 42.0, 8332.417142857144, 1355.4137142857144, 4160.011428571429 - 0.45, 35000.0, 42.0, 8262.194857142873, 1313.725714285715, 4106.421142857142 - 0.5, 35000.0, 42.0, 8179.936571428611, 1275.6845714285678, 4046.574857142831 - 0.55, 35000.0, 42.0, 8086.038857142861, 1241.9657142857097, 3982.2394285714136 - 0.6000000000000001, 35000.0, 42.0, 7966.02914285714, 1204.9262857142887, 3904.806285714297 - 0.65, 35000.0, 42.0, 7818.606285714302, 1163.144000000013, 3812.2542857143144 - 0.7000000000000001, 35000.0, 42.0, 7660.693142857147, 1124.4411428571445, 3715.48742857143 - 0.75, 35000.0, 42.0, 7493.827428571417, 1088.7485714285742, 3615.6125714285768 - 0.8, 35000.0, 42.0, 7317.391999999944, 1056.118857142862, 3512.3440000000082 - 0.0, 35000.0, 44.0, 8587.819428573372, 1801.9645714290405, 4452.923428571376 - 0.05, 35000.0, 44.0, 8659.064571429954, 1746.7828571431594, 4463.093714285574 - 0.1, 35000.0, 44.0, 8708.27542857236, 1691.6988571430365, 4463.144571428395 -0.15000000000000002, 35000.0, 44.0, 8736.614285714872, 1637.1822857143798, 4453.651428571252 - 0.2, 35000.0, 44.0, 8745.24342857176, 1583.7028571428973, 4435.189714285565 - 0.25, 35000.0, 44.0, 8735.325142857298, 1531.7302857142959, 4408.3348571427505 -0.30000000000000004, 35000.0, 44.0, 8708.021714285764, 1481.7342857142835, 4373.662285714225 -0.35000000000000003, 35000.0, 44.0, 8664.49542857143, 1434.184571428568, 4331.747428571408 - 0.4, 35000.0, 44.0, 8605.908571428572, 1389.5508571428572, 4283.165714285715 - 0.45, 35000.0, 44.0, 8533.423428571467, 1348.3028571428592, 4228.4925714285655 - 0.5, 35000.0, 44.0, 8448.202285714384, 1310.9102857142816, 4168.303428571376 - 0.55, 35000.0, 44.0, 8351.40742857143, 1277.8428571428462, 4103.173714285676 - 0.6000000000000001, 35000.0, 44.0, 8227.42057142856, 1241.5091428571486, 4024.469142857164 - 0.65, 35000.0, 44.0, 8075.069142857163, 1200.3240000000246, 3930.4971428572007 - 0.7000000000000001, 35000.0, 44.0, 7912.164571428568, 1162.2925714285732, 3832.561714285716 - 0.75, 35000.0, 44.0, 7739.681714285673, 1127.374285714288, 3731.238285714297 - 0.8, 35000.0, 44.0, 7557.551999999866, 1095.667428571431, 3626.7240000000224 - 0.0, 35000.0, 46.0, 8776.180800000748, 1865.99520000034, 4697.955199999519 - 0.05, 35000.0, 46.0, 8869.845600000495, 1801.1456000002263, 4672.445599999682 - 0.1, 35000.0, 46.0, 8936.320800000314, 1738.4688000001406, 4644.051199999805 -0.15000000000000002, 35000.0, 46.0, 8977.342400000181, 1678.200000000079, 4612.5111999998935 - 0.2, 35000.0, 46.0, 8994.646400000098, 1620.5744000000377, 4577.564799999951 - 0.25, 35000.0, 46.0, 8989.968800000042, 1565.8272000000131, 4538.951199999989 -0.30000000000000004, 35000.0, 46.0, 8965.045600000014, 1514.193600000001, 4496.409600000004 -0.35000000000000003, 35000.0, 46.0, 8921.612800000004, 1465.9087999999977, 4449.679200000006 - 0.4, 35000.0, 46.0, 8861.406399999994, 1421.2079999999994, 4398.4992 - 0.45, 35000.0, 46.0, 8786.16239999998, 1380.3264000000024, 4342.608799999992 - 0.5, 35000.0, 46.0, 8697.61679999995, 1343.4992000000034, 4281.7471999999825 - 0.55, 35000.0, 46.0, 8597.505600000017, 1310.96160000001, 4215.653600000065 - 0.6000000000000001, 35000.0, 46.0, 8469.23439999998, 1275.1735999999958, 4135.600799999983 - 0.65, 35000.0, 46.0, 8311.445599999952, 1234.4319999999877, 4040.013599999954 - 0.7000000000000001, 35000.0, 46.0, 8142.903200000006, 1196.8736, 3940.586399999994 - 0.75, 35000.0, 46.0, 7964.284800000029, 1162.5632000000014, 3837.5039999999813 - 0.8, 35000.0, 46.0, 7775.856000000067, 1131.5008000000068, 3731.5071999999577 - 0.0, 35000.0, 48.0, 9079.113600001861, 1920.1944000006904, 4867.6983999995155 - 0.05, 35000.0, 48.0, 9179.595200001253, 1850.4112000004677, 4835.803199999678 - 0.1, 35000.0, 48.0, 9250.897600000797, 1783.9216000002984, 4802.1263999998 -0.15000000000000002, 35000.0, 48.0, 9294.94480000047, 1720.8320000001745, 4766.2623999998905 - 0.2, 35000.0, 48.0, 9313.660800000254, 1661.2488000000894, 4727.805599999951 - 0.25, 35000.0, 48.0, 9308.969600000113, 1605.278400000036, 4686.350399999988 -0.30000000000000004, 35000.0, 48.0, 9282.795200000042, 1553.0272000000082, 4641.491200000006 -0.35000000000000003, 35000.0, 48.0, 9237.061600000006, 1504.6015999999981, 4592.822400000009 - 0.4, 35000.0, 48.0, 9173.692799999993, 1460.107999999999, 4539.938399999998 - 0.45, 35000.0, 48.0, 9094.61279999997, 1419.6528000000035, 4482.433599999983 - 0.5, 35000.0, 48.0, 9001.745599999917, 1383.342400000006, 4419.9023999999645 - 0.55, 35000.0, 48.0, 8897.0152, 1351.2832000000146, 4351.939200000092 - 0.6000000000000001, 35000.0, 48.0, 8762.976799999957, 1315.8551999999916, 4269.6895999999715 - 0.65, 35000.0, 48.0, 8597.879199999888, 1275.3599999999767, 4171.387199999926 - 0.7000000000000001, 35000.0, 48.0, 8421.490400000015, 1238.0032, 4069.09679999999 - 0.75, 35000.0, 48.0, 8234.71360000005, 1203.9864000000039, 3962.8839999999695 - 0.8, 35000.0, 48.0, 8037.680000000124, 1173.0856000000133, 3853.91039999994 - 0.0, 35000.0, 50.0, 9446.60000000331, 1970.8000000011382, 5016.999999999679 - 0.05, 35000.0, 50.0, 9534.100000002234, 1897.2000000007772, 4985.099999999786 - 0.1, 35000.0, 50.0, 9594.700000001427, 1827.8000000005006, 4951.199999999868 -0.15000000000000002, 35000.0, 50.0, 9630.000000000842, 1762.6000000002973, 4914.8999999999305 - 0.2, 35000.0, 50.0, 9641.600000000451, 1701.6000000001563, 4875.799999999976 - 0.25, 35000.0, 50.0, 9631.100000000211, 1644.8000000000668, 4833.500000000004 -0.30000000000000004, 35000.0, 50.0, 9600.100000000073, 1592.200000000018, 4787.600000000014 -0.35000000000000003, 35000.0, 50.0, 9550.200000000013, 1543.7999999999988, 4737.700000000011 - 0.4, 35000.0, 50.0, 9482.999999999989, 1499.599999999998, 4683.399999999998 - 0.45, 35000.0, 50.0, 9400.099999999959, 1459.600000000005, 4624.299999999974 - 0.5, 35000.0, 50.0, 9303.099999999884, 1423.8000000000102, 4559.999999999941 - 0.55, 35000.0, 50.0, 9193.599999999971, 1392.2000000000205, 4490.100000000122 - 0.6000000000000001, 35000.0, 50.0, 9053.49999999992, 1357.0999999999854, 4405.499999999956 - 0.65, 35000.0, 50.0, 8880.6999999998, 1316.7999999999624, 4304.299999999888 - 0.7000000000000001, 35000.0, 50.0, 8696.100000000022, 1279.6000000000015, 4198.899999999984 - 0.75, 35000.0, 50.0, 8500.800000000077, 1245.8000000000077, 4089.3999999999583 - 0.8, 35000.0, 50.0, 8294.80000000019, 1215.0000000000227, 3977.199999999917 - 0.0, 35000.0, 52.0, 9903.990400005077, 2015.4056000016687, 5163.8376000000635 - 0.05, 35000.0, 52.0, 9953.05280000343, 1940.1808000011451, 5134.396800000047 - 0.1, 35000.0, 52.0, 9983.06240000219, 1869.6304000007422, 5102.273600000035 -0.15000000000000002, 35000.0, 52.0, 9994.6232000013, 1803.6960000004447, 5067.121600000033 - 0.2, 35000.0, 52.0, 9988.339200000693, 1742.3192000002368, 5028.594400000033 - 0.25, 35000.0, 52.0, 9964.81440000032, 1685.4416000001042, 4986.345600000032 -0.30000000000000004, 35000.0, 52.0, 9924.65280000011, 1633.0048000000297, 4940.028800000028 -0.35000000000000003, 35000.0, 52.0, 9868.45840000002, 1584.9503999999995, 4889.297600000018 - 0.4, 35000.0, 52.0, 9796.835199999985, 1541.2199999999973, 4833.805599999996 - 0.45, 35000.0, 52.0, 9710.387199999943, 1501.7552000000076, 4773.206399999961 - 0.5, 35000.0, 52.0, 9609.718399999843, 1466.497600000016, 4707.15359999991 - 0.55, 35000.0, 52.0, 9495.43279999993, 1435.388800000027, 4635.300800000158 - 0.6000000000000001, 35000.0, 52.0, 9348.983199999875, 1400.6487999999774, 4548.158399999936 - 0.65, 35000.0, 52.0, 9168.144799999689, 1360.5439999999435, 4443.8847999998425 - 0.7000000000000001, 35000.0, 52.0, 8975.109600000034, 1323.5328000000025, 4335.167199999977 - 0.75, 35000.0, 52.0, 8770.998400000113, 1289.917600000013, 4222.299999999943 - 0.8, 35000.0, 52.0, 8555.792000000274, 1259.2664000000348, 4106.61759999989 - 0.0, 35000.0, 54.0, 10476.635200007171, 2051.6048000022697, 5326.188800000733 - 0.05, 35000.0, 54.0, 10456.14640000485, 1978.0224000015626, 5297.754400000501 - 0.1, 35000.0, 54.0, 10431.319200003105, 1908.9392000010153, 5266.3488000003335 -0.15000000000000002, 35000.0, 54.0, 10400.92960000184, 1844.312000000611, 5231.624800000212 - 0.2, 35000.0, 54.0, 10363.753600000984, 1784.0976000003282, 5193.235200000134 - 0.25, 35000.0, 54.0, 10318.567200000449, 1728.252800000145, 5150.832800000084 -0.30000000000000004, 35000.0, 54.0, 10264.146400000158, 1676.7344000000428, 5104.0704000000505 -0.35000000000000003, 35000.0, 54.0, 10199.26720000003, 1629.4991999999997, 5052.600800000025 - 0.4, 35000.0, 54.0, 10122.705599999983, 1586.5039999999958, 4996.076799999994 - 0.45, 35000.0, 54.0, 10033.237599999931, 1547.7056000000107, 4934.1511999999475 - 0.5, 35000.0, 54.0, 9929.639199999801, 1513.060800000024, 4866.476799999874 - 0.55, 35000.0, 54.0, 9810.686399999877, 1482.5264000000345, 4792.706400000198 - 0.6000000000000001, 35000.0, 54.0, 9657.605599999823, 1448.2423999999676, 4702.791199999911 - 0.65, 35000.0, 54.0, 9468.450399999556, 1408.3839999999204, 4595.274399999781 - 0.7000000000000001, 35000.0, 54.0, 9266.896800000046, 1371.6704000000047, 4483.069599999969 - 0.75, 35000.0, 54.0, 9053.763200000154, 1338.2528000000198, 4366.831999999926 - 0.8, 35000.0, 54.0, 8829.23200000037, 1307.9072000000506, 4247.404799999859 - 0.0, 35000.0, 56.0, 11189.884800009584, 2076.991200002928, 5522.031200001751 - 0.05, 35000.0, 56.0, 11063.073600006486, 2009.3936000020176, 5489.233600001199 - 0.1, 35000.0, 56.0, 10954.804800004153, 1945.2528000013142, 5454.4272000007895 -0.15000000000000002, 35000.0, 56.0, 10861.034400002462, 1884.6400000007934, 5417.107200000493 - 0.2, 35000.0, 56.0, 10777.718400001315, 1827.6264000004273, 5376.768800000292 - 0.25, 35000.0, 56.0, 10700.812800000598, 1774.2832000001897, 5332.907200000165 -0.30000000000000004, 35000.0, 56.0, 10626.273600000206, 1724.6816000000565, 5285.017600000086 -0.35000000000000003, 35000.0, 56.0, 10550.056800000035, 1678.8927999999996, 5232.595200000038 - 0.4, 35000.0, 56.0, 10468.118399999974, 1636.9879999999944, 5175.135199999993 - 0.45, 35000.0, 56.0, 10376.414399999918, 1599.038400000014, 5112.132799999932 - 0.5, 35000.0, 56.0, 10270.900799999754, 1565.1152000000332, 5043.083199999836 - 0.55, 35000.0, 56.0, 10147.533599999804, 1535.289600000043, 4967.481600000247 - 0.6000000000000001, 35000.0, 56.0, 9987.54639999976, 1501.6215999999558, 4874.524799999875 - 0.65, 35000.0, 56.0, 9789.853599999382, 1462.1119999998928, 4763.601599999707 - 0.7000000000000001, 35000.0, 56.0, 9579.839200000064, 1425.8816000000083, 4647.778399999963 - 0.75, 35000.0, 56.0, 9357.548800000206, 1392.7192000000296, 4528.243999999905 - 0.8, 35000.0, 56.0, 9123.696000000473, 1362.9448000000696, 4404.803199999823 + 0.0, 0.0, 0.52, 794.3999999999999, 618.3999999999999, 1035.8999999999999 + 0.0, 0.0, 0.56, 1191.5999999999997, 651.7, 1194.4999999999995 + 0.0, 0.0, 0.6, 1588.8999999999996, 684.8000000000001, 1353.7999999999993 + 0.0, 0.0, 0.64, 1986.100000000001, 717.6999999999996, 1513.600000000001 + 0.0, 0.0, 0.68, 2383.2999999999993, 750.4000000000004, 1674.2 + 0.0, 0.0, 0.72, 2780.500000000001, 785.0000000000003, 1842.099999999999 + 0.0, 0.0, 0.76, 3177.6999999999985, 820.3, 2013.2000000000007 + 0.0, 0.0, 0.8, 3574.9000000000005, 855.4999999999987, 2185.7999999999993 + 0.0, 0.0, 0.84, 3798.0720000000024, 875.2782857142853, 2283.190285714286 + 0.0, 0.0, 0.88, 3922.952000000004, 886.341142857142, 2338.2131428571433 + 0.0, 0.0, 0.92, 4066.411199999998, 898.8888, 2400.8423999999995 + 0.0, 0.0, 0.96, 4263.050399999998, 916.1335999999998, 2486.788799999999 + 0.0, 0.0, 1.0, 4465.199999999999, 934.2999999999996, 2577.499999999998 + 0.0, 5000.0, 0.52, 889.3999999999999, 671.3999999999999, 1101.3999999999999 + 0.0, 5000.0, 0.56, 1334.1, 709.4000000000001, 1276.9000000000005 + 0.0, 5000.0, 0.6, 1778.8000000000004, 747.2000000000003, 1453.0000000000018 + 0.0, 5000.0, 0.64, 2223.3999999999987, 784.8000000000002, 1629.7999999999997 + 0.0, 5000.0, 0.68, 2668.1, 822.2999999999998, 1807.6999999999998 + 0.0, 5000.0, 0.72, 3112.8, 862.1999999999997, 1994.6000000000017 + 0.0, 5000.0, 0.76, 3557.5000000000023, 902.9000000000009, 2185.9000000000015 + 0.0, 5000.0, 0.8, 4002.1999999999944, 943.3999999999988, 2377.8 + 0.0, 5000.0, 0.84, 4252.814285714287, 966.3125714285716, 2486.596 + 0.0, 5000.0, 0.88, 4392.5771428571425, 979.1782857142856, 2548.0960000000005 + 0.0, 5000.0, 0.92, 4549.907999999997, 993.4679999999992, 2616.6967999999974 + 0.0, 5000.0, 0.96, 4762.855999999996, 1012.7919999999986, 2709.617599999996 + 0.0, 5000.0, 1.0, 4979.099999999995, 1032.8999999999978, 2806.899999999994 + 0.0, 10000.0, 0.52, 1121.9999999999998, 814.8999999999999, 1262.2999999999997 + 0.0, 10000.0, 0.56, 1682.9000000000005, 866.3999999999999, 1477.6999999999996 + 0.0, 10000.0, 0.6, 2244.000000000002, 917.4, 1693.5999999999992 + 0.0, 10000.0, 0.64, 2804.8999999999987, 968.4000000000002, 1911.200000000001 + 0.0, 10000.0, 0.68, 3365.899999999997, 1019.2000000000002, 2129.8 + 0.0, 10000.0, 0.72, 3926.900000000005, 1071.8000000000018, 2355.8000000000006 + 0.0, 10000.0, 0.76, 4487.900000000003, 1126.2999999999984, 2588.8999999999996 + 0.0, 10000.0, 0.8, 5048.899999999998, 1181.0, 2824.3999999999965 + 0.0, 10000.0, 0.84, 5369.339428571428, 1212.1582857142855, 2959.351999999999 + 0.0, 10000.0, 0.88, 5545.653714285712, 1229.4411428571425, 3035.331999999998 + 0.0, 10000.0, 0.92, 5721.667199999998, 1247.2167999999995, 3114.342399999999 + 0.0, 10000.0, 0.96, 5946.4263999999985, 1270.449599999999, 3217.5327999999995 + 0.0, 10000.0, 1.0, 6174.199999999997, 1294.6999999999987, 3325.1999999999994 + 0.0, 15000.0, 0.52, 1231.4999999999934, 884.1999999999911, 1375.3000000000052 + 0.0, 15000.0, 0.56, 1845.2999999999683, 936.0999999999684, 1599.799999999946 + 0.0, 15000.0, 0.6, 2465.5999999997866, 993.0999999999193, 1820.3999999998093 + 0.0, 15000.0, 0.64, 3070.3999999999896, 1050.999999999959, 2057.8999999998896 + 0.0, 15000.0, 0.68, 3700.500000000119, 1104.3999999999803, 2296.099999999792 + 0.0, 15000.0, 0.72, 4312.89999999986, 1156.0999999999253, 2537.7999999998397 + 0.0, 15000.0, 0.76, 4919.19999999985, 1218.8999999999473, 2778.199999999837 + 0.0, 15000.0, 0.8, 5536.000000000075, 1286.6999999999873, 3042.9999999999577 + 0.0, 15000.0, 0.84, 5894.917142857293, 1325.1942857142812, 3191.828571428538 + 0.0, 15000.0, 0.88, 6096.44857142881, 1345.4971428571446, 3272.994285714213 + 0.0, 15000.0, 0.92, 6290.805599999711, 1363.729599999995, 3359.2095999999237 + 0.0, 15000.0, 0.96, 6528.771199999519, 1385.9991999999752, 3474.3791999998894 + 0.0, 15000.0, 1.0, 6761.699999999236, 1408.399999999948, 3593.5999999998494 + 0.0, 20000.0, 0.52, 1005.0999999999442, -179.8000000000082, -972.099999999996 + 0.0, 20000.0, 0.56, 1499.400000000155, 58.29999999996068, -409.499999999999 + 0.0, 20000.0, 0.6, 1993.7000000003677, 236.59999999991925, 148.1999999999089 + 0.0, 20000.0, 0.64, 2524.3999999997613, 414.79999999957806, 704.8999999990343 + 0.0, 20000.0, 0.68, 3035.199999999369, 576.599999999807, 1189.9999999984575 + 0.0, 20000.0, 0.72, 3553.4999999979827, 724.3999999991906, 1687.499999999159 + 0.0, 20000.0, 0.76, 4047.799999998764, 902.5000000000281, 2282.5999999976952 + 0.0, 20000.0, 0.8, 4558.599999998213, 1013.7000000002164, 2889.6999999998075 + 0.0, 20000.0, 0.84, 4843.655428571438, 1055.781142857111, 3050.746285714762 + 0.0, 20000.0, 0.88, 4996.649714286513, 1058.9125714285788, 2962.8291428588177 + 0.0, 20000.0, 0.92, 5169.605600002497, 1073.749600000052, 2931.046400000766 + 0.0, 20000.0, 0.96, 5397.8672000045635, 1109.9752000001365, 3044.4808000015146 + 0.0, 20000.0, 1.0, 5600.100000007005, 1136.3000000002728, 3176.2000000024345 + 0.0, 25000.0, 0.52, 1454.9999999999484, 1019.3999999999954, 1480.0999999997996 + 0.0, 25000.0, 0.56, 2278.299999999715, 1094.6999999998795, 1873.4999999997287 + 0.0, 25000.0, 0.6, 3040.799999999219, 1180.799999999564, 2124.2999999987683 + 0.0, 25000.0, 0.64, 3745.299999999083, 1266.6999999997893, 2485.0999999995415 + 0.0, 25000.0, 0.68, 4545.299999997396, 1284.5999999996125, 2619.8000000001202 + 0.0, 25000.0, 0.72, 5200.299999996687, 1386.8999999996997, 2950.400000000227 + 0.0, 25000.0, 0.76, 6179.599999998828, 1476.8999999993048, 3390.8999999997313 + 0.0, 25000.0, 0.8, 6774.100000001599, 1477.2999999995213, 3427.5000000001737 + 0.0, 25000.0, 0.84, 7201.338857143723, 1531.8771428571938, 3623.85314285827 + 0.0, 25000.0, 0.88, 7515.267428573812, 1612.0485714287408, 3889.6645714312112 + 0.0, 25000.0, 0.92, 7781.253599999968, 1670.7576000000292, 4065.1528000006115 + 0.0, 25000.0, 0.96, 8041.831200000129, 1697.8952000001418, 4129.50960000108 + 0.0, 25000.0, 1.0, 8316.700000000581, 1720.3000000002658, 4200.9000000017 + 0.0, 30000.0, 0.52, 1587.7999999999893, 1074.6999999999748, 1549.299999999925 + 0.0, 30000.0, 0.56, 2577.699999999213, 1142.3999999998246, 1948.0000000003222 + 0.0, 30000.0, 0.6, 3346.7999999986814, 1253.799999999447, 2131.4000000006454 + 0.0, 30000.0, 0.64, 4046.699999999955, 1324.400000000169, 2579.499999998938 + 0.0, 30000.0, 0.68, 4934.5999999973865, 1431.000000000178, 2947.7999999993012 + 0.0, 30000.0, 0.72, 5728.000000000285, 1447.6999999999337, 2984.199999998774 + 0.0, 30000.0, 0.76, 6611.4999999956635, 1658.5999999995806, 3733.2000000005555 + 0.0, 30000.0, 0.8, 7535.400000000952, 1639.5000000003574, 3802.2000000005596 + 0.0, 30000.0, 0.84, 8005.990285715036, 1673.2474285716232, 3948.437142857921 + 0.0, 30000.0, 0.88, 8214.073142859635, 1737.461714286159, 4137.528571430464 + 0.0, 30000.0, 0.92, 8447.301600000092, 1800.6648000001267, 4315.3656 + 0.0, 30000.0, 0.96, 8799.627200001054, 1849.573600000298, 4467.291200000452 + 0.0, 30000.0, 1.0, 9171.300000002611, 1889.1000000005297, 4618.100000001108 + 0.0, 35000.0, 0.52, 1860.4999999998781, 1134.3999999999799, 1545.4999999998604 + 0.0, 35000.0, 0.56, 2646.6999999994337, 1179.499999999923, 1909.3999999996133 + 0.0, 35000.0, 0.6, 3462.499999998352, 1306.499999999773, 2426.999999998648 + 0.0, 35000.0, 0.64, 4472.699999998527, 1341.9999999994682, 2586.4999999985885 + 0.0, 35000.0, 0.68, 5314.899999996407, 1525.0999999996734, 3099.3999999973057 + 0.0, 35000.0, 0.72, 6140.699999998994, 1569.3999999997231, 3342.499999998407 + 0.0, 35000.0, 0.76, 7175.399999999354, 1721.900000000009, 3713.0999999989745 + 0.0, 35000.0, 0.8, 8001.200000002285, 1705.9000000002864, 3886.30000000061 + 0.0, 35000.0, 0.84, 8413.310857143115, 1739.1531428573096, 4151.494857142577 + 0.0, 35000.0, 0.88, 8587.819428573372, 1801.9645714290405, 4452.923428571376 + 0.0, 35000.0, 0.92, 8776.180800000748, 1865.99520000034, 4697.955199999519 + 0.0, 35000.0, 0.96, 9079.113600001861, 1920.1944000006904, 4867.6983999995155 + 0.0, 35000.0, 1.0, 9446.60000000331, 1970.8000000011382, 5016.999999999679 + 0.05, 0.0, 0.52, 794.7000000000002, 563.7, 1033.8000000000002 + 0.05, 0.0, 0.56, 1192.0999999999997, 597.0999999999993, 1192.4999999999975 + 0.05, 0.0, 0.6, 1589.4999999999993, 630.3999999999978, 1351.7999999999934 + 0.05, 0.0, 0.64, 1986.9000000000042, 663.4000000000009, 1511.6000000000063 + 0.05, 0.0, 0.68, 2384.199999999992, 696.2999999999997, 1672.300000000002 + 0.05, 0.0, 0.72, 2781.5999999999995, 731.0999999999974, 1840.1999999999955 + 0.05, 0.0, 0.76, 3178.999999999995, 766.4000000000009, 2011.3000000000038 + 0.05, 0.0, 0.8, 3576.3000000000106, 801.6999999999987, 2184.000000000001 + 0.05, 0.0, 0.84, 3799.5371428571525, 821.5680000000007, 2281.459428571425 + 0.05, 0.0, 0.88, 3924.448571428588, 832.7080000000001, 2336.5137142857066 + 0.05, 0.0, 0.92, 4067.9040000000005, 845.3103999999973, 2399.1103999999937 + 0.05, 0.0, 0.96, 4264.508000000001, 862.5927999999951, 2484.9727999999873 + 0.05, 0.0, 1.0, 4466.5999999999985, 880.7999999999923, 2575.599999999979 + 0.05, 5000.0, 0.52, 889.6000000000004, 614.6, 1099.3000000000004 + 0.05, 5000.0, 0.56, 1334.3, 652.600000000001, 1274.6000000000006 + 0.05, 5000.0, 0.6, 1779.0999999999979, 690.7000000000019, 1450.8000000000025 + 0.05, 5000.0, 0.64, 2223.900000000005, 728.3999999999988, 1627.6000000000022 + 0.05, 5000.0, 0.68, 2668.7000000000035, 765.8999999999959, 1805.5999999999967 + 0.05, 5000.0, 0.72, 3113.499999999998, 806.0999999999967, 1992.6000000000008 + 0.05, 5000.0, 0.76, 3558.2000000000053, 846.9000000000011, 2183.9000000000165 + 0.05, 5000.0, 0.8, 4002.999999999997, 887.4999999999983, 2375.8000000000143 + 0.05, 5000.0, 0.84, 4253.683428571426, 910.5022857142882, 2484.6691428571444 + 0.05, 5000.0, 0.88, 4393.477714285705, 923.4451428571472, 2546.260571428572 + 0.05, 5000.0, 0.92, 4550.772799999993, 937.7863999999995, 2614.872799999997 + 0.05, 5000.0, 0.96, 4763.633599999985, 957.1447999999989, 2707.713599999995 + 0.05, 5000.0, 1.0, 4979.799999999974, 977.2999999999981, 2804.8999999999924 + 0.05, 10000.0, 0.52, 1122.2, 753.6000000000003, 1260.2 + 0.05, 10000.0, 0.56, 1683.3000000000013, 805.3, 1475.6999999999991 + 0.05, 10000.0, 0.6, 2244.3000000000025, 856.4999999999984, 1691.6000000000001 + 0.05, 10000.0, 0.64, 2805.499999999996, 907.6999999999973, 1909.2000000000041 + 0.05, 10000.0, 0.68, 3366.4999999999977, 958.4999999999984, 2127.9999999999945 + 0.05, 10000.0, 0.72, 3927.6999999999907, 1011.3999999999996, 2353.900000000007 + 0.05, 10000.0, 0.76, 4488.70000000002, 1065.9999999999975, 2587.2000000000025 + 0.05, 10000.0, 0.8, 5049.799999999994, 1120.9000000000042, 2822.5999999999985 + 0.05, 10000.0, 0.84, 5370.272000000004, 1152.1399999999983, 2957.494857142854 + 0.05, 10000.0, 0.88, 5546.5720000000065, 1169.4399999999982, 3033.443428571422 + 0.05, 10000.0, 0.92, 5722.548799999993, 1187.2552000000028, 3112.422399999987 + 0.05, 10000.0, 0.96, 5947.265599999985, 1210.5704000000046, 3215.5727999999776 + 0.05, 10000.0, 1.0, 6174.9999999999745, 1234.9000000000074, 3323.1999999999653 + 0.05, 15000.0, 0.52, 1239.299999999997, 824.599999999995, 1372.2000000000028 + 0.05, 15000.0, 0.56, 1857.4999999999802, 878.9999999999816, 1600.4999999999734 + 0.05, 15000.0, 0.6, 2479.699999999888, 935.9999999999544, 1827.6999999999039 + 0.05, 15000.0, 0.64, 3093.2999999999865, 993.4999999999733, 2064.1999999999266 + 0.05, 15000.0, 0.68, 3720.500000000043, 1048.3999999999883, 2302.1999999998884 + 0.05, 15000.0, 0.72, 4338.199999999933, 1103.499999999959, 2545.5999999999067 + 0.05, 15000.0, 0.76, 4952.799999999873, 1165.3999999999614, 2792.199999999927 + 0.05, 15000.0, 0.8, 5573.000000000046, 1230.2999999999934, 3052.9999999999777 + 0.05, 15000.0, 0.84, 5930.8811428572135, 1267.7657142857086, 3203.362285714262 + 0.05, 15000.0, 0.88, 6129.732571428681, 1288.482857142852, 3288.6651428570876 + 0.05, 15000.0, 0.92, 6323.630399999844, 1308.0736000000006, 3376.665599999961 + 0.05, 15000.0, 0.96, 6565.076799999741, 1332.2871999999934, 3490.363199999942 + 0.05, 15000.0, 1.0, 6804.999999999589, 1356.9999999999811, 3607.9999999999213 + 0.05, 20000.0, 0.52, 1106.39999999996, 68.79999999999444, -301.19999999999766 + 0.05, 20000.0, 0.56, 1653.6000000001154, 258.49999999997067, 174.7000000000039 + 0.05, 20000.0, 0.6, 2200.8000000002758, 405.2999999999379, 648.2999999999498 + 0.05, 20000.0, 0.64, 2774.5999999998685, 551.9999999996978, 1122.6999999993177 + 0.05, 20000.0, 0.68, 3333.7999999995004, 686.7999999998589, 1545.1999999989152 + 0.05, 20000.0, 0.72, 3897.79999999865, 811.9999999994433, 1978.999999999422 + 0.05, 20000.0, 0.76, 4444.999999999165, 959.6000000000246, 2485.5999999983915 + 0.05, 20000.0, 0.8, 5004.199999998734, 1059.9000000001495, 3002.399999999782 + 0.05, 20000.0, 0.84, 5319.062285714257, 1102.126285714259, 3166.3811428574527 + 0.05, 20000.0, 0.88, 5489.325142857627, 1111.2491428571377, 3131.912571429708 + 0.05, 20000.0, 0.92, 5672.192800001668, 1128.4488000000244, 3136.948000000519 + 0.05, 20000.0, 0.96, 5909.93760000307, 1162.4856000000757, 3252.272000001029 + 0.05, 20000.0, 1.0, 6129.900000004725, 1189.7000000001613, 3381.5000000016544 + 0.05, 25000.0, 0.52, 1470.3999999999637, 948.9999999999962, 1485.3999999998584 + 0.05, 25000.0, 0.56, 2273.6999999997906, 1024.4999999999134, 1847.5999999998128 + 0.05, 25000.0, 0.6, 3033.1999999994314, 1107.2999999996928, 2109.39999999915 + 0.05, 25000.0, 0.64, 3752.49999999933, 1189.899999999847, 2449.8999999996854 + 0.05, 25000.0, 0.68, 4539.599999998129, 1224.1999999997247, 2629.600000000122 + 0.05, 25000.0, 0.72, 5222.899999997663, 1318.7999999997667, 2949.8000000001707 + 0.05, 25000.0, 0.76, 6137.499999999119, 1405.6999999995166, 3354.799999999818 + 0.05, 25000.0, 0.8, 6777.300000001191, 1431.1999999996553, 3478.000000000095 + 0.05, 25000.0, 0.84, 7205.9742857148285, 1483.7662857143125, 3672.2222857150814 + 0.05, 25000.0, 0.88, 7498.117142858703, 1547.6891428572442, 3890.3251428590083 + 0.05, 25000.0, 0.92, 7753.888799999919, 1596.3480000000088, 4043.9128000004284 + 0.05, 25000.0, 0.96, 8022.317599999999, 1624.9440000000818, 4127.097600000756 + 0.05, 25000.0, 1.0, 8301.30000000027, 1650.500000000162, 4216.50000000119 + 0.05, 30000.0, 0.52, 1607.3999999999937, 1006.499999999982, 1558.1999999999473 + 0.05, 30000.0, 0.56, 2551.49999999945, 1079.099999999876, 1932.7000000002267 + 0.05, 30000.0, 0.6, 3338.3999999990897, 1182.8999999996108, 2153.7000000004614 + 0.05, 30000.0, 0.64, 4074.899999999916, 1257.6000000001118, 2566.0999999992223 + 0.05, 30000.0, 0.68, 4945.799999998146, 1357.5000000001237, 2920.1999999995073 + 0.05, 30000.0, 0.72, 5749.8000000002285, 1395.1999999999523, 3042.3999999991433 + 0.05, 30000.0, 0.76, 6617.199999996998, 1571.0999999997098, 3674.700000000362 + 0.05, 30000.0, 0.8, 7513.300000000715, 1583.6000000002516, 3826.2000000003773 + 0.05, 30000.0, 0.84, 7985.145142857598, 1622.9342857144159, 3990.0468571433676 + 0.05, 30000.0, 0.88, 8208.216571430181, 1677.3771428574441, 4158.575428572685 + 0.05, 30000.0, 0.92, 8445.921600000001, 1730.664800000082, 4317.977599999974 + 0.05, 30000.0, 0.96, 8785.815200000641, 1775.6096000001992, 4466.731200000284 + 0.05, 30000.0, 1.0, 9139.600000001694, 1814.1000000003587, 4615.600000000735 + 0.05, 35000.0, 0.52, 1839.8999999999116, 1055.4999999999857, 1573.4999999999002 + 0.05, 35000.0, 0.56, 2656.8999999995813, 1114.6999999999477, 1930.6999999997274 + 0.05, 35000.0, 0.6, 3493.799999998788, 1230.7999999998467, 2396.3999999990688 + 0.05, 35000.0, 0.64, 4470.399999998946, 1282.1999999996144, 2608.2999999990197 + 0.05, 35000.0, 0.68, 5327.299999997423, 1439.2999999997676, 3073.8999999980924 + 0.05, 35000.0, 0.72, 6172.299999999443, 1495.1999999998102, 3343.9999999989122 + 0.05, 35000.0, 0.76, 7167.199999999515, 1633.6000000000142, 3722.2999999992676 + 0.05, 35000.0, 0.8, 8012.20000000163, 1651.800000000201, 3957.4000000004644 + 0.05, 35000.0, 0.84, 8453.65314285734, 1692.6057142858167, 4211.559428571177 + 0.05, 35000.0, 0.88, 8659.064571429954, 1746.7828571431594, 4463.093714285574 + 0.05, 35000.0, 0.92, 8869.845600000495, 1801.1456000002263, 4672.445599999682 + 0.05, 35000.0, 0.96, 9179.595200001253, 1850.4112000004677, 4835.803199999678 + 0.05, 35000.0, 1.0, 9534.100000002234, 1897.2000000007772, 4985.099999999786 + 0.1, 0.0, 0.52, 794.3, 508.8000000000001, 1027.5000000000007 + 0.1, 0.0, 0.56, 1191.5000000000005, 542.3999999999995, 1185.899999999994 + 0.1, 0.0, 0.6, 1588.7000000000019, 575.8999999999962, 1345.0999999999865 + 0.1, 0.0, 0.64, 1985.9000000000055, 609.1000000000029, 1504.7000000000212 + 0.1, 0.0, 0.68, 2383.099999999966, 642.0999999999981, 1665.200000000004 + 0.1, 0.0, 0.72, 2780.200000000006, 676.9999999999911, 1832.999999999994 + 0.1, 0.0, 0.76, 3177.399999999991, 712.5000000000006, 2003.800000000018 + 0.1, 0.0, 0.8, 3574.5000000000277, 748.1000000000004, 2176.699999999999 + 0.1, 0.0, 0.84, 3797.654857142873, 768.0862857142888, 2274.138857142845 + 0.1, 0.0, 0.88, 3922.5034285714564, 779.229142857147, 2329.027428571406 + 0.1, 0.0, 0.92, 4065.7584000000097, 791.8023999999932, 2391.42319999998 + 0.1, 0.0, 0.96, 4261.984800000016, 809.0727999999885, 2477.090399999966 + 0.1, 0.0, 1.0, 4463.600000000023, 827.2999999999823, 2567.4999999999477 + 0.1, 5000.0, 0.52, 889.0000000000015, 557.5000000000002, 1092.8000000000009 + 0.1, 5000.0, 0.56, 1333.4000000000005, 595.8000000000034, 1267.800000000004 + 0.1, 5000.0, 0.6, 1777.899999999997, 634.0000000000047, 1443.800000000009 + 0.1, 5000.0, 0.64, 2222.300000000032, 671.8999999999932, 1620.5000000000032 + 0.1, 5000.0, 0.68, 2666.9000000000055, 709.5999999999892, 1798.099999999987 + 0.1, 5000.0, 0.72, 3111.300000000007, 749.8999999999895, 1985.2999999999984 + 0.1, 5000.0, 0.76, 3555.7000000000094, 791.0000000000016, 2176.3000000000575 + 0.1, 5000.0, 0.8, 4000.2999999999993, 831.7999999999965, 2368.0000000000427 + 0.1, 5000.0, 0.84, 4250.895999999973, 854.8514285714348, 2476.6691428571467 + 0.1, 5000.0, 0.88, 4390.535999999959, 867.7657142857265, 2538.0605714285725 + 0.1, 5000.0, 0.92, 4547.20639999999, 882.1103999999964, 2606.4727999999886 + 0.1, 5000.0, 0.96, 4759.016799999973, 901.540799999993, 2699.113599999979 + 0.1, 5000.0, 1.0, 4974.1999999999525, 921.7999999999882, 2796.0999999999653 + 0.1, 10000.0, 0.52, 1121.099999999999, 692.4000000000004, 1253.3 + 0.1, 10000.0, 0.56, 1681.8000000000025, 744.3999999999999, 1468.6 + 0.1, 10000.0, 0.6, 2242.300000000005, 795.7999999999945, 1684.3000000000056 + 0.1, 10000.0, 0.64, 2802.899999999985, 847.199999999995, 1901.800000000008 + 0.1, 10000.0, 0.68, 3363.400000000002, 898.2999999999928, 2120.4999999999827 + 0.1, 10000.0, 0.72, 3924.099999999962, 951.299999999996, 2346.3000000000293 + 0.1, 10000.0, 0.76, 4484.600000000045, 1006.1999999999955, 2579.3000000000097 + 0.1, 10000.0, 0.8, 5045.200000000003, 1061.3000000000125, 2814.6000000000017 + 0.1, 10000.0, 0.84, 5365.426285714286, 1092.6542857142804, 2949.2908571428484 + 0.1, 10000.0, 0.88, 5541.569142857143, 1110.0171428571364, 3024.9794285714142 + 0.1, 10000.0, 0.92, 5717.199999999958, 1127.8952000000081, 3103.7303999999594 + 0.1, 10000.0, 0.96, 5941.327999999926, 1151.2904000000128, 3206.692799999931 + 0.1, 10000.0, 1.0, 6168.399999999882, 1175.7000000000198, 3314.099999999893 + 0.1, 15000.0, 0.52, 1242.099999999999, 763.2999999999976, 1363.8000000000009 + 0.1, 15000.0, 0.56, 1862.1999999999907, 819.3999999999908, 1594.299999999989 + 0.1, 15000.0, 0.6, 2484.4999999999527, 876.4999999999782, 1825.2999999999615 + 0.1, 15000.0, 0.64, 3102.6999999999903, 933.7999999999855, 2060.9999999999604 + 0.1, 15000.0, 0.68, 3727.0000000000036, 989.7999999999946, 2298.599999999951 + 0.1, 15000.0, 0.72, 4347.099999999976, 1047.0999999999813, 2542.699999999954 + 0.1, 15000.0, 0.76, 4965.899999999921, 1108.5999999999776, 2792.999999999975 + 0.1, 15000.0, 0.8, 5587.200000000024, 1171.6999999999962, 3050.999999999989 + 0.1, 15000.0, 0.84, 5943.880571428597, 1208.5234285714241, 3201.948571428556 + 0.1, 15000.0, 0.88, 6140.746285714322, 1229.4977142857083, 3289.434285714251 + 0.1, 15000.0, 0.92, 6333.903199999929, 1249.9472000000028, 3378.187199999981 + 0.1, 15000.0, 0.96, 6576.854399999883, 1275.402400000001, 3490.6543999999717 + 0.1, 15000.0, 1.0, 6820.4999999998145, 1301.599999999998, 3606.999999999961 + 0.1, 20000.0, 0.52, 1185.399999999973, 254.6999999999964, 228.7000000000013 + 0.1, 20000.0, 0.56, 1773.9000000000829, 405.89999999997883, 635.3000000000055 + 0.1, 20000.0, 0.6, 2362.4000000001984, 527.5999999999539, 1041.499999999978 + 0.1, 20000.0, 0.64, 2969.599999999941, 649.1999999997931, 1449.6999999995398 + 0.1, 20000.0, 0.68, 3566.4999999996157, 762.4999999999006, 1821.8999999992723 + 0.1, 20000.0, 0.72, 4166.19999999915, 869.6999999996369, 2204.3999999996245 + 0.1, 20000.0, 0.76, 4754.699999999465, 993.1000000000199, 2640.0999999989294 + 0.1, 20000.0, 0.8, 5351.599999999146, 1084.6000000000981, 3084.399999999789 + 0.1, 20000.0, 0.84, 5689.7377142856685, 1126.9245714285498, 3250.2691428573294 + 0.1, 20000.0, 0.88, 5873.494857143123, 1140.8702857142741, 3258.020571429297 + 0.1, 20000.0, 0.92, 6063.965600001045, 1160.035200000007, 3292.092000000332 + 0.1, 20000.0, 0.96, 6308.819200001942, 1192.4144000000351, 3408.6720000006612 + 0.1, 20000.0, 1.0, 6542.300000003, 1220.4000000000844, 3535.700000001062 + 0.1, 25000.0, 0.52, 1480.599999999976, 879.8999999999971, 1484.1999999999043 + 0.1, 25000.0, 0.56, 2267.1999999998516, 955.5999999999411, 1821.3999999998762 + 0.1, 25000.0, 0.6, 3023.4999999996016, 1035.8999999997932, 2091.2999999994413 + 0.1, 25000.0, 0.64, 3753.399999999525, 1115.999999999894, 2415.2999999997933 + 0.1, 25000.0, 0.68, 4529.2999999987105, 1163.2999999998128, 2630.100000000109 + 0.1, 25000.0, 0.72, 5233.999999998426, 1251.8999999998252, 2941.800000000121 + 0.1, 25000.0, 0.76, 6096.599999999359, 1336.49999999968, 3317.999999999882 + 0.1, 25000.0, 0.8, 6771.30000000085, 1381.4999999997615, 3507.900000000041 + 0.1, 25000.0, 0.84, 7200.592571428879, 1432.57200000001, 3700.2308571433914 + 0.1, 25000.0, 0.88, 7475.1782857152275, 1483.972000000053, 3881.239428572684 + 0.1, 25000.0, 0.92, 7722.371999999904, 1524.8983999999964, 4017.819200000287 + 0.1, 25000.0, 0.96, 7996.259999999931, 1554.66480000004, 4115.570400000506 + 0.1, 25000.0, 1.0, 8277.700000000077, 1582.7000000000874, 4218.800000000796 + 0.1, 30000.0, 0.52, 1620.5999999999967, 938.6999999999878, 1559.3999999999648 + 0.1, 30000.0, 0.56, 2527.299999999633, 1015.2999999999162, 1914.3000000001516 + 0.1, 30000.0, 0.6, 3326.8999999994, 1113.1999999997383, 2164.600000000316 + 0.1, 30000.0, 0.64, 4091.199999999899, 1191.2000000000673, 2547.999999999454 + 0.1, 30000.0, 0.68, 4947.499999998739, 1286.0000000000807, 2890.5999999996675 + 0.1, 30000.0, 0.72, 5758.600000000174, 1339.9999999999666, 3079.29999999943 + 0.1, 30000.0, 0.76, 6612.199999998024, 1488.499999999809, 3619.1000000002186 + 0.1, 30000.0, 0.8, 7485.300000000515, 1526.3000000001698, 3835.600000000238 + 0.1, 30000.0, 0.84, 7957.532000000242, 1570.200000000082, 4013.237714286026 + 0.1, 30000.0, 0.88, 8192.07200000096, 1616.9600000001933, 4165.394857143638 + 0.1, 30000.0, 0.92, 8432.85839999995, 1662.436800000049, 4309.990399999962 + 0.1, 30000.0, 0.96, 8762.304800000347, 1704.293600000125, 4455.86880000016 + 0.1, 30000.0, 1.0, 9101.30000000102, 1742.0000000002287, 4602.800000000455 + 0.1, 35000.0, 0.52, 1822.0999999999385, 980.2999999999904, 1590.6999999999316 + 0.1, 35000.0, 0.56, 2662.6999999997015, 1050.5999999999663, 1941.9999999998163 + 0.1, 35000.0, 0.6, 3515.799999999142, 1158.399999999902, 2366.499999999392 + 0.1, 35000.0, 0.64, 4465.1999999992795, 1222.4999999997315, 2619.399999999354 + 0.1, 35000.0, 0.68, 5332.999999998226, 1359.099999999842, 3047.0999999987075 + 0.1, 35000.0, 0.72, 6192.4999999997435, 1424.6999999998754, 3338.8999999992966 + 0.1, 35000.0, 0.76, 7155.099999999643, 1551.9000000000142, 3721.4999999994993 + 0.1, 35000.0, 0.8, 8014.600000001109, 1597.4000000001347, 4005.8000000003403 + 0.1, 35000.0, 0.84, 8478.786857143004, 1644.3017142857702, 4251.2331428569305 + 0.1, 35000.0, 0.88, 8708.27542857236, 1691.6988571430365, 4463.144571428395 + 0.1, 35000.0, 0.92, 8936.320800000314, 1738.4688000001406, 4644.051199999805 + 0.1, 35000.0, 0.96, 9250.897600000797, 1783.9216000002984, 4802.1263999998 + 0.1, 35000.0, 1.0, 9594.700000001427, 1827.8000000005006, 4951.199999999868 +0.15000000000000002, 0.0, 0.52, 793.2000000000002, 454.1000000000001, 1016.8 +0.15000000000000002, 0.0, 0.56, 1189.7999999999984, 487.79999999999933, 1174.899999999999 +0.15000000000000002, 0.0, 0.6, 1586.4999999999966, 521.499999999999, 1333.6999999999996 +0.15000000000000002, 0.0, 0.64, 1983.0999999999956, 554.9000000000004, 1492.9999999999945 +0.15000000000000002, 0.0, 0.68, 2379.5999999999967, 588.0999999999991, 1653.1000000000013 +0.15000000000000002, 0.0, 0.72, 2776.1999999999857, 623.2000000000028, 1820.3999999999862 +0.15000000000000002, 0.0, 0.76, 3172.799999999992, 658.7999999999964, 1990.899999999992 +0.15000000000000002, 0.0, 0.8, 3569.400000000006, 694.7000000000066, 2163.9000000000137 +0.15000000000000002, 0.0, 0.84, 3792.300571428572, 714.8657142857145, 2261.2485714285663 +0.15000000000000002, 0.0, 0.88, 3916.9462857142858, 726.102857142858, 2315.8942857142756 +0.15000000000000002, 0.0, 0.92, 4059.713600000006, 738.7287999999996, 2377.928799999996 +0.15000000000000002, 0.0, 0.96, 4255.115200000006, 756.0375999999991, 2463.1575999999936 +0.15000000000000002, 0.0, 1.0, 4455.800000000005, 774.2999999999989, 2553.0999999999917 +0.15000000000000002, 5000.0, 0.52, 886.8999999999999, 500.6000000000001, 1081.4000000000005 +0.15000000000000002, 5000.0, 0.56, 1330.399999999998, 539.0999999999999, 1256.1999999999987 +0.15000000000000002, 5000.0, 0.6, 1773.8999999999965, 577.3999999999993, 1431.5999999999972 +0.15000000000000002, 5000.0, 0.64, 2217.399999999995, 615.499999999996, 1607.7000000000046 +0.15000000000000002, 5000.0, 0.68, 2660.799999999998, 653.5999999999992, 1785.4 +0.15000000000000002, 5000.0, 0.72, 3104.299999999984, 693.9999999999997, 1971.8999999999946 +0.15000000000000002, 5000.0, 0.76, 3547.700000000015, 735.2999999999942, 2162.2999999999984 +0.15000000000000002, 5000.0, 0.8, 3991.2000000000303, 776.4000000000046, 2354.1999999999966 +0.15000000000000002, 5000.0, 0.84, 4241.228000000004, 799.6308571428572, 2462.8480000000027 +0.15000000000000002, 5000.0, 0.88, 4380.568000000013, 812.6394285714288, 2524.0280000000057 +0.15000000000000002, 5000.0, 0.92, 4536.743200000002, 827.0336000000023, 2592.0464000000034 +0.15000000000000002, 5000.0, 0.96, 4747.798400000002, 846.4992000000034, 2684.164800000004 +0.15000000000000002, 5000.0, 1.0, 4962.299999999995, 866.8000000000046, 2780.6000000000063 +0.15000000000000002, 10000.0, 0.52, 1118.9, 631.5000000000003, 1241.7000000000003 +0.15000000000000002, 10000.0, 0.56, 1678.2999999999968, 683.7999999999988, 1456.5999999999979 +0.15000000000000002, 10000.0, 0.6, 2237.7999999999925, 735.4999999999965, 1672.0999999999974 +0.15000000000000002, 10000.0, 0.64, 2797.199999999987, 787.2999999999975, 1889.2000000000014 +0.15000000000000002, 10000.0, 0.68, 3356.6999999999957, 838.7, 2107.399999999981 +0.15000000000000002, 10000.0, 0.72, 3916.0999999999967, 891.9999999999985, 2332.799999999998 +0.15000000000000002, 10000.0, 0.76, 4475.499999999992, 947.1999999999925, 2565.5999999999954 +0.15000000000000002, 10000.0, 0.8, 5035.000000000034, 1002.6000000000054, 2800.4000000000156 +0.15000000000000002, 10000.0, 0.84, 5354.653714285712, 1034.0645714285697, 2934.670285714286 +0.15000000000000002, 10000.0, 0.88, 5530.450857142859, 1051.430285714282, 3009.973142857142 +0.15000000000000002, 10000.0, 0.92, 5705.499199999995, 1069.3272000000002, 3088.3000000000006 +0.15000000000000002, 10000.0, 0.96, 5928.670399999991, 1092.7984, 3190.783999999996 +0.15000000000000002, 10000.0, 1.0, 6154.599999999991, 1117.2999999999993, 3297.6999999999903 +0.15000000000000002, 15000.0, 0.52, 1240.7999999999997, 700.9999999999991, 1350.4 +0.15000000000000002, 15000.0, 0.56, 1860.6999999999973, 758.1999999999967, 1581.799999999997 +0.15000000000000002, 15000.0, 0.6, 2481.599999999988, 815.4999999999928, 1814.3999999999899 +0.15000000000000002, 15000.0, 0.64, 3100.9999999999955, 872.7999999999953, 2049.3999999999864 +0.15000000000000002, 15000.0, 0.68, 3722.299999999992, 929.5999999999987, 2286.399999999986 +0.15000000000000002, 15000.0, 0.72, 4342.399999999994, 988.1999999999946, 2530.3999999999864 +0.15000000000000002, 15000.0, 0.76, 4962.0999999999685, 1049.6999999999914, 2782.3999999999933 +0.15000000000000002, 15000.0, 0.8, 5582.600000000005, 1111.8999999999978, 3038.4999999999955 +0.15000000000000002, 15000.0, 0.84, 5937.8880000000045, 1148.3942857142836, 3189.270285714279 +0.15000000000000002, 15000.0, 0.88, 6133.2680000000055, 1169.4971428571396, 3277.393142857127 +0.15000000000000002, 15000.0, 0.92, 6325.419199999976, 1190.4112000000018, 3366.0663999999924 +0.15000000000000002, 15000.0, 0.96, 6568.270399999964, 1216.5624000000025, 3477.456799999986 +0.15000000000000002, 15000.0, 1.0, 6812.999999999942, 1243.600000000003, 3592.6999999999803 +0.15000000000000002, 20000.0, 0.52, 1244.3999999999828, 385.0999999999981, 633.0000000000009 +0.15000000000000002, 20000.0, 0.56, 1863.8000000000561, 506.5999999999858, 985.7000000000063 +0.15000000000000002, 20000.0, 0.6, 2483.2000000001344, 608.8999999999676, 1339.2999999999959 +0.15000000000000002, 20000.0, 0.64, 3115.0999999999854, 711.0999999998659, 1695.5999999997084 +0.15000000000000002, 20000.0, 0.68, 3740.099999999717, 807.7999999999333, 2028.3999999995408 +0.15000000000000002, 20000.0, 0.72, 4366.499999999508, 901.0999999997791, 2370.599999999772 +0.15000000000000002, 20000.0, 0.76, 4985.899999999675, 1005.9000000000144, 2750.99999999933 +0.15000000000000002, 20000.0, 0.8, 5610.899999999465, 1090.500000000061, 3138.599999999819 +0.15000000000000002, 20000.0, 0.84, 5966.458857142813, 1132.8879999999838, 3305.4188571429568 +0.15000000000000002, 20000.0, 0.88, 6160.327428571556, 1150.6079999999865, 3345.4074285718552 +0.15000000000000002, 20000.0, 0.92, 6356.304800000598, 1171.371199999998, 3401.5880000001966 +0.15000000000000002, 20000.0, 0.96, 6606.093600001129, 1202.5544000000114, 3518.8400000003926 +0.15000000000000002, 20000.0, 1.0, 6849.300000001754, 1231.2000000000369, 3643.900000000631 +0.15000000000000002, 25000.0, 0.52, 1485.999999999985, 812.2999999999979, 1477.099999999939 +0.15000000000000002, 25000.0, 0.56, 2258.6999999999007, 888.1999999999621, 1794.6999999999232 +0.15000000000000002, 25000.0, 0.6, 3011.4999999997362, 966.6999999998686, 2070.099999999656 +0.15000000000000002, 25000.0, 0.64, 3748.199999999674, 1044.99999999993, 2380.8999999998705 +0.15000000000000002, 25000.0, 0.68, 4514.2999999991625, 1102.29999999988, 2622.0000000000873 +0.15000000000000002, 25000.0, 0.72, 5234.199999998997, 1186.3999999998748, 2926.80000000008 +0.15000000000000002, 25000.0, 0.76, 6055.899999999557, 1269.3999999998014, 3280.0999999999267 +0.15000000000000002, 25000.0, 0.8, 6756.2000000005755, 1328.999999999844, 3519.2000000000085 +0.15000000000000002, 25000.0, 0.84, 7185.327428571578, 1379.0297142857141, 3709.804000000335 +0.15000000000000002, 25000.0, 0.88, 7446.061714286227, 1421.1668571428775, 3862.9840000007894 +0.15000000000000002, 25000.0, 0.92, 7686.098399999908, 1456.3887999999902, 3986.804000000181 +0.15000000000000002, 25000.0, 0.96, 7963.300799999905, 1487.0736000000131, 4095.3440000003193 +0.15000000000000002, 25000.0, 1.0, 8245.699999999973, 1517.0000000000382, 4208.700000000499 +0.15000000000000002, 30000.0, 0.52, 1627.8999999999987, 871.5999999999921, 1553.599999999978 +0.15000000000000002, 30000.0, 0.56, 2504.49999999977, 951.3999999999465, 1892.9000000000947 +0.15000000000000002, 30000.0, 0.6, 3312.199999999628, 1044.8999999998339, 2165.100000000203 +0.15000000000000002, 30000.0, 0.64, 4096.399999999897, 1125.5000000000352, 2525.399999999637 +0.15000000000000002, 30000.0, 0.68, 4940.099999999187, 1216.6000000000492, 2858.7999999997874 +0.15000000000000002, 30000.0, 0.72, 5755.100000000121, 1282.7999999999768, 3096.9999999996426 +0.15000000000000002, 30000.0, 0.76, 6596.799999998783, 1410.5999999998814, 3565.6000000001195 +0.15000000000000002, 30000.0, 0.8, 7451.000000000353, 1468.100000000108, 3831.5000000001364 +0.15000000000000002, 30000.0, 0.84, 7922.7782857143875, 1515.6548571429043, 4019.493714285886 +0.15000000000000002, 30000.0, 0.88, 8165.64114285765, 1556.5834285715432, 4158.970857143299 +0.15000000000000002, 30000.0, 0.92, 8408.235199999925, 1596.1136000000251, 4291.961599999959 +0.15000000000000002, 30000.0, 0.96, 8728.92640000015, 1635.6552000000713, 4435.215200000077 +0.15000000000000002, 30000.0, 1.0, 9055.80000000054, 1672.8000000001334, 4580.200000000255 +0.15000000000000002, 35000.0, 0.52, 1806.4999999999595, 908.6999999999938, 1598.0999999999558 +0.15000000000000002, 35000.0, 0.56, 2664.199999999797, 987.4999999999794, 1944.199999999884 +0.15000000000000002, 35000.0, 0.6, 3528.999999999421, 1089.2999999999413, 2336.899999999629 +0.15000000000000002, 35000.0, 0.64, 4456.699999999534, 1163.2999999998235, 2620.699999999601 +0.15000000000000002, 35000.0, 0.68, 5331.899999998844, 1284.299999999898, 3018.799999999172 +0.15000000000000002, 35000.0, 0.72, 6201.599999999921, 1357.8999999999241, 3327.4999999995766 +0.15000000000000002, 35000.0, 0.76, 7138.399999999748, 1476.5000000000111, 3711.4999999996785 +0.15000000000000002, 35000.0, 0.8, 8008.10000000072, 1543.2000000000853, 4033.6000000002405 +0.15000000000000002, 35000.0, 0.84, 8489.108571428673, 1594.9165714285964, 4272.282857142688 +0.15000000000000002, 35000.0, 0.88, 8736.614285714872, 1637.1822857143798, 4453.651428571252 +0.15000000000000002, 35000.0, 0.92, 8977.342400000181, 1678.200000000079, 4612.5111999998935 +0.15000000000000002, 35000.0, 0.96, 9294.94480000047, 1720.8320000001745, 4766.2623999998905 +0.15000000000000002, 35000.0, 1.0, 9630.000000000842, 1762.6000000002973, 4914.8999999999305 + 0.2, 0.0, 0.52, 791.4, 399.60000000000025, 1001.9999999999999 + 0.2, 0.0, 0.56, 1186.9999999999964, 433.59999999999894, 1159.5000000000023 + 0.2, 0.0, 0.6, 1582.5999999999922, 467.4999999999981, 1317.8000000000077 + 0.2, 0.0, 0.64, 1978.299999999995, 501.10000000000264, 1476.5999999999874 + 0.2, 0.0, 0.68, 2373.9999999999945, 534.4999999999957, 1636.200000000012 + 0.2, 0.0, 0.72, 2769.5999999999817, 569.8000000000047, 1802.6999999999653 + 0.2, 0.0, 0.76, 3165.2999999999884, 605.6999999999906, 1972.8999999999737 + 0.2, 0.0, 0.8, 3561.0000000000164, 642.0000000000198, 2145.600000000041 + 0.2, 0.0, 0.84, 3783.4702857142884, 662.3085714285754, 2242.7314285714187 + 0.2, 0.0, 0.88, 3907.8331428571446, 673.5342857142958, 2297.145714285699 + 0.2, 0.0, 0.92, 4049.93040000002, 686.1359999999979, 2358.7471999999843 + 0.2, 0.0, 0.96, 4244.164800000027, 703.4719999999961, 2443.3343999999784 + 0.2, 0.0, 1.0, 4443.500000000032, 721.7999999999943, 2532.5999999999704 + 0.2, 5000.0, 0.52, 884.0999999999996, 443.90000000000003, 1066.0000000000007 + 0.2, 5000.0, 0.56, 1326.0999999999967, 482.69999999999953, 1239.8999999999962 + 0.2, 5000.0, 0.6, 1768.09999999999, 521.1999999999996, 1414.5999999999974 + 0.2, 5000.0, 0.64, 2210.1999999999684, 559.4999999999877, 1590.0000000000196 + 0.2, 5000.0, 0.68, 2652.1999999999857, 598.1000000000003, 1767.8999999999944 + 0.2, 5000.0, 0.72, 3094.1999999999375, 638.6999999999967, 1953.2999999999784 + 0.2, 5000.0, 0.76, 3536.2000000000503, 680.0999999999866, 2142.9000000000024 + 0.2, 5000.0, 0.8, 3978.300000000092, 721.6000000000138, 2334.0999999999963 + 0.2, 5000.0, 0.84, 4227.624000000026, 745.0388571428615, 2442.5142857143 + 0.2, 5000.0, 0.88, 4366.524000000057, 758.1274285714361, 2503.6571428571697 + 0.2, 5000.0, 0.92, 4521.7152000000115, 772.5536000000072, 2571.379199999999 + 0.2, 5000.0, 0.96, 4731.18640000001, 792.0512000000111, 2662.8584 + 0.2, 5000.0, 1.0, 4944.200000000009, 812.4000000000163, 2758.6000000000004 + 0.2, 10000.0, 0.52, 1115.4000000000003, 571.2000000000008, 1225.6000000000006 + 0.2, 10000.0, 0.56, 1672.9999999999945, 623.8999999999962, 1439.9999999999986 + 0.2, 10000.0, 0.6, 2230.699999999989, 675.9999999999893, 1654.8000000000072 + 0.2, 10000.0, 0.64, 2788.299999999961, 728.0999999999955, 1871.4000000000187 + 0.2, 10000.0, 0.68, 3346.0999999999854, 779.9000000000004, 2088.999999999939 + 0.2, 10000.0, 0.72, 3903.6999999999935, 833.6000000000054, 2313.6999999999975 + 0.2, 10000.0, 0.76, 4461.30000000001, 889.1999999999794, 2545.8999999999796 + 0.2, 10000.0, 0.8, 5019.00000000009, 945.0000000000168, 2780.4000000000437 + 0.2, 10000.0, 0.84, 5337.733714285725, 976.6359999999968, 2914.098857142852 + 0.2, 10000.0, 0.88, 5513.010857142885, 994.0359999999911, 2988.667428571416 + 0.2, 10000.0, 0.92, 5687.161600000011, 1011.9640000000002, 3066.2663999999886 + 0.2, 10000.0, 0.96, 5908.875200000028, 1035.5120000000006, 3168.0767999999703 + 0.2, 10000.0, 1.0, 6133.200000000053, 1060.1000000000029, 3274.299999999943 + 0.2, 15000.0, 0.52, 1236.2999999999997, 638.3999999999999, 1332.2999999999997 + 0.2, 15000.0, 0.56, 1854.2999999999993, 696.2999999999997, 1563.5999999999995 + 0.2, 15000.0, 0.6, 2472.599999999999, 753.8999999999996, 1796.1999999999996 + 0.2, 15000.0, 0.64, 3090.5999999999995, 811.4000000000004, 2030.5000000000014 + 0.2, 15000.0, 0.68, 3708.6999999999975, 868.7999999999998, 2266.7 + 0.2, 15000.0, 0.72, 4326.900000000001, 928.1000000000004, 2510.0000000000036 + 0.2, 15000.0, 0.76, 4945.000000000002, 989.9000000000005, 2762.1999999999966 + 0.2, 15000.0, 0.8, 5563.1999999999925, 1051.899999999999, 3016.999999999999 + 0.2, 15000.0, 0.84, 5916.8759999999975, 1088.305142857143, 3167.010285714286 + 0.2, 15000.0, 0.88, 6111.075999999997, 1109.4365714285716, 3254.633142857144 + 0.2, 15000.0, 0.92, 6301.973599999998, 1130.5264000000002, 3342.5951999999975 + 0.2, 15000.0, 0.96, 6543.491199999997, 1156.9848000000006, 3452.974399999996 + 0.2, 15000.0, 1.0, 6787.299999999996, 1184.400000000001, 3567.199999999994 + 0.2, 20000.0, 0.52, 1285.6999999999898, 467.199999999999, 927.1000000000003 + 0.2, 20000.0, 0.56, 1926.800000000035, 566.699999999991, 1239.3000000000052 + 0.2, 20000.0, 0.6, 2567.9000000000833, 654.5999999999785, 1553.2000000000046 + 0.2, 20000.0, 0.64, 3216.8000000000075, 742.3999999999195, 1870.0999999998303 + 0.2, 20000.0, 0.68, 3861.3999999998023, 826.7999999999581, 2172.9999999997344 + 0.2, 20000.0, 0.72, 4506.499999999746, 909.7999999998779, 2484.4999999998754 + 0.2, 20000.0, 0.76, 5147.599999999816, 1000.9000000000087, 2823.1999999996133 + 0.2, 20000.0, 0.8, 5792.199999999696, 1080.3000000000352, 3167.8999999998628 + 0.2, 20000.0, 0.84, 6160.002857142823, 1122.7285714285606, 3334.8388571428995 + 0.2, 20000.0, 0.88, 6360.991428571477, 1143.2942857142732, 3398.3274285716498 + 0.2, 20000.0, 0.92, 6560.591200000301, 1165.3191999999956, 3470.5456000001022 + 0.2, 20000.0, 0.96, 6813.342400000581, 1195.6984000000002, 3587.935200000208 + 0.2, 20000.0, 1.0, 7062.900000000908, 1224.9000000000108, 3711.200000000335 + 0.2, 25000.0, 0.52, 1486.9999999999914, 746.3999999999986, 1464.6999999999641 + 0.2, 25000.0, 0.56, 2248.099999999939, 822.4999999999774, 1767.2999999999565 + 0.2, 25000.0, 0.6, 2996.9999999998377, 899.7999999999233, 2045.8999999998052 + 0.2, 25000.0, 0.64, 3737.0999999997866, 976.8999999999573, 2346.299999999923 + 0.2, 25000.0, 0.68, 4494.499999999497, 1041.5999999999285, 2606.000000000061 + 0.2, 25000.0, 0.72, 5224.099999999409, 1122.4999999999154, 2905.200000000048 + 0.2, 25000.0, 0.76, 6014.399999999714, 1204.4999999998868, 3240.699999999956 + 0.2, 25000.0, 0.8, 6732.1000000003605, 1274.4999999999059, 3513.8999999999933 + 0.2, 25000.0, 0.84, 7160.3125714286225, 1323.8748571428516, 3702.866857143047 + 0.2, 25000.0, 0.88, 7410.378285714515, 1359.5434285714298, 3836.135428571882 + 0.2, 25000.0, 0.92, 7644.463199999928, 1390.799199999989, 3950.7992000001054 + 0.2, 25000.0, 0.96, 7923.082399999916, 1422.1863999999987, 4066.8344000001857 + 0.2, 25000.0, 1.0, 8205.09999999994, 1453.5000000000089, 4187.10000000029 + 0.2, 30000.0, 0.52, 1629.7999999999997, 805.4999999999953, 1541.4999999999875 + 0.2, 30000.0, 0.56, 2482.4999999998668, 887.7999999999686, 1868.6000000000545 + 0.2, 30000.0, 0.6, 3294.1999999997865, 978.1999999999024, 2156.20000000012 + 0.2, 30000.0, 0.64, 4091.299999999907, 1060.8000000000136, 2498.4999999997767 + 0.2, 30000.0, 0.68, 4923.999999999512, 1149.4000000000262, 2824.599999999873 + 0.2, 30000.0, 0.72, 5740.000000000074, 1224.2999999999845, 3097.5999999997935 + 0.2, 30000.0, 0.76, 6571.299999999316, 1337.199999999932, 3513.400000000056 + 0.2, 30000.0, 0.8, 7410.000000000224, 1409.500000000064, 3815.0000000000664 + 0.2, 30000.0, 0.84, 7880.511428571448, 1459.9091428571674, 4010.298857142938 + 0.2, 30000.0, 0.88, 8128.925714285927, 1496.6205714286325, 4140.287428571644 + 0.2, 30000.0, 0.92, 8372.175199999921, 1531.828000000011, 4264.448799999964 + 0.2, 30000.0, 0.96, 8685.51040000003, 1569.7240000000345, 4405.281600000025 + 0.2, 30000.0, 1.0, 9002.500000000233, 1606.500000000068, 4548.300000000124 + 0.2, 35000.0, 0.52, 1792.4999999999754, 840.5999999999964, 1596.6999999999734 + 0.2, 35000.0, 0.56, 2661.4999999998713, 925.6999999999883, 1938.1999999999327 + 0.2, 35000.0, 0.6, 3533.8999999996345, 1023.4999999999671, 2307.199999999794 + 0.2, 35000.0, 0.64, 4444.49999999972, 1104.9999999998931, 2613.0999999997753 + 0.2, 35000.0, 0.68, 5323.899999999298, 1214.6999999999387, 2988.7999999995077 + 0.2, 35000.0, 0.72, 6199.900000000008, 1294.7999999999581, 3310.09999999977 + 0.2, 35000.0, 0.76, 7116.39999999983, 1407.1000000000063, 3693.0999999998103 + 0.2, 35000.0, 0.8, 7992.400000000436, 1489.7000000000505, 4042.9000000001597 + 0.2, 35000.0, 0.84, 8485.01485714292, 1545.1257142857212, 4276.475428571305 + 0.2, 35000.0, 0.88, 8745.24342857176, 1583.7028571428973, 4435.189714285565 + 0.2, 35000.0, 0.92, 8994.646400000098, 1620.5744000000377, 4577.564799999951 + 0.2, 35000.0, 0.96, 9313.660800000254, 1661.2488000000894, 4727.805599999951 + 0.2, 35000.0, 1.0, 9641.600000000451, 1701.6000000001563, 4875.799999999976 + 0.25, 0.0, 0.52, 788.1000000000004, 345.4, 983.1000000000009 + 0.25, 0.0, 0.56, 1182.2000000000012, 379.69999999999965, 1139.7999999999952 + 0.25, 0.0, 0.6, 1576.1999999999996, 413.69999999999874, 1297.1999999999828 + 0.25, 0.0, 0.64, 1970.200000000027, 447.4999999999964, 1455.2000000000214 + 0.25, 0.0, 0.68, 2364.299999999955, 481.19999999999845, 1614.1000000000063 + 0.25, 0.0, 0.72, 2758.400000000019, 516.5999999999946, 1779.5000000000075 + 0.25, 0.0, 0.76, 3152.3999999999733, 552.9999999999947, 1949.6000000000051 + 0.25, 0.0, 0.8, 3546.4000000000606, 589.4999999999928, 2121.200000000043 + 0.25, 0.0, 0.84, 3768.107428571425, 609.8942857142835, 2217.779428571414 + 0.25, 0.0, 0.88, 3891.9817142857214, 621.1371428571389, 2271.8937142856967 + 0.25, 0.0, 0.92, 4032.6207999999756, 633.7560000000003, 2332.9552000000035 + 0.25, 0.0, 0.96, 4224.345599999962, 651.1320000000009, 2416.662400000004 + 0.25, 0.0, 1.0, 4421.199999999948, 669.5000000000016, 2505.0000000000027 + 0.25, 5000.0, 0.52, 879.5000000000009, 387.6000000000001, 1046.3000000000006 + 0.25, 5000.0, 0.56, 1319.3000000000015, 426.5999999999988, 1219.1000000000035 + 0.25, 5000.0, 0.6, 1758.9999999999973, 465.29999999999666, 1392.6999999999957 + 0.25, 5000.0, 0.64, 2198.6999999999875, 503.6999999999985, 1566.7999999999743 + 0.25, 5000.0, 0.68, 2638.4999999999955, 542.8999999999983, 1744.700000000022 + 0.25, 5000.0, 0.72, 3078.200000000006, 583.6000000000073, 1928.6999999999796 + 0.25, 5000.0, 0.76, 3517.8999999999855, 625.2000000000011, 2117.100000000016 + 0.25, 5000.0, 0.8, 3957.600000000038, 667.0000000000048, 2307.6999999999857 + 0.25, 5000.0, 0.84, 4205.762285714297, 690.5857142857113, 2415.6399999999803 + 0.25, 5000.0, 0.88, 4344.045142857173, 703.7228571428527, 2476.3199999999647 + 0.25, 5000.0, 0.92, 4497.9184000000305, 718.1751999999892, 2543.3775999999866 + 0.25, 5000.0, 0.96, 4705.228800000038, 737.7103999999805, 2633.975199999982 + 0.25, 5000.0, 1.0, 4916.200000000045, 758.0999999999698, 2728.799999999976 + 0.25, 10000.0, 0.52, 1108.8000000000006, 511.0000000000005, 1204.4 + 0.25, 10000.0, 0.56, 1663.2999999999952, 563.9999999999945, 1417.69999999999 + 0.25, 10000.0, 0.6, 2217.699999999972, 616.5999999999831, 1631.4999999999766 + 0.25, 10000.0, 0.64, 2772.0000000000373, 669.1000000000006, 1846.9000000000046 + 0.25, 10000.0, 0.68, 3326.3999999999915, 721.0999999999908, 2063.3000000000034 + 0.25, 10000.0, 0.72, 3880.799999999999, 775.1999999999941, 2286.8999999999905 + 0.25, 10000.0, 0.76, 4435.299999999985, 831.1999999999887, 2517.8999999999523 + 0.25, 10000.0, 0.8, 4989.7000000000335, 887.0999999999974, 2751.099999999979 + 0.25, 10000.0, 0.84, 5306.431999999984, 918.9074285714361, 2884.1657142856957 + 0.25, 10000.0, 0.88, 5480.671999999987, 936.5217142857279, 2958.462857142824 + 0.25, 10000.0, 0.92, 5654.46399999998, 954.6799999999889, 3035.7135999999937 + 0.25, 10000.0, 0.96, 5876.115999999971, 978.4439999999819, 3136.927199999986 + 0.25, 10000.0, 1.0, 6100.199999999964, 1003.1999999999736, 3242.3999999999783 + 0.25, 15000.0, 0.52, 1229.5, 576.2, 1309.8000000000002 + 0.25, 15000.0, 0.56, 1844.2999999999954, 634.6000000000003, 1540.2999999999997 + 0.25, 15000.0, 0.6, 2459.0999999999904, 692.6000000000005, 1771.8999999999999 + 0.25, 15000.0, 0.64, 3073.8999999999983, 750.5000000000001, 2005.4000000000026 + 0.25, 15000.0, 0.68, 3688.500000000011, 808.3999999999975, 2240.5999999999995 + 0.25, 15000.0, 0.72, 4303.399999999998, 868.100000000001, 2482.8000000000084 + 0.25, 15000.0, 0.76, 4918.2000000000035, 930.4000000000007, 2734.199999999999 + 0.25, 15000.0, 0.8, 5532.999999999983, 992.700000000001, 2988.000000000002 + 0.25, 15000.0, 0.84, 5884.817142857137, 1029.1828571428587, 3136.851428571433 + 0.25, 15000.0, 0.88, 6077.948571428567, 1050.2714285714321, 3223.2457142857256 + 0.25, 15000.0, 0.92, 6267.361599999999, 1071.3535999999988, 3310.0656000000045 + 0.25, 15000.0, 0.96, 6506.683199999997, 1097.8871999999983, 3419.411200000009 + 0.25, 15000.0, 1.0, 6748.199999999997, 1125.3999999999971, 3532.6000000000163 + 0.25, 20000.0, 0.52, 1311.599999999995, 508.1999999999997, 1126.4 + 0.25, 20000.0, 0.56, 1966.400000000019, 592.2999999999951, 1409.5000000000043 + 0.25, 20000.0, 0.6, 2621.2000000000453, 670.0999999999875, 1694.700000000008 + 0.25, 20000.0, 0.64, 3280.4000000000137, 747.7999999999568, 1982.8999999999126 + 0.25, 20000.0, 0.68, 3937.1999999998734, 823.5999999999764, 2263.999999999864 + 0.25, 20000.0, 0.72, 4593.999999999889, 899.3999999999414, 2552.9999999999413 + 0.25, 20000.0, 0.76, 5248.799999999903, 981.0000000000036, 2861.5999999998025 + 0.25, 20000.0, 0.8, 5905.599999999857, 1056.7000000000187, 3175.1999999999107 + 0.25, 20000.0, 0.84, 6281.146857142841, 1099.1582857142796, 3341.5377142857255 + 0.25, 20000.0, 0.88, 6486.655428571444, 1121.7611428571342, 3421.0348571429504 + 0.25, 20000.0, 0.92, 6688.205600000124, 1144.7415999999964, 3504.074400000045 + 0.25, 20000.0, 0.96, 6942.147200000243, 1174.6391999999971, 3621.116800000093 + 0.25, 20000.0, 1.0, 7195.100000000388, 1204.300000000001, 3742.70000000015 + 0.25, 25000.0, 0.52, 1483.9999999999957, 682.3999999999992, 1447.599999999981 + 0.25, 25000.0, 0.56, 2235.2999999999656, 758.6999999999877, 1738.9999999999777 + 0.25, 25000.0, 0.6, 2979.7999999999092, 835.2999999999602, 2018.7999999999022 + 0.25, 25000.0, 0.64, 3720.2999999998688, 911.6999999999771, 2311.0999999999553 + 0.25, 25000.0, 0.68, 4469.799999999732, 981.5999999999617, 2582.8000000000343 + 0.25, 25000.0, 0.72, 5204.2999999996855, 1060.3999999999487, 2877.4000000000246 + 0.25, 25000.0, 0.76, 5971.099999999834, 1141.8999999999432, 3199.3999999999746 + 0.25, 25000.0, 0.8, 6699.100000000202, 1218.7999999999495, 3493.9999999999886 + 0.25, 25000.0, 0.84, 7125.681714285716, 1267.8428571428503, 3681.344571428665 + 0.25, 25000.0, 0.88, 7367.738857142927, 1299.3714285714204, 3801.270285714508 + 0.25, 25000.0, 0.92, 7596.861599999954, 1328.1095999999907, 3909.736800000056 + 0.25, 25000.0, 0.96, 7875.247199999942, 1360.0191999999931, 4030.457600000098 + 0.25, 25000.0, 1.0, 8155.6999999999525, 1392.2999999999956, 4154.900000000149 + 0.25, 30000.0, 0.52, 1626.8000000000002, 740.6999999999975, 1523.7999999999938 + 0.25, 30000.0, 0.56, 2460.6999999999307, 824.8999999999833, 1841.5000000000277 + 0.25, 30000.0, 0.6, 3272.799999999889, 913.2999999999483, 2138.900000000062 + 0.25, 30000.0, 0.64, 4076.699999999927, 997.4000000000016, 2467.4999999998777 + 0.25, 30000.0, 0.68, 4899.599999999736, 1084.5000000000118, 2787.79999999993 + 0.25, 30000.0, 0.72, 5714.000000000036, 1165.19999999999, 3083.1999999998925 + 0.25, 30000.0, 0.76, 6535.999999999666, 1268.0999999999651, 3461.7000000000194 + 0.25, 30000.0, 0.8, 7361.900000000124, 1351.0000000000339, 3787.200000000023 + 0.25, 30000.0, 0.84, 7830.358857142836, 1403.5731428571528, 3987.13714285717 + 0.25, 30000.0, 0.88, 8081.92742857148, 1437.444571428599, 4110.328571428653 + 0.25, 30000.0, 0.92, 8324.801599999939, 1469.7128000000018, 4228.009599999973 + 0.25, 30000.0, 0.96, 8631.887199999976, 1506.5296000000126, 4366.579199999999 + 0.25, 30000.0, 1.0, 8940.80000000006, 1543.1000000000267, 4507.600000000046 + 0.25, 35000.0, 0.52, 1779.4999999999866, 775.8999999999982, 1587.4999999999857 + 0.25, 35000.0, 0.56, 2654.699999999926, 865.4999999999941, 1924.899999999966 + 0.25, 35000.0, 0.6, 3530.9999999997904, 960.9999999999835, 2276.9999999999004 + 0.25, 35000.0, 0.64, 4428.199999999852, 1047.999999999943, 2597.4999999998895 + 0.25, 35000.0, 0.68, 5308.899999999618, 1150.0999999999672, 2956.899999999735 + 0.25, 35000.0, 0.72, 6187.700000000031, 1235.399999999979, 3286.999999999892 + 0.25, 35000.0, 0.76, 7088.399999999894, 1343.4000000000012, 3667.0999999999026 + 0.25, 35000.0, 0.8, 7967.200000000238, 1437.400000000027, 4035.800000000097 + 0.25, 35000.0, 0.84, 8466.90228571432, 1495.6045714285688, 4265.577714285634 + 0.25, 35000.0, 0.88, 8735.325142857298, 1531.7302857142959, 4408.3348571427505 + 0.25, 35000.0, 0.92, 8989.968800000042, 1565.8272000000131, 4538.951199999989 + 0.25, 35000.0, 0.96, 9308.969600000113, 1605.278400000036, 4686.350399999988 + 0.25, 35000.0, 1.0, 9631.100000000211, 1644.8000000000668, 4833.500000000004 +0.30000000000000004, 0.0, 0.52, 784.1000000000001, 292.0, 960.5 +0.30000000000000004, 0.0, 0.56, 1176.0999999999988, 326.6000000000004, 1116.1999999999994 +0.30000000000000004, 0.0, 0.6, 1568.1999999999978, 360.90000000000094, 1272.6000000000001 +0.30000000000000004, 0.0, 0.64, 1960.1999999999966, 394.9000000000022, 1429.5000000000084 +0.30000000000000004, 0.0, 0.68, 2352.200000000006, 428.9000000000019, 1587.3999999999999 +0.30000000000000004, 0.0, 0.72, 2744.3000000000065, 464.40000000000106, 1751.4000000000015 +0.30000000000000004, 0.0, 0.76, 3136.300000000012, 501.3000000000025, 1921.40000000001 +0.30000000000000004, 0.0, 0.8, 3528.3999999999974, 537.9999999999978, 2091.8999999999924 +0.30000000000000004, 0.0, 0.84, 3749.2005714285697, 558.5085714285731, 2187.8091428571415 +0.30000000000000004, 0.0, 0.88, 3872.3862857142844, 569.8142857142893, 2241.4405714285717 +0.30000000000000004, 0.0, 0.92, 4011.0344000000005, 582.4928000000006, 2301.8015999999975 +0.30000000000000004, 0.0, 0.96, 4199.4368, 599.9456000000005, 2384.5111999999954 +0.30000000000000004, 0.0, 1.0, 4393.100000000003, 618.4000000000002, 2471.7999999999906 +0.30000000000000004, 5000.0, 0.52, 873.8000000000001, 332.1, 1022.5000000000003 +0.30000000000000004, 5000.0, 0.56, 1310.7000000000012, 371.30000000000007, 1194.1000000000017 +0.30000000000000004, 5000.0, 0.6, 1747.8000000000036, 410.20000000000033, 1366.2000000000057 +0.30000000000000004, 5000.0, 0.64, 2184.700000000002, 449.2000000000004, 1539.9000000000033 +0.30000000000000004, 5000.0, 0.68, 2621.600000000003, 488.70000000000095, 1716.8999999999971 +0.30000000000000004, 5000.0, 0.72, 3058.5000000000236, 529.6000000000008, 1899.3000000000125 +0.30000000000000004, 5000.0, 0.76, 3495.40000000001, 571.6000000000023, 2086.5999999999985 +0.30000000000000004, 5000.0, 0.8, 3932.2999999999943, 613.5999999999992, 2276.0000000000014 +0.30000000000000004, 5000.0, 0.84, 4178.917142857152, 637.3039999999997, 2383.2531428571424 +0.30000000000000004, 5000.0, 0.88, 4316.228571428592, 650.5039999999999, 2443.464571428575 +0.30000000000000004, 5000.0, 0.92, 4468.493600000002, 664.9935999999988, 2509.7656000000006 +0.30000000000000004, 5000.0, 0.96, 4673.4072, 684.563199999998, 2599.235199999998 +0.30000000000000004, 5000.0, 1.0, 4882.099999999998, 704.999999999997, 2692.899999999991 +0.30000000000000004, 10000.0, 0.52, 1100.7999999999995, 451.79999999999995, 1179.0999999999997 +0.30000000000000004, 10000.0, 0.56, 1651.2000000000003, 505.3000000000004, 1391.000000000001 +0.30000000000000004, 10000.0, 0.6, 2201.7000000000035, 558.3000000000019, 1603.4000000000003 +0.30000000000000004, 10000.0, 0.64, 2752.0000000000086, 611.2000000000019, 1817.300000000006 +0.30000000000000004, 10000.0, 0.68, 3302.40000000003, 663.7000000000037, 2032.5000000000036 +0.30000000000000004, 10000.0, 0.72, 3852.9, 718.1000000000035, 2254.4000000000115 +0.30000000000000004, 10000.0, 0.76, 4403.200000000018, 774.499999999999, 2483.900000000001 +0.30000000000000004, 10000.0, 0.8, 4953.7000000000035, 831.0000000000001, 2716.0000000000036 +0.30000000000000004, 10000.0, 0.84, 5268.006857142857, 863.0605714285714, 2848.3714285714277 +0.30000000000000004, 10000.0, 0.88, 5440.9754285714325, 880.7262857142866, 2922.1857142857184 +0.30000000000000004, 10000.0, 0.92, 5614.526400000004, 898.9616000000004, 2998.899199999995 +0.30000000000000004, 10000.0, 0.96, 5836.448800000003, 922.8912000000001, 3099.3983999999896 +0.30000000000000004, 10000.0, 1.0, 6060.400000000004, 947.8, 3203.9999999999836 +0.30000000000000004, 15000.0, 0.52, 1221.3000000000004, 515.0999999999998, 1283.2 +0.30000000000000004, 15000.0, 0.56, 1832.0000000000014, 574.0000000000005, 1512.4999999999993 +0.30000000000000004, 15000.0, 0.6, 2442.700000000006, 632.5000000000022, 1742.6999999999987 +0.30000000000000004, 15000.0, 0.64, 3053.3000000000025, 690.9999999999985, 1975.20000000001 +0.30000000000000004, 15000.0, 0.68, 3664.000000000012, 749.4000000000009, 2209.200000000005 +0.30000000000000004, 15000.0, 0.72, 4274.700000000011, 809.5000000000056, 2450.100000000021 +0.30000000000000004, 15000.0, 0.76, 4885.300000000011, 872.4000000000012, 2700.200000000017 +0.30000000000000004, 15000.0, 0.8, 5495.999999999997, 935.2999999999981, 2953.000000000012 +0.30000000000000004, 15000.0, 0.84, 5845.684000000015, 971.9542857142842, 3100.4765714285804 +0.30000000000000004, 15000.0, 0.88, 6037.664000000037, 992.9571428571413, 3185.3222857143046 +0.30000000000000004, 15000.0, 0.92, 6225.378400000012, 1013.9535999999991, 3270.7696000000105 +0.30000000000000004, 15000.0, 0.96, 6462.01280000002, 1040.487199999998, 3378.971200000014 +0.30000000000000004, 15000.0, 1.0, 6700.500000000035, 1067.9999999999964, 3491.000000000017 +0.30000000000000004, 20000.0, 0.52, 1324.3999999999976, 515.3, 1246.3 +0.30000000000000004, 20000.0, 0.56, 1986.100000000008, 589.4999999999977, 1509.7000000000028 +0.30000000000000004, 20000.0, 0.6, 2647.8000000000193, 660.799999999994, 1775.3000000000065 +0.30000000000000004, 20000.0, 0.64, 3311.6000000000117, 731.9999999999808, 2043.6999999999628 +0.30000000000000004, 20000.0, 0.68, 3974.2999999999283, 802.2999999999888, 2309.699999999942 +0.30000000000000004, 20000.0, 0.72, 4636.799999999964, 873.4999999999774, 2582.99999999998 +0.30000000000000004, 20000.0, 0.76, 5298.4999999999545, 949.0999999999999, 2871.0999999999153 +0.30000000000000004, 20000.0, 0.8, 5961.199999999953, 1022.4000000000092, 3163.3999999999564 +0.30000000000000004, 20000.0, 0.84, 6340.667999999997, 1064.8891428571403, 3328.523999999998 +0.30000000000000004, 20000.0, 0.88, 6548.4880000000085, 1088.8405714285675, 3417.7840000000247 +0.30000000000000004, 20000.0, 0.92, 6750.528800000034, 1112.5007999999993, 3507.2840000000133 +0.30000000000000004, 20000.0, 0.96, 7004.089600000071, 1142.1695999999993, 3623.5440000000294 +0.30000000000000004, 20000.0, 1.0, 7257.900000000114, 1172.2000000000007, 3743.5000000000496 +0.30000000000000004, 25000.0, 0.52, 1477.399999999998, 620.4999999999995, 1426.399999999992 +0.30000000000000004, 25000.0, 0.56, 2220.199999999984, 696.9999999999942, 1709.599999999991 +0.30000000000000004, 25000.0, 0.6, 2959.699999999957, 773.299999999983, 1988.8999999999592 +0.30000000000000004, 25000.0, 0.64, 3697.999999999927, 849.3999999999895, 2274.8999999999746 +0.30000000000000004, 25000.0, 0.68, 4440.099999999881, 922.6999999999824, 2553.100000000012 +0.30000000000000004, 25000.0, 0.72, 5175.39999999986, 1000.2999999999731, 2843.800000000009 +0.30000000000000004, 25000.0, 0.76, 5924.999999999919, 1081.699999999976, 3155.7999999999856 +0.30000000000000004, 25000.0, 0.8, 6657.300000000092, 1162.6999999999775, 3461.4999999999923 +0.30000000000000004, 25000.0, 0.84, 7081.568571428556, 1211.669142857137, 3647.162285714319 +0.30000000000000004, 25000.0, 0.88, 7317.754285714288, 1240.9205714285629, 3758.965142857226 +0.30000000000000004, 25000.0, 0.92, 7542.688799999979, 1268.2999999999943, 3863.5488000000246 +0.30000000000000004, 25000.0, 0.96, 7819.437599999977, 1300.5879999999934, 3986.629600000043 +0.30000000000000004, 25000.0, 1.0, 8097.299999999982, 1333.4999999999923, 4113.000000000064 +0.30000000000000004, 30000.0, 0.52, 1619.4000000000003, 677.499999999999, 1501.1999999999973 +0.30000000000000004, 30000.0, 0.56, 2438.4999999999704, 763.0999999999925, 1811.7000000000112 +0.30000000000000004, 30000.0, 0.6, 3247.8999999999514, 850.3999999999766, 2114.2000000000253 +0.30000000000000004, 30000.0, 0.64, 4053.399999999951, 935.5999999999959, 2432.5999999999453 +0.30000000000000004, 30000.0, 0.68, 4867.299999999877, 1022.0000000000036, 2748.1999999999675 +0.30000000000000004, 30000.0, 0.72, 5677.800000000008, 1106.1999999999941, 3055.8999999999546 +0.30000000000000004, 30000.0, 0.76, 6491.199999999871, 1203.099999999985, 3409.700000000004 +0.30000000000000004, 30000.0, 0.8, 7306.300000000056, 1293.1000000000156, 3749.2000000000016 +0.30000000000000004, 30000.0, 0.84, 7771.947999999975, 1347.2571428571462, 3951.492571428575 +0.30000000000000004, 30000.0, 0.88, 8024.6479999999865, 1379.4285714285809, 4070.0782857143013 +0.30000000000000004, 30000.0, 0.92, 8266.237599999959, 1409.9007999999988, 4183.201599999981 +0.30000000000000004, 30000.0, 0.96, 8567.887199999966, 1446.1016000000016, 4319.619199999991 +0.30000000000000004, 30000.0, 1.0, 8870.099999999984, 1482.6000000000056, 4458.600000000007 +0.30000000000000004, 35000.0, 0.52, 1766.8999999999937, 714.4999999999991, 1571.4999999999936 +0.30000000000000004, 35000.0, 0.56, 2643.899999999963, 807.1999999999972, 1905.1999999999862 +0.30000000000000004, 35000.0, 0.6, 3520.7999999998983, 901.7999999999921, 2245.899999999961 +0.30000000000000004, 35000.0, 0.64, 4407.399999999934, 992.6999999999754, 2574.7999999999565 +0.30000000000000004, 35000.0, 0.68, 5286.799999999824, 1090.299999999984, 2922.8999999998778 +0.30000000000000004, 35000.0, 0.72, 6165.300000000021, 1179.6999999999916, 3258.4999999999613 +0.30000000000000004, 35000.0, 0.76, 7053.699999999942, 1285.0999999999976, 3634.2999999999606 +0.30000000000000004, 35000.0, 0.8, 7932.200000000108, 1386.8000000000127, 4014.400000000049 +0.30000000000000004, 35000.0, 0.84, 8435.167428571436, 1447.028571428567, 4241.35657142853 +0.30000000000000004, 35000.0, 0.88, 8708.021714285764, 1481.7342857142835, 4373.662285714225 +0.30000000000000004, 35000.0, 0.92, 8965.045600000014, 1514.193600000001, 4496.409600000004 +0.30000000000000004, 35000.0, 0.96, 9282.795200000042, 1553.0272000000082, 4641.491200000006 +0.30000000000000004, 35000.0, 1.0, 9600.100000000073, 1592.200000000018, 4787.600000000014 +0.35000000000000003, 0.0, 0.52, 779.4999999999995, 239.9999999999999, 934.2999999999998 +0.35000000000000003, 0.0, 0.56, 1169.1999999999994, 274.8000000000004, 1088.9000000000017 +0.35000000000000003, 0.0, 0.6, 1558.9999999999955, 309.4000000000007, 1244.0000000000045 +0.35000000000000003, 0.0, 0.64, 1948.699999999988, 343.7999999999993, 1399.8000000000038 +0.35000000000000003, 0.0, 0.68, 2338.5000000000023, 378.0000000000026, 1556.5000000000073 +0.35000000000000003, 0.0, 0.72, 2728.200000000007, 414.1000000000014, 1720.300000000005 +0.35000000000000003, 0.0, 0.76, 3117.9000000000324, 451.20000000000147, 1888.800000000004 +0.35000000000000003, 0.0, 0.8, 3507.6999999999994, 488.19999999999754, 2057.9000000000037 +0.35000000000000003, 0.0, 0.84, 3727.3782857142837, 508.95314285714204, 2153.3948571428546 +0.35000000000000003, 0.0, 0.88, 3849.8411428571385, 520.4445714285696, 2207.043428571425 +0.35000000000000003, 0.0, 0.92, 3986.7007999999896, 533.2288, 2266.931999999988 +0.35000000000000003, 0.0, 0.96, 4172.157599999983, 550.7216000000002, 2348.491999999979 +0.35000000000000003, 0.0, 1.0, 4362.9999999999745, 569.2, 2434.4999999999677 +0.35000000000000003, 5000.0, 0.52, 867.8999999999999, 277.9999999999999, 995.2999999999998 +0.35000000000000003, 5000.0, 0.56, 1301.8000000000047, 317.6000000000011, 1165.4999999999982 +0.35000000000000003, 5000.0, 0.6, 1735.700000000011, 356.8000000000029, 1336.1999999999985 +0.35000000000000003, 5000.0, 0.64, 2169.6000000000145, 396.5000000000004, 1509.8000000000006 +0.35000000000000003, 5000.0, 0.68, 2603.5999999999854, 436.300000000002, 1685.2999999999913 +0.35000000000000003, 5000.0, 0.72, 3037.5000000000073, 477.3999999999997, 1865.9000000000108 +0.35000000000000003, 5000.0, 0.76, 3471.5000000000173, 519.7999999999987, 2052.1999999999925 +0.35000000000000003, 5000.0, 0.8, 3905.4000000000137, 562.1999999999967, 2240.1000000000013 +0.35000000000000003, 5000.0, 0.84, 4150.467428571426, 586.1199999999977, 2346.621142857133 +0.35000000000000003, 5000.0, 0.88, 4286.881714285712, 599.3999999999958, 2406.4525714285533 +0.35000000000000003, 5000.0, 0.92, 4437.5039999999835, 613.8703999999998, 2472.034399999989 +0.35000000000000003, 5000.0, 0.96, 4639.831999999975, 633.3807999999995, 2560.304799999984 +0.35000000000000003, 5000.0, 1.0, 4845.99999999996, 653.799999999999, 2652.6999999999775 +0.35000000000000003, 10000.0, 0.52, 1092.2999999999995, 394.39999999999975, 1150.2999999999995 +0.35000000000000003, 10000.0, 0.56, 1638.4000000000037, 448.50000000000074, 1360.5000000000018 +0.35000000000000003, 10000.0, 0.6, 2184.500000000013, 502.00000000000455, 1571.7000000000041 +0.35000000000000003, 10000.0, 0.64, 2730.699999999993, 555.3000000000033, 1783.9000000000074 +0.35000000000000003, 10000.0, 0.68, 3276.8000000000075, 608.3999999999988, 1997.699999999999 +0.35000000000000003, 10000.0, 0.72, 3822.900000000017, 663.3000000000029, 2217.9999999999955 +0.35000000000000003, 10000.0, 0.76, 4369.100000000019, 720.2000000000031, 2446.00000000001 +0.35000000000000003, 10000.0, 0.8, 4915.2, 777.3000000000013, 2676.600000000004 +0.35000000000000003, 10000.0, 0.84, 5226.857142857138, 809.7074285714272, 2808.1342857142854 +0.35000000000000003, 10000.0, 0.88, 5398.48857142856, 827.5617142857124, 2881.477142857144 +0.35000000000000003, 10000.0, 0.92, 5571.716799999977, 845.9727999999993, 2957.6743999999926 +0.35000000000000003, 10000.0, 0.96, 5793.753599999962, 870.1095999999983, 3057.4287999999897 +0.35000000000000003, 10000.0, 1.0, 6017.399999999947, 895.1999999999973, 3161.0999999999863 +0.35000000000000003, 15000.0, 0.52, 1212.5999999999997, 455.7999999999999, 1252.8 +0.35000000000000003, 15000.0, 0.56, 1818.7000000000014, 515.4000000000009, 1480.8000000000018 +0.35000000000000003, 15000.0, 0.6, 2425.0000000000014, 574.5000000000028, 1709.8000000000043 +0.35000000000000003, 15000.0, 0.64, 3031.1999999999853, 633.799999999999, 1941.0000000000111 +0.35000000000000003, 15000.0, 0.68, 3637.500000000005, 692.7999999999969, 2173.599999999999 +0.35000000000000003, 15000.0, 0.72, 4243.600000000032, 753.6000000000024, 2413.1999999999857 +0.35000000000000003, 15000.0, 0.76, 4849.89999999999, 817.1000000000023, 2662.000000000006 +0.35000000000000003, 15000.0, 0.8, 5456.199999999981, 880.6999999999936, 2913.4999999999986 +0.35000000000000003, 15000.0, 0.84, 5803.449142857134, 917.5462857142838, 3059.568571428571 +0.35000000000000003, 15000.0, 0.88, 5994.000571428554, 938.449142857139, 3142.9542857142847 +0.35000000000000003, 15000.0, 0.92, 6179.819199999972, 959.3871999999965, 3226.999199999991 +0.35000000000000003, 15000.0, 0.96, 6413.646399999961, 986.0023999999931, 3333.8583999999814 +0.35000000000000003, 15000.0, 1.0, 6648.999999999941, 1013.5999999999881, 3444.4999999999704 +0.35000000000000003, 20000.0, 0.52, 1326.3999999999994, 495.70000000000005, 1302.2 +0.35000000000000003, 20000.0, 0.56, 1989.400000000002, 564.3999999999994, 1553.300000000002 +0.35000000000000003, 20000.0, 0.6, 2652.400000000004, 632.0999999999984, 1806.5000000000034 +0.35000000000000003, 20000.0, 0.64, 3316.1000000000045, 699.6999999999941, 2062.19999999999 +0.35000000000000003, 20000.0, 0.68, 3979.4999999999704, 766.9999999999966, 2318.3999999999833 +0.35000000000000003, 20000.0, 0.72, 4642.699999999993, 835.6999999999936, 2581.399999999997 +0.35000000000000003, 20000.0, 0.76, 5305.69999999998, 908.0999999999988, 2856.599999999974 +0.35000000000000003, 20000.0, 0.8, 5969.0999999999985, 980.1000000000039, 3135.3999999999883 +0.35000000000000003, 20000.0, 0.84, 6349.343428571432, 1022.6331428571428, 3298.8062857142804 +0.35000000000000003, 20000.0, 0.88, 6557.657714285726, 1047.3645714285706, 3392.8291428571415 +0.35000000000000003, 20000.0, 0.92, 6758.941600000002, 1071.4592000000007, 3485.284000000001 +0.35000000000000003, 20000.0, 0.96, 7010.751200000009, 1101.0824000000014, 3600.3760000000034 +0.35000000000000003, 20000.0, 1.0, 7263.300000000014, 1131.4000000000024, 3718.7000000000066 +0.35000000000000003, 25000.0, 0.52, 1467.5999999999995, 560.9, 1401.6999999999975 +0.35000000000000003, 25000.0, 0.56, 2202.699999999995, 637.5999999999984, 1678.8999999999971 +0.35000000000000003, 25000.0, 0.6, 2936.499999999985, 713.8999999999953, 1956.2999999999884 +0.35000000000000003, 25000.0, 0.64, 3670.399999999968, 789.9999999999972, 2237.299999999987 +0.35000000000000003, 25000.0, 0.68, 4405.299999999963, 865.2999999999945, 2517.6 +0.35000000000000003, 25000.0, 0.72, 5137.999999999957, 942.3999999999902, 2804.800000000001 +0.35000000000000003, 25000.0, 0.76, 5875.09999999997, 1023.9999999999931, 3109.499999999996 +0.35000000000000003, 25000.0, 0.8, 6606.800000000024, 1106.9999999999932, 3418.3999999999974 +0.35000000000000003, 25000.0, 0.84, 7028.10685714285, 1156.08914285714, 3602.2451428571476 +0.35000000000000003, 25000.0, 0.88, 7260.035428571417, 1184.4605714285656, 3709.7965714285865 +0.35000000000000003, 25000.0, 0.92, 7481.339999999995, 1211.3503999999978, 3812.167200000008 +0.35000000000000003, 25000.0, 0.96, 7755.2959999999985, 1243.908799999997, 3935.766400000014 +0.35000000000000003, 25000.0, 1.0, 8029.700000000007, 1277.1999999999953, 4062.3000000000193 +0.35000000000000003, 30000.0, 0.52, 1608.1000000000001, 616.1999999999997, 1474.3999999999992 +0.35000000000000003, 30000.0, 0.56, 2415.29999999999, 702.7999999999972, 1779.300000000003 +0.35000000000000003, 30000.0, 0.6, 3219.399999999983, 789.699999999992, 2083.100000000007 +0.35000000000000003, 30000.0, 0.64, 4022.1999999999757, 875.6999999999963, 2393.9999999999845 +0.35000000000000003, 30000.0, 0.68, 4827.499999999959, 962.0000000000003, 2705.5999999999885 +0.35000000000000003, 30000.0, 0.72, 5632.099999999996, 1047.9999999999973, 3017.7999999999856 +0.35000000000000003, 30000.0, 0.76, 6437.199999999969, 1141.9999999999939, 3356.5999999999995 +0.35000000000000003, 30000.0, 0.8, 7242.800000000016, 1236.3000000000054, 3702.0999999999963 +0.35000000000000003, 30000.0, 0.84, 7704.906285714271, 1291.5714285714287, 3904.8491428571397 +0.35000000000000003, 30000.0, 0.88, 7957.08914285712, 1322.9457142857161, 4020.520571428566 +0.35000000000000003, 30000.0, 0.92, 8196.606399999982, 1352.524799999998, 4130.582399999993 +0.35000000000000003, 30000.0, 0.96, 8493.340799999982, 1388.469599999998, 4264.912799999993 +0.35000000000000003, 30000.0, 1.0, 8789.799999999981, 1424.9999999999984, 4401.7999999999965 +0.35000000000000003, 35000.0, 0.52, 1754.099999999998, 656.2999999999998, 1549.699999999998 +0.35000000000000003, 35000.0, 0.56, 2629.199999999987, 751.0999999999989, 1879.9999999999961 +0.35000000000000003, 35000.0, 0.6, 3503.7999999999643, 845.8999999999972, 2213.49999999999 +0.35000000000000003, 35000.0, 0.64, 4381.69999999998, 939.4999999999934, 2545.8999999999896 +0.35000000000000003, 35000.0, 0.68, 5257.499999999943, 1035.0999999999945, 2886.599999999958 +0.35000000000000003, 35000.0, 0.72, 6133.0, 1127.6999999999969, 3224.8999999999924 +0.35000000000000003, 35000.0, 0.76, 7011.599999999979, 1231.899999999997, 3595.4999999999905 +0.35000000000000003, 35000.0, 0.8, 7887.100000000033, 1338.4000000000049, 3980.8000000000175 +0.35000000000000003, 35000.0, 0.84, 8390.206857142855, 1400.07314285714, 4205.578857142842 +0.35000000000000003, 35000.0, 0.88, 8664.49542857143, 1434.184571428568, 4331.747428571408 +0.35000000000000003, 35000.0, 0.92, 8921.612800000004, 1465.9087999999977, 4449.679200000006 +0.35000000000000003, 35000.0, 0.96, 9237.061600000006, 1504.6015999999981, 4592.822400000009 +0.35000000000000003, 35000.0, 1.0, 9550.200000000013, 1543.7999999999988, 4737.700000000011 + 0.4, 0.0, 0.52, 773.8999999999988, 189.10000000000008, 904.8000000000008 + 0.4, 0.0, 0.56, 1160.6999999999969, 224.30000000000058, 1058.000000000005 + 0.4, 0.0, 0.6, 1547.699999999982, 259.2000000000002, 1211.8000000000125 + 0.4, 0.0, 0.64, 1934.599999999947, 293.8999999999996, 1366.1000000000142 + 0.4, 0.0, 0.68, 2321.600000000001, 328.400000000007, 1521.6000000000197 + 0.4, 0.0, 0.72, 2708.5000000000246, 365.20000000000385, 1684.8000000000018 + 0.4, 0.0, 0.76, 3095.500000000084, 402.7000000000048, 1851.7000000000137 + 0.4, 0.0, 0.8, 3482.300000000003, 439.89999999999156, 2019.3000000000188 + 0.4, 0.0, 0.84, 3700.5217142857246, 460.9017142857136, 2114.331428571431 + 0.4, 0.0, 0.88, 3822.178857142878, 472.6388571428555, 2167.96571428572 + 0.4, 0.0, 0.92, 3957.2919999999767, 485.5728000000009, 2227.315199999967 + 0.4, 0.0, 0.96, 4139.86799999996, 503.10960000000176, 2307.610399999941 + 0.4, 0.0, 1.0, 4327.899999999938, 521.6000000000031, 2392.1999999999075 + 0.4, 5000.0, 0.52, 860.8999999999996, 225.19999999999987, 964.8999999999996 + 0.4, 5000.0, 0.56, 1291.400000000011, 265.1000000000026, 1133.3999999999946 + 0.4, 5000.0, 0.6, 1721.8000000000252, 304.80000000000706, 1302.8999999999926 + 0.4, 5000.0, 0.64, 2152.3000000000407, 345.3000000000017, 1475.9999999999952 + 0.4, 5000.0, 0.68, 2582.699999999959, 385.40000000000697, 1649.5999999999601 + 0.4, 5000.0, 0.72, 3013.2000000000353, 426.799999999999, 1828.8000000000156 + 0.4, 5000.0, 0.76, 3443.6000000000554, 469.59999999999604, 2013.499999999989 + 0.4, 5000.0, 0.8, 3874.1000000000536, 512.3999999999902, 2199.700000000006 + 0.4, 5000.0, 0.84, 4117.335428571429, 536.5279999999932, 2305.252571428543 + 0.4, 5000.0, 0.88, 4252.589714285717, 549.8879999999883, 2364.4582857142327 + 0.4, 5000.0, 0.92, 4401.111199999951, 564.3936000000014, 2429.113599999973 + 0.4, 5000.0, 0.96, 4600.218399999918, 583.9392000000015, 2516.023199999963 + 0.4, 5000.0, 1.0, 4803.299999999868, 604.4000000000012, 2606.9999999999545 + 0.4, 10000.0, 0.52, 1082.2999999999977, 338.39999999999964, 1117.8999999999992 + 0.4, 10000.0, 0.56, 1623.4000000000092, 393.0000000000019, 1326.4000000000076 + 0.4, 10000.0, 0.6, 2164.600000000028, 447.3000000000116, 1535.8000000000147 + 0.4, 10000.0, 0.64, 2705.6999999999575, 501.1000000000083, 1746.4000000000153 + 0.4, 10000.0, 0.68, 3247.0000000000114, 554.7999999999929, 1958.400000000004 + 0.4, 10000.0, 0.72, 3788.2000000000103, 610.1000000000084, 2176.69999999999 + 0.4, 10000.0, 0.76, 4329.3, 667.8000000000079, 2403.0000000000273 + 0.4, 10000.0, 0.8, 4870.400000000013, 725.500000000003, 2631.700000000023 + 0.4, 10000.0, 0.84, 5179.052571428571, 758.2502857142815, 2762.217714285721 + 0.4, 10000.0, 0.88, 5349.158285714294, 776.2931428571355, 2835.054857142874 + 0.4, 10000.0, 0.92, 5521.9647999999215, 794.9119999999962, 2910.759199999978 + 0.4, 10000.0, 0.96, 5744.025599999883, 819.3079999999936, 3009.786399999969 + 0.4, 10000.0, 1.0, 5967.199999999839, 844.5999999999902, 3112.499999999959 + 0.4, 15000.0, 0.52, 1202.1999999999996, 397.99999999999994, 1218.9 + 0.4, 15000.0, 0.56, 1803.3000000000034, 458.30000000000115, 1445.100000000005 + 0.4, 15000.0, 0.6, 2404.400000000004, 518.3000000000048, 1672.9000000000135 + 0.4, 15000.0, 0.64, 3005.4999999999573, 578.0999999999952, 1902.3000000000384 + 0.4, 15000.0, 0.68, 3606.5999999999813, 637.8999999999854, 2133.5999999999835 + 0.4, 15000.0, 0.72, 4207.50000000006, 699.4000000000054, 2371.299999999957 + 0.4, 15000.0, 0.76, 4808.599999999972, 763.7000000000013, 2618.5000000000164 + 0.4, 15000.0, 0.8, 5409.699999999943, 828.1999999999821, 2868.8000000000056 + 0.4, 15000.0, 0.84, 5754.105714285685, 865.2954285714229, 3013.3177142857153 + 0.4, 15000.0, 0.88, 5943.022857142802, 886.0697142857038, 3094.954857142859 + 0.4, 15000.0, 0.92, 6126.624799999937, 906.9175999999906, 3177.29599999997 + 0.4, 15000.0, 0.96, 6357.1495999999015, 933.6111999999812, 3282.559999999943 + 0.4, 15000.0, 1.0, 6588.899999999859, 961.2999999999682, 3391.5999999999094 + 0.4, 20000.0, 0.52, 1319.9, 456.6, 1309.5 + 0.4, 20000.0, 0.56, 1979.7999999999997, 523.1000000000001, 1553.7000000000003 + 0.4, 20000.0, 0.6, 2639.699999999999, 589.4000000000007, 1799.8000000000009 + 0.4, 20000.0, 0.64, 3299.5999999999985, 655.5999999999995, 2048.0999999999995 + 0.4, 20000.0, 0.68, 3959.599999999997, 721.8000000000011, 2298.3999999999983 + 0.4, 20000.0, 0.72, 4619.5, 789.5999999999985, 2555.1000000000035 + 0.4, 20000.0, 0.76, 5279.4, 860.9000000000002, 2822.999999999998 + 0.4, 20000.0, 0.8, 5939.400000000004, 932.5000000000005, 3094.099999999998 + 0.4, 20000.0, 0.84, 6317.950285714288, 975.1022857142859, 3255.3931428571423 + 0.4, 20000.0, 0.88, 6525.333142857148, 1000.1651428571432, 3350.4245714285703 + 0.4, 20000.0, 0.92, 6724.824800000002, 1024.4792000000004, 3443.183999999999 + 0.4, 20000.0, 0.96, 6973.713600000004, 1054.1704000000007, 3556.771999999998 + 0.4, 20000.0, 1.0, 7223.300000000006, 1084.7000000000007, 3673.3999999999974 + 0.4, 25000.0, 0.52, 1455.0, 503.8, 1374.1 + 0.4, 25000.0, 0.56, 2182.6999999999994, 580.7, 1646.7000000000007 + 0.4, 25000.0, 0.6, 2909.999999999998, 657.2000000000003, 1921.1000000000015 + 0.4, 25000.0, 0.64, 3637.699999999999, 733.5000000000002, 2197.899999999997 + 0.4, 25000.0, 0.68, 4365.299999999996, 809.8000000000004, 2477.000000000002 + 0.4, 25000.0, 0.72, 5092.700000000005, 886.8999999999991, 2760.8000000000006 + 0.4, 25000.0, 0.76, 5820.399999999995, 968.8999999999997, 3060.100000000005 + 0.4, 25000.0, 0.8, 6547.699999999996, 1052.5000000000002, 3366.7000000000003 + 0.4, 25000.0, 0.84, 6965.430285714287, 1101.838285714286, 3548.5182857142845 + 0.4, 25000.0, 0.88, 7194.193142857149, 1130.2611428571436, 3654.34114285714 + 0.4, 25000.0, 0.92, 7412.210400000001, 1157.2407999999998, 3755.5240000000003 + 0.4, 25000.0, 0.96, 7682.464800000002, 1189.9975999999997, 3878.284 + 0.4, 25000.0, 1.0, 7952.700000000003, 1223.4999999999995, 4003.6999999999994 + 0.4, 30000.0, 0.52, 1593.4, 557.1, 1444.1 + 0.4, 30000.0, 0.56, 2390.5, 644.3999999999997, 1744.400000000001 + 0.4, 30000.0, 0.6, 3187.1999999999994, 731.3999999999991, 2046.6000000000026 + 0.4, 30000.0, 0.64, 3983.899999999997, 818.0000000000001, 2351.8999999999983 + 0.4, 30000.0, 0.68, 4780.600000000001, 904.6000000000005, 2659.800000000002 + 0.4, 30000.0, 0.72, 5577.5999999999985, 991.3000000000011, 2971.0000000000005 + 0.4, 30000.0, 0.76, 6374.300000000005, 1084.5999999999985, 3301.6000000000004 + 0.4, 30000.0, 0.8, 7170.999999999996, 1181.1000000000004, 3647.0 + 0.4, 30000.0, 0.84, 7628.861142857143, 1237.1262857142856, 3848.690857142856 + 0.4, 30000.0, 0.88, 7879.252571428573, 1268.369142857143, 3962.639428571426 + 0.4, 30000.0, 0.92, 8116.031200000005, 1297.7175999999995, 4070.7096000000006 + 0.4, 30000.0, 0.96, 8408.078400000006, 1333.6631999999995, 4202.971200000001 + 0.4, 30000.0, 1.0, 8699.300000000008, 1370.2999999999988, 4337.700000000001 + 0.4, 35000.0, 0.52, 1740.5, 601.2, 1523.1 + 0.4, 35000.0, 0.56, 2610.699999999999, 697.5000000000002, 1850.1999999999998 + 0.4, 35000.0, 0.6, 3480.4999999999973, 793.3000000000004, 2179.4 + 0.4, 35000.0, 0.64, 4350.700000000001, 888.7999999999992, 2511.7000000000007 + 0.4, 35000.0, 0.68, 5220.899999999998, 984.2999999999994, 2847.799999999995 + 0.4, 35000.0, 0.72, 6091.099999999998, 1079.3999999999994, 3186.500000000004 + 0.4, 35000.0, 0.76, 6961.40000000001, 1183.500000000001, 3551.5000000000005 + 0.4, 35000.0, 0.8, 7831.599999999993, 1292.7000000000007, 3937.100000000001 + 0.4, 35000.0, 0.84, 8332.417142857144, 1355.4137142857144, 4160.011428571429 + 0.4, 35000.0, 0.88, 8605.908571428572, 1389.5508571428572, 4283.165714285715 + 0.4, 35000.0, 0.92, 8861.406399999994, 1421.2079999999994, 4398.4992 + 0.4, 35000.0, 0.96, 9173.692799999993, 1460.107999999999, 4539.938399999998 + 0.4, 35000.0, 1.0, 9482.999999999989, 1499.599999999998, 4683.399999999998 + 0.45, 0.0, 0.52, 766.7000000000006, 139.39999999999992, 872.3999999999997 + 0.45, 0.0, 0.56, 1150.100000000001, 174.8999999999994, 1023.900000000005 + 0.45, 0.0, 0.6, 1533.6000000000042, 210.0999999999986, 1175.9000000000117 + 0.45, 0.0, 0.64, 1916.9000000000524, 245.00000000000563, 1328.4000000000326 + 0.45, 0.0, 0.68, 2300.300000000006, 280.50000000000574, 1483.8000000000052 + 0.45, 0.0, 0.72, 2683.6000000000604, 317.400000000008, 1644.9000000000265 + 0.45, 0.0, 0.76, 3067.000000000039, 355.0000000000085, 1809.7000000000405 + 0.45, 0.0, 0.8, 3450.399999999949, 392.9000000000062, 1976.4999999999807 + 0.45, 0.0, 0.84, 3666.8017142857066, 414.2360000000001, 2070.9297142857076 + 0.45, 0.0, 0.88, 3787.2988571428464, 426.05600000000055, 2123.946857142843 + 0.45, 0.0, 0.92, 3920.2888000000107, 438.9608, 2182.2727999999975 + 0.45, 0.0, 0.96, 4099.56160000002, 456.4455999999999, 2261.101599999999 + 0.45, 0.0, 1.0, 4284.300000000036, 474.89999999999986, 2344.1000000000026 + 0.45, 5000.0, 0.52, 852.2999999999992, 173.69999999999973, 931.3000000000001 + 0.45, 5000.0, 0.56, 1278.3999999999967, 213.80000000000052, 1097.8000000000095 + 0.45, 5000.0, 0.6, 1704.3999999999824, 254.5000000000039, 1267.0000000000318 + 0.45, 5000.0, 0.64, 2130.6000000000295, 295.20000000000374, 1437.9999999999986 + 0.45, 5000.0, 0.68, 2556.700000000042, 335.7000000000041, 1609.8000000000136 + 0.45, 5000.0, 0.72, 2982.8000000000447, 377.40000000000566, 1786.8000000000086 + 0.45, 5000.0, 0.76, 3409.0000000000414, 420.5000000000035, 1969.5000000000175 + 0.45, 5000.0, 0.8, 3835.1000000000436, 463.60000000000286, 2153.8000000000106 + 0.45, 5000.0, 0.84, 4075.9971428571416, 487.91142857142825, 2258.285714285695 + 0.45, 5000.0, 0.88, 4209.868571428575, 501.3657142857142, 2316.8028571428276 + 0.45, 5000.0, 0.92, 4356.031199999997, 515.8983999999978, 2380.3855999999837 + 0.45, 5000.0, 0.96, 4551.522400000001, 535.436799999997, 2465.6911999999775 + 0.45, 5000.0, 1.0, 4751.1000000000095, 555.8999999999959, 2554.999999999969 + 0.45, 10000.0, 0.52, 1070.3999999999994, 283.5000000000001, 1082.0999999999983 + 0.45, 10000.0, 0.56, 1605.4999999999905, 338.80000000000246, 1288.5000000000105 + 0.45, 10000.0, 0.6, 2140.6999999999834, 393.6000000000079, 1495.700000000027 + 0.45, 10000.0, 0.64, 2675.90000000002, 448.1000000000125, 1704.2000000000453 + 0.45, 10000.0, 0.68, 3211.0, 502.6000000000112, 1914.6000000000029 + 0.45, 10000.0, 0.72, 3746.2000000000417, 558.2000000000107, 2130.1000000000467 + 0.45, 10000.0, 0.76, 4281.300000000142, 616.5000000000093, 2354.399999999996 + 0.45, 10000.0, 0.8, 4816.600000000032, 674.7000000000002, 2580.9000000000087 + 0.45, 10000.0, 0.84, 5121.676571428543, 707.7971428571328, 2710.143999999971 + 0.45, 10000.0, 0.88, 5289.822285714233, 726.0885714285541, 2782.2439999999397 + 0.45, 10000.0, 0.92, 5461.776000000007, 744.9463999999954, 2857.2207999999882 + 0.45, 10000.0, 0.96, 5683.384000000027, 769.5927999999924, 2955.27759999998 + 0.45, 10000.0, 1.0, 5905.60000000006, 795.0999999999883, 3056.799999999968 + 0.45, 15000.0, 0.52, 1189.6999999999991, 341.2999999999998, 1180.9999999999982 + 0.45, 15000.0, 0.56, 1784.3000000000145, 402.4000000000025, 1405.4000000000015 + 0.45, 15000.0, 0.6, 2379.1000000000404, 463.2000000000075, 1631.2000000000023 + 0.45, 15000.0, 0.64, 2974.000000000015, 523.8000000000079, 1858.8000000000377 + 0.45, 15000.0, 0.68, 3568.7999999999925, 584.3000000000116, 2088.1000000000154 + 0.45, 15000.0, 0.72, 4163.50000000006, 646.50000000001, 2323.9000000000137 + 0.45, 15000.0, 0.76, 4758.300000000009, 711.6000000000201, 2569.1000000000354 + 0.45, 15000.0, 0.8, 5353.100000000098, 776.899999999997, 2817.200000000044 + 0.45, 15000.0, 0.84, 5694.053714285671, 814.2199999999917, 2959.835999999987 + 0.45, 15000.0, 0.88, 5880.990857142777, 834.8799999999842, 3039.775999999976 + 0.45, 15000.0, 0.92, 6061.947199999943, 855.6296000000003, 3120.4103999999443 + 0.45, 15000.0, 0.96, 6288.546399999911, 882.3592000000009, 3223.8847999999184 + 0.45, 15000.0, 1.0, 6515.999999999878, 910.1000000000014, 3331.0999999998885 + 0.45, 20000.0, 0.52, 1307.2, 405.19999999999993, 1283.6000000000001 + 0.45, 20000.0, 0.56, 1960.800000000001, 471.7000000000001, 1524.2999999999997 + 0.45, 20000.0, 0.6, 2614.400000000004, 538.1000000000007, 1766.700000000001 + 0.45, 20000.0, 0.64, 3267.8000000000015, 604.3999999999997, 2011.1 + 0.45, 20000.0, 0.68, 3921.40000000001, 670.8000000000031, 2257.9999999999995 + 0.45, 20000.0, 0.72, 4575.000000000013, 738.7999999999998, 2511.0000000000064 + 0.45, 20000.0, 0.76, 5228.60000000003, 810.4000000000055, 2775.200000000009 + 0.45, 20000.0, 0.8, 5882.199999999979, 882.2999999999971, 3042.3999999999774 + 0.45, 20000.0, 0.84, 6257.265714285695, 925.0085714285698, 3201.2931428571464 + 0.45, 20000.0, 0.88, 6462.682857142827, 950.0742857142837, 3294.824571428578 + 0.45, 20000.0, 0.92, 6659.5592000000015, 974.4231999999953, 3386.093599999999 + 0.45, 20000.0, 0.96, 6904.558400000006, 1004.2263999999922, 3497.8911999999978 + 0.45, 20000.0, 1.0, 7149.900000000014, 1034.899999999989, 3612.699999999995 + 0.45, 25000.0, 0.52, 1440.0000000000005, 449.3999999999999, 1344.2000000000007 + 0.45, 25000.0, 0.56, 2160.0999999999976, 526.5000000000007, 1612.8000000000036 + 0.45, 25000.0, 0.6, 2880.0, 603.3000000000014, 1883.400000000012 + 0.45, 25000.0, 0.64, 3600.1000000000267, 679.9000000000007, 2156.3000000000106 + 0.45, 25000.0, 0.68, 4319.9999999999945, 756.6000000000035, 2432.0000000000227 + 0.45, 25000.0, 0.72, 5040.100000000032, 834.0000000000003, 2712.200000000007 + 0.45, 25000.0, 0.76, 5759.899999999995, 916.5000000000026, 3007.2000000000203 + 0.45, 25000.0, 0.8, 6480.099999999998, 1000.0000000000008, 3308.3999999999965 + 0.45, 25000.0, 0.84, 6893.672571428577, 1049.6520000000028, 3487.9068571428634 + 0.45, 25000.0, 0.88, 7119.838285714304, 1078.5920000000062, 3593.1754285714424 + 0.45, 25000.0, 0.92, 7334.695199999984, 1105.9511999999988, 3693.5511999999962 + 0.45, 25000.0, 0.96, 7600.586399999967, 1138.8703999999989, 3814.5983999999926 + 0.45, 25000.0, 1.0, 7866.099999999945, 1172.5, 3938.0999999999894 + 0.45, 30000.0, 0.52, 1575.8000000000004, 500.5, 1411.0 + 0.45, 30000.0, 0.56, 2363.5000000000045, 588.300000000001, 1707.1000000000022 + 0.45, 30000.0, 0.6, 3151.200000000014, 675.7000000000023, 2005.7000000000075 + 0.45, 30000.0, 0.64, 3939.3000000000116, 762.8000000000062, 2306.4999999999927 + 0.45, 30000.0, 0.68, 4727.000000000025, 849.9000000000025, 2610.6000000000136 + 0.45, 30000.0, 0.72, 5515.000000000019, 936.8000000000055, 2917.6000000000095 + 0.45, 30000.0, 0.76, 6302.800000000017, 1030.7000000000016, 3243.899999999998 + 0.45, 30000.0, 0.8, 7090.499999999998, 1127.9999999999977, 3585.0000000000086 + 0.45, 30000.0, 0.84, 7543.440000000008, 1184.5319999999995, 3784.501714285713 + 0.45, 30000.0, 0.88, 7791.14000000002, 1216.071999999999, 3897.418857142859 + 0.45, 30000.0, 0.92, 8024.635200000016, 1245.6120000000008, 4004.1408000000047 + 0.45, 30000.0, 0.96, 8311.930400000023, 1281.7120000000018, 4134.305600000006 + 0.45, 30000.0, 1.0, 8598.000000000038, 1318.500000000003, 4266.800000000006 + 0.45, 35000.0, 0.52, 1725.5, 549.1, 1492.7000000000003 + 0.45, 35000.0, 0.56, 2588.5000000000014, 646.700000000002, 1816.6999999999991 + 0.45, 35000.0, 0.6, 3451.400000000006, 744.0000000000051, 2143.2000000000035 + 0.45, 35000.0, 0.64, 4314.000000000006, 840.9999999999957, 2473.100000000003 + 0.45, 35000.0, 0.68, 5176.900000000013, 937.7000000000019, 2806.3000000000125 + 0.45, 35000.0, 0.72, 6039.900000000043, 1034.8000000000009, 3143.600000000012 + 0.45, 35000.0, 0.76, 6902.400000000037, 1139.6000000000108, 3503.0999999999963 + 0.45, 35000.0, 0.8, 7765.3999999999705, 1250.1999999999973, 3885.3999999999955 + 0.45, 35000.0, 0.84, 8262.194857142873, 1313.725714285715, 4106.421142857142 + 0.45, 35000.0, 0.88, 8533.423428571467, 1348.3028571428592, 4228.4925714285655 + 0.45, 35000.0, 0.92, 8786.16239999998, 1380.3264000000024, 4342.608799999992 + 0.45, 35000.0, 0.96, 9094.61279999997, 1419.6528000000035, 4482.433599999983 + 0.45, 35000.0, 1.0, 9400.099999999959, 1459.600000000005, 4624.299999999974 + 0.5, 0.0, 0.52, 758.8000000000015, 91.2, 837.2999999999996 + 0.5, 0.0, 0.56, 1138.2000000000016, 127.0999999999993, 987.0000000000101 + 0.5, 0.0, 0.6, 1517.600000000001, 162.4999999999988, 1136.900000000023 + 0.5, 0.0, 0.64, 1897.0000000001098, 198.20000000001303, 1288.8000000000757 + 0.5, 0.0, 0.68, 2276.4000000000196, 234.20000000001184, 1442.9000000000074 + 0.5, 0.0, 0.72, 2655.8000000000998, 271.3000000000183, 1601.6000000000483 + 0.5, 0.0, 0.76, 3035.2000000000885, 309.5000000000235, 1765.0000000000925 + 0.5, 0.0, 0.8, 3414.5999999998758, 347.70000000001437, 1930.0999999999738 + 0.5, 0.0, 0.84, 3628.9405714285504, 369.25600000000026, 2023.5525714285661 + 0.5, 0.0, 0.88, 3748.2262857142546, 381.21600000000245, 2075.898285714275 + 0.5, 0.0, 0.92, 3878.9584000000186, 394.1552000000022, 2133.162399999998 + 0.5, 0.0, 0.96, 4054.6448000000455, 411.5944000000027, 2210.400800000002 + 0.5, 0.0, 1.0, 4235.800000000087, 430.0000000000032, 2291.7000000000094 + 0.5, 5000.0, 0.52, 842.499999999998, 123.69999999999924, 895.0 + 0.5, 5000.0, 0.56, 1263.7999999999824, 164.49999999999994, 1060.1000000000172 + 0.5, 5000.0, 0.6, 1685.199999999936, 205.90000000000433, 1228.3000000000616 + 0.5, 5000.0, 0.64, 2106.4000000000447, 247.00000000000506, 1396.9999999999957 + 0.5, 5000.0, 0.68, 2527.700000000062, 287.8000000000047, 1566.8000000000197 + 0.5, 5000.0, 0.72, 2949.000000000104, 329.80000000001155, 1741.4000000000092 + 0.5, 5000.0, 0.76, 3370.300000000086, 373.30000000000666, 1921.8000000000318 + 0.5, 5000.0, 0.8, 3791.5000000001223, 416.7000000000046, 2103.8000000000447 + 0.5, 5000.0, 0.84, 4029.854285714292, 441.23142857142983, 2207.0839999999603 + 0.5, 5000.0, 0.88, 4162.277142857168, 454.8257142857177, 2264.9239999999436 + 0.5, 5000.0, 0.92, 4305.893600000012, 469.3863999999965, 2327.416799999966 + 0.5, 5000.0, 0.96, 4497.407200000029, 488.8727999999944, 2411.00959999995 + 0.5, 5000.0, 1.0, 4693.100000000058, 509.29999999999234, 2498.4999999999363 + 0.5, 10000.0, 0.52, 1057.1000000000008, 230.5, 1043.599999999999 + 0.5, 10000.0, 0.56, 1585.599999999999, 286.39999999999924, 1247.6000000000024 + 0.5, 10000.0, 0.6, 2114.0999999999926, 341.9000000000003, 1452.5000000000134 + 0.5, 10000.0, 0.64, 2642.7999999999893, 397.0000000000046, 1658.600000000018 + 0.5, 10000.0, 0.68, 3171.3000000000443, 452.2000000000056, 1866.8000000000281 + 0.5, 10000.0, 0.72, 3699.900000000006, 508.3000000000059, 2079.5000000000136 + 0.5, 10000.0, 0.76, 4228.39999999997, 567.3000000000048, 2301.3000000000306 + 0.5, 10000.0, 0.8, 4756.899999999926, 626.200000000003, 2525.399999999999 + 0.5, 10000.0, 0.84, 5058.004571428514, 659.7011428571462, 2653.353714285705 + 0.5, 10000.0, 0.88, 5224.150285714197, 678.2125714285801, 2724.790857142849 + 0.5, 10000.0, 0.92, 5395.198400000011, 697.2807999999976, 2799.0631999999982 + 0.5, 10000.0, 0.96, 5616.160800000016, 722.177599999995, 2896.0783999999976 + 0.5, 10000.0, 1.0, 5837.200000000023, 747.8999999999913, 2996.299999999997 + 0.5, 15000.0, 0.52, 1174.7999999999988, 286.4000000000001, 1140.1000000000004 + 0.5, 15000.0, 0.56, 1762.2999999999943, 348.3000000000014, 1362.1999999999985 + 0.5, 15000.0, 0.6, 2349.6000000000013, 410.0000000000053, 1585.7999999999995 + 0.5, 15000.0, 0.64, 2937.0999999999644, 471.40000000000333, 1811.0000000000111 + 0.5, 15000.0, 0.68, 3524.4999999999804, 532.7000000000016, 2038.000000000021 + 0.5, 15000.0, 0.72, 4111.999999999978, 595.5000000000041, 2271.000000000022 + 0.5, 15000.0, 0.76, 4699.300000000061, 661.400000000005, 2514.1000000000354 + 0.5, 15000.0, 0.8, 5286.799999999995, 727.3999999999978, 2759.799999999956 + 0.5, 15000.0, 0.84, 5623.517142857109, 765.038285714279, 2900.5422857142703 + 0.5, 15000.0, 0.88, 5808.068571428527, 785.7811428571315, 2978.9051428571083 + 0.5, 15000.0, 0.92, 5986.792800000008, 806.6008000000066, 3058.061599999969 + 0.5, 15000.0, 0.96, 6210.585599999995, 833.4576000000097, 3159.9951999999525 + 0.5, 15000.0, 1.0, 6434.899999999978, 861.3000000000139, 3265.4999999999345 + 0.5, 20000.0, 0.52, 1290.6000000000001, 348.7, 1239.9000000000003 + 0.5, 20000.0, 0.56, 1935.9000000000065, 416.2999999999994, 1478.5000000000002 + 0.5, 20000.0, 0.6, 2581.200000000018, 483.5999999999992, 1718.7000000000062 + 0.5, 20000.0, 0.64, 3226.400000000018, 550.7999999999982, 1960.899999999999 + 0.5, 20000.0, 0.68, 3871.70000000001, 618.1000000000041, 2205.5 + 0.5, 20000.0, 0.72, 4517.00000000005, 686.9000000000052, 2456.0000000000146 + 0.5, 20000.0, 0.76, 5162.300000000085, 759.5000000000152, 2718.100000000029 + 0.5, 20000.0, 0.8, 5807.599999999935, 832.1999999999914, 2983.1999999999166 + 0.5, 20000.0, 0.84, 6178.066857142799, 875.0639999999937, 3139.5148571428567 + 0.5, 20000.0, 0.88, 6380.875428571324, 899.923999999991, 3230.2834285714375 + 0.5, 20000.0, 0.92, 6574.525599999973, 924.1535999999832, 3319.1223999999947 + 0.5, 20000.0, 0.96, 6814.867199999965, 954.0431999999731, 3428.8927999999873 + 0.5, 20000.0, 1.0, 7055.099999999962, 984.7999999999603, 3541.6999999999757 + 0.5, 25000.0, 0.52, 1423.0000000000007, 397.89999999999964, 1312.6000000000008 + 0.5, 25000.0, 0.56, 2134.7999999999934, 475.2000000000012, 1577.000000000008 + 0.5, 25000.0, 0.6, 2846.299999999994, 552.3000000000028, 1843.3000000000306 + 0.5, 25000.0, 0.64, 3557.800000000058, 629.1999999999988, 2112.1000000000354 + 0.5, 25000.0, 0.68, 4269.29999999997, 706.1000000000066, 2383.3000000000657 + 0.5, 25000.0, 0.72, 4980.8000000000675, 783.899999999994, 2659.400000000022 + 0.5, 25000.0, 0.76, 5692.59999999997, 866.9000000000085, 2950.400000000044 + 0.5, 25000.0, 0.8, 6404.100000000028, 950.2999999999971, 3245.4999999999814 + 0.5, 25000.0, 0.84, 6812.967428571416, 1000.2657142857178, 3422.3360000000207 + 0.5, 25000.0, 0.88, 7036.581714285719, 1029.7228571428648, 3526.876000000044 + 0.5, 25000.0, 0.92, 7248.189599999935, 1057.4615999999926, 3626.180799999988 + 0.5, 25000.0, 0.96, 7509.303199999883, 1090.5431999999914, 3745.125599999981 + 0.5, 25000.0, 1.0, 7769.69999999981, 1124.2999999999925, 3866.3999999999733 + 0.5, 30000.0, 0.52, 1555.8000000000009, 446.69999999999993, 1375.8 + 0.5, 30000.0, 0.56, 2333.700000000011, 534.900000000002, 1667.5000000000027 + 0.5, 30000.0, 0.6, 3111.300000000041, 622.8000000000069, 1961.4000000000187 + 0.5, 30000.0, 0.64, 3889.200000000014, 710.4000000000132, 2257.999999999972 + 0.5, 30000.0, 0.68, 4667.100000000053, 798.0000000000057, 2557.8000000000284 + 0.5, 30000.0, 0.72, 5445.000000000064, 885.2000000000113, 2859.700000000022 + 0.5, 30000.0, 0.76, 6223.000000000046, 980.100000000007, 3182.699999999982 + 0.5, 30000.0, 0.8, 7000.9000000000215, 1077.4999999999943, 3517.200000000018 + 0.5, 30000.0, 0.84, 7448.270285714279, 1134.3988571428533, 3713.765714285701 + 0.5, 30000.0, 0.88, 7692.753142857138, 1166.4274285714228, 3825.8428571428403 + 0.5, 30000.0, 0.92, 7922.541600000007, 1196.3408000000006, 3931.4336000000017 + 0.5, 30000.0, 0.96, 8204.727200000014, 1232.6456000000023, 4059.4271999999996 + 0.5, 30000.0, 1.0, 8485.30000000003, 1269.6000000000056, 4189.599999999999 + 0.5, 35000.0, 0.52, 1708.499999999999, 499.9, 1459.5000000000005 + 0.5, 35000.0, 0.56, 2562.699999999996, 599.0000000000051, 1780.3999999999978 + 0.5, 35000.0, 0.6, 3416.9999999999986, 698.0000000000143, 2104.500000000016 + 0.5, 35000.0, 0.64, 4271.200000000004, 796.4999999999858, 2431.000000000011 + 0.5, 35000.0, 0.68, 5125.400000000017, 895.1000000000043, 2761.9000000000315 + 0.5, 35000.0, 0.72, 5979.700000000166, 993.9000000000038, 3096.5000000000323 + 0.5, 35000.0, 0.76, 6833.900000000062, 1099.9000000000285, 3451.0999999999835 + 0.5, 35000.0, 0.8, 7688.1999999999425, 1211.3999999999933, 3827.800000000001 + 0.5, 35000.0, 0.84, 8179.936571428611, 1275.6845714285678, 4046.574857142831 + 0.5, 35000.0, 0.88, 8448.202285714384, 1310.9102857142816, 4168.303428571376 + 0.5, 35000.0, 0.92, 8697.61679999995, 1343.4992000000034, 4281.7471999999825 + 0.5, 35000.0, 0.96, 9001.745599999917, 1383.342400000006, 4419.9023999999645 + 0.5, 35000.0, 1.0, 9303.099999999884, 1423.8000000000102, 4559.999999999941 + 0.55, 0.0, 0.52, 751.100000000003, 44.80000000000016, 799.6999999999994 + 0.55, 0.0, 0.56, 1125.8000000000018, 81.39999999999979, 947.7000000000164 + 0.55, 0.0, 0.6, 1500.5999999999913, 116.80000000000094, 1095.4000000000356 + 0.55, 0.0, 0.64, 1876.3000000001823, 154.60000000002424, 1249.4000000001347 + 0.55, 0.0, 0.68, 2251.700000000041, 189.40000000001965, 1398.700000000003 + 0.55, 0.0, 0.72, 2627.40000000013, 227.5000000000315, 1555.9000000000656 + 0.55, 0.0, 0.76, 3002.900000000154, 267.6000000000488, 1719.8000000001648 + 0.55, 0.0, 0.8, 3377.4999999997526, 304.8000000000261, 1880.69999999998 + 0.55, 0.0, 0.84, 3589.66057142853, 326.26171428571485, 1972.5628571428542 + 0.55, 0.0, 0.88, 3707.986285714229, 338.6388571428631, 2024.7314285714333 + 0.55, 0.0, 0.92, 3836.5680000000334, 351.9184000000067, 2081.341600000003 + 0.55, 0.0, 0.96, 4008.5240000000895, 369.42080000000914, 2156.943200000013 + 0.55, 0.0, 1.0, 4186.00000000017, 387.8000000000115, 2236.500000000026 + 0.55, 5000.0, 0.52, 831.8999999999961, 75.39999999999847, 856.5 + 0.55, 5000.0, 0.56, 1248.5999999999558, 117.99999999999854, 1021.7000000000273 + 0.55, 5000.0, 0.6, 1665.8999999998473, 159.0000000000029, 1186.600000000099 + 0.55, 5000.0, 0.64, 2081.600000000049, 201.5000000000045, 1354.1999999999891 + 0.55, 5000.0, 0.68, 2497.8000000000643, 242.3000000000015, 1521.5000000000139 + 0.55, 5000.0, 0.72, 2914.500000000179, 284.6000000000189, 1694.0999999999929 + 0.55, 5000.0, 0.76, 3330.100000000133, 328.80000000000956, 1872.0000000000455 + 0.55, 5000.0, 0.8, 3746.400000000256, 372.6000000000075, 2051.10000000011 + 0.55, 5000.0, 0.84, 3982.308571428589, 397.44914285714697, 2153.010857142785 + 0.55, 5000.0, 0.88, 4113.3742857143525, 411.26057142858264, 2210.2594285713376 + 0.55, 5000.0, 0.92, 4254.328000000051, 425.859199999996, 2271.773599999942 + 0.55, 5000.0, 0.96, 4441.536000000103, 445.2463999999928, 2353.67919999992 + 0.55, 5000.0, 1.0, 4633.0000000001755, 465.59999999998894, 2439.299999999902 + 0.55, 10000.0, 0.52, 1042.6000000000001, 179.29999999999998, 1002.6000000000007 + 0.55, 10000.0, 0.56, 1564.0000000000055, 236.00000000000037, 1204.000000000004 + 0.55, 10000.0, 0.6, 2085.4000000000074, 292.2000000000006, 1406.4000000000149 + 0.55, 10000.0, 0.64, 2606.600000000016, 348.0000000000107, 1610.0000000000307 + 0.55, 10000.0, 0.68, 3128.000000000024, 403.6999999999965, 1815.1999999999946 + 0.55, 10000.0, 0.72, 3649.4000000000683, 460.59999999999997, 2025.3 + 0.55, 10000.0, 0.76, 4170.59999999997, 520.3000000000054, 2244.7000000000517 + 0.55, 10000.0, 0.8, 4692.00000000004, 580.1000000000063, 2466.3000000000325 + 0.55, 10000.0, 0.84, 4988.7777142857085, 614.0217142857181, 2592.787999999999 + 0.55, 10000.0, 0.88, 5152.554857142842, 632.6788571428621, 2663.34799999999 + 0.55, 10000.0, 0.92, 5322.3992000000335, 651.959999999999, 2736.7175999999868 + 0.55, 10000.0, 0.96, 5542.486400000049, 677.2039999999977, 2832.5271999999754 + 0.55, 10000.0, 1.0, 5762.100000000065, 703.1999999999969, 2931.299999999959 + 0.55, 15000.0, 0.52, 1157.3000000000004, 233.30000000000015, 1096.0000000000025 + 0.55, 15000.0, 0.56, 1735.7999999999986, 296.1000000000017, 1315.5000000000102 + 0.55, 15000.0, 0.6, 2314.4999999999955, 358.6000000000043, 1536.2000000000264 + 0.55, 15000.0, 0.64, 2893.200000000062, 420.69999999999783, 1758.5000000000275 + 0.55, 15000.0, 0.68, 3471.8000000000343, 482.8000000000065, 1982.7999999999934 + 0.55, 15000.0, 0.72, 4050.5000000000045, 546.2000000000025, 2212.7000000000075 + 0.55, 15000.0, 0.76, 4628.999999999999, 612.8000000000155, 2452.4999999999995 + 0.55, 15000.0, 0.8, 5207.700000000001, 679.7000000000069, 2695.299999999985 + 0.55, 15000.0, 0.84, 5539.113142857136, 717.7954285714259, 2834.433714285703 + 0.55, 15000.0, 0.88, 5720.944571428542, 738.7297142857082, 2911.9308571428223 + 0.55, 15000.0, 0.92, 5898.782399999986, 759.7600000000025, 2990.2087999999762 + 0.55, 15000.0, 0.96, 6122.44879999998, 786.9160000000031, 3090.909599999964 + 0.55, 15000.0, 1.0, 6345.999999999977, 815.0000000000043, 3194.8999999999496 + 0.55, 20000.0, 0.52, 1272.4000000000024, 294.3000000000004, 1193.8000000000009 + 0.55, 20000.0, 0.56, 1908.6000000000147, 363.00000000000165, 1429.7000000000007 + 0.55, 20000.0, 0.6, 2544.8000000000293, 431.3000000000053, 1667.3000000000022 + 0.55, 20000.0, 0.64, 3181.1000000000245, 499.500000000012, 1907.1999999999969 + 0.55, 20000.0, 0.68, 3817.3000000000893, 567.7999999999964, 2149.2000000000053 + 0.55, 20000.0, 0.72, 4453.30000000002, 637.5000000000103, 2396.999999999963 + 0.55, 20000.0, 0.76, 5089.500000000036, 711.1000000000041, 2656.6000000000354 + 0.55, 20000.0, 0.8, 5725.700000000126, 784.9000000000196, 2919.4000000000224 + 0.55, 20000.0, 0.84, 6091.1308571428135, 827.9805714285656, 3073.0668571428637 + 0.55, 20000.0, 0.88, 6291.079428571333, 852.5462857142722, 3161.05542857143 + 0.55, 20000.0, 0.92, 6481.104799999988, 876.5328000000027, 3247.379999999995 + 0.55, 20000.0, 0.96, 6716.22159999996, 906.4136000000022, 3354.9359999999947 + 0.55, 20000.0, 1.0, 6950.899999999918, 937.2000000000022, 3465.499999999996 + 0.55, 25000.0, 0.52, 1404.4000000000003, 349.49999999999994, 1279.9000000000012 + 0.55, 25000.0, 0.56, 2106.700000000014, 427.0000000000018, 1539.1000000000079 + 0.55, 25000.0, 0.6, 2808.7000000000344, 504.30000000000587, 1800.9000000000221 + 0.55, 25000.0, 0.64, 3510.9999999999977, 581.4000000000095, 2064.9000000000065 + 0.55, 25000.0, 0.68, 4213.100000000103, 658.7000000000023, 2331.6000000000163 + 0.55, 25000.0, 0.72, 4915.400000000029, 736.8000000000192, 2602.800000000043 + 0.55, 25000.0, 0.76, 5617.500000000001, 820.2000000000104, 2889.300000000063 + 0.55, 25000.0, 0.8, 6319.80000000016, 904.2000000000176, 3179.9999999999845 + 0.55, 25000.0, 0.84, 6723.448571428582, 954.4148571428586, 3353.730857142858 + 0.55, 25000.0, 0.88, 6944.034285714296, 983.9234285714305, 3456.019428571424 + 0.55, 25000.0, 0.92, 7152.088800000006, 1011.7519999999979, 3553.3448000000185 + 0.55, 25000.0, 0.96, 7408.257600000019, 1045.0319999999956, 3670.281600000026 + 0.55, 25000.0, 1.0, 7663.300000000044, 1078.9999999999927, 3789.5000000000337 + 0.55, 30000.0, 0.52, 1533.9000000000008, 396.0000000000004, 1339.2000000000007 + 0.55, 30000.0, 0.56, 2300.500000000009, 484.6000000000037, 1625.6999999999994 + 0.55, 30000.0, 0.6, 3067.400000000038, 572.9000000000085, 1914.6999999999998 + 0.55, 30000.0, 0.64, 3834.4000000000387, 661.1000000000118, 2206.60000000001 + 0.55, 30000.0, 0.68, 4601.300000000055, 749.0000000000072, 2501.2000000000317 + 0.55, 30000.0, 0.72, 5368.300000000053, 837.2000000000046, 2799.400000000028 + 0.55, 30000.0, 0.76, 6135.2000000000735, 932.5999999999977, 3117.1999999999857 + 0.55, 30000.0, 0.8, 6901.800000000202, 1030.1000000000163, 3444.70000000003 + 0.55, 30000.0, 0.84, 7342.979428571434, 1087.3371428571372, 3637.966857142841 + 0.55, 30000.0, 0.88, 7584.093714285688, 1119.808571428556, 3748.8954285713894 + 0.55, 30000.0, 0.92, 7809.873600000028, 1150.0368000000044, 3853.145600000005 + 0.55, 30000.0, 0.96, 8086.299200000051, 1186.4936000000089, 3978.847200000004 + 0.55, 30000.0, 1.0, 8360.600000000073, 1223.6000000000151, 4106.599999999999 + 0.55, 35000.0, 0.52, 1688.8999999999992, 453.50000000000057, 1424.500000000001 + 0.55, 35000.0, 0.56, 2533.40000000001, 554.7000000000041, 1742.2000000000169 + 0.55, 35000.0, 0.6, 3377.800000000043, 655.3000000000116, 2062.9000000000547 + 0.55, 35000.0, 0.64, 4221.899999999968, 755.7000000000103, 2386.299999999966 + 0.55, 35000.0, 0.68, 5066.300000000096, 856.3000000000052, 2714.400000000019 + 0.55, 35000.0, 0.72, 5910.800000000018, 956.6999999999982, 3045.5000000000637 + 0.55, 35000.0, 0.76, 6755.200000000072, 1064.0999999999985, 3396.300000000068 + 0.55, 35000.0, 0.8, 7599.700000000093, 1176.8000000000009, 3766.4000000000597 + 0.55, 35000.0, 0.84, 8086.038857142861, 1241.9657142857097, 3982.2394285714136 + 0.55, 35000.0, 0.88, 8351.40742857143, 1277.8428571428462, 4103.173714285676 + 0.55, 35000.0, 0.92, 8597.505600000017, 1310.96160000001, 4215.653600000065 + 0.55, 35000.0, 0.96, 8897.0152, 1351.2832000000146, 4351.939200000092 + 0.55, 35000.0, 1.0, 9193.599999999971, 1392.2000000000205, 4490.100000000122 + 0.6000000000000001, 0.0, 0.52, 744.5000000000052, 0.5000000000005871, 759.7999999999993 + 0.6000000000000001, 0.0, 0.56, 1113.700000000002, 38.30000000000135, 906.4000000000234 + 0.6000000000000001, 0.0, 0.6, 1483.4999999999702, 73.40000000000593, 1052.0000000000464 + 0.6000000000000001, 0.0, 0.64, 1856.2000000002672, 115.30000000003959, 1212.30000000021 + 0.6000000000000001, 0.0, 0.68, 2228.0000000000755, 146.00000000002862, 1350.9999999999866 + 0.6000000000000001, 0.0, 0.72, 2600.700000000137, 186.60000000004715, 1508.8000000000682 + 0.6000000000000001, 0.0, 0.76, 2972.9000000002357, 230.70000000008724, 1676.3000000002592 + 0.6000000000000001, 0.0, 0.8, 3341.6999999995714, 264.7000000000414, 1828.900000000006 + 0.6000000000000001, 0.0, 0.84, 3551.683999999926, 285.5531428571436, 1918.3234285714323 + 0.6000000000000001, 0.0, 0.88, 3669.603999999906, 298.84457142858287, 1971.3577142857475 + 0.6000000000000001, 0.0, 0.92, 3796.3848000000553, 313.0128000000148, 2028.168000000018 + 0.6000000000000001, 0.0, 0.96, 3964.6056000001518, 330.7896000000209, 2102.1640000000357 + 0.6000000000000001, 0.0, 1.0, 4138.500000000296, 349.20000000002756, 2180.000000000062 + 0.6000000000000001, 5000.0, 0.52, 820.8999999999936, 28.999999999997407, 816.3000000000002 + 0.6000000000000001, 5000.0, 0.56, 1233.7999999999122, 75.099999999996, 984.0000000000391 + 0.6000000000000001, 5000.0, 0.6, 1648.1999999997042, 113.79999999999895, 1141.7000000001447 + 0.6000000000000001, 5000.0, 0.64, 2058.100000000035, 159.5000000000013, 1310.7999999999774 + 0.6000000000000001, 5000.0, 0.68, 2469.1000000000377, 199.79999999999222, 1474.7999999999881 + 0.6000000000000001, 5000.0, 0.72, 2882.000000000266, 242.40000000002726, 1646.399999999951 + 0.6000000000000001, 5000.0, 0.76, 3291.000000000171, 287.80000000001144, 1821.7000000000553 + 0.6000000000000001, 5000.0, 0.8, 3702.9000000004603, 332.20000000001266, 1997.1000000002166 + 0.6000000000000001, 5000.0, 0.84, 3936.7617142857493, 357.5257142857232, 2097.4297142855976 + 0.6000000000000001, 5000.0, 0.88, 4066.7188571429856, 371.66285714288114, 2154.2468571427253 + 0.6000000000000001, 5000.0, 0.92, 4204.964000000129, 386.31839999999715, 2215.0223999999184 + 0.6000000000000001, 5000.0, 0.96, 4387.572000000239, 405.5567999999925, 2295.400799999892 + 0.6000000000000001, 5000.0, 1.0, 4574.500000000388, 425.7999999999868, 2379.199999999875 + 0.6000000000000001, 10000.0, 0.52, 1027.0999999999997, 130.0999999999999, 959.4999999999998 + 0.6000000000000001, 10000.0, 0.56, 1540.6000000000006, 187.7, 1158.1999999999998 + 0.6000000000000001, 10000.0, 0.6, 2054.100000000003, 244.70000000000005, 1357.900000000001 + 0.6000000000000001, 10000.0, 0.64, 2567.7000000000003, 301.30000000000024, 1558.9000000000055 + 0.6000000000000001, 10000.0, 0.68, 3081.200000000004, 357.9, 1761.6999999999973 + 0.6000000000000001, 10000.0, 0.72, 3594.700000000011, 415.30000000000194, 1968.399999999987 + 0.6000000000000001, 10000.0, 0.76, 4108.200000000019, 475.69999999999686, 2184.8999999999855 + 0.6000000000000001, 10000.0, 0.8, 4621.900000000005, 536.2000000000004, 2403.6999999999925 + 0.6000000000000001, 10000.0, 0.84, 4914.137714285733, 570.5502857142865, 2528.579428571436 + 0.6000000000000001, 10000.0, 0.88, 5075.49485714289, 589.4731428571451, 2598.2137142857287 + 0.6000000000000001, 10000.0, 0.92, 5243.853599999988, 609.0391999999999, 2670.64159999999 + 0.6000000000000001, 10000.0, 0.96, 5462.49519999998, 634.6223999999991, 2765.175199999983 + 0.6000000000000001, 10000.0, 1.0, 5680.09999999997, 660.8999999999979, 2862.3999999999737 + 0.6000000000000001, 15000.0, 0.52, 1138.2999999999995, 182.39999999999986, 1050.0 + 0.6000000000000001, 15000.0, 0.56, 1707.4999999999975, 246.09999999999985, 1266.4000000000003 + 0.6000000000000001, 15000.0, 0.6, 2276.5999999999967, 309.50000000000017, 1484.2000000000005 + 0.6000000000000001, 15000.0, 0.64, 2845.799999999996, 372.29999999999956, 1703.1999999999935 + 0.6000000000000001, 15000.0, 0.68, 3414.8999999999833, 435.2000000000006, 1924.4999999999957 + 0.6000000000000001, 15000.0, 0.72, 3984.1000000000045, 499.20000000000124, 2150.6999999999907 + 0.6000000000000001, 15000.0, 0.76, 4553.200000000002, 566.8000000000013, 2387.400000000006 + 0.6000000000000001, 15000.0, 0.8, 5122.4000000000015, 634.3999999999974, 2627.2000000000094 + 0.6000000000000001, 15000.0, 0.84, 5448.109142857159, 672.9971428571438, 2764.5742857142995 + 0.6000000000000001, 15000.0, 0.88, 5627.000571428604, 694.2885714285736, 2841.03714285717 + 0.6000000000000001, 15000.0, 0.92, 5803.741599999973, 715.6183999999982, 2918.3160000000016 + 0.6000000000000001, 15000.0, 0.96, 6027.011199999953, 743.0367999999975, 3017.712000000006 + 0.6000000000000001, 15000.0, 1.0, 6249.49999999993, 771.2999999999964, 3120.1000000000104 + 0.6000000000000001, 20000.0, 0.52, 1252.4999999999995, 242.19999999999976, 1145.4999999999993 + 0.6000000000000001, 20000.0, 0.56, 1878.900000000001, 311.8999999999993, 1378.6000000000017 + 0.6000000000000001, 20000.0, 0.6, 2505.3000000000084, 381.3999999999982, 1613.600000000007 + 0.6000000000000001, 20000.0, 0.64, 3131.5000000000055, 450.6000000000005, 1850.4000000000067 + 0.6000000000000001, 20000.0, 0.68, 3757.7999999999834, 519.8999999999997, 2089.6000000000076 + 0.6000000000000001, 20000.0, 0.72, 4384.199999999981, 590.3999999999977, 2334.4000000000037 + 0.6000000000000001, 20000.0, 0.76, 5010.400000000011, 665.100000000002, 2591.100000000006 + 0.6000000000000001, 20000.0, 0.8, 5636.700000000023, 740.1000000000043, 2851.100000000011 + 0.6000000000000001, 20000.0, 0.84, 5996.593142857138, 783.454285714289, 3002.0245714285684 + 0.6000000000000001, 20000.0, 0.88, 6193.384571428569, 807.7571428571495, 3087.3502857142826 + 0.6000000000000001, 20000.0, 0.92, 6379.58399999998, 831.5351999999978, 3171.1527999999976 + 0.6000000000000001, 20000.0, 0.96, 6609.291999999968, 861.450399999996, 3276.309599999994 + 0.6000000000000001, 20000.0, 1.0, 6838.199999999953, 892.2999999999936, 3384.499999999989 + 0.6000000000000001, 25000.0, 0.52, 1384.0, 304.7, 1246.5999999999995 + 0.6000000000000001, 25000.0, 0.56, 2075.6999999999985, 382.2999999999994, 1500.6999999999962 + 0.6000000000000001, 25000.0, 0.6, 2767.6999999999966, 459.79999999999825, 1757.09999999999 + 0.6000000000000001, 25000.0, 0.64, 3459.6999999999957, 537.0999999999992, 2015.900000000005 + 0.6000000000000001, 25000.0, 0.68, 4151.700000000002, 614.4999999999986, 2277.500000000001 + 0.6000000000000001, 25000.0, 0.72, 4843.399999999994, 692.8000000000033, 2543.4999999999923 + 0.6000000000000001, 25000.0, 0.76, 5535.400000000016, 776.8999999999985, 2825.499999999998 + 0.6000000000000001, 25000.0, 0.8, 6227.400000000023, 861.2000000000024, 3111.100000000017 + 0.6000000000000001, 25000.0, 0.84, 6625.392571428571, 911.5131428571457, 3281.2645714285695 + 0.6000000000000001, 25000.0, 0.88, 6842.878285714283, 941.0245714285761, 3380.990285714283 + 0.6000000000000001, 25000.0, 0.92, 7047.215200000018, 968.9295999999969, 3476.0184000000013 + 0.6000000000000001, 25000.0, 0.96, 7298.046400000026, 1002.4031999999945, 3590.6007999999993 + 0.6000000000000001, 25000.0, 1.0, 7547.300000000036, 1036.599999999992, 3707.499999999996 + 0.6000000000000001, 30000.0, 0.52, 1509.4, 348.4999999999999, 1301.2000000000005 + 0.6000000000000001, 30000.0, 0.56, 2264.2000000000003, 437.50000000000006, 1581.900000000003 + 0.6000000000000001, 30000.0, 0.6, 3019.0000000000095, 526.3000000000012, 1866.1000000000095 + 0.6000000000000001, 30000.0, 0.64, 3773.899999999983, 614.5999999999995, 2151.699999999997 + 0.6000000000000001, 30000.0, 0.68, 4528.400000000022, 703.3999999999979, 2441.800000000004 + 0.6000000000000001, 30000.0, 0.72, 5283.200000000008, 792.3999999999996, 2735.7000000000094 + 0.6000000000000001, 30000.0, 0.76, 6038.100000000012, 888.2000000000058, 3047.3000000000125 + 0.6000000000000001, 30000.0, 0.8, 6792.599999999982, 985.2999999999995, 3366.5999999999935 + 0.6000000000000001, 30000.0, 0.84, 7227.0005714285835, 1042.8874285714319, 3556.457142857151 + 0.6000000000000001, 30000.0, 0.88, 7464.266285714311, 1076.1017142857208, 3666.72857142859 + 0.6000000000000001, 30000.0, 0.92, 7685.423199999985, 1106.8999999999967, 3769.9951999999976 + 0.6000000000000001, 30000.0, 0.96, 7955.3743999999815, 1143.6039999999957, 3893.3903999999957 + 0.6000000000000001, 30000.0, 1.0, 8222.899999999983, 1180.8999999999942, 4018.5999999999917 + 0.6000000000000001, 35000.0, 0.52, 1663.8000000000002, 407.3999999999999, 1385.3999999999999 + 0.6000000000000001, 35000.0, 0.56, 2495.5000000000014, 510.1000000000005, 1698.899999999999 + 0.6000000000000001, 35000.0, 0.6, 3327.6000000000045, 611.9000000000013, 2014.5999999999997 + 0.6000000000000001, 35000.0, 0.64, 4159.300000000017, 713.9000000000005, 2334.2999999999984 + 0.6000000000000001, 35000.0, 0.68, 4991.399999999993, 815.6000000000008, 2657.000000000009 + 0.6000000000000001, 35000.0, 0.72, 5823.100000000008, 917.099999999993, 2983.399999999981 + 0.6000000000000001, 35000.0, 0.76, 6655.200000000003, 1025.9000000000017, 3329.3999999999933 + 0.6000000000000001, 35000.0, 0.8, 7486.900000000014, 1139.1000000000047, 3692.399999999998 + 0.6000000000000001, 35000.0, 0.84, 7966.02914285714, 1204.9262857142887, 3904.806285714297 + 0.6000000000000001, 35000.0, 0.88, 8227.42057142856, 1241.5091428571486, 4024.469142857164 + 0.6000000000000001, 35000.0, 0.92, 8469.23439999998, 1275.1735999999958, 4135.600799999983 + 0.6000000000000001, 35000.0, 0.96, 8762.976799999957, 1315.8551999999916, 4269.6895999999715 + 0.6000000000000001, 35000.0, 1.0, 9053.49999999992, 1357.0999999999854, 4405.499999999956 + 0.65, 0.0, 0.52, 739.9000000000082, -41.399999999998585, 717.7999999999993 + 0.65, 0.0, 0.56, 1102.7000000000025, -1.6999999999956197, 863.5000000000305 + 0.65, 0.0, 0.6, 1467.1999999999348, 32.7000000000148, 1007.3000000000532 + 0.65, 0.0, 0.64, 1838.1000000003596, 81.40000000005975, 1179.6000000003005 + 0.65, 0.0, 0.68, 2207.100000000123, 103.90000000003882, 1299.5999999999538 + 0.65, 0.0, 0.72, 2578.0000000001087, 149.20000000006468, 1461.3000000000482 + 0.65, 0.0, 0.76, 2948.0000000003306, 200.20000000014124, 1636.7000000003732 + 0.65, 0.0, 0.8, 3309.79999999932, 227.9000000000601, 1775.3000000000607 + 0.65, 0.0, 0.84, 3517.733142857028, 247.43028571428658, 1861.1971428571542 + 0.65, 0.0, 0.88, 3636.1045714284332, 262.3531428571625, 1916.6885714286482 + 0.65, 0.0, 0.92, 3761.676000000088, 278.2008000000278, 1974.9992000000434 + 0.65, 0.0, 0.96, 3926.2960000002395, 296.56560000004004, 2047.4984000000763 + 0.65, 0.0, 1.0, 4096.900000000471, 315.1000000000537, 2123.7000000001217 + 0.65, 5000.0, 0.52, 809.8999999999904, -15.300000000003926, 774.9000000000003 + 0.65, 5000.0, 0.56, 1220.3999999998478, 36.599999999992164, 948.400000000052 + 0.65, 5000.0, 0.6, 1633.7999999994947, 70.29999999999177, 1093.4000000001977 + 0.65, 5000.0, 0.64, 2037.7999999999925, 121.79999999999454, 1267.9999999999586 + 0.65, 5000.0, 0.68, 2443.699999999969, 160.8999999999749, 1427.5999999999335 + 0.65, 5000.0, 0.72, 2854.2000000003595, 203.80000000003648, 1599.7999999998729 + 0.65, 5000.0, 0.76, 3255.6000000001904, 251.10000000001185, 1772.500000000057 + 0.65, 5000.0, 0.8, 3664.1000000007493, 296.4000000000208, 1943.200000000376 + 0.65, 5000.0, 0.84, 3896.615428571486, 322.4222857143016, 2041.7039999998224 + 0.65, 5000.0, 0.88, 4025.869714285932, 337.0251428571861, 2098.323999999821 + 0.65, 5000.0, 0.92, 4161.4312000002565, 351.7656000000006, 2158.729599999896 + 0.65, 5000.0, 0.96, 4339.178400000461, 370.80319999999494, 2237.87519999987 + 0.65, 5000.0, 1.0, 4521.300000000733, 390.899999999987, 2319.9999999998645 + 0.65, 10000.0, 0.52, 1008.7999999999988, 83.40000000000003, 916.5999999999998 + 0.65, 10000.0, 0.56, 1513.2000000000055, 141.39999999999966, 1111.7999999999972 + 0.65, 10000.0, 0.6, 2017.6000000000108, 198.8999999999989, 1307.8999999999996 + 0.65, 10000.0, 0.64, 2521.9999999999905, 255.90000000000026, 1505.000000000005 + 0.65, 10000.0, 0.68, 3026.3999999999987, 312.7999999999965, 1703.8999999999803 + 0.65, 10000.0, 0.72, 3530.7000000000185, 370.60000000000673, 1906.999999999947 + 0.65, 10000.0, 0.76, 4035.100000000027, 431.4999999999858, 2119.5999999999494 + 0.65, 10000.0, 0.8, 4539.500000000015, 492.50000000000205, 2334.5999999999844 + 0.65, 10000.0, 0.84, 4826.608571428629, 527.1560000000028, 2457.445142857165 + 0.65, 10000.0, 0.88, 4985.134285714386, 546.236000000007, 2525.976571428618 + 0.65, 10000.0, 0.92, 5149.893599999957, 565.8439999999995, 2596.8887999999724 + 0.65, 10000.0, 0.96, 5363.487199999935, 591.4119999999979, 2689.169599999951 + 0.65, 10000.0, 1.0, 5576.29999999991, 617.6999999999953, 2784.099999999923 + 0.65, 15000.0, 0.52, 1118.199999999999, 133.79999999999976, 1002.4999999999995 + 0.65, 15000.0, 0.56, 1677.299999999996, 198.49999999999997, 1215.600000000003 + 0.65, 15000.0, 0.6, 2236.2999999999965, 262.60000000000036, 1429.900000000005 + 0.65, 15000.0, 0.64, 2795.3999999999746, 326.3999999999976, 1645.6999999999646 + 0.65, 15000.0, 0.68, 3354.4999999999727, 390.1000000000029, 1863.5000000000045 + 0.65, 15000.0, 0.72, 3913.600000000023, 454.8000000000038, 2085.899999999964 + 0.65, 15000.0, 0.76, 4472.69999999999, 523.2000000000046, 2319.5000000000205 + 0.65, 15000.0, 0.8, 5031.8000000000375, 591.7999999999894, 2555.700000000038 + 0.65, 15000.0, 0.84, 5351.469714285756, 630.9074285714318, 2691.053714285754 + 0.65, 15000.0, 0.88, 5527.186857142933, 652.4217142857206, 2766.4308571429347 + 0.65, 15000.0, 0.92, 5702.401599999911, 674.0127999999967, 2842.6720000000173 + 0.65, 15000.0, 0.96, 5924.619199999856, 701.8095999999952, 2940.6760000000327 + 0.65, 15000.0, 1.0, 6145.399999999792, 730.3999999999937, 3041.400000000052 + 0.65, 20000.0, 0.52, 1231.1999999999991, 192.39999999999958, 1095.3999999999985 + 0.65, 20000.0, 0.56, 1846.6999999999978, 263.2999999999973, 1325.5999999999988 + 0.65, 20000.0, 0.6, 2462.3000000000093, 333.8999999999911, 1557.4000000000058 + 0.65, 20000.0, 0.64, 3077.899999999995, 404.1000000000018, 1791.1000000000167 + 0.65, 20000.0, 0.68, 3693.5999999999267, 474.4999999999986, 2027.3000000000156 + 0.65, 20000.0, 0.72, 4309.199999999932, 545.8999999999965, 2268.4000000000046 + 0.65, 20000.0, 0.76, 4924.800000000025, 621.8000000000065, 2521.99999999999 + 0.65, 20000.0, 0.8, 5540.400000000042, 697.8000000000127, 2778.700000000005 + 0.65, 20000.0, 0.84, 5894.298857142844, 741.505142857155, 2926.9468571428497 + 0.65, 20000.0, 0.88, 6087.727428571416, 765.756571428595, 3009.95542857142 + 0.65, 20000.0, 0.92, 6270.048799999944, 789.4479999999937, 3091.4344000000046 + 0.65, 20000.0, 0.96, 6494.361599999901, 819.3679999999896, 3194.104800000001 + 0.65, 20000.0, 1.0, 6717.499999999845, 850.1999999999838, 3299.6999999999916 + 0.65, 25000.0, 0.52, 1361.4000000000008, 263.1000000000003, 1211.9999999999984 + 0.65, 25000.0, 0.56, 2042.2000000000032, 340.79999999999836, 1460.3999999999892 + 0.65, 25000.0, 0.6, 2722.800000000008, 418.3999999999948, 1711.3999999999728 + 0.65, 25000.0, 0.64, 3403.599999999991, 495.9999999999917, 1964.900000000015 + 0.65, 25000.0, 0.68, 4084.199999999999, 573.3999999999971, 2220.7999999999847 + 0.65, 25000.0, 0.72, 4764.99999999998, 652.6000000000051, 2482.799999999981 + 0.65, 25000.0, 0.76, 5445.600000000083, 736.8999999999974, 2759.099999999982 + 0.65, 25000.0, 0.8, 6126.40000000009, 821.3000000000078, 3038.200000000074 + 0.65, 25000.0, 0.84, 6518.05942857144, 871.5240000000081, 3204.2394285714313 + 0.65, 25000.0, 0.88, 6731.9337142857285, 900.884000000014, 3301.373714285718 + 0.65, 25000.0, 0.92, 6932.150400000042, 928.7879999999915, 3394.168800000013 + 0.65, 25000.0, 0.96, 7177.292800000061, 962.4519999999857, 3506.369600000017 + 0.65, 25000.0, 1.0, 7420.400000000085, 996.8999999999791, 3620.900000000017 + 0.65, 30000.0, 0.52, 1483.199999999999, 304.70000000000005, 1262.4000000000012 + 0.65, 30000.0, 0.56, 2224.600000000006, 394.1000000000001, 1538.000000000003 + 0.65, 30000.0, 0.6, 2966.2000000000376, 483.20000000000147, 1815.9000000000085 + 0.65, 30000.0, 0.64, 3707.7999999999215, 572.2000000000019, 2096.3999999999837 + 0.65, 30000.0, 0.68, 4449.500000000066, 661.4999999999881, 2381.099999999997 + 0.65, 30000.0, 0.72, 5190.800000000018, 750.800000000003, 2668.700000000013 + 0.65, 30000.0, 0.76, 5932.400000000043, 847.3000000000072, 2974.7000000000153 + 0.65, 30000.0, 0.8, 6673.999999999963, 943.8000000000064, 3285.199999999985 + 0.65, 30000.0, 0.84, 7101.120000000055, 1001.6154285714383, 3471.247428571451 + 0.65, 30000.0, 0.88, 7334.240000000122, 1035.509714285733, 3580.5817142857536 + 0.65, 30000.0, 0.92, 7550.5663999999515, 1066.8567999999893, 3682.5720000000065 + 0.65, 30000.0, 0.96, 7813.852799999946, 1103.8095999999841, 3803.3280000000104 + 0.65, 30000.0, 1.0, 8074.3999999999505, 1141.2999999999777, 3925.700000000014 + 0.65, 35000.0, 0.52, 1632.900000000002, 361.50000000000006, 1343.0999999999983 + 0.65, 35000.0, 0.56, 2449.5000000000095, 464.5000000000012, 1650.1999999999987 + 0.65, 35000.0, 0.6, 3265.700000000031, 567.200000000002, 1960.3999999999976 + 0.65, 35000.0, 0.64, 4082.300000000032, 669.5999999999979, 2273.399999999983 + 0.65, 35000.0, 0.68, 4898.599999999959, 771.6999999999952, 2589.9000000000033 + 0.65, 35000.0, 0.72, 5715.200000000004, 873.799999999988, 2909.6999999999302 + 0.65, 35000.0, 0.76, 6531.499999999962, 983.3000000000014, 3249.0999999999735 + 0.65, 35000.0, 0.8, 7348.100000000084, 1096.8000000000154, 3603.7999999999884 + 0.65, 35000.0, 0.84, 7818.606285714302, 1163.144000000013, 3812.2542857143144 + 0.65, 35000.0, 0.88, 8075.069142857163, 1200.3240000000246, 3930.4971428572007 + 0.65, 35000.0, 0.92, 8311.445599999952, 1234.4319999999877, 4040.013599999954 + 0.65, 35000.0, 0.96, 8597.879199999888, 1275.3599999999767, 4171.387199999926 + 0.65, 35000.0, 1.0, 8880.6999999998, 1316.7999999999624, 4304.299999999888 + 0.7000000000000001, 0.0, 0.52, 738.2000000000118, -80.59999999999746, 673.8999999999996 + 0.7000000000000001, 0.0, 0.56, 1093.6000000000015, -38.099999999990914, 819.4000000000376 + 0.7000000000000001, 0.0, 0.6, 1452.599999999881, -4.8999999999716835, 961.9000000000542 + 0.7000000000000001, 0.0, 0.64, 1823.4000000004567, 54.00000000008495, 1153.4000000004041 + 0.7000000000000001, 0.0, 0.68, 2190.800000000187, 63.000000000049226, 1244.2999999999001 + 0.7000000000000001, 0.0, 0.72, 2561.6000000000345, 115.90000000008331, 1414.3999999999967 + 0.7000000000000001, 0.0, 0.76, 2931.0000000004366, 177.50000000021322, 1603.2000000005073 + 0.7000000000000001, 0.0, 0.8, 3284.3999999989837, 194.9000000000819, 1720.5000000001526 + 0.7000000000000001, 0.0, 0.84, 3490.5302857141164, 212.19314285714373, 1801.5468571428787 + 0.7000000000000001, 0.0, 0.88, 3610.51314285695, 229.68457142860188, 1861.6354285715677 + 0.7000000000000001, 0.0, 0.92, 3735.7088000001313, 248.24480000004607, 1923.192800000083 + 0.7000000000000001, 0.0, 0.96, 3897.001600000358, 267.6136000000677, 1994.3816000001375 + 0.7000000000000001, 0.0, 1.0, 4064.8000000007037, 286.4000000000919, 2069.1000000002136 + 0.7000000000000001, 5000.0, 0.52, 799.2999999999864, -57.30000000000565, 732.8000000000008 + 0.7000000000000001, 5000.0, 0.56, 1209.3999999997584, 3.299999999986767, 916.3000000000667 + 0.7000000000000001, 5000.0, 0.6, 1624.399999999207, 28.499999999980787, 1041.5000000002565 + 0.7000000000000001, 5000.0, 0.64, 2022.599999999913, 89.19999999998285, 1226.9999999999316 + 0.7000000000000001, 5000.0, 0.68, 2423.6999999998466, 126.19999999994727, 1380.7999999998428 + 0.7000000000000001, 5000.0, 0.72, 2833.8000000004577, 169.40000000004574, 1555.799999999749 + 0.7000000000000001, 5000.0, 0.76, 3226.5000000001824, 219.50000000000998, 1726.0000000000468 + 0.7000000000000001, 5000.0, 0.8, 3633.1000000011363, 266.1000000000327, 1890.8000000005964 + 0.7000000000000001, 5000.0, 0.84, 3865.27142857151, 293.10000000002503, 1987.1971428568866 + 0.7000000000000001, 5000.0, 0.88, 3994.3857142860475, 308.34000000006984, 2043.9285714283387 + 0.7000000000000001, 5000.0, 0.92, 4127.359200000445, 323.20240000000723, 2104.461599999879 + 0.7000000000000001, 5000.0, 0.96, 4300.018400000786, 341.984800000001, 2182.8031999998616 + 0.7000000000000001, 5000.0, 1.0, 4477.100000001231, 361.89999999999065, 2263.499999999879 + 0.7000000000000001, 10000.0, 0.52, 988.9999999999976, 39.09999999999999, 872.7999999999997 + 0.7000000000000001, 10000.0, 0.56, 1483.4000000000121, 97.49999999999858, 1063.8999999999926 + 0.7000000000000001, 10000.0, 0.6, 1977.9000000000206, 155.39999999999577, 1256.0999999999956 + 0.7000000000000001, 10000.0, 0.64, 2472.3999999999705, 212.69999999999823, 1449.2000000000062 + 0.7000000000000001, 10000.0, 0.68, 2966.899999999968, 269.99999999998926, 1643.9999999999427 + 0.7000000000000001, 10000.0, 0.72, 3461.5000000000027, 328.00000000001444, 1842.7999999998792 + 0.7000000000000001, 10000.0, 0.76, 3955.9000000000055, 389.2999999999638, 2051.29999999989 + 0.7000000000000001, 10000.0, 0.8, 4450.3000000000375, 450.60000000000474, 2262.099999999973 + 0.7000000000000001, 10000.0, 0.84, 4731.915428571553, 485.610285714291, 2382.8611428571876 + 0.7000000000000001, 10000.0, 0.88, 4887.389714285944, 505.01314285715677, 2450.3925714286665 + 0.7000000000000001, 10000.0, 0.92, 5048.108799999895, 524.7295999999998, 2519.7063999999564 + 0.7000000000000001, 10000.0, 0.96, 5255.973599999848, 550.2031999999964, 2609.4087999999215 + 0.7000000000000001, 10000.0, 1.0, 5463.3999999997895, 576.3999999999915, 2701.699999999875 + 0.7000000000000001, 15000.0, 0.52, 1096.7999999999984, 87.5999999999993, 953.6999999999985 + 0.7000000000000001, 15000.0, 0.56, 1645.2999999999952, 153.2000000000002, 1163.3000000000095 + 0.7000000000000001, 15000.0, 0.6, 2193.7000000000075, 218.29999999999995, 1374.1000000000195 + 0.7000000000000001, 15000.0, 0.64, 2742.0999999999385, 282.8999999999945, 1586.2999999999108 + 0.7000000000000001, 15000.0, 0.68, 3290.399999999983, 347.50000000000756, 1800.500000000035 + 0.7000000000000001, 15000.0, 0.72, 3838.800000000095, 412.90000000001186, 2019.099999999922 + 0.7000000000000001, 15000.0, 0.76, 4387.299999999957, 482.30000000001246, 2248.8000000000397 + 0.7000000000000001, 15000.0, 0.8, 4935.700000000113, 551.6999999999747, 2481.400000000086 + 0.7000000000000001, 15000.0, 0.84, 5248.9994285714965, 591.3297142857195, 2614.7371428572164 + 0.7000000000000001, 15000.0, 0.88, 5421.3537142858395, 613.1868571428666, 2689.028571428719 + 0.7000000000000001, 15000.0, 0.92, 5594.767199999808, 635.1111999999958, 2764.2288000000476 + 0.7000000000000001, 15000.0, 0.96, 5815.546399999703, 663.2583999999939, 2860.817600000086 + 0.7000000000000001, 15000.0, 1.0, 6034.299999999572, 692.0999999999915, 2959.800000000134 + 0.7000000000000001, 20000.0, 0.52, 1206.3, 144.69999999999987, 1043.4999999999995 + 0.7000000000000001, 20000.0, 0.56, 1809.6000000000029, 216.79999999999967, 1269.8 + 0.7000000000000001, 20000.0, 0.6, 2412.7000000000053, 288.399999999999, 1497.9999999999989 + 0.7000000000000001, 20000.0, 0.64, 3015.899999999993, 359.7000000000004, 1727.8999999999985 + 0.7000000000000001, 20000.0, 0.68, 3619.000000000014, 431.0999999999968, 1960.3000000000043 + 0.7000000000000001, 20000.0, 0.72, 4222.299999999992, 503.1000000000008, 2196.8999999999946 + 0.7000000000000001, 20000.0, 0.76, 4825.299999999981, 580.2999999999962, 2447.0999999999945 + 0.7000000000000001, 20000.0, 0.8, 5428.599999999991, 657.5999999999975, 2700.799999999995 + 0.7000000000000001, 20000.0, 0.84, 5775.149714285731, 701.7868571428565, 2846.4885714285792 + 0.7000000000000001, 20000.0, 0.88, 5964.666857142878, 726.035428571427, 2927.2742857142975 + 0.7000000000000001, 20000.0, 0.92, 6144.852799999988, 749.7559999999979, 3006.827999999995 + 0.7000000000000001, 20000.0, 0.96, 6367.4415999999865, 779.8879999999971, 3107.6959999999917 + 0.7000000000000001, 20000.0, 1.0, 6588.199999999982, 810.8999999999957, 3211.2999999999874 + 0.7000000000000001, 25000.0, 0.52, 1334.1, 213.69999999999993, 1155.8999999999996 + 0.7000000000000001, 25000.0, 0.56, 2001.200000000002, 292.80000000000007, 1401.0999999999976 + 0.7000000000000001, 25000.0, 0.6, 2668.200000000005, 371.8999999999996, 1648.7999999999927 + 0.7000000000000001, 25000.0, 0.64, 3335.2999999999856, 450.39999999999907, 1898.2999999999981 + 0.7000000000000001, 25000.0, 0.68, 4002.4999999999973, 529.7999999999972, 2151.799999999994 + 0.7000000000000001, 25000.0, 0.72, 4669.400000000001, 609.9999999999991, 2410.100000000002 + 0.7000000000000001, 25000.0, 0.76, 5336.5999999999985, 695.5999999999977, 2682.2999999999965 + 0.7000000000000001, 25000.0, 0.8, 6003.499999999999, 781.2000000000024, 2957.8999999999955 + 0.7000000000000001, 25000.0, 0.84, 6387.5434285714555, 831.6040000000007, 3120.2634285714416 + 0.7000000000000001, 25000.0, 0.88, 6597.277714285766, 860.5640000000012, 3213.737714285736 + 0.7000000000000001, 25000.0, 0.92, 6792.506399999961, 888.1607999999969, 3303.269599999996 + 0.7000000000000001, 25000.0, 0.96, 7030.520799999938, 921.8175999999955, 3412.6071999999936 + 0.7000000000000001, 25000.0, 1.0, 7266.099999999911, 956.2999999999932, 3524.2999999999893 + 0.7000000000000001, 30000.0, 0.52, 1455.0, 264.99999999999983, 1224.5000000000002 + 0.7000000000000001, 30000.0, 0.56, 2182.3000000000006, 354.7000000000002, 1493.600000000002 + 0.7000000000000001, 30000.0, 0.6, 2909.6999999999953, 444.10000000000053, 1765.6000000000056 + 0.7000000000000001, 30000.0, 0.64, 3637.2999999999693, 533.5000000000038, 2040.4000000000024 + 0.7000000000000001, 30000.0, 0.68, 4364.599999999989, 623.0999999999985, 2318.2999999999984 + 0.7000000000000001, 30000.0, 0.72, 5092.199999999991, 712.6999999999987, 2600.099999999993 + 0.7000000000000001, 30000.0, 0.76, 5819.599999999999, 809.2999999999932, 2899.000000000002 + 0.7000000000000001, 30000.0, 0.8, 6547.000000000017, 906.1000000000039, 3202.3999999999983 + 0.7000000000000001, 30000.0, 0.84, 6966.170285714314, 964.2091428571446, 3384.349714285726 + 0.7000000000000001, 30000.0, 0.88, 7194.873142857193, 998.380571428573, 3491.4068571428784 + 0.7000000000000001, 30000.0, 0.92, 7406.174399999981, 1029.9631999999979, 3591.2031999999986 + 0.7000000000000001, 30000.0, 0.96, 7662.532799999965, 1067.114399999996, 3709.2224000000006 + 0.7000000000000001, 30000.0, 1.0, 7915.7999999999465, 1104.7999999999934, 3828.800000000001 + 0.7000000000000001, 35000.0, 0.52, 1600.0, 319.39999999999986, 1300.8 + 0.7000000000000001, 35000.0, 0.56, 2399.6999999999994, 423.00000000000034, 1601.4000000000003 + 0.7000000000000001, 35000.0, 0.6, 3199.7999999999993, 526.1999999999999, 1904.2999999999945 + 0.7000000000000001, 35000.0, 0.64, 3999.7999999999856, 628.7999999999979, 2210.299999999994 + 0.7000000000000001, 35000.0, 0.68, 4799.799999999972, 731.3999999999995, 2520.000000000005 + 0.7000000000000001, 35000.0, 0.72, 5599.799999999981, 834.199999999998, 2833.999999999987 + 0.7000000000000001, 35000.0, 0.76, 6399.7999999999865, 944.0000000000002, 3165.4999999999895 + 0.7000000000000001, 35000.0, 0.8, 7199.499999999986, 1057.6000000000017, 3511.0999999999913 + 0.7000000000000001, 35000.0, 0.84, 7660.693142857147, 1124.4411428571445, 3715.48742857143 + 0.7000000000000001, 35000.0, 0.88, 7912.164571428568, 1162.2925714285732, 3832.561714285716 + 0.7000000000000001, 35000.0, 0.92, 8142.903200000006, 1196.8736, 3940.586399999994 + 0.7000000000000001, 35000.0, 0.96, 8421.490400000015, 1238.0032, 4069.09679999999 + 0.7000000000000001, 35000.0, 1.0, 8696.100000000022, 1279.6000000000015, 4198.899999999984 + 0.75, 0.0, 0.52, 740.3000000000164, -116.79999999999583, 628.3000000000001 + 0.75, 0.0, 0.56, 1087.2000000000007, -70.39999999998402, 774.5000000000434 + 0.75, 0.0, 0.6, 1440.5999999998055, -38.999999999952564, 916.400000000046 + 0.75, 0.0, 0.64, 1813.5000000005543, 34.20000000011595, 1135.8000000005218 + 0.75, 0.0, 0.68, 2180.90000000027, 23.20000000005996, 1184.8999999998196 + 0.75, 0.0, 0.72, 2553.7999999998992, 87.30000000010247, 1369.0999999999046 + 0.75, 0.0, 0.76, 2924.7000000005523, 164.0000000003058, 1578.000000000662 + 0.75, 0.0, 0.8, 3268.099999998551, 166.20000000010737, 1665.1000000002898 + 0.75, 0.0, 0.84, 3472.797714285481, 180.14171428571498, 1739.7354285714625 + 0.75, 0.0, 0.88, 3595.8548571426036, 201.35885714290197, 1807.1097142859367 + 0.75, 0.0, 0.92, 3721.750400000186, 223.90720000007113, 1874.106400000141 + 0.75, 0.0, 0.96, 3880.1288000005084, 244.79840000010572, 1944.2488000002259 + 0.75, 0.0, 1.0, 4045.8000000010043, 264.00000000014484, 2017.7000000003432 + 0.75, 5000.0, 0.52, 789.4999999999815, -96.80000000000771, 690.5000000000016 + 0.75, 5000.0, 0.56, 1201.7999999996393, -24.0000000000205, 889.1000000000821 + 0.75, 5000.0, 0.6, 1621.699999998828, -11.600000000034981, 985.8000000003217 + 0.75, 5000.0, 0.64, 2014.3999999997889, 62.49999999996572, 1188.9999999998931 + 0.75, 5000.0, 0.68, 2411.199999999661, 96.29999999990719, 1335.2999999997057 + 0.75, 5000.0, 0.72, 2823.5000000005525, 139.80000000005504, 1515.8999999995704 + 0.75, 5000.0, 0.76, 3206.3000000001352, 193.80000000000518, 1683.8000000000222 + 0.75, 5000.0, 0.8, 3613.0000000016353, 242.20000000004927, 1841.3000000008892 + 0.75, 5000.0, 0.84, 3846.131428571539, 270.5200000000369, 1935.2725714282155 + 0.75, 5000.0, 0.88, 3975.8257142861953, 286.6000000001051, 1992.4982857139955 + 0.75, 5000.0, 0.92, 4106.377600000704, 301.63040000001786, 2053.78479999987 + 0.75, 5000.0, 0.96, 4273.755200001236, 320.1008000000111, 2131.885599999872 + 0.75, 5000.0, 1.0, 4445.60000000192, 339.7999999999984, 2211.499999999929 + 0.75, 10000.0, 0.52, 968.9999999999952, -2.9000000000003356, 826.9999999999994 + 0.75, 10000.0, 0.56, 1452.8000000000206, 56.39999999999629, 1013.5999999999852 + 0.75, 10000.0, 0.6, 1937.0000000000239, 114.79999999999015, 1202.1999999999873 + 0.75, 10000.0, 0.64, 2421.7999999999365, 172.5999999999939, 1392.4000000000126 + 0.75, 10000.0, 0.68, 2905.9999999998986, 231.09999999997763, 1584.199999999879 + 0.75, 10000.0, 0.72, 3391.1999999999402, 289.0000000000268, 1777.4999999997817 + 0.75, 10000.0, 0.76, 3875.1999999999343, 350.69999999992757, 1982.49999999981 + 0.75, 10000.0, 0.8, 4359.80000000007, 412.1000000000081, 2189.299999999961 + 0.75, 10000.0, 0.84, 4635.783428571652, 447.68457142857994, 2308.3034285715025 + 0.75, 10000.0, 0.88, 4788.1777142861465, 467.85028571430826, 2375.2177142858754 + 0.75, 10000.0, 0.92, 4946.088799999796, 488.0511999999994, 2443.3415999999525 + 0.75, 10000.0, 0.96, 5150.465599999701, 513.6263999999941, 2530.791199999912 + 0.75, 10000.0, 1.0, 5354.099999999589, 539.7999999999861, 2620.4999999998554 + 0.75, 15000.0, 0.52, 1073.8999999999978, 43.89999999999827, 903.799999999996 + 0.75, 15000.0, 0.56, 1611.599999999996, 110.10000000000034, 1109.7000000000223 + 0.75, 15000.0, 0.6, 2148.9000000000287, 176.9999999999987, 1317.600000000049 + 0.75, 15000.0, 0.64, 2685.9999999998913, 241.69999999999118, 1525.2999999998287 + 0.75, 15000.0, 0.68, 3222.400000000026, 307.400000000016, 1736.2000000000955 + 0.75, 15000.0, 0.72, 3759.5000000002574, 373.4000000000287, 1951.0999999998637 + 0.75, 15000.0, 0.76, 4296.799999999892, 444.4000000000265, 2175.3000000000698 + 0.75, 15000.0, 0.8, 4833.900000000233, 513.8999999999512, 2404.900000000159 + 0.75, 15000.0, 0.84, 5140.50285714295, 554.0674285714351, 2536.4897142858263 + 0.75, 15000.0, 0.88, 5309.351428571605, 576.6417142857251, 2609.7468571430886 + 0.75, 15000.0, 0.92, 5480.843199999666, 599.0815999999965, 2683.938400000099 + 0.75, 15000.0, 0.96, 5700.066399999483, 627.4071999999932, 2779.152800000173 + 0.75, 15000.0, 1.0, 5916.799999999257, 656.1999999999891, 2876.3000000002635 + 0.75, 20000.0, 0.52, 1179.5000000000002, 99.60000000000001, 990.4999999999994 + 0.75, 20000.0, 0.56, 1769.3000000000038, 172.6999999999994, 1212.700000000002 + 0.75, 20000.0, 0.6, 2359.000000000007, 245.39999999999836, 1436.7000000000012 + 0.75, 20000.0, 0.64, 2948.7999999999843, 317.9000000000018, 1662.8 + 0.75, 20000.0, 0.68, 3538.5000000000496, 389.9999999999918, 1890.7000000000203 + 0.75, 20000.0, 0.72, 4128.300000000007, 463.1000000000031, 2123.3999999999933 + 0.75, 20000.0, 0.76, 4717.99999999996, 541.3999999999933, 2369.499999999979 + 0.75, 20000.0, 0.8, 5307.799999999969, 619.5999999999923, 2618.49999999999 + 0.75, 20000.0, 0.84, 5646.232000000031, 664.2725714285705, 2761.4828571428798 + 0.75, 20000.0, 0.88, 5831.552000000042, 688.7582857142826, 2840.791428571465 + 0.75, 20000.0, 0.92, 6010.113599999974, 712.7447999999963, 2919.082399999988 + 0.75, 20000.0, 0.96, 6232.075199999963, 743.225599999994, 3018.3847999999803 + 0.75, 20000.0, 1.0, 6451.399999999955, 774.4999999999918, 3120.099999999966 + 0.75, 25000.0, 0.52, 1305.0999999999995, 166.90000000000015, 1099.1 + 0.75, 25000.0, 0.56, 1957.7000000000046, 247.70000000000056, 1341.0999999999956 + 0.75, 25000.0, 0.6, 2610.100000000011, 328.1000000000009, 1584.5999999999874 + 0.75, 25000.0, 0.64, 3262.6999999999543, 408.39999999999856, 1831.30000000001 + 0.75, 25000.0, 0.68, 3915.3999999999724, 488.9999999999934, 2080.7999999999815 + 0.75, 25000.0, 0.72, 4567.800000000037, 570.2999999999942, 2334.8000000000025 + 0.75, 25000.0, 0.76, 5220.399999999995, 657.1999999999964, 2602.699999999995 + 0.75, 25000.0, 0.8, 5873.000000000003, 744.1000000000058, 2874.3999999999915 + 0.75, 25000.0, 0.84, 6248.869714285774, 794.7125714285745, 3033.0422857143094 + 0.75, 25000.0, 0.88, 6453.926857142969, 823.2582857142911, 3123.0051428571774 + 0.75, 25000.0, 0.92, 6644.0047999999015, 850.5399999999938, 3209.364799999998 + 0.75, 25000.0, 0.96, 6875.105599999839, 884.195999999989, 3315.8015999999934 + 0.75, 25000.0, 1.0, 7103.399999999762, 918.6999999999824, 3424.5999999999854 + 0.75, 30000.0, 0.52, 1424.8999999999999, 229.8999999999998, 1187.8000000000002 + 0.75, 30000.0, 0.56, 2137.1999999999985, 319.60000000000144, 1450.3000000000043 + 0.75, 30000.0, 0.6, 2849.7999999999915, 409.30000000000354, 1715.400000000016 + 0.75, 30000.0, 0.64, 3562.0999999999185, 498.700000000012, 1983.3000000000247 + 0.75, 30000.0, 0.68, 4274.699999999954, 588.2999999999934, 2254.6999999999734 + 0.75, 30000.0, 0.72, 4987.0000000000355, 678.2999999999993, 2529.7000000000044 + 0.75, 30000.0, 0.76, 5699.400000000033, 774.9999999999859, 2821.6999999999966 + 0.75, 30000.0, 0.8, 6411.90000000006, 872.200000000006, 3117.899999999978 + 0.75, 30000.0, 0.84, 6822.594285714351, 930.4034285714331, 3295.165714285756 + 0.75, 30000.0, 0.88, 7046.477142857264, 964.5177142857187, 3399.1828571429387 + 0.75, 30000.0, 0.92, 7252.4111999999795, 996.1327999999958, 3496.380799999999 + 0.75, 30000.0, 0.96, 7501.522399999964, 1033.4735999999912, 3611.701600000002 + 0.75, 30000.0, 1.0, 7747.199999999949, 1071.399999999985, 3728.6000000000067 + 0.75, 35000.0, 0.52, 1565.1000000000004, 281.49999999999994, 1258.8000000000004 + 0.75, 35000.0, 0.56, 2347.499999999999, 385.50000000000165, 1552.0000000000034 + 0.75, 35000.0, 0.6, 3129.9000000000065, 488.70000000000266, 1847.7999999999977 + 0.75, 35000.0, 0.64, 3912.1999999999653, 591.6999999999978, 2146.399999999986 + 0.75, 35000.0, 0.68, 4694.999999999933, 694.6000000000014, 2448.8000000000147 + 0.75, 35000.0, 0.72, 5477.299999999948, 797.8999999999977, 2755.399999999964 + 0.75, 35000.0, 0.76, 6259.700000000037, 908.2000000000018, 3079.799999999976 + 0.75, 35000.0, 0.8, 7042.3999999999505, 1021.5000000000006, 3415.6999999999675 + 0.75, 35000.0, 0.84, 7493.827428571417, 1088.7485714285742, 3615.6125714285768 + 0.75, 35000.0, 0.88, 7739.681714285673, 1127.374285714288, 3731.238285714297 + 0.75, 35000.0, 0.92, 7964.284800000029, 1162.5632000000014, 3837.5039999999813 + 0.75, 35000.0, 0.96, 8234.71360000005, 1203.9864000000039, 3962.8839999999695 + 0.75, 35000.0, 1.0, 8500.800000000077, 1245.8000000000077, 4089.3999999999583 + 0.8, 0.0, 0.52, 747.100000000022, -149.69999999999374, 581.200000000001 + 0.8, 0.0, 0.56, 1084.2999999999981, -98.09999999997468, 729.2000000000479 + 0.8, 0.0, 0.6, 1432.0999999997046, -69.19999999992686, 871.400000000027 + 0.8, 0.0, 0.64, 1809.8000000006484, 23.100000000153102, 1128.9000000006508 + 0.8, 0.0, 0.68, 2179.200000000373, -15.59999999992965, 1121.1999999997092 + 0.8, 0.0, 0.72, 2556.8999999996936, 64.00000000012136, 1326.3999999997632 + 0.8, 0.0, 0.76, 2931.9000000006763, 161.10000000042135, 1563.3000000008367 + 0.8, 0.0, 0.8, 3263.4999999980128, 142.30000000013598, 1609.700000000479 + 0.8, 0.0, 0.84, 3467.257714285403, 151.5760000000003, 1676.125714285762 + 0.8, 0.0, 0.88, 3595.1548571425315, 177.89600000006257, 1754.0228571431858 + 0.8, 0.0, 0.92, 3723.0680000002553, 205.95040000010377, 1829.0976000002192 + 0.8, 0.0, 0.96, 3879.0840000006974, 228.9848000001556, 1898.5352000003447 + 0.8, 0.0, 1.0, 4043.5000000013792, 248.8000000002147, 1971.0000000005175 + 0.8, 5000.0, 0.52, 780.8999999999758, -133.60000000001025, 648.5000000000026 + 0.8, 5000.0, 0.56, 1198.5999999994885, -44.50000000002988, 868.2000000000982 + 0.8, 5000.0, 0.6, 1627.399999998345, -50.00000000005599, 926.1000000003925 + 0.8, 5000.0, 0.64, 2015.099999999612, 42.499999999941565, 1155.199999999843 + 0.8, 5000.0, 0.68, 2408.2999999993963, 71.79999999985246, 1291.9999999995161 + 0.8, 5000.0, 0.72, 2826.000000000639, 115.60000000006342, 1481.5999999993257 + 0.8, 5000.0, 0.76, 3197.6000000000386, 174.7999999999967, 1647.4999999999782 + 0.8, 5000.0, 0.8, 3606.900000002263, 225.60000000007128, 1796.1000000012639 + 0.8, 5000.0, 0.84, 3842.5971428572866, 255.6434285714798, 1887.2937142852363 + 0.8, 5000.0, 0.88, 3973.748571429236, 272.79771428586406, 1945.4708571425058 + 0.8, 5000.0, 0.92, 4102.116000001048, 288.0512000000331, 2008.2655999998708 + 0.8, 5000.0, 0.96, 4264.052000001828, 306.1504000000269, 2086.823199999904 + 0.8, 5000.0, 1.0, 4430.500000002824, 325.60000000001185, 2165.8000000000197 + 0.8, 10000.0, 0.52, 950.0999999999913, -42.700000000001296, 778.0999999999987 + 0.8, 10000.0, 0.56, 1423.0000000000284, 18.499999999992284, 959.9999999999756 + 0.8, 10000.0, 0.6, 1896.9000000000165, 77.69999999998123, 1145.8999999999755 + 0.8, 10000.0, 0.64, 2373.0999999998844, 136.4999999999861, 1335.500000000029 + 0.8, 10000.0, 0.68, 2846.9999999997767, 197.69999999996048, 1526.6999999997836 + 0.8, 10000.0, 0.72, 3323.8999999998096, 255.10000000004425, 1712.7999999996516 + 0.8, 10000.0, 0.76, 3797.599999999791, 317.2999999998736, 1915.6999999997065 + 0.8, 10000.0, 0.8, 4273.500000000116, 378.6000000000113, 2119.2999999999447 + 0.8, 10000.0, 0.84, 4543.937714286082, 415.1502857142977, 2237.248000000112 + 0.8, 10000.0, 0.88, 4693.414857143587, 436.79314285717567, 2304.2080000002484 + 0.8, 10000.0, 0.92, 4851.423199999644, 458.1639999999989, 2372.041599999971 + 0.8, 10000.0, 0.96, 5057.474399999483, 484.31199999999075, 2458.2151999999396 + 0.8, 10000.0, 1.0, 5261.09999999929, 510.6999999999796, 2545.7999999998933 + 0.8, 15000.0, 0.52, 1049.2999999999972, 2.7999999999962597, 852.9999999999918 + 0.8, 15000.0, 0.56, 1576.3000000000002, 69.10000000000036, 1055.000000000044 + 0.8, 15000.0, 0.6, 2102.0000000000673, 139.099999999996, 1261.2000000000985 + 0.8, 15000.0, 0.64, 2627.1999999998334, 202.69999999998748, 1462.9999999997149 + 0.8, 15000.0, 0.68, 3150.300000000119, 269.800000000029, 1671.3000000001969 + 0.8, 15000.0, 0.72, 3675.500000000545, 336.20000000005797, 1882.6999999997915 + 0.8, 15000.0, 0.76, 4200.999999999786, 409.80000000004867, 2099.00000000011 + 0.8, 15000.0, 0.8, 4726.200000000402, 478.1999999999177, 2326.8000000002585 + 0.8, 15000.0, 0.84, 5025.784571428686, 518.9240000000054, 2457.1765714287217 + 0.8, 15000.0, 0.88, 5191.030285714511, 542.8440000000081, 2529.502285714616 + 0.8, 15000.0, 0.92, 5360.634399999468, 566.0919999999987, 2602.752800000178 + 0.8, 15000.0, 0.96, 5578.45279999918, 594.2799999999941, 2696.6976000003006 + 0.8, 15000.0, 1.0, 5793.49999999883, 622.4999999999868, 2791.9000000004485 + 0.8, 20000.0, 0.52, 1151.1, 56.90000000000004, 936.8999999999988 + 0.8, 20000.0, 0.56, 1726.6999999999996, 131.19999999999857, 1154.9000000000037 + 0.8, 20000.0, 0.6, 2302.399999999991, 205.09999999999587, 1374.8000000000025 + 0.8, 20000.0, 0.64, 2877.9999999999704, 278.5000000000004, 1596.3000000000106 + 0.8, 20000.0, 0.68, 3453.5000000001037, 351.89999999998366, 1820.2000000000428 + 0.8, 20000.0, 0.72, 4029.1000000000327, 426.0000000000039, 2048.3999999999915 + 0.8, 20000.0, 0.76, 4604.699999999901, 505.19999999998845, 2289.699999999941 + 0.8, 20000.0, 0.8, 5180.199999999955, 584.1999999999842, 2533.599999999981 + 0.8, 20000.0, 0.84, 5510.153714285759, 629.4194285714284, 2673.9337142857607 + 0.8, 20000.0, 0.88, 5691.070857142921, 654.2937142857113, 2752.0508571429345 + 0.8, 20000.0, 0.92, 5867.386399999943, 678.6751999999939, 2829.2207999999837 + 0.8, 20000.0, 0.96, 6087.684799999924, 709.5823999999909, 2926.8735999999676 + 0.8, 20000.0, 1.0, 6304.699999999901, 741.1999999999881, 3026.599999999941 + 0.8, 25000.0, 0.52, 1274.5999999999985, 123.2000000000004, 1042.9000000000005 + 0.8, 25000.0, 0.56, 1911.900000000004, 205.4000000000019, 1280.4999999999918 + 0.8, 25000.0, 0.6, 2549.200000000011, 287.50000000000364, 1520.3999999999812 + 0.8, 25000.0, 0.64, 3186.4999999999013, 369.39999999999765, 1763.1000000000288 + 0.8, 25000.0, 0.68, 3823.7999999999156, 451.09999999998695, 2008.1999999999596 + 0.8, 25000.0, 0.72, 4461.10000000011, 533.499999999984, 2257.4999999999955 + 0.8, 25000.0, 0.76, 5098.399999999977, 621.5999999999931, 2521.299999999995 + 0.8, 25000.0, 0.8, 5735.699999999997, 709.800000000007, 2788.5999999999844 + 0.8, 25000.0, 0.84, 6102.97542857153, 760.6862857142926, 2943.3862857143095 + 0.8, 25000.0, 0.88, 6303.269714285897, 788.9091428571545, 3029.909142857169 + 0.8, 25000.0, 0.92, 6488.021599999819, 815.9351999999893, 3113.1296000000057 + 0.8, 25000.0, 0.96, 6711.87919999971, 849.5983999999813, 3216.5872000000036 + 0.8, 25000.0, 1.0, 6932.699999999577, 884.0999999999691, 3322.3999999999965 + 0.8, 30000.0, 0.52, 1393.0999999999995, 199.89999999999964, 1153.4 + 0.8, 30000.0, 0.56, 2089.6999999999935, 289.500000000003, 1408.8000000000045 + 0.8, 30000.0, 0.6, 2786.2999999999847, 378.80000000000797, 1666.4000000000203 + 0.8, 30000.0, 0.64, 3482.8999999998223, 467.9000000000236, 1926.6000000000683 + 0.8, 30000.0, 0.68, 4179.399999999887, 557.4999999999814, 2190.599999999913 + 0.8, 30000.0, 0.72, 4876.000000000127, 647.6, 2458.5000000000296 + 0.8, 30000.0, 0.76, 5572.600000000122, 744.3999999999743, 2742.9999999999636 + 0.8, 30000.0, 0.8, 6269.100000000107, 841.500000000005, 3031.3999999999432 + 0.8, 30000.0, 0.84, 6670.848571428687, 899.5817142857236, 3203.6674285715258 + 0.8, 30000.0, 0.88, 6889.794285714496, 933.6188571428669, 3304.501714285903 + 0.8, 30000.0, 0.92, 7090.157600000024, 965.3359999999917, 3398.9488000000015 + 0.8, 30000.0, 0.96, 7331.615200000043, 1002.9559999999844, 3511.3616000000075 + 0.8, 30000.0, 1.0, 7569.300000000063, 1041.1999999999748, 3625.400000000015 + 0.8, 35000.0, 0.52, 1528.2000000000012, 248.2000000000001, 1218.200000000001 + 0.8, 35000.0, 0.56, 2292.200000000004, 351.900000000004, 1503.1000000000101 + 0.8, 35000.0, 0.6, 3056.300000000028, 455.2000000000091, 1790.8000000000047 + 0.8, 35000.0, 0.64, 3820.0999999998994, 558.400000000001, 2081.7999999999674 + 0.8, 35000.0, 0.68, 4584.1999999998825, 661.6000000000024, 2376.7000000000335 + 0.8, 35000.0, 0.72, 5348.299999999879, 765.2000000000007, 2675.7999999999124 + 0.8, 35000.0, 0.76, 6112.400000000117, 875.899999999998, 2992.099999999943 + 0.8, 35000.0, 0.8, 6876.399999999898, 988.5000000000006, 3317.199999999918 + 0.8, 35000.0, 0.84, 7317.391999999944, 1056.118857142862, 3512.3440000000082 + 0.8, 35000.0, 0.88, 7557.551999999866, 1095.667428571431, 3626.7240000000224 + 0.8, 35000.0, 0.92, 7775.856000000067, 1131.5008000000068, 3731.5071999999577 + 0.8, 35000.0, 0.96, 8037.680000000124, 1173.0856000000133, 3853.91039999994 + 0.8, 35000.0, 1.0, 8294.80000000019, 1215.0000000000227, 3977.199999999917 diff --git a/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py b/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py index 5686a33a0..229a932d0 100644 --- a/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py +++ b/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py @@ -12,6 +12,10 @@ V3_bug_fixed_options = get_option_defaults() V3_bug_fixed_options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') +V3_bug_fixed_options.set_val( + Aircraft.CrewPayload.Design.NUM_PASSENGERS, val=180, units='unitless') +# we keep CrewPayload.NUM_PASSENGERS here because preprocess_crewpayload is often not run in these +# tests which prevents these values being assigned from Design.NUM_PASSENGERS as would normally happen V3_bug_fixed_options.set_val( Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') V3_bug_fixed_options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_FLOPS_data.py b/aviary/models/large_single_aisle_1/large_single_aisle_1_FLOPS_data.py index c5fd70877..5ec622a3f 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_FLOPS_data.py +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_FLOPS_data.py @@ -45,18 +45,23 @@ # Crew and Payload # --------------------------- +inputs.set_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, 0) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, 11) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, 169, units='unitless') +inputs.set_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, 158) inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0) -inputs.set_val(Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, 1.0) inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 11) +inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 169, units='unitless') +inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 158) + +inputs.set_val(Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, 1.0) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS, 3) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW, 2) inputs.set_val(Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER, 1.0) inputs.set_val(Aircraft.CrewPayload.NUM_GALLEY_CREW, 0) inputs.set_val(Aircraft.CrewPayload.MISC_CARGO, 0., 'lbm') inputs.set_val(Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 169, units='unitless') inputs.set_val(Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER, 1.) -inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 158) inputs.set_val(Aircraft.CrewPayload.MASS_PER_PASSENGER, 180., 'lbm') inputs.set_val(Aircraft.CrewPayload.WING_CARGO, 0., 'lbm') @@ -189,7 +194,7 @@ inputs.set_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY, 1.92669766647637) inputs.set_val(Aircraft.Wing.AREA, 1370.0, 'ft**2') inputs.set_val(Aircraft.Wing.ASPECT_RATIO, 11.22091) -inputs.set_val(Aircraft.Wing.BENDING_MASS_SCALER, 1.0) +inputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, 1.0) inputs.set_val(Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, np.array([0.31, 0.23, 0.084])) inputs.set_val(Aircraft.Wing.COMPOSITE_FRACTION, 0.2) inputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 137, 'ft**2') @@ -364,8 +369,8 @@ outputs.set_val(Aircraft.VerticalTail.FINENESS, 0.1195) outputs.set_val(Aircraft.VerticalTail.MASS, 1221.8, 'lbm') -outputs.set_val(Aircraft.Wing.BENDING_FACTOR, 11.5918) -outputs.set_val(Aircraft.Wing.BENDING_MASS, 8184.8, 'lbm') +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 11.5918) +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 8184.8, 'lbm') outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 10.49, 'ft') # Not in FLOPS output; calculated from inputs. outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 137, 'ft**2') diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv index bcdd6d0a0..09894b55c 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv @@ -9,7 +9,7 @@ aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,7.6,lbm -aircraft:crew_and_payload:num_passengers,180,unitless +aircraft:crew_and_payload:design:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_per_passenger,5,lbm aircraft:crew_and_payload:water_mass_per_occupant,3,lbm @@ -26,6 +26,7 @@ aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless aircraft:engine:additional_mass_fraction,0.14,unitless aircraft:engine:data_file,models/engines/turbofan_23k_1.deck,unitless +aircraft:engine:global_throttle, True, unitless aircraft:engine:mass_scaler,1,unitless aircraft:engine:mass_specific,0.21366,lbm/lbf aircraft:engine:num_engines,2,unitless @@ -33,6 +34,7 @@ aircraft:engine:pod_mass_scaler,1,unitless aircraft:engine:pylon_factor,1.25,unitless aircraft:engine:reference_diameter,5.8,ft aircraft:engine:reference_sls_thrust,28690,lbf +aircraft:engine:scale_factor,1.0,unitless aircraft:engine:scaled_sls_thrust,28690,lbf aircraft:engine:type,7,unitless aircraft:engine:wing_locations,0.35,unitless diff --git a/aviary/models/large_single_aisle_2/large_single_aisle_2_FLOPS_data.py b/aviary/models/large_single_aisle_2/large_single_aisle_2_FLOPS_data.py index c6c0f8e34..889dbc855 100644 --- a/aviary/models/large_single_aisle_2/large_single_aisle_2_FLOPS_data.py +++ b/aviary/models/large_single_aisle_2/large_single_aisle_2_FLOPS_data.py @@ -50,19 +50,23 @@ # Crew and Payload # --------------------------- -inputs.set_val(Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 35., 'lbm') +inputs.set_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, 0) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, 12) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, 162, units='unitless') +inputs.set_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, 150) inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0) +inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 12) +inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 162, units='unitless') +inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 150) + +inputs.set_val(Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 35., 'lbm') inputs.set_val(Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, 1.0) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS, 5) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW, 2) inputs.set_val(Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 12) inputs.set_val(Aircraft.CrewPayload.NUM_GALLEY_CREW, 1) -inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0) inputs.set_val(Aircraft.CrewPayload.MISC_CARGO, 4077., 'lbm') inputs.set_val(Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 150) -inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 162, units='unitless') inputs.set_val(Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER, 1.) inputs.set_val(Aircraft.CrewPayload.MASS_PER_PASSENGER, 165., 'lbm') inputs.set_val(Aircraft.CrewPayload.WING_CARGO, 0., 'lbm') @@ -213,7 +217,7 @@ inputs.set_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY, 1.87) inputs.set_val(Aircraft.Wing.AREA, 1341.0, 'ft**2') inputs.set_val(Aircraft.Wing.ASPECT_RATIO, 9.45) -inputs.set_val(Aircraft.Wing.BENDING_MASS_SCALER, 1.0) +inputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, 1.0) inputs.set_val(Aircraft.Wing.COMPOSITE_FRACTION, 0.0) inputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO, 0.333) inputs.set_val(Aircraft.Wing.GLOVE_AND_BAT, 0.0, 'ft**2') @@ -393,8 +397,8 @@ outputs.set_val(Aircraft.VerticalTail.FINENESS, 0.1375) outputs.set_val(Aircraft.VerticalTail.MASS, 1035.6, 'lbm') -outputs.set_val(Aircraft.Wing.BENDING_FACTOR, 8.8294) -outputs.set_val(Aircraft.Wing.BENDING_MASS, 6016.9, 'lbm') +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 8.8294) +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 6016.9, 'lbm') outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 11.91, 'ft') outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 0.333 * 1341.0, 'ft**2') outputs.set_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 0.940000) diff --git a/aviary/models/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS_data.py b/aviary/models/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS_data.py index c08f43020..322332a86 100644 --- a/aviary/models/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS_data.py +++ b/aviary/models/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS_data.py @@ -50,19 +50,23 @@ # Crew and Payload # --------------------------- -inputs.set_val(Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 35., 'lbm') +inputs.set_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, 0) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, 12) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, 162, units='unitless') +inputs.set_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, 150) inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0) +inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 12) +inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 162, units='unitless') +inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 150) + +inputs.set_val(Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 35., 'lbm') inputs.set_val(Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, 1.0) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS, 5) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW, 2) inputs.set_val(Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 12) inputs.set_val(Aircraft.CrewPayload.NUM_GALLEY_CREW, 1) -inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0) inputs.set_val(Aircraft.CrewPayload.MISC_CARGO, 4077., 'lbm') inputs.set_val(Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 150) -inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 162, units='unitless') inputs.set_val(Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER, 1.) inputs.set_val(Aircraft.CrewPayload.MASS_PER_PASSENGER, 165., 'lbm') inputs.set_val(Aircraft.CrewPayload.WING_CARGO, 0., 'lbm') @@ -200,7 +204,7 @@ inputs.set_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY, 1.87) inputs.set_val(Aircraft.Wing.AREA, 1341.0, 'ft**2') inputs.set_val(Aircraft.Wing.ASPECT_RATIO, 9.45) -inputs.set_val(Aircraft.Wing.BENDING_MASS_SCALER, 1.0) +inputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, 1.0) inputs.set_val(Aircraft.Wing.COMPOSITE_FRACTION, 0.0) inputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO, 0.333) inputs.set_val(Aircraft.Wing.GLOVE_AND_BAT, 0.0, 'ft**2') @@ -371,8 +375,8 @@ outputs.set_val(Aircraft.VerticalTail.FINENESS, 0.1375) outputs.set_val(Aircraft.VerticalTail.MASS, 1707., 'lbm') -outputs.set_val(Aircraft.Wing.BENDING_FACTOR, 8.8294) -outputs.set_val(Aircraft.Wing.BENDING_MASS, 6016.9, 'lbm') +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 8.8294) +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 6016.9, 'lbm') outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 11.91, 'ft') outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 0.333 * 1341.0, 'ft**2') outputs.set_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 0.940000) diff --git a/aviary/models/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS_data.py b/aviary/models/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS_data.py index 2aca006c4..7711d695f 100644 --- a/aviary/models/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS_data.py +++ b/aviary/models/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS_data.py @@ -46,19 +46,18 @@ # Crew and Payload # --------------------------- inputs.set_val(Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 35., 'lbm') -inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, 0) inputs.set_val(Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, 1.0) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS, 5) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW, 2) inputs.set_val(Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 12) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, 12) inputs.set_val(Aircraft.CrewPayload.NUM_GALLEY_CREW, 1) -inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0) inputs.set_val(Aircraft.CrewPayload.MISC_CARGO, 4077., 'lbm') inputs.set_val(Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 162, units='unitless') +inputs.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, 162, units='unitless') inputs.set_val(Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER, 1.) -inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 150) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, 150) inputs.set_val(Aircraft.CrewPayload.MASS_PER_PASSENGER, 165., 'lbm') inputs.set_val(Aircraft.CrewPayload.WING_CARGO, 0., 'lbm') @@ -205,7 +204,7 @@ inputs.set_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY, 1.87) inputs.set_val(Aircraft.Wing.AREA, 1341.0, 'ft**2') inputs.set_val(Aircraft.Wing.ASPECT_RATIO, 9.42519) -inputs.set_val(Aircraft.Wing.BENDING_MASS_SCALER, 1.0) +inputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, 1.0) inputs.set_val( Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, np.array([0.4441, 0.2313, 0.0729])) inputs.set_val(Aircraft.Wing.COMPOSITE_FRACTION, 0.0) @@ -395,8 +394,8 @@ outputs.set_val(Aircraft.VerticalTail.FINENESS, 0.1375) outputs.set_val(Aircraft.VerticalTail.MASS, 1035.6, 'lbm') -outputs.set_val(Aircraft.Wing.BENDING_FACTOR, 9.0236) -outputs.set_val(Aircraft.Wing.BENDING_MASS, 6276.3, 'lbm') +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 9.0236) +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 6276.3, 'lbm') outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 11.91, 'ft') outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 0.333 * 1341.0, 'ft**2') outputs.set_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 0.959104) diff --git a/aviary/models/large_turboprop_freighter/__init__.py b/aviary/models/large_turboprop_freighter/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/models/large_turboprop_freighter/large_turboprop_freighter.csv b/aviary/models/large_turboprop_freighter/large_turboprop_freighter.csv new file mode 100644 index 000000000..2fc5ebf5f --- /dev/null +++ b/aviary/models/large_turboprop_freighter/large_turboprop_freighter.csv @@ -0,0 +1,288 @@ +############ +# SETTINGS # +############ +settings:problem_type, fallout, unitless +settings:equations_of_motion, 2DOF +settings:mass_method, GASP + +############ +# AIRCRAFT # +############ +aircraft:design:subsonic_drag_coeff_factor, 1.447, unitless + +# Design +aircraft:design:cg_delta, 0.25, unitless +aircraft:design:cockpit_control_mass_coefficient, 20, unitless +aircraft:design:drag_increment, 0.0015, unitless +aircraft:design:emergency_equipment_mass, 25, lbm +aircraft:design:max_structural_speed, 320, mi/h +aircraft:design:part25_structural_category, 3, unitless +aircraft:design:reserve_fuel_additional, 0.667, lbm +aircraft:design:static_margin, 0.05, unitless +aircraft:design:structural_mass_increment, 0, lbm +aircraft:design:supercritical_drag_shift, 0, unitless + +# Misc Systems +aircraft:air_conditioning:mass_coefficient, 2.65, unitless +aircraft:anti_icing:mass, 644, lbm +aircraft:apu:mass, 756, lbm +aircraft:avionics:mass, 936, lbm +aircraft:controls:cockpit_control_mass_scaler, 1, unitless +aircraft:controls:control_mass_increment, 0, lbm +aircraft:controls:stability_augmentation_system_mass, 0, lbm +aircraft:controls:stability_augmentation_system_mass_scaler, 1, unitless +aircraft:hydraulics:flight_control_mass_coefficient, 0.102, unitless +aircraft:hydraulics:gear_mass_coefficient, 0.11, unitless +aircraft:instruments:mass_coefficient, 0.0416, unitless + +# Crew and Payload +aircraft:crew_and_payload:cargo_mass, 31273, lbm +aircraft:crew_and_payload:catering_items_mass_per_passenger, 0, lbm +aircraft:crew_and_payload:num_passengers, 60, unitless +aircraft:crew_and_payload:passenger_mass_with_bags, 190, lbm +aircraft:crew_and_payload:passenger_service_mass_per_passenger, 0, lbm +aircraft:crew_and_payload:water_mass_per_occupant, 0, lbm + +# Engine/Propulsion +# setting electrical mass may not do anything +aircraft:electrical:mass, 300, lbm +aircraft:engine:additional_mass_fraction, 0.34, unitless +aircraft:engine:data_file, models/engines/turboshaft_4465hp.deck +aircraft:engine:mass_scaler, 1, unitless +aircraft:engine:mass_specific, 0.37026, lbm/lbf +aircraft:engine:num_engines, 4, unitless +aircraft:engine:num_propeller_blades, 4, unitless +aircraft:engine:pod_mass_scaler, 1, unitless +aircraft:engine:propeller_activity_factor, 167, unitless +aircraft:engine:propeller_diameter, 13.5, ft +aircraft:engine:propeller_integrated_lift_coefficient, 0.5, unitless +aircraft:engine:propeller_tip_speed_max, 720, ft/s +aircraft:engine:pylon_factor, 0.7, unitless +aircraft:engine:reference_diameter, 5.8, ft +aircraft:engine:reference_sls_thrust, 5000, lbf +aircraft:engine:rpm_design, 13820, rpm +aircraft:engine:fixed_rpm, 13820, rpm +aircraft:engine:scaled_sls_thrust, 5000, lbf +aircraft:engine:type, 6, unitless +aircraft:engine:wing_locations, [0.385, 0.385], unitless +aircraft:engine:gearbox:gear_ratio, 13.550135501355014, unitless +aircraft:engine:gearbox:efficiency, 1.0, unitless +aircraft:engine:gearbox:shaft_power_design, 4465, hp +aircraft:engine:gearbox:specific_torque, 100.0, N*m/kg + +# Fuel +aircraft:fuel:density, 6.687, lbm/galUS +aircraft:fuel:fuel_margin, 15, unitless +aircraft:fuel:fuel_system_mass_coefficient, 0.065, unitless +aircraft:fuel:fuel_system_mass_scaler, 1, unitless +aircraft:fuel:unusable_fuel_mass_coefficient, 4.5, unitless +aircraft:fuel:wing_fuel_fraction, 0.324, unitless + +# Fuselage +aircraft:fuselage:aisle_width, 48.8, inch +aircraft:fuselage:delta_diameter, 5, ft +aircraft:fuselage:flat_plate_area_increment, 2, ft**2 +aircraft:fuselage:form_factor, 1.25, unitless +aircraft:fuselage:mass_coefficient, 145.87, unitless +aircraft:fuselage:nose_fineness, 1, unitless +aircraft:fuselage:num_aisles, 1, unitless +aircraft:fuselage:num_seats_abreast, 6, unitless +aircraft:fuselage:pilot_compartment_length, 10.6, ft +aircraft:fuselage:pressure_differential, 6.55, psi +aircraft:fuselage:seat_pitch, 41.24, inch +aircraft:fuselage:seat_width, 18, inch +aircraft:fuselage:tail_fineness, 2.9, unitless +aircraft:fuselage:wetted_area_factor, 1, unitless + +# H-Tail +aircraft:horizontal_tail:area, 0, ft**2 +aircraft:horizontal_tail:aspect_ratio, 6.03, unitless +aircraft:horizontal_tail:form_factor, 1.25, unitless +aircraft:horizontal_tail:mass_coefficient, 0.2285, unitless +aircraft:horizontal_tail:moment_ratio, 0.3061, unitless +aircraft:horizontal_tail:sweep, 0, deg +aircraft:horizontal_tail:taper_ratio, 0.374, unitless +aircraft:horizontal_tail:thickness_to_chord, 0.15, unitless +aircraft:horizontal_tail:vertical_tail_fraction, 0, unitless +aircraft:horizontal_tail:volume_coefficient, 0.8614, unitless + +# Landing Gear +aircraft:landing_gear:fixed_gear, False, unitless +aircraft:landing_gear:main_gear_location, 0, unitless +aircraft:landing_gear:main_gear_mass_coefficient, 0.916, unitless +aircraft:landing_gear:mass_coefficient, 0.0337, unitless +aircraft:landing_gear:tail_hook_mass_scaler, 1, unitless +aircraft:landing_gear:total_mass_scaler, 1, unitless + +# Nacelle +aircraft:nacelle:clearance_ratio, 0.2, unitless +aircraft:nacelle:core_diameter_ratio, 1.15, unitless +aircraft:nacelle:fineness, 0.38, unitless +aircraft:nacelle:form_factor, 1.5, unitless +aircraft:nacelle:mass_specific, 3, lbm/ft**2 + +# V-Tail +aircraft:vertical_tail:area, 0, ft**2 +aircraft:vertical_tail:aspect_ratio, 1.81, unitless +aircraft:vertical_tail:form_factor, 1.25, unitless +aircraft:vertical_tail:mass_coefficient, 0.2035, unitless +aircraft:vertical_tail:moment_ratio, 2.809, unitless +aircraft:vertical_tail:sweep, 0, deg +aircraft:vertical_tail:taper_ratio, 0.296, unitless +aircraft:vertical_tail:thickness_to_chord, 0.15, unitless +aircraft:vertical_tail:volume_coefficient, 0.05355, unitless + +# Wing +aircraft:wing:aspect_ratio, 10.078, unitless +aircraft:wing:center_distance, 0.45, unitless +aircraft:wing:choose_fold_location, True, unitless +aircraft:wing:flap_chord_ratio, 0.28, unitless +aircraft:wing:flap_deflection_landing, 15, deg +aircraft:wing:flap_deflection_takeoff, 10, deg +aircraft:wing:flap_drag_increment_optimum, 0.23, unitless +aircraft:wing:flap_lift_increment_optimum, 1.4, unitless +aircraft:wing:flap_span_ratio, 0.6, unitless +aircraft:wing:flap_type, double_slotted, unitless +aircraft:wing:fold_dimensional_location_specified, False, unitless +aircraft:wing:fold_mass_coefficient, 0, unitless +aircraft:wing:folded_span, 0, ft +aircraft:wing:form_factor, 1.25, unitless +aircraft:wing:fuselage_interference_factor, 1, unitless +aircraft:wing:has_fold, False, unitless +aircraft:wing:has_strut, False, unitless +aircraft:wing:height, 14.5, ft +aircraft:wing:high_lift_mass_coefficient, 1.2, unitless +aircraft:wing:incidence, 2, deg +aircraft:wing:loading, 88.846, lbf/ft**2 +aircraft:wing:mass_coefficient, 131.32, unitless +aircraft:wing:max_lift_ref, 1.5, unitless +aircraft:wing:max_slat_deflection_landing, 0, deg +aircraft:wing:max_slat_deflection_takeoff, 0, deg +aircraft:wing:max_thickness_location, 0.35, unitless +aircraft:wing:min_pressure_location, 0.3, unitless +aircraft:wing:mounting_type, 1, unitless +aircraft:wing:num_flap_segments, 2, unitless +aircraft:wing:optimum_flap_deflection, 55, deg +aircraft:wing:optimum_slat_deflection, 45, deg +aircraft:wing:slat_chord_ratio, 0, unitless +aircraft:wing:slat_lift_increment_optimum, 0.93, unitless +aircraft:wing:slat_span_ratio, 0.9, unitless +aircraft:wing:surface_ctrl_mass_coefficient, 0.588, unitless +aircraft:wing:sweep, 0, deg +aircraft:wing:taper_ratio, 0.52, unitless +aircraft:wing:thickness_to_chord_root, 0.18, unitless +aircraft:wing:thickness_to_chord_tip, 0.12, unitless +aircraft:wing:zero_lift_angle, -1, deg + +# Misc Mass (zeroed out) +aircraft:strut:area_ratio, 0, unitless +aircraft:strut:attachment_location, 0, ft +aircraft:strut:attachment_location_dimensionless, 0, unitless +aircraft:strut:dimensional_location_specified, False, unitless +aircraft:strut:fuselage_interference_factor, 0, unitless +aircraft:strut:mass_coefficient, 0, unitless +aircraft:furnishings:mass, 0, lbm + +########### +# MISSION # +########### +mission:summary:fuel_flow_scaler, 1, unitless + +# Design +mission:design:cruise_altitude, 21000, ft +mission:design:gross_mass, 155000, lbm +mission:design:mach, 0.475, unitless +mission:design:range, 2020, NM +mission:design:rate_of_climb_at_top_of_climb, 300, ft/min + +# Takeoff and Landing +mission:landing:airport_altitude, 0, ft +mission:landing:braking_delay, 2, s +mission:landing:glide_to_stall_ratio, 1.3, unitless +mission:landing:maximum_flare_load_factor, 1.15, unitless +mission:landing:maximum_sink_rate, 900, ft/min +mission:landing:obstacle_height, 50, ft +mission:landing:touchdown_sink_rate, 5, ft/s +mission:takeoff:decision_speed_increment, 5, kn +mission:takeoff:rotation_speed_increment, 5, kn +mission:taxi:duration, 0.15, h + +################### +# Initial Guesses # +################### +actual_takeoff_mass, 0 +climb_range, 0 +cruise_mass_final, 0 +flight_duration, 0 +fuel_burn_per_passenger_mile, 0.1 +reserves, 0 +rotation_mass, 0.99 +time_to_climb, 0 + +###################### +# Unconverted Values # +###################### +INGASP.ACDCDR, 1, 1, 1, 1, 1.15, 1.392, 1.7855, 3.5714, 5.36 +INGASP.ACLS, 0, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8 +INGASP.BENGOB, 0.05 +INGASP.CK10, 1 +INGASP.CK11, 1 +INGASP.CK18, 1 +INGASP.CK7, 1 +INGASP.CK8, 1 +INGASP.CK9, 1 +INGASP.CW, , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 +INGASP.DCDSE, 0 +INGASP.EMCRU, 0.475 +INGASP.HNCRU, 21000 +INGASP.HPORT, 0 +INGASP.HSCREQ, 10000 +INGASP.HTMAX, 400 +INGASP.ICLM, 1 +INGASP.ICRUS, 0 +INGASP.IFERRY, 0 +INGASP.IPART, 1 +INGASP.ISWING, 0 +INGASP.IWLD, 2 +INGASP.JENGSZ, 2 +INGASP.KNAC, 1 +INGASP.KWCD, 9 +INGASP.LCWING, 0 +INGASP.MX, 0 +INGASP.NFAIL, 0 +INGASP.RCCRU, 10 +INGASP.RELP, 0 +INGASP.RELR, 0.4 +INGASP.RF, 3, 100, 10000, 1500, 4, 5, 0, 1 +INGASP.ROSCAB, 500 +INGASP.RWCRTX, 0.985 +INGASP.SKPES, 0.335 +INGASP.TBO, 0 +INGASP.TDELLD, 0 +INGASP.TDELTO, 0 +INGASP.TDELTX, 0 +INGASP.TIDLE, 200 +INGASP.VCLMB, 180 +INGASP.VRAT, 1.15 +INGASP.WLPCT, 0.976 +INGASP.WPLX, 25000 +INGASP.XLFMAX, 1.2 +INGASP.XTORQ, 4500 +INPROP.ANCQHP, 0.03405 +INPROP.BLANG, 0 +INPROP.CTI, 0.2 +INPROP.DIST, 1000 +INPROP.GR, 13.550135501355014 +INPROP.HNOYS, 1000 +INPROP.IDATE, 1980 +INPROP.JSIZE, 1 +INPROP.KNOYS, -1 +INPROP.KODECR, 7 +INPROP.KODETH, 6 +INPROP.NTYP, 5 +INPROP.PCLER, 0.1724 +INPROP.PCNCCL, 1.0228 +INPROP.PCNCCR, 1.05357 +INPROP.PCNCTO, 1 +INPROP.WKPFAC, 1.1 +INPROP.WPROP1, 4500 diff --git a/aviary/models/large_turboprop_freighter/phase_info.py b/aviary/models/large_turboprop_freighter/phase_info.py new file mode 100644 index 000000000..3566a67c7 --- /dev/null +++ b/aviary/models/large_turboprop_freighter/phase_info.py @@ -0,0 +1,364 @@ +from aviary.variable_info.enums import SpeedType, ThrottleAllocation + +# Energy method +energy_phase_info = { + "pre_mission": {"include_takeoff": False, "optimize_mass": True}, + "climb": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "num_segments": 5, + "order": 3, + "solve_for_distance": False, + "initial_mach": (0.2, "unitless"), + "final_mach": (0.475, "unitless"), + "mach_bounds": ((0.08, 0.478), "unitless"), + "initial_altitude": (0.0, "ft"), + "final_altitude": (21_000.0, "ft"), + "altitude_bounds": ((0.0, 22_000.0), "ft"), + "throttle_enforcement": "path_constraint", + "fix_initial": True, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((0.0, 0.0), "min"), + "duration_bounds": ((24.0, 192.0), "min"), + "add_initial_mass_constraint": False, + }, + }, + "cruise": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "num_segments": 5, + "order": 3, + "solve_for_distance": False, + "initial_mach": (0.475, "unitless"), + "final_mach": (0.475, "unitless"), + "mach_bounds": ((0.47, 0.48), "unitless"), + "initial_altitude": (21_000.0, "ft"), + "final_altitude": (21_000.0, "ft"), + "altitude_bounds": ((20_000.0, 22_000.0), "ft"), + "throttle_enforcement": "boundary_constraint", + "fix_initial": False, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((64.0, 192.0), "min"), + "duration_bounds": ((56.5, 169.5), "min"), + }, + }, + "descent": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "num_segments": 5, + "order": 3, + "solve_for_distance": False, + "initial_mach": (0.475, "unitless"), + "final_mach": (0.1, "unitless"), + "mach_bounds": ((0.08, 0.48), "unitless"), + "initial_altitude": (21_000.0, "ft"), + "final_altitude": (500.0, "ft"), + "altitude_bounds": ((0.0, 22_000.0), "ft"), + "throttle_enforcement": "path_constraint", + "fix_initial": False, + "constrain_final": True, + "fix_duration": False, + "initial_bounds": ((100, 361.5), "min"), + "duration_bounds": ((29.0, 87.0), "min"), + }, + }, + "post_mission": { + "include_landing": False, + "constrain_range": True, + "target_range": (2_020.0, "nmi"), + }, +} + +# 2DOF +two_dof_phase_info = { + 'groundroll': { + 'user_options': { + 'num_segments': 1, + 'order': 3, + 'connect_initial_mass': False, + 'fix_initial': True, + 'fix_initial_mass': False, + 'duration_ref': (50.0, 's'), + 'duration_bounds': ((1.0, 100.0), 's'), + 'velocity_lower': (0, 'kn'), + 'velocity_upper': (1000, 'kn'), + 'velocity_ref': (150, 'kn'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'ft'), + 'distance_upper': (10.0e3, 'ft'), + 'distance_ref': (3000, 'ft'), + 'distance_defect_ref': (3000, 'ft'), + }, + 'initial_guesses': { + 'time': ([0.0, 40.0], 's'), + 'velocity': ([0.066, 143.1], 'kn'), + 'distance': ([0.0, 1000.0], 'ft'), + 'throttle': ([0.956, 0.956], 'unitless'), + }, + }, + 'rotation': { + 'user_options': { + 'num_segments': 1, + 'order': 3, + 'fix_initial': False, + 'duration_bounds': ((1, 100), 's'), + 'duration_ref': (50.0, 's'), + 'velocity_lower': (0, 'kn'), + 'velocity_upper': (1000, 'kn'), + 'velocity_ref': (100, 'kn'), + 'velocity_ref0': (0, 'kn'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'ft'), + 'distance_upper': (10_000, 'ft'), + 'distance_ref': (5000, 'ft'), + 'distance_defect_ref': (5000, 'ft'), + 'angle_lower': (0.0, 'rad'), + 'angle_upper': (5.0, 'rad'), + 'angle_ref': (5.0, 'rad'), + 'angle_defect_ref': (5.0, 'rad'), + 'normal_ref': (10000, 'lbf'), + }, + 'initial_guesses': { + 'time': ([40.0, 5.0], 's'), + 'alpha': ([0.0, 2.5], 'deg'), + 'velocity': ([143, 150.0], 'kn'), + 'distance': ([3680.37217765, 4000], 'ft'), + 'throttle': ([0.956, 0.956], 'unitless'), + }, + }, + 'ascent': { + 'user_options': { + 'num_segments': 4, + 'order': 3, + 'fix_initial': False, + 'velocity_lower': (0, 'kn'), + 'velocity_upper': (700, 'kn'), + 'velocity_ref': (200, 'kn'), + 'velocity_ref0': (0, 'kn'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'ft'), + 'distance_upper': (15_000, 'ft'), + 'distance_ref': (1e4, 'ft'), + 'distance_defect_ref': (1e4, 'ft'), + 'alt_lower': (0, 'ft'), + 'alt_upper': (700, 'ft'), + 'alt_ref': (1000, 'ft'), + 'alt_defect_ref': (1000, 'ft'), + 'final_altitude': (500, 'ft'), + 'alt_constraint_ref': (500, 'ft'), + 'angle_lower': (-10, 'rad'), + 'angle_upper': (20, 'rad'), + 'angle_ref': (57.2958, 'deg'), + 'angle_defect_ref': (57.2958, 'deg'), + 'pitch_constraint_lower': (0.0, 'deg'), + 'pitch_constraint_upper': (15.0, 'deg'), + 'pitch_constraint_ref': (1.0, 'deg'), + }, + 'initial_guesses': { + 'time': ([45.0, 25.0], 's'), + 'flight_path_angle': ([0.0, 8.0], 'deg'), + 'alpha': ([2.5, 1.5], 'deg'), + 'velocity': ([150.0, 185.0], 'kn'), + 'distance': ([4.0e3, 10.0e3], 'ft'), + 'altitude': ([0.0, 500.0], 'ft'), + 'tau_gear': (0.2, 'unitless'), + 'tau_flaps': (0.9, 'unitless'), + 'throttle': ([0.956, 0.956], 'unitless'), + }, + }, + 'accel': { + 'user_options': { + 'num_segments': 1, + 'order': 3, + 'fix_initial': False, + 'alt': (500, 'ft'), + 'EAS_constraint_eq': (250, 'kn'), + 'duration_bounds': ((1, 200), 's'), + 'duration_ref': (1000, 's'), + 'velocity_lower': (150, 'kn'), + 'velocity_upper': (270, 'kn'), + 'velocity_ref': (250, 'kn'), + 'velocity_ref0': (150, 'kn'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'NM'), + 'distance_upper': (150, 'NM'), + 'distance_ref': (5, 'NM'), + 'distance_defect_ref': (5, 'NM'), + }, + 'initial_guesses': { + 'time': ([70.0, 13.0], 's'), + 'velocity': ([185.0, 250.0], 'kn'), + 'distance': ([10.0e3, 20.0e3], 'ft'), + 'throttle': ([0.956, 0.956], 'unitless'), + }, + }, + 'climb1': { + 'user_options': { + 'num_segments': 1, + 'order': 3, + 'fix_initial': False, + 'EAS_target': (250, 'kn'), + 'mach_cruise': 0.475, + 'target_mach': False, + 'final_altitude': (10.0e3, 'ft'), + 'duration_bounds': ((30, 300), 's'), + 'duration_ref': (1000, 's'), + 'alt_lower': (400, 'ft'), + 'alt_upper': (11_000, 'ft'), + 'alt_ref': (10.0e3, 'ft'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'NM'), + 'distance_upper': (500, 'NM'), + 'distance_ref': (10, 'NM'), + 'distance_ref0': (0, 'NM'), + }, + 'initial_guesses': { + 'time': ([1.0, 2.0], 'min'), + 'distance': ([20.0e3, 100.0e3], 'ft'), + 'altitude': ([500.0, 10.0e3], 'ft'), + 'throttle': ([0.956, 0.956], 'unitless'), + }, + }, + 'climb2': { + 'user_options': { + 'num_segments': 3, + 'order': 3, + 'fix_initial': False, + 'EAS_target': (250, 'kn'), + 'mach_cruise': 0.475, + 'target_mach': True, + 'final_altitude': (21_000, 'ft'), + 'required_available_climb_rate': (0.1, 'ft/min'), + 'duration_bounds': ((200, 17_000), 's'), + 'duration_ref': (5000, 's'), + 'alt_lower': (9000, 'ft'), + 'alt_upper': (22_000, 'ft'), + 'alt_ref': (20_000, 'ft'), + 'alt_ref0': (0, 'ft'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (10, 'NM'), + 'distance_upper': (1000, 'NM'), + 'distance_ref': (500, 'NM'), + 'distance_ref0': (0, 'NM'), + 'distance_defect_ref': (500, 'NM'), + }, + 'initial_guesses': { + 'time': ([216.0, 1300.0], 's'), + 'distance': ([100.0e3, 200.0e3], 'ft'), + 'altitude': ([10_000, 21_000], 'ft'), + 'throttle': ([0.956, 0.956], 'unitless'), + }, + }, + 'cruise': { + 'user_options': { + 'alt_cruise': (21_000, 'ft'), + 'mach_cruise': 0.475, + }, + 'initial_guesses': { + # [Initial mass, delta mass] for special cruise phase. + 'mass': ([150_000.0, -35_000], 'lbm'), + 'initial_distance': (100.0e3, 'ft'), + 'initial_time': (1_000.0, 's'), + 'altitude': (21_000, 'ft'), + 'mach': (0.475, 'unitless'), + }, + }, + 'desc1': { + 'user_options': { + 'num_segments': 3, + 'order': 3, + 'fix_initial': False, + 'input_initial': False, + 'EAS_limit': (350, 'kn'), + 'mach_cruise': 0.475, + 'input_speed_type': SpeedType.MACH, + 'final_altitude': (10_000, 'ft'), + 'duration_bounds': ((300.0, 900.0), 's'), + 'duration_ref': (1000, 's'), + 'alt_lower': (1000, 'ft'), + 'alt_upper': (22_000, 'ft'), + 'alt_ref': (20_000, 'ft'), + 'alt_ref0': (0, 'ft'), + 'alt_constraint_ref': (10000, 'ft'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (140_000, 'lbm'), + 'mass_ref0': (0, 'lbm'), + 'mass_defect_ref': (140_000, 'lbm'), + 'distance_lower': (1_000.0, 'NM'), + 'distance_upper': (3_000.0, 'NM'), + 'distance_ref': (2_020, 'NM'), + 'distance_ref0': (0, 'NM'), + 'distance_defect_ref': (100, 'NM'), + }, + 'initial_guesses': { + 'mass': (136000.0, 'lbm'), + 'altitude': ([20_000, 10_000], 'ft'), + 'throttle': ([0.0, 0.0], 'unitless'), + 'distance': ([0.92 * 2_020, 0.96 * 2_020], 'NM'), + 'time': ([28000.0, 500.0], 's'), + }, + }, + 'desc2': { + 'user_options': { + 'num_segments': 1, + 'order': 7, + 'fix_initial': False, + 'input_initial': False, + 'EAS_limit': (250, 'kn'), + 'mach_cruise': 0.80, + 'input_speed_type': SpeedType.EAS, + 'final_altitude': (1000, 'ft'), + 'duration_bounds': ((100.0, 5000), 's'), + 'duration_ref': (500, 's'), + 'alt_lower': (500, 'ft'), + 'alt_upper': (11_000, 'ft'), + 'alt_ref': (10.0e3, 'ft'), + 'alt_ref0': (1000, 'ft'), + 'alt_constraint_ref': (1000, 'ft'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'NM'), + 'distance_upper': (5000, 'NM'), + 'distance_ref': (3500, 'NM'), + 'distance_defect_ref': (100, 'NM'), + }, + 'initial_guesses': { + 'mass': (136000.0, 'lbm'), + 'altitude': ([10.0e3, 1.0e3], 'ft'), + 'throttle': ([0.0, 0.0], 'unitless'), + 'distance': ([0.96 * 2_020, 2_020], 'NM'), + 'time': ([28500.0, 500.0], 's'), + }, + }, +} + +phase_info = two_dof_phase_info diff --git a/aviary/models/multi_engine_single_aisle/multi_engine_single_aisle_data.py b/aviary/models/multi_engine_single_aisle/multi_engine_single_aisle_data.py index 000d8098e..f5773cf40 100644 --- a/aviary/models/multi_engine_single_aisle/multi_engine_single_aisle_data.py +++ b/aviary/models/multi_engine_single_aisle/multi_engine_single_aisle_data.py @@ -45,20 +45,24 @@ # Crew and Payload # --------------------------- -inputs.set_val(Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 35., 'lbm') +inputs.set_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, 0) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, 12) +inputs.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, 162, units='unitless') +inputs.set_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, 150) inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0) +inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 12) +inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 162, units='unitless') +inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 150) + +inputs.set_val(Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 35., 'lbm') inputs.set_val(Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, 1.0) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS, 5) inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW, 2) inputs.set_val(Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 12) inputs.set_val(Aircraft.CrewPayload.NUM_GALLEY_CREW, 1) -inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 0) inputs.set_val(Aircraft.CrewPayload.MISC_CARGO, 4077., 'lbm') inputs.set_val(Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER, 1.0) -inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 162, units='unitless') inputs.set_val(Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER, 1.) -inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 150) inputs.set_val(Aircraft.CrewPayload.MASS_PER_PASSENGER, 165., 'lbm') inputs.set_val(Aircraft.CrewPayload.WING_CARGO, 0., 'lbm') @@ -152,7 +156,8 @@ engine_1_inputs.set_val(Aircraft.Engine.DATA_FILE, filename) engine_1_inputs.set_val(Aircraft.Engine.MASS, 7400, 'lbm') engine_1_inputs.set_val(Aircraft.Engine.REFERENCE_MASS, 7400, 'lbm') -engine_1_inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, 28928.1/2, 'lbf') +# engine_1_inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, 28928.1/2, 'lbf') +engine_1_inputs.set_val(Aircraft.Engine.SCALE_FACTOR, 0.3837186) # engine_1_inputs.set_val(Aircraft.Engine.REFERENCE_SLS_THRUST, 28928.1, 'lbf') engine_1_inputs.set_val(Aircraft.Engine.NUM_ENGINES, 2) engine_1_inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 0) @@ -184,7 +189,8 @@ engine_2_inputs.set_val(Aircraft.Engine.DATA_FILE, filename) engine_2_inputs.set_val(Aircraft.Engine.MASS, 6293.8, 'lbm') engine_2_inputs.set_val(Aircraft.Engine.REFERENCE_MASS, 6293.8, 'lbm') -engine_2_inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, 22200.5/2, 'lbf') +# engine_2_inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, 22200.5/2, 'lbf') +engine_2_inputs.set_val(Aircraft.Engine.SCALE_FACTOR, 0.65151911) # engine_2_inputs.set_val(Aircraft.Engine.REFERENCE_SLS_THRUST, 22200.5, 'lbf') engine_2_inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 0.0) engine_2_inputs.set_val(Aircraft.Engine.NUM_ENGINES, 2) @@ -226,7 +232,7 @@ inputs.set_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY, 1.87) inputs.set_val(Aircraft.Wing.AREA, 1341.0, 'ft**2') inputs.set_val(Aircraft.Wing.ASPECT_RATIO, 9.42519) -inputs.set_val(Aircraft.Wing.BENDING_MASS_SCALER, 1.0) +inputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, 1.0) inputs.set_val( Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, np.array([0.4441, 0.2313, 0.0729])) inputs.set_val(Aircraft.Wing.COMPOSITE_FRACTION, 0.0) @@ -404,8 +410,8 @@ outputs.set_val(Aircraft.VerticalTail.FINENESS, 0.1195) outputs.set_val(Aircraft.VerticalTail.MASS, 1221.8, 'lbm') -outputs.set_val(Aircraft.Wing.BENDING_FACTOR, 11.5918) -outputs.set_val(Aircraft.Wing.BENDING_MASS, 8184.8, 'lbm') +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 11.5918) +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 8184.8, 'lbm') outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 10.49, 'ft') # Not in FLOPS output; calculated from inputs. outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 137, 'ft**2') diff --git a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv index df8ea4f96..0d7afc190 100644 --- a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv +++ b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv @@ -9,7 +9,7 @@ aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,8598,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,6,lbm -aircraft:crew_and_payload:num_passengers,96,unitless +aircraft:crew_and_payload:design:num_passengers,96,unitless aircraft:crew_and_payload:passenger_mass_with_bags,210,lbm aircraft:crew_and_payload:passenger_service_mass_per_passenger,7.6,lbm aircraft:crew_and_payload:water_mass_per_occupant,3,lbm @@ -26,6 +26,7 @@ aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.025,unitless aircraft:engine:additional_mass_fraction,0.14,unitless aircraft:engine:data_file,models/engines/turbofan_23k_1.deck,unitless +aircraft:engine:global_throttle, True, unitless aircraft:engine:mass_scaler,1,unitless aircraft:engine:mass_specific,0.2153,lbm/lbf aircraft:engine:num_engines,2,unitless @@ -33,6 +34,7 @@ aircraft:engine:pod_mass_scaler,1,unitless aircraft:engine:pylon_factor,0.6,unitless aircraft:engine:reference_diameter,6.04,ft aircraft:engine:reference_sls_thrust,28690,lbf +aircraft:engine:scale_factor,0.8295573370512374,unitless aircraft:engine:scaled_sls_thrust,23800,lbf aircraft:engine:type,7,unitless aircraft:engine:wing_locations,0.272,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv index c2fa1d8a1..29b7a41ec 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv @@ -7,17 +7,17 @@ aircraft:canard:aspect_ratio,0.0,unitless aircraft:canard:thickness_to_chord,0.0,unitless aircraft:crew_and_payload:baggage_mass_per_passenger,45.0,lbm aircraft:crew_and_payload:cargo_container_mass_scaler,1.0,unitless +aircraft:crew_and_payload:design:num_business_class,0,unitless +aircraft:crew_and_payload:design:num_first_class,11,unitless +aircraft:crew_and_payload:design:num_passengers,169,unitless +aircraft:crew_and_payload:design:num_tourist_class,158,unitless aircraft:crew_and_payload:flight_crew_mass_scaler,1.0,unitless aircraft:crew_and_payload:mass_per_passenger,180.0,lbm aircraft:crew_and_payload:misc_cargo,0.0,lbm aircraft:crew_and_payload:non_flight_crew_mass_scaler,1.0,unitless -aircraft:crew_and_payload:num_business_class,0,unitless -aircraft:crew_and_payload:num_first_class,11,unitless aircraft:crew_and_payload:num_flight_attendants,3,unitless aircraft:crew_and_payload:num_flight_crew,2,unitless aircraft:crew_and_payload:num_galley_crew,0,unitless -aircraft:crew_and_payload:num_passengers,169,unitless -aircraft:crew_and_payload:num_tourist_class,158,unitless aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless aircraft:crew_and_payload:wing_cargo,0.0,lbm aircraft:design:base_area,0.0,ft**2 @@ -114,7 +114,7 @@ aircraft:wing:aeroelastic_tailoring_factor,0.0,unitless aircraft:wing:airfoil_technology,1.92669766647637,unitless aircraft:wing:area,1370.0,ft**2 aircraft:wing:aspect_ratio,11.22091,unitless -aircraft:wing:bending_mass_scaler,1.0,unitless +aircraft:wing:BENDING_MATERIAL_MASS_SCALER,1.0,unitless aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless aircraft:wing:composite_fraction,0.2,unitless aircraft:wing:control_surface_area,137,ft**2 diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv index 1f408f98b..4eee8d79b 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv @@ -7,17 +7,17 @@ aircraft:canard:aspect_ratio,0.0,unitless aircraft:canard:thickness_to_chord,0.0,unitless aircraft:crew_and_payload:baggage_mass_per_passenger,45.0,lbm aircraft:crew_and_payload:cargo_container_mass_scaler,1.0,unitless +aircraft:crew_and_payload:design:num_business_class,0,unitless +aircraft:crew_and_payload:design:num_first_class,11,unitless +aircraft:crew_and_payload:design:num_passengers,169,unitless +aircraft:crew_and_payload:design:num_tourist_class,158,unitless aircraft:crew_and_payload:flight_crew_mass_scaler,1.0,unitless aircraft:crew_and_payload:mass_per_passenger,180.0,lbm aircraft:crew_and_payload:misc_cargo,0.0,lbm aircraft:crew_and_payload:non_flight_crew_mass_scaler,1.0,unitless -aircraft:crew_and_payload:num_business_class,0,unitless -aircraft:crew_and_payload:num_first_class,11,unitless aircraft:crew_and_payload:num_flight_attendants,3,unitless aircraft:crew_and_payload:num_flight_crew,2,unitless aircraft:crew_and_payload:num_galley_crew,0,unitless -aircraft:crew_and_payload:num_passengers,169,unitless -aircraft:crew_and_payload:num_tourist_class,158,unitless aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless aircraft:crew_and_payload:wing_cargo,0.0,lbm aircraft:design:base_area,0.0,ft**2 @@ -114,7 +114,7 @@ aircraft:wing:aeroelastic_tailoring_factor,0.0,unitless aircraft:wing:airfoil_technology,1.92669766647637,unitless aircraft:wing:area,1370.0,ft**2 aircraft:wing:aspect_ratio,11.22091,unitless -aircraft:wing:bending_mass_scaler,1.0,unitless +aircraft:wing:BENDING_MATERIAL_MASS_SCALER,1.0,unitless aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless aircraft:wing:composite_fraction,0.2,unitless aircraft:wing:control_surface_area,137,ft**2 diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv index fdd379976..8d97f49aa 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv @@ -2,7 +2,6 @@ aircraft:controls:cockpit_control_mass_scaler,1,unitless aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless -aircraft:crew_and_payload:num_passengers,169,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless @@ -15,6 +14,7 @@ aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless aircraft:engine:constant_fuel_consumption,0.,lbm/h aircraft:engine:data_file,models/engines/turbofan_23k_1.deck,unitless +aircraft:engine:global_throttle, True, unitless aircraft:engine:enable_sizing,False,unitless aircraft:engine:mass_specific,0.21366,lbm/lbf aircraft:engine:fuel_flow_scaler_constant_term,0.,unitless @@ -163,26 +163,25 @@ aircraft:canard:area,0.0,ft**2 aircraft:canard:aspect_ratio,0.0,unitless aircraft:canard:thickness_to_chord,0.0,unitless aircraft:crew_and_payload:cargo_container_mass_scaler,1.0,unitless +aircraft:crew_and_payload:design:num_business_class,0,unitless +aircraft:crew_and_payload:design:num_first_class,11,unitless +aircraft:crew_and_payload:design:num_passengers,169,unitless +aircraft:crew_and_payload:design:num_tourist_class,158,unitless aircraft:crew_and_payload:flight_crew_mass_scaler,1.0,unitless aircraft:crew_and_payload:mass_per_passenger,180.0,lbm aircraft:crew_and_payload:misc_cargo,0.0,lbm aircraft:crew_and_payload:non_flight_crew_mass_scaler,1.0,unitless -aircraft:crew_and_payload:num_business_class,0,unitless -aircraft:crew_and_payload:num_first_class,11,unitless aircraft:crew_and_payload:num_flight_attendants,3,unitless aircraft:crew_and_payload:num_flight_crew,2,unitless aircraft:crew_and_payload:num_galley_crew,0,unitless -aircraft:crew_and_payload:num_tourist_class,158,unitless aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless aircraft:crew_and_payload:wing_cargo,0.0,lbm aircraft:design:base_area,0.0,ft**2 aircraft:design:empty_mass_margin_scaler,0.0,unitless -aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless aircraft:design:touchdown_mass,152800.0,lbm aircraft:design:subsonic_drag_coeff_factor,1.0,unitless aircraft:design:supersonic_drag_coeff_factor,1.0,unitless aircraft:design:use_alt_mass,False,unitless -aircraft:design:zero_lift_drag_coeff_factor,0.930890028006548,unitless aircraft:electrical:mass_scaler,1.25,unitless aircraft:fins:area,0.0,ft**2 aircraft:fins:mass_scaler,1.0,unitless @@ -220,7 +219,7 @@ aircraft:vertical_tail:mass_scaler,1.0,unitless aircraft:vertical_tail:num_tails,1,unitless aircraft:wing:aeroelastic_tailoring_factor,0.0,unitless aircraft:wing:airfoil_technology,1.92669766647637,unitless -aircraft:wing:bending_mass_scaler,1.0,unitless +aircraft:wing:BENDING_MATERIAL_MASS_SCALER,1.0,unitless aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless aircraft:wing:composite_fraction,0.2,unitless aircraft:wing:control_surface_area,137,ft**2 diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index d27a939e6..84956f3f6 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -16,17 +16,17 @@ aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:crew_and_payload:cargo_container_mass_scaler,1.0,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,7.6,lbm +aircraft:crew_and_payload:design:num_business_class,0,unitless +aircraft:crew_and_payload:design:num_first_class,11,unitless +aircraft:crew_and_payload:design:num_passengers,180,unitless +aircraft:crew_and_payload:design:num_tourist_class,169,unitless aircraft:crew_and_payload:flight_crew_mass_scaler,1.0,unitless aircraft:crew_and_payload:mass_per_passenger,180.0,lbm aircraft:crew_and_payload:misc_cargo,0.0,lbm aircraft:crew_and_payload:non_flight_crew_mass_scaler,1.0,unitless -aircraft:crew_and_payload:num_business_class,0,unitless -aircraft:crew_and_payload:num_first_class,11,unitless aircraft:crew_and_payload:num_flight_attendants,3,unitless aircraft:crew_and_payload:num_flight_crew,2,unitless aircraft:crew_and_payload:num_galley_crew,0,unitless -aircraft:crew_and_payload:num_passengers,180,unitless -aircraft:crew_and_payload:num_tourist_class,169,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_per_passenger,5,lbm aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless @@ -204,7 +204,7 @@ aircraft:wing:airfoil_technology,1.92669766647637,unitless aircraft:wing:area,1370.0,ft**2 aircraft:wing:aspect_ratio,10.13,unitless aircraft:wing:average_chord,12.615,ft -aircraft:wing:bending_mass_scaler,1.0,unitless +aircraft:wing:BENDING_MATERIAL_MASS_SCALER,1.0,unitless aircraft:wing:center_distance,0.463,unitless aircraft:wing:choose_fold_location,True,unitless aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv index cf6ab17bc..3a052eca2 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv @@ -8,7 +8,7 @@ aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,7.6,lbm -aircraft:crew_and_payload:num_passengers,180,unitless +aircraft:crew_and_payload:design:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_per_passenger,5,lbm aircraft:crew_and_payload:water_mass_per_occupant,3,lbm @@ -24,6 +24,7 @@ aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless aircraft:engine:additional_mass_fraction,0.135,unitless aircraft:engine:data_file,models/engines/turbofan_23k_1.deck,unitless +aircraft:engine:global_throttle, True, unitless aircraft:engine:mass_scaler,1,unitless aircraft:engine:mass_specific,0.21366,lbm/lbf aircraft:engine:mass_scaler,1,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm_lbm_s.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm_lbm_s.csv index b9f818cbd..59605ee88 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm_lbm_s.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm_lbm_s.csv @@ -8,7 +8,7 @@ aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,7.6,lbm -aircraft:crew_and_payload:num_passengers,180,unitless +aircraft:crew_and_payload:design:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_per_passenger,5,lbm aircraft:crew_and_payload:water_mass_per_occupant,3,lbm @@ -25,6 +25,7 @@ aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless aircraft:engine:additional_mass_fraction,0.135,unitless aircraft:engine:data_file,models/engines/turbofan_23k_1_lbm_s.deck,unitless +aircraft:engine:global_throttle, True, unitless aircraft:engine:mass_scaler,1,unitless aircraft:engine:mass_specific,0.21366,lbm/lbf aircraft:engine:mass_scaler,1,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_solved2dof.csv b/aviary/models/test_aircraft/aircraft_for_bench_solved2dof.csv index 1d2c97329..3aebc639f 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_solved2dof.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_solved2dof.csv @@ -7,17 +7,17 @@ aircraft:canard:aspect_ratio,0.0,unitless aircraft:canard:thickness_to_chord,0.0,unitless aircraft:crew_and_payload:baggage_mass_per_passenger,45.0,lbm aircraft:crew_and_payload:cargo_container_mass_scaler,1.0,unitless +aircraft:crew_and_payload:design:num_business_class,0,unitless +aircraft:crew_and_payload:design:num_first_class,11,unitless +aircraft:crew_and_payload:design:num_passengers,169,unitless +aircraft:crew_and_payload:design:num_tourist_class,158,unitless aircraft:crew_and_payload:flight_crew_mass_scaler,1.0,unitless aircraft:crew_and_payload:mass_per_passenger,180.0,lbm aircraft:crew_and_payload:misc_cargo,0.0,lbm aircraft:crew_and_payload:non_flight_crew_mass_scaler,1.0,unitless -aircraft:crew_and_payload:num_business_class,0,unitless -aircraft:crew_and_payload:num_first_class,11,unitless aircraft:crew_and_payload:num_flight_attendants,3,unitless aircraft:crew_and_payload:num_flight_crew,2,unitless aircraft:crew_and_payload:num_galley_crew,0,unitless -aircraft:crew_and_payload:num_passengers,169,unitless -aircraft:crew_and_payload:num_tourist_class,158,unitless aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless aircraft:crew_and_payload:wing_cargo,0.0,lbm aircraft:design:base_area,0.0,ft**2 @@ -114,7 +114,7 @@ aircraft:wing:aeroelastic_tailoring_factor,0.0,unitless aircraft:wing:airfoil_technology,1.92669766647637,unitless aircraft:wing:area,1370.0,ft**2 aircraft:wing:aspect_ratio,11.22091,unitless -aircraft:wing:bending_mass_scaler,1.0,unitless +aircraft:wing:BENDING_MATERIAL_MASS_SCALER,1.0,unitless aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless aircraft:wing:composite_fraction,0.2,unitless aircraft:wing:control_surface_area,137,ft**2 diff --git a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv index 7626f4481..7b23f37b1 100644 --- a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv +++ b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv @@ -9,7 +9,7 @@ aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,15970,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,10,lbm -aircraft:crew_and_payload:num_passengers,154,unitless +aircraft:crew_and_payload:design:num_passengers,154,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_per_passenger,5,lbm aircraft:crew_and_payload:water_mass_per_occupant,3,lbm @@ -26,6 +26,7 @@ aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless aircraft:engine:additional_mass_fraction,0.165,unitless aircraft:engine:data_file,models/engines/turbofan_23k_1.deck,unitless +aircraft:engine:global_throttle,True aircraft:engine:mass_scaler,1,unitless aircraft:engine:mass_specific,0.21366,lbm/lbf aircraft:engine:num_engines,2,unitless @@ -33,6 +34,7 @@ aircraft:engine:pod_mass_scaler,1,unitless aircraft:engine:pylon_factor,1.25,unitless aircraft:engine:reference_diameter,6.15,ft aircraft:engine:reference_sls_thrust,28690,lbf +aircraft:engine:scale_factor,0.7376089229696758,unitless aircraft:engine:scaled_sls_thrust,21162,lbf aircraft:engine:type,7,unitless aircraft:engine:wing_locations,0.2143,unitless diff --git a/aviary/subsystems/aerodynamics/aero_common.py b/aviary/subsystems/aerodynamics/aero_common.py index 964a0fa72..de4750977 100644 --- a/aviary/subsystems/aerodynamics/aero_common.py +++ b/aviary/subsystems/aerodynamics/aero_common.py @@ -20,16 +20,25 @@ def setup(self): nn = self.options['num_nodes'] self.add_input( - Dynamic.Mission.STATIC_PRESSURE, np.ones(nn), units='lbf/ft**2', - desc='Static pressure at each evaulation point.') + Dynamic.Atmosphere.STATIC_PRESSURE, + np.ones(nn), + units='lbf/ft**2', + desc='Static pressure at each evaulation point.', + ) self.add_input( - Dynamic.Mission.MACH, np.ones(nn), units='unitless', - desc='Mach at each evaulation point.') + Dynamic.Atmosphere.MACH, + np.ones(nn), + units='unitless', + desc='Mach at each evaulation point.', + ) self.add_output( - Dynamic.Mission.DYNAMIC_PRESSURE, val=np.ones(nn), units='lbf/ft**2', - desc='pressure caused by fluid motion') + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + val=np.ones(nn), + units='lbf/ft**2', + desc='pressure caused by fluid motion', + ) def setup_partials(self): nn = self.options['num_nodes'] @@ -37,22 +46,27 @@ def setup_partials(self): rows_cols = np.arange(nn) self.declare_partials( - Dynamic.Mission.DYNAMIC_PRESSURE, [ - Dynamic.Mission.STATIC_PRESSURE, Dynamic.Mission.MACH], - rows=rows_cols, cols=rows_cols) + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + [Dynamic.Atmosphere.STATIC_PRESSURE, Dynamic.Atmosphere.MACH], + rows=rows_cols, + cols=rows_cols, + ) def compute(self, inputs, outputs): gamma = self.options['gamma'] - P = inputs[Dynamic.Mission.STATIC_PRESSURE] - M = inputs[Dynamic.Mission.MACH] + P = inputs[Dynamic.Atmosphere.STATIC_PRESSURE] + M = inputs[Dynamic.Atmosphere.MACH] - outputs[Dynamic.Mission.DYNAMIC_PRESSURE] = 0.5 * gamma * P * M**2 + outputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] = 0.5 * gamma * P * M**2 def compute_partials(self, inputs, partials): gamma = self.options['gamma'] - P = inputs[Dynamic.Mission.STATIC_PRESSURE] - M = inputs[Dynamic.Mission.MACH] - - partials[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH] = gamma * P * M - partials[Dynamic.Mission.DYNAMIC_PRESSURE, - Dynamic.Mission.STATIC_PRESSURE] = 0.5 * gamma * M**2 + P = inputs[Dynamic.Atmosphere.STATIC_PRESSURE] + M = inputs[Dynamic.Atmosphere.MACH] + + partials[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.MACH] = ( + gamma * P * M + ) + partials[ + Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.STATIC_PRESSURE + ] = (0.5 * gamma * M**2) diff --git a/aviary/subsystems/aerodynamics/aerodynamics_builder.py b/aviary/subsystems/aerodynamics/aerodynamics_builder.py index 7de423498..d56a97715 100644 --- a/aviary/subsystems/aerodynamics/aerodynamics_builder.py +++ b/aviary/subsystems/aerodynamics/aerodynamics_builder.py @@ -104,10 +104,10 @@ def build_pre_mission(self, aviary_inputs): code_origin = self.code_origin if code_origin is GASP: - aero_group = PreMissionAero(aviary_options=aviary_inputs) + aero_group = PreMissionAero() elif code_origin is FLOPS: - aero_group = Design(aviary_options=aviary_inputs) + aero_group = Design() return aero_group @@ -118,12 +118,10 @@ def build_mission(self, num_nodes, aviary_inputs, **kwargs): method = None if self.code_origin is FLOPS: if method is None: - aero_group = ComputedAeroGroup(num_nodes=num_nodes, - aviary_options=aviary_inputs) + aero_group = ComputedAeroGroup(num_nodes=num_nodes) elif method == 'computed': aero_group = ComputedAeroGroup(num_nodes=num_nodes, - aviary_options=aviary_inputs, **kwargs) elif method == 'low_speed': @@ -162,7 +160,6 @@ def build_mission(self, num_nodes, aviary_inputs, **kwargs): **kwargs) else: aero_group = CruiseAero(num_nodes=num_nodes, - aviary_options=aviary_inputs, **kwargs) elif method == 'low_speed': @@ -180,7 +177,6 @@ def build_mission(self, num_nodes, aviary_inputs, **kwargs): else: aero_group = LowSpeedAero(num_nodes=num_nodes, - aviary_options=aviary_inputs, **kwargs) else: @@ -201,37 +197,46 @@ def mission_inputs(self, **kwargs): if self.code_origin is FLOPS: if method == 'computed': - promotes = [Dynamic.Mission.STATIC_PRESSURE, - Dynamic.Mission.MACH, - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.MASS, - 'aircraft:*', 'mission:*'] + promotes = [ + Dynamic.Atmosphere.STATIC_PRESSURE, + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Vehicle.MASS, + 'aircraft:*', + 'mission:*', + ] elif method == 'solved_alpha': - promotes = [Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, - Dynamic.Mission.MASS, - Dynamic.Mission.STATIC_PRESSURE, - 'aircraft:*'] + promotes = [ + Dynamic.Mission.ALTITUDE, + Dynamic.Atmosphere.MACH, + Dynamic.Vehicle.MASS, + Dynamic.Atmosphere.STATIC_PRESSURE, + 'aircraft:*', + ] elif method == 'low_speed': - promotes = ['angle_of_attack', - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.FLIGHT_PATH_ANGLE, - Mission.Takeoff.DRAG_COEFFICIENT_MIN, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.HEIGHT, - Aircraft.Wing.SPAN, - Dynamic.Mission.DYNAMIC_PRESSURE, - Aircraft.Wing.AREA] + promotes = [ + 'angle_of_attack', + Dynamic.Mission.ALTITUDE, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Mission.Takeoff.DRAG_COEFFICIENT_MIN, + Aircraft.Wing.ASPECT_RATIO, + Aircraft.Wing.HEIGHT, + Aircraft.Wing.SPAN, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + Aircraft.Wing.AREA, + ] elif method == 'tabular': - promotes = [Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, - Dynamic.Mission.MASS, - Dynamic.Mission.VELOCITY, - Dynamic.Mission.DENSITY, - 'aircraft:*'] + promotes = [ + Dynamic.Mission.ALTITUDE, + Dynamic.Atmosphere.MACH, + Dynamic.Vehicle.MASS, + Dynamic.Mission.VELOCITY, + Dynamic.Atmosphere.DENSITY, + 'aircraft:*', + ] else: raise ValueError('FLOPS-based aero method is not one of the following: ' @@ -262,24 +267,25 @@ def mission_outputs(self, **kwargs): promotes = ['*'] if self.code_origin is FLOPS: - promotes = [Dynamic.Mission.DRAG, Dynamic.Mission.LIFT] + promotes = [Dynamic.Vehicle.DRAG, Dynamic.Vehicle.LIFT] elif self.code_origin is GASP: if method == 'low_speed': - promotes = [Dynamic.Mission.DRAG, - Dynamic.Mission.LIFT, - 'CL', 'CD', 'flap_factor', 'gear_factor'] + promotes = [ + Dynamic.Vehicle.DRAG, + Dynamic.Vehicle.LIFT, + 'CL', + 'CD', + 'flap_factor', + 'gear_factor', + ] elif method == 'cruise': if 'output_alpha' in kwargs: if kwargs['output_alpha']: - promotes = [Dynamic.Mission.DRAG, - Dynamic.Mission.LIFT, - 'alpha'] + promotes = [Dynamic.Vehicle.DRAG, Dynamic.Vehicle.LIFT, 'alpha'] else: - promotes = [Dynamic.Mission.DRAG, - Dynamic.Mission.LIFT, - 'CL_max'] + promotes = [Dynamic.Vehicle.DRAG, Dynamic.Vehicle.LIFT, 'CL_max'] else: raise ValueError('GASP-based aero method is not one of the following: ' @@ -622,7 +628,7 @@ def report(self, prob, reports_folder, **kwargs): AERO_2DOF_INPUTS = [ Aircraft.Design.CG_DELTA, - Aircraft.Design.DRAG_COEFFICIENT_INCREMENT, # drag increment? + Aircraft.Design.DRAG_COEFFICIENT_INCREMENT, # drag increment? Aircraft.Design.STATIC_MARGIN, Aircraft.Fuselage.AVG_DIAMETER, Aircraft.Fuselage.FLAT_PLATE_AREA_INCREMENT, @@ -667,4 +673,8 @@ def report(self, prob, reports_folder, **kwargs): AERO_CLEAN_2DOF_INPUTS = [ Aircraft.Design.SUPERCRITICAL_DIVERGENCE_SHIFT, # super drag shift? Mission.Design.LIFT_COEFFICIENT_MAX_FLAPS_UP, + Aircraft.Design.LIFT_DEPENDENT_DRAG_COEFF_FACTOR, + Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR, + Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, + Aircraft.Design.ZERO_LIFT_DRAG_COEFF_FACTOR, ] diff --git a/aviary/subsystems/aerodynamics/flops_based/buffet_lift.py b/aviary/subsystems/aerodynamics/flops_based/buffet_lift.py index 1a415f735..f97334ab5 100644 --- a/aviary/subsystems/aerodynamics/flops_based/buffet_lift.py +++ b/aviary/subsystems/aerodynamics/flops_based/buffet_lift.py @@ -23,10 +23,8 @@ def setup(self): # Simulation inputs self.add_input( - Dynamic.Mission.MACH, - shape=(nn), - units='unitless', - desc="Mach number") + Dynamic.Atmosphere.MACH, shape=(nn), units='unitless', desc="Mach number" + ) # Aero design inputs add_aviary_input(self, Mission.Design.MACH, 0.0) @@ -45,10 +43,8 @@ def setup_partials(self): nn = self.options["num_nodes"] self.declare_partials( - 'DELCLB', - Dynamic.Mission.MACH, - rows=np.arange(nn), - cols=np.arange(nn)) + 'DELCLB', Dynamic.Atmosphere.MACH, rows=np.arange(nn), cols=np.arange(nn) + ) self.declare_partials('DELCLB', [Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, Aircraft.Wing.SWEEP, @@ -113,7 +109,7 @@ def compute_partials(self, inputs, partials): # wrt CAM dCLB_dCAM = FCLB * AR / 10.0 * cos_fact - partials["DELCLB", Dynamic.Mission.MACH] = dCLB_dMach + partials["DELCLB", Dynamic.Atmosphere.MACH] = dCLB_dMach partials["DELCLB", Mission.Design.MACH] = dCLB_ddesign_Mach partials['DELCLB', Aircraft.Wing.ASPECT_RATIO] = dCLB_dAR partials['DELCLB', Aircraft.Wing.THICKNESS_TO_CHORD] = dCLB_dTC diff --git a/aviary/subsystems/aerodynamics/flops_based/compressibility_drag.py b/aviary/subsystems/aerodynamics/flops_based/compressibility_drag.py index 9a320d2fe..f6bcfb66e 100644 --- a/aviary/subsystems/aerodynamics/flops_based/compressibility_drag.py +++ b/aviary/subsystems/aerodynamics/flops_based/compressibility_drag.py @@ -1,4 +1,3 @@ - import numpy as np import openmdao.api as om from openmdao.components.interp_util.interp import InterpND @@ -22,10 +21,8 @@ def setup(self): # Simulation inputs self.add_input( - Dynamic.Mission.MACH, - shape=(nn), - units='unitless', - desc="Mach number") + Dynamic.Atmosphere.MACH, shape=(nn), units='unitless', desc="Mach number" + ) # Aero design inputs add_aviary_input(self, Mission.Design.MACH, 0.0) @@ -50,8 +47,12 @@ def setup_partials(self): nn = self.options["num_nodes"] row_col = np.arange(nn) - self.declare_partials(of='compress_drag_coeff', wrt=[Dynamic.Mission.MACH], - rows=row_col, cols=row_col) + self.declare_partials( + of='compress_drag_coeff', + wrt=[Dynamic.Atmosphere.MACH], + rows=row_col, + cols=row_col, + ) wrt2 = [Aircraft.Wing.THICKNESS_TO_CHORD, Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.SWEEP, Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, @@ -67,7 +68,7 @@ def compute(self, inputs, outputs): Calculate compressibility drag. """ - del_mach = inputs[Dynamic.Mission.MACH] - inputs[Mission.Design.MACH] + del_mach = inputs[Dynamic.Atmosphere.MACH] - inputs[Mission.Design.MACH] idx_super = np.where(del_mach > 0.05) idx_sub = np.where(del_mach <= 0.05) @@ -84,7 +85,7 @@ def _compute_supersonic(self, inputs, outputs, idx): Calculate compressibility drag for supersonic speeds. """ - mach = inputs[Dynamic.Mission.MACH][idx] + mach = inputs[Dynamic.Atmosphere.MACH][idx] nn = len(mach) del_mach = mach - inputs[Mission.Design.MACH] AR = inputs[Aircraft.Wing.ASPECT_RATIO] @@ -166,7 +167,7 @@ def _compute_subsonic(self, inputs, outputs, idx): Calculate compressibility drag for subsonic speeds. """ - mach = inputs[Dynamic.Mission.MACH][idx] + mach = inputs[Dynamic.Atmosphere.MACH][idx] nn = len(mach) del_mach = mach - inputs[Mission.Design.MACH] TC = inputs[Aircraft.Wing.THICKNESS_TO_CHORD] @@ -224,7 +225,7 @@ def compute_partials(self, inputs, partials): :type partials: _type_ """ - del_mach = inputs[Dynamic.Mission.MACH] - inputs[Mission.Design.MACH] + del_mach = inputs[Dynamic.Atmosphere.MACH] - inputs[Mission.Design.MACH] idx_super = np.where(del_mach > 0.05) idx_sub = np.where(del_mach <= 0.05) @@ -235,7 +236,7 @@ def compute_partials(self, inputs, partials): def _compute_partials_supersonic(self, inputs, partials, idx): - mach = inputs[Dynamic.Mission.MACH][idx] + mach = inputs[Dynamic.Atmosphere.MACH][idx] nn = len(mach) AR = inputs[Aircraft.Wing.ASPECT_RATIO] TC = inputs[Aircraft.Wing.THICKNESS_TO_CHORD] @@ -353,7 +354,7 @@ def _compute_partials_supersonic(self, inputs, partials, idx): dCd_dwing_taper_ratio = dCd3_dCD3 * dCD3_dART * dART_dwing_taper_ratio dCd_dsweep25 = dCd3_dsweep25 - partials["compress_drag_coeff", Dynamic.Mission.MACH][idx] = dCd_dMach + partials["compress_drag_coeff", Dynamic.Atmosphere.MACH][idx] = dCd_dMach partials["compress_drag_coeff", Mission.Design.MACH][idx, 0] = dCd_ddesign_Mach partials["compress_drag_coeff", Aircraft.Wing.THICKNESS_TO_CHORD][idx, 0] = dCd_dTC partials["compress_drag_coeff", @@ -377,7 +378,7 @@ def _compute_partials_supersonic(self, inputs, partials, idx): def _compute_partials_subsonic(self, inputs, partials, idx): - mach = inputs[Dynamic.Mission.MACH][idx] + mach = inputs[Dynamic.Atmosphere.MACH][idx] nn = len(mach) TC = inputs[Aircraft.Wing.THICKNESS_TO_CHORD] max_camber_70 = inputs[Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN] @@ -417,7 +418,7 @@ def _compute_partials_subsonic(self, inputs, partials, idx): # wrt max_camber_70 dCd_dmax_camber_70 = CD1 * (1.0 / 10.0) * TC**(5.0 / 3.0) - partials["compress_drag_coeff", Dynamic.Mission.MACH][idx] = dCd_dMach + partials["compress_drag_coeff", Dynamic.Atmosphere.MACH][idx] = dCd_dMach partials["compress_drag_coeff", Mission.Design.MACH][idx, 0] = dCd_ddesign_Mach partials["compress_drag_coeff", Aircraft.Wing.THICKNESS_TO_CHORD][idx, 0] = dCd_dTC partials["compress_drag_coeff", diff --git a/aviary/subsystems/aerodynamics/flops_based/computed_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/computed_aero_group.py index 33f61c5d6..93f80e009 100644 --- a/aviary/subsystems/aerodynamics/flops_based/computed_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/computed_aero_group.py @@ -17,7 +17,6 @@ from aviary.subsystems.aerodynamics.flops_based.skin_friction import SkinFriction from aviary.subsystems.aerodynamics.flops_based.skin_friction_drag import \ SkinFrictionDrag -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Aircraft, Dynamic, Mission @@ -33,16 +32,12 @@ def initialize(self): self.options.declare( 'gamma', default=1.4, desc='Ratio of specific heats for air.') - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') def setup(self): num_nodes = self.options["num_nodes"] gamma = self.options['gamma'] - aviary_options: AviaryValues = self.options['aviary_options'] - comp = MuxComponent(aviary_options=aviary_options) + comp = MuxComponent() self.add_subsystem( 'Mux', comp, promotes_inputs=['aircraft:*'], @@ -51,47 +46,68 @@ def setup(self): 'laminar_fractions_upper', 'laminar_fractions_lower']) self.add_subsystem( - 'DynamicPressure', DynamicPressure(num_nodes=num_nodes, gamma=gamma), - promotes_inputs=[Dynamic.Mission.MACH, Dynamic.Mission.STATIC_PRESSURE], - promotes_outputs=[Dynamic.Mission.DYNAMIC_PRESSURE]) + 'DynamicPressure', + DynamicPressure(num_nodes=num_nodes, gamma=gamma), + promotes_inputs=[ + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.STATIC_PRESSURE, + ], + promotes_outputs=[Dynamic.Atmosphere.DYNAMIC_PRESSURE], + ) comp = LiftEqualsWeight(num_nodes=num_nodes) self.add_subsystem( - name=Dynamic.Mission.LIFT, subsys=comp, - promotes_inputs=[Aircraft.Wing.AREA, Dynamic.Mission.MASS, - Dynamic.Mission.DYNAMIC_PRESSURE], - promotes_outputs=['cl', Dynamic.Mission.LIFT]) + name=Dynamic.Vehicle.LIFT, + subsys=comp, + promotes_inputs=[ + Aircraft.Wing.AREA, + Dynamic.Vehicle.MASS, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + ], + promotes_outputs=['cl', Dynamic.Vehicle.LIFT], + ) comp = LiftDependentDrag(num_nodes=num_nodes, gamma=gamma) self.add_subsystem( - 'PressureDrag', comp, + 'PressureDrag', + comp, promotes_inputs=[ - Dynamic.Mission.MACH, Dynamic.Mission.LIFT, Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Atmosphere.MACH, + Dynamic.Vehicle.LIFT, + Dynamic.Atmosphere.STATIC_PRESSURE, Mission.Design.MACH, Mission.Design.LIFT_COEFFICIENT, Aircraft.Wing.AREA, Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD]) + Aircraft.Wing.THICKNESS_TO_CHORD, + ], + ) comp = InducedDrag( - num_nodes=num_nodes, gamma=gamma, aviary_options=aviary_options) + num_nodes=num_nodes, gamma=gamma) self.add_subsystem( - 'InducedDrag', comp, + 'InducedDrag', + comp, promotes_inputs=[ - Dynamic.Mission.MACH, Dynamic.Mission.LIFT, Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Atmosphere.MACH, + Dynamic.Vehicle.LIFT, + Dynamic.Atmosphere.STATIC_PRESSURE, Aircraft.Wing.AREA, Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.SPAN_EFFICIENCY_FACTOR, Aircraft.Wing.SWEEP, - Aircraft.Wing.TAPER_RATIO]) + Aircraft.Wing.TAPER_RATIO, + ], + ) comp = CompressibilityDrag(num_nodes=num_nodes) self.add_subsystem( - 'CompressibilityDrag', comp, + 'CompressibilityDrag', + comp, promotes_inputs=[ - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, Mission.Design.MACH, Aircraft.Design.BASE_AREA, Aircraft.Wing.AREA, @@ -102,17 +118,24 @@ def setup(self): Aircraft.Wing.THICKNESS_TO_CHORD, Aircraft.Fuselage.CROSS_SECTION, Aircraft.Fuselage.DIAMETER_TO_WING_SPAN, - Aircraft.Fuselage.LENGTH_TO_DIAMETER]) + Aircraft.Fuselage.LENGTH_TO_DIAMETER, + ], + ) - comp = SkinFriction(num_nodes=num_nodes, aviary_options=aviary_options) + comp = SkinFriction(num_nodes=num_nodes) self.add_subsystem( - 'SkinFrictionCoef', comp, + 'SkinFrictionCoef', + comp, promotes_inputs=[ - Dynamic.Mission.MACH, Dynamic.Mission.STATIC_PRESSURE, Dynamic.Mission.TEMPERATURE, - 'characteristic_lengths'], - promotes_outputs=['skin_friction_coeff', 'Re']) - - comp = SkinFrictionDrag(num_nodes=num_nodes, aviary_options=aviary_options) + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.STATIC_PRESSURE, + Dynamic.Atmosphere.TEMPERATURE, + 'characteristic_lengths', + ], + promotes_outputs=['skin_friction_coeff', 'Re'], + ) + + comp = SkinFrictionDrag(num_nodes=num_nodes) self.add_subsystem( 'SkinFrictionDrag', comp, promotes_inputs=[ @@ -122,25 +145,33 @@ def setup(self): comp = ComputedDrag(num_nodes=num_nodes) self.add_subsystem( - 'Drag', comp, + 'Drag', + comp, promotes_inputs=[ - Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH, Aircraft.Wing.AREA, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + Dynamic.Atmosphere.MACH, + Aircraft.Wing.AREA, Aircraft.Design.ZERO_LIFT_DRAG_COEFF_FACTOR, Aircraft.Design.LIFT_DEPENDENT_DRAG_COEFF_FACTOR, Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR, - Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR], - promotes_outputs=['CDI', 'CD0', 'CD', Dynamic.Mission.DRAG]) + Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, + ], + promotes_outputs=['CDI', 'CD0', 'CD', Dynamic.Vehicle.DRAG], + ) buf = BuffetLift(num_nodes=num_nodes) self.add_subsystem( - 'Buffet', buf, + 'Buffet', + buf, promotes_inputs=[ - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, Mission.Design.MACH, Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD]) + Aircraft.Wing.THICKNESS_TO_CHORD, + ], + ) self.connect('PressureDrag.CD', 'Drag.pressure_drag_coeff') self.connect('InducedDrag.induced_drag_coeff', 'Drag.induced_drag_coeff') @@ -174,15 +205,21 @@ def setup(self): desc='zero-lift drag coefficient') self.add_subsystem( - Dynamic.Mission.DRAG, TotalDrag(num_nodes=nn), + Dynamic.Vehicle.DRAG, + TotalDrag(num_nodes=nn), promotes_inputs=[ Aircraft.Design.ZERO_LIFT_DRAG_COEFF_FACTOR, Aircraft.Design.LIFT_DEPENDENT_DRAG_COEFF_FACTOR, Aircraft.Wing.AREA, Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR, Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, - 'CDI', 'CD0', Dynamic.Mission.MACH, Dynamic.Mission.DYNAMIC_PRESSURE], - promotes_outputs=['CD', Dynamic.Mission.DRAG]) + 'CDI', + 'CD0', + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + ], + promotes_outputs=['CD', Dynamic.Vehicle.DRAG], + ) self.set_input_defaults(Aircraft.Wing.AREA, 1., 'ft**2') diff --git a/aviary/subsystems/aerodynamics/flops_based/design.py b/aviary/subsystems/aerodynamics/flops_based/design.py index e95d5df21..37d0f14e9 100644 --- a/aviary/subsystems/aerodynamics/flops_based/design.py +++ b/aviary/subsystems/aerodynamics/flops_based/design.py @@ -6,8 +6,7 @@ import openmdao.api as om from openmdao.components.interp_util.interp import InterpND -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -26,9 +25,8 @@ def __init__(self, **kwargs): self.des_mach_coeff = [0.32, 57.2958, 0.144] def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Wing.AIRFOIL_TECHNOLOGY) + add_aviary_option(self, Mission.Constraints.MAX_MACH) def setup(self): # Aircraft design inputs @@ -45,9 +43,8 @@ def setup_partials(self): self.declare_partials(of='*', wrt='*') def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - AITEK = aviary_options.get_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY) - VMAX = aviary_options.get_val(Mission.Constraints.MAX_MACH) + AITEK = self.options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] + VMAX = self.options[Mission.Constraints.MAX_MACH] AR, CAM, SW25, TC = inputs.values() @@ -88,9 +85,8 @@ def compute(self, inputs, outputs): outputs[Mission.Design.MACH] = DESM2D + DMDSWP + DMDAR def compute_partials(self, inputs, partials): - aviary_options: AviaryValues = self.options['aviary_options'] - AITEK = aviary_options.get_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY) - VMAX = aviary_options.get_val(Mission.Constraints.MAX_MACH) + AITEK = self.options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] + VMAX = self.options[Mission.Constraints.MAX_MACH] AR, CAM, SW25, TC = inputs.values() diff --git a/aviary/subsystems/aerodynamics/flops_based/drag.py b/aviary/subsystems/aerodynamics/flops_based/drag.py index d2b5e1b67..7e188bafe 100644 --- a/aviary/subsystems/aerodynamics/flops_based/drag.py +++ b/aviary/subsystems/aerodynamics/flops_based/drag.py @@ -24,8 +24,11 @@ def setup(self): add_aviary_input(self, Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, val=1.) self.add_input( - Dynamic.Mission.MACH, val=np.ones(nn), units='unitless', - desc='ratio of local fluid speed to local speed of sound') + Dynamic.Atmosphere.MACH, + val=np.ones(nn), + units='unitless', + desc='ratio of local fluid speed to local speed of sound', + ) self.add_input( 'CD_prescaled', val=np.ones(nn), units='unitless', @@ -41,8 +44,7 @@ def setup_partials(self): Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR] ) - self.declare_partials('CD', - Dynamic.Mission.MACH, dependent=False) + self.declare_partials('CD', Dynamic.Atmosphere.MACH, dependent=False) nn = self.options['num_nodes'] rows_cols = np.arange(nn) @@ -54,7 +56,7 @@ def setup_partials(self): def compute(self, inputs, outputs): FCDSUB = inputs[Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR] FCDSUP = inputs[Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR] - M = inputs[Dynamic.Mission.MACH] + M = inputs[Dynamic.Atmosphere.MACH] CD_prescaled = inputs['CD_prescaled'] @@ -66,7 +68,7 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, partials): FCDSUB = inputs[Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR] FCDSUP = inputs[Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR] - M = inputs[Dynamic.Mission.MACH] + M = inputs[Dynamic.Atmosphere.MACH] CD_prescaled = inputs['CD_prescaled'] idx_sup = np.where(M >= 1.0) @@ -102,45 +104,48 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.AREA, val=1., units='m**2') self.add_input( - Dynamic.Mission.DYNAMIC_PRESSURE, val=np.ones(nn), units='N/m**2', - desc='pressure caused by fluid motion') + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + val=np.ones(nn), + units='N/m**2', + desc='pressure caused by fluid motion', + ) self.add_input( 'CD', val=np.ones(nn), units='unitless', desc='total drag coefficient') - self.add_output(Dynamic.Mission.DRAG, val=np.ones(nn), - units='N', desc='total drag') + self.add_output( + Dynamic.Vehicle.DRAG, val=np.ones(nn), units='N', desc='total drag' + ) def setup_partials(self): nn = self.options['num_nodes'] rows_cols = np.arange(nn) - self.declare_partials( - Dynamic.Mission.DRAG, - Aircraft.Wing.AREA - ) + self.declare_partials(Dynamic.Vehicle.DRAG, Aircraft.Wing.AREA) self.declare_partials( - Dynamic.Mission.DRAG, - [Dynamic.Mission.DYNAMIC_PRESSURE, 'CD'], - rows=rows_cols, cols=rows_cols) + Dynamic.Vehicle.DRAG, + [Dynamic.Atmosphere.DYNAMIC_PRESSURE, 'CD'], + rows=rows_cols, + cols=rows_cols, + ) def compute(self, inputs, outputs): S = inputs[Aircraft.Wing.AREA] - q = inputs[Dynamic.Mission.DYNAMIC_PRESSURE] + q = inputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] CD = inputs['CD'] - outputs[Dynamic.Mission.DRAG] = q * S * CD + outputs[Dynamic.Vehicle.DRAG] = q * S * CD def compute_partials(self, inputs, partials): S = inputs[Aircraft.Wing.AREA] - q = inputs[Dynamic.Mission.DYNAMIC_PRESSURE] + q = inputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] CD = inputs['CD'] - partials[Dynamic.Mission.DRAG, Aircraft.Wing.AREA] = q * CD - partials[Dynamic.Mission.DRAG, Dynamic.Mission.DYNAMIC_PRESSURE] = S * CD - partials[Dynamic.Mission.DRAG, 'CD'] = q * S + partials[Dynamic.Vehicle.DRAG, Aircraft.Wing.AREA] = q * CD + partials[Dynamic.Vehicle.DRAG, Dynamic.Atmosphere.DYNAMIC_PRESSURE] = S * CD + partials[Dynamic.Vehicle.DRAG, 'CD'] = q * S class TotalDrag(om.Group): diff --git a/aviary/subsystems/aerodynamics/flops_based/drag_polar.py b/aviary/subsystems/aerodynamics/flops_based/drag_polar.py index 1e673bb5c..6b968ca5e 100644 --- a/aviary/subsystems/aerodynamics/flops_based/drag_polar.py +++ b/aviary/subsystems/aerodynamics/flops_based/drag_polar.py @@ -6,7 +6,7 @@ import openmdao.api as om from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input +from aviary.variable_info.functions import add_aviary_input, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -20,13 +20,10 @@ class DragPolar(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - aviary_options = self.options['aviary_options'] - num_engine_type = len(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Canard.WETTED_AREA, 0.0) add_aviary_input(self, Aircraft.Fuselage.WETTED_AREA, 0.0) diff --git a/aviary/subsystems/aerodynamics/flops_based/ground_effect.py b/aviary/subsystems/aerodynamics/flops_based/ground_effect.py index 1b1ca9de6..3130ed5da 100644 --- a/aviary/subsystems/aerodynamics/flops_based/ground_effect.py +++ b/aviary/subsystems/aerodynamics/flops_based/ground_effect.py @@ -42,8 +42,9 @@ def setup(self): add_aviary_input(self, Dynamic.Mission.ALTITUDE, np.zeros(nn), units='m') - add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, - val=np.zeros(nn), units='rad') + add_aviary_input( + self, Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad' + ) self.add_input( 'minimum_drag_coefficient', 0.0, @@ -83,17 +84,21 @@ def setup_partials(self): ) self.declare_partials( - 'lift_coefficient', [Dynamic.Mission.ALTITUDE, 'base_lift_coefficient'], - rows=rows_cols, cols=rows_cols + 'lift_coefficient', + [Dynamic.Mission.ALTITUDE, 'base_lift_coefficient'], + rows=rows_cols, + cols=rows_cols, ) self.declare_partials( 'lift_coefficient', [ - 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE, 'minimum_drag_coefficient', + 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE, + 'minimum_drag_coefficient', 'base_drag_coefficient', ], - dependent=False + dependent=False, ) self.declare_partials( @@ -104,10 +109,14 @@ def setup_partials(self): self.declare_partials( 'drag_coefficient', [ - 'angle_of_attack', Dynamic.Mission.ALTITUDE, Dynamic.Mission.FLIGHT_PATH_ANGLE, - 'base_drag_coefficient', 'base_lift_coefficient' + 'angle_of_attack', + Dynamic.Mission.ALTITUDE, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + 'base_drag_coefficient', + 'base_lift_coefficient', ], - rows=rows_cols, cols=rows_cols + rows=rows_cols, + cols=rows_cols, ) self.declare_partials('drag_coefficient', 'minimum_drag_coefficient', @@ -224,7 +233,9 @@ def compute_partials(self, inputs, J, discrete_inputs=None): (d_hf_alt * lift_coeff_factor_denom) - (height_factor * d_lcfd_alt) ) / lift_coeff_factor_denom**2 - J['lift_coefficient', Dynamic.Mission.ALTITUDE] = base_lift_coefficient * d_lcf_alt + J['lift_coefficient', Dynamic.Mission.ALTITUDE] = ( + base_lift_coefficient * d_lcf_alt + ) J['lift_coefficient', 'base_lift_coefficient'] = lift_coeff_factor # endregion lift_coefficient wrt [altitude, base_lift_coefficient] diff --git a/aviary/subsystems/aerodynamics/flops_based/induced_drag.py b/aviary/subsystems/aerodynamics/flops_based/induced_drag.py index 8ac3f4726..33bc9f033 100644 --- a/aviary/subsystems/aerodynamics/flops_based/induced_drag.py +++ b/aviary/subsystems/aerodynamics/flops_based/induced_drag.py @@ -2,8 +2,7 @@ import openmdao.api as om import scipy.constants as _units -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input +from aviary.variable_info.functions import add_aviary_input, add_aviary_option from aviary.variable_info.variables import Aircraft, Dynamic @@ -19,21 +18,25 @@ def initialize(self): self.options.declare( 'gamma', default=1.4, desc='Ratio of specific heats for air.') - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + + add_aviary_option(self, Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION) def setup(self): nn = self.options["num_nodes"] # Simulation inputs self.add_input( - Dynamic.Mission.MACH, shape=(nn), units='unitless', desc="Mach number") + Dynamic.Atmosphere.MACH, shape=(nn), units='unitless', desc="Mach number" + ) self.add_input( - Dynamic.Mission.LIFT, shape=(nn), units="lbf", desc="Lift magnitude") + Dynamic.Vehicle.LIFT, shape=(nn), units="lbf", desc="Lift magnitude" + ) self.add_input( - Dynamic.Mission.STATIC_PRESSURE, np.ones(nn), units='lbf/ft**2', - desc='Static pressure at each evaulation point.') + Dynamic.Atmosphere.STATIC_PRESSURE, + np.ones(nn), + units='lbf/ft**2', + desc='Static pressure at each evaulation point.', + ) # Aero design inputs add_aviary_input(self, Aircraft.Wing.AREA, 0.0) @@ -53,8 +56,14 @@ def setup_partials(self): row_col = np.arange(nn) self.declare_partials( 'induced_drag_coeff', - [Dynamic.Mission.MACH, Dynamic.Mission.LIFT, Dynamic.Mission.STATIC_PRESSURE], - rows=row_col, cols=row_col) + [ + Dynamic.Atmosphere.MACH, + Dynamic.Vehicle.LIFT, + Dynamic.Atmosphere.STATIC_PRESSURE, + ], + rows=row_col, + cols=row_col, + ) wrt = [ Aircraft.Wing.AREA, @@ -68,13 +77,11 @@ def setup_partials(self): def compute(self, inputs, outputs): options = self.options gamma = options['gamma'] - aviary_options: AviaryValues = options['aviary_options'] mach, lift, P, Sref, AR, span_efficiency_factor, SW25, TR = inputs.values() CL = 2.0 * lift / (Sref * gamma * P * mach ** 2) - redux, _ = aviary_options.get_item( - Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, (False, None)) + redux = self.options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] if redux: # Adjustment for extreme taper ratios. @@ -113,10 +120,8 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, partials): options = self.options gamma = options['gamma'] - aviary_options: AviaryValues = options['aviary_options'] mach, lift, P, Sref, AR, span_efficiency_factor, SW25, TR = inputs.values() - redux, _ = aviary_options.get_item( - Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, (False, None)) + redux = self.options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] if redux: sqrt_AR = np.sqrt(AR) @@ -143,9 +148,11 @@ def compute_partials(self, inputs, partials): dCDi_dAR = -CL ** 2 / (np.pi * AR ** 2 * span_efficiency) dCDi_dspan = -CL ** 2 / (np.pi * AR * span_efficiency ** 2) - partials['induced_drag_coeff', Dynamic.Mission.MACH] = dCDi_dCL * dCL_dmach - partials['induced_drag_coeff', Dynamic.Mission.LIFT] = dCDi_dCL * dCL_dL - partials['induced_drag_coeff', Dynamic.Mission.STATIC_PRESSURE] = dCDi_dCL * dCL_dP + partials['induced_drag_coeff', Dynamic.Atmosphere.MACH] = dCDi_dCL * dCL_dmach + partials['induced_drag_coeff', Dynamic.Vehicle.LIFT] = dCDi_dCL * dCL_dL + partials['induced_drag_coeff', Dynamic.Atmosphere.STATIC_PRESSURE] = ( + dCDi_dCL * dCL_dP + ) partials['induced_drag_coeff', Aircraft.Wing.ASPECT_RATIO] = dCDi_dAR partials['induced_drag_coeff', Aircraft.Wing.SPAN_EFFICIENCY_FACTOR] = 0.0 partials['induced_drag_coeff', Aircraft.Wing.SWEEP] = 0.0 @@ -207,17 +214,19 @@ def compute_partials(self, inputs, partials): dCDi_dCAYT = CL ** 2 dCDi_dCL = 2.0 * CAYT * CL - partials['induced_drag_coeff', Dynamic.Mission.MACH] += \ + partials['induced_drag_coeff', Dynamic.Atmosphere.MACH] += ( dCDi_dCL * dCL_dmach + dCDi_dCAYT * dCAYT_dmach - partials['induced_drag_coeff', Dynamic.Mission.LIFT] += dCDi_dCL * dCL_dL + ) + partials['induced_drag_coeff', Dynamic.Vehicle.LIFT] += dCDi_dCL * dCL_dL partials['induced_drag_coeff', Aircraft.Wing.ASPECT_RATIO] += ( dCDi_dCAYT * dTH_dAR * (dCAYT_dCOSA * dCOSA_dTH + dCAYT_dCOSB * dCOSB_dTH)) partials['induced_drag_coeff', Aircraft.Wing.SWEEP] += ( dCDi_dCAYT * dtansw_dsw * (dCAYT_dCOSA * dCOSA_dtansw + dCAYT_dCOSB * dCOSB_dtansw)) - partials['induced_drag_coeff', - Dynamic.Mission.STATIC_PRESSURE] += dCDi_dCL * dCL_dP + partials['induced_drag_coeff', Dynamic.Atmosphere.STATIC_PRESSURE] += ( + dCDi_dCL * dCL_dP + ) partials['induced_drag_coeff', Aircraft.Wing.TAPER_RATIO] += ( dCDi_dCAYT * dTH_dTR * (dCAYT_dCOSA * dCOSA_dTH + dCAYT_dCOSB * dCOSB_dTH)) diff --git a/aviary/subsystems/aerodynamics/flops_based/lift.py b/aviary/subsystems/aerodynamics/flops_based/lift.py index 7f126d1d7..0e1e59985 100644 --- a/aviary/subsystems/aerodynamics/flops_based/lift.py +++ b/aviary/subsystems/aerodynamics/flops_based/lift.py @@ -22,40 +22,47 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.AREA, val=1., units='m**2') self.add_input( - Dynamic.Mission.DYNAMIC_PRESSURE, val=np.ones(nn), units='N/m**2', - desc='pressure caused by fluid motion') + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + val=np.ones(nn), + units='N/m**2', + desc='pressure caused by fluid motion', + ) self.add_input( name='cl', val=np.ones(nn), desc='current coefficient of lift', units='unitless') - self.add_output(name=Dynamic.Mission.LIFT, + self.add_output(name=Dynamic.Vehicle.LIFT, val=np.ones(nn), desc='Lift', units='N') def setup_partials(self): nn = self.options['num_nodes'] rows_cols = np.arange(nn) - self.declare_partials(Dynamic.Mission.LIFT, Aircraft.Wing.AREA) + self.declare_partials(Dynamic.Vehicle.LIFT, Aircraft.Wing.AREA) self.declare_partials( - Dynamic.Mission.LIFT, [Dynamic.Mission.DYNAMIC_PRESSURE, 'cl'], rows=rows_cols, cols=rows_cols) + Dynamic.Vehicle.LIFT, + [Dynamic.Atmosphere.DYNAMIC_PRESSURE, 'cl'], + rows=rows_cols, + cols=rows_cols, + ) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): S = inputs[Aircraft.Wing.AREA] - q = inputs[Dynamic.Mission.DYNAMIC_PRESSURE] + q = inputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] CL = inputs['cl'] - outputs[Dynamic.Mission.LIFT] = q * S * CL + outputs[Dynamic.Vehicle.LIFT] = q * S * CL def compute_partials(self, inputs, partials, discrete_inputs=None): S = inputs[Aircraft.Wing.AREA] - q = inputs[Dynamic.Mission.DYNAMIC_PRESSURE] + q = inputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] CL = inputs['cl'] - partials[Dynamic.Mission.LIFT, Aircraft.Wing.AREA] = q * CL - partials[Dynamic.Mission.LIFT, Dynamic.Mission.DYNAMIC_PRESSURE] = S * CL - partials[Dynamic.Mission.LIFT, 'cl'] = q * S + partials[Dynamic.Vehicle.LIFT, Aircraft.Wing.AREA] = q * CL + partials[Dynamic.Vehicle.LIFT, Dynamic.Atmosphere.DYNAMIC_PRESSURE] = S * CL + partials[Dynamic.Vehicle.LIFT, 'cl'] = q * S class LiftEqualsWeight(om.ExplicitComponent): @@ -74,18 +81,21 @@ def setup(self): add_aviary_input(self, varname=Aircraft.Wing.AREA, val=1.0, units='m**2') self.add_input( - name=Dynamic.Mission.MASS, val=np.ones(nn), desc='current aircraft mass', + name=Dynamic.Vehicle.MASS, val=np.ones(nn), desc='current aircraft mass', units='kg') self.add_input( - Dynamic.Mission.DYNAMIC_PRESSURE, val=np.ones(nn), units='N/m**2', - desc='pressure caused by fluid motion') + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + val=np.ones(nn), + units='N/m**2', + desc='pressure caused by fluid motion', + ) self.add_output( name='cl', val=np.ones(nn), desc='current coefficient of lift', units='unitless') - self.add_output(name=Dynamic.Mission.LIFT, + self.add_output(name=Dynamic.Vehicle.LIFT, val=np.ones(nn), desc='Lift', units='N') def setup_partials(self): @@ -93,29 +103,36 @@ def setup_partials(self): row_col = np.arange(nn) self.declare_partials( - Dynamic.Mission.LIFT, Dynamic.Mission.MASS, rows=row_col, cols=row_col, val=grav_metric) + Dynamic.Vehicle.LIFT, Dynamic.Vehicle.MASS, rows=row_col, cols=row_col, val=grav_metric) self.declare_partials( - Dynamic.Mission.LIFT, [Aircraft.Wing.AREA, Dynamic.Mission.DYNAMIC_PRESSURE], dependent=False) + Dynamic.Vehicle.LIFT, + [Aircraft.Wing.AREA, Dynamic.Atmosphere.DYNAMIC_PRESSURE], + dependent=False, + ) self.declare_partials('cl', Aircraft.Wing.AREA) self.declare_partials( - 'cl', [Dynamic.Mission.MASS, Dynamic.Mission.DYNAMIC_PRESSURE], rows=row_col, cols=row_col) + 'cl', + [Dynamic.Vehicle.MASS, Dynamic.Atmosphere.DYNAMIC_PRESSURE], + rows=row_col, + cols=row_col, + ) def compute(self, inputs, outputs): S = inputs[Aircraft.Wing.AREA] - q = inputs[Dynamic.Mission.DYNAMIC_PRESSURE] - weight = grav_metric * inputs[Dynamic.Mission.MASS] + q = inputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] + weight = grav_metric * inputs[Dynamic.Vehicle.MASS] outputs['cl'] = weight / (q * S) - outputs[Dynamic.Mission.LIFT] = weight + outputs[Dynamic.Vehicle.LIFT] = weight def compute_partials(self, inputs, partials, discrete_inputs=None): S = inputs[Aircraft.Wing.AREA] - q = inputs[Dynamic.Mission.DYNAMIC_PRESSURE] - weight = grav_metric * inputs[Dynamic.Mission.MASS] + q = inputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] + weight = grav_metric * inputs[Dynamic.Vehicle.MASS] f = weight / q # df = 0. @@ -123,10 +140,10 @@ def compute_partials(self, inputs, partials, discrete_inputs=None): # dg = 1. partials['cl', Aircraft.Wing.AREA] = -f / g**2 - partials['cl', Dynamic.Mission.MASS] = grav_metric / (q * S) + partials['cl', Dynamic.Vehicle.MASS] = grav_metric / (q * S) f = weight / S # df = 0. g = q # dg = 1. - partials['cl', Dynamic.Mission.DYNAMIC_PRESSURE] = -f / g**2 + partials['cl', Dynamic.Atmosphere.DYNAMIC_PRESSURE] = -f / g**2 diff --git a/aviary/subsystems/aerodynamics/flops_based/lift_dependent_drag.py b/aviary/subsystems/aerodynamics/flops_based/lift_dependent_drag.py index 9c8140008..96c592634 100644 --- a/aviary/subsystems/aerodynamics/flops_based/lift_dependent_drag.py +++ b/aviary/subsystems/aerodynamics/flops_based/lift_dependent_drag.py @@ -22,12 +22,18 @@ def setup(self): nn = self.options["num_nodes"] # Simulation inputs - self.add_input(Dynamic.Mission.MACH, shape=( - nn), units='unitless', desc="Mach number") - self.add_input(Dynamic.Mission.LIFT, shape=( - nn), units="lbf", desc="Lift magnitude") - self.add_input(Dynamic.Mission.STATIC_PRESSURE, np.ones(nn), units='lbf/ft**2', - desc='Static pressure at each evaulation point.') + self.add_input( + Dynamic.Atmosphere.MACH, shape=(nn), units='unitless', desc="Mach number" + ) + self.add_input( + Dynamic.Vehicle.LIFT, shape=(nn), units="lbf", desc="Lift magnitude" + ) + self.add_input( + Dynamic.Atmosphere.STATIC_PRESSURE, + np.ones(nn), + units='lbf/ft**2', + desc='Static pressure at each evaulation point.', + ) # Aero design inputs add_aviary_input(self, Mission.Design.LIFT_COEFFICIENT, 0.0) @@ -47,8 +53,16 @@ def setup(self): def setup_partials(self): nn = self.options["num_nodes"] - self.declare_partials('CD', [Dynamic.Mission.MACH, Dynamic.Mission.LIFT, Dynamic.Mission.STATIC_PRESSURE], - rows=np.arange(nn), cols=np.arange(nn)) + self.declare_partials( + 'CD', + [ + Dynamic.Atmosphere.MACH, + Dynamic.Vehicle.LIFT, + Dynamic.Atmosphere.STATIC_PRESSURE, + ], + rows=np.arange(nn), + cols=np.arange(nn), + ) wrt = [Mission.Design.LIFT_COEFFICIENT, Mission.Design.MACH, @@ -286,9 +300,9 @@ def compute_partials(self, inputs, partials): dFCDP_dSW25 = dFCDP_dA * dA_dSW25 dCD_dSW25 = dDCDP_dFCDP * dFCDP_dSW25 - partials["CD", Dynamic.Mission.MACH] = dCD_dmach + dCD_dCL * ddelCL_dmach - partials["CD", Dynamic.Mission.LIFT] = dCD_dCL * ddelCL_dL - partials["CD", Dynamic.Mission.STATIC_PRESSURE] = dCD_dCL * ddelCL_dP + partials["CD", Dynamic.Atmosphere.MACH] = dCD_dmach + dCD_dCL * ddelCL_dmach + partials["CD", Dynamic.Vehicle.LIFT] = dCD_dCL * ddelCL_dL + partials["CD", Dynamic.Atmosphere.STATIC_PRESSURE] = dCD_dCL * ddelCL_dP partials["CD", Aircraft.Wing.AREA] = dCD_dCL * ddelCL_dSref partials["CD", Aircraft.Wing.ASPECT_RATIO] = dCD_dAR partials["CD", Aircraft.Wing.THICKNESS_TO_CHORD] = dCD_dTC @@ -298,9 +312,9 @@ def compute_partials(self, inputs, partials): partials["CD", Mission.Design.MACH] = -dCD_dmach if self.clamp_indices: - partials["CD", Dynamic.Mission.MACH][self.clamp_indices] = 0.0 - partials["CD", Dynamic.Mission.LIFT][self.clamp_indices] = 0.0 - partials["CD", Dynamic.Mission.STATIC_PRESSURE][self.clamp_indices] = 0.0 + partials["CD", Dynamic.Atmosphere.MACH][self.clamp_indices] = 0.0 + partials["CD", Dynamic.Vehicle.LIFT][self.clamp_indices] = 0.0 + partials["CD", Dynamic.Atmosphere.STATIC_PRESSURE][self.clamp_indices] = 0.0 partials["CD", Aircraft.Wing.AREA][self.clamp_indices] = 0.0 partials["CD", Aircraft.Wing.ASPECT_RATIO][self.clamp_indices] = 0.0 partials["CD", Aircraft.Wing.THICKNESS_TO_CHORD][self.clamp_indices] = 0.0 diff --git a/aviary/subsystems/aerodynamics/flops_based/mux_component.py b/aviary/subsystems/aerodynamics/flops_based/mux_component.py index bd0ce2f44..a1560a477 100644 --- a/aviary/subsystems/aerodynamics/flops_based/mux_component.py +++ b/aviary/subsystems/aerodynamics/flops_based/mux_component.py @@ -1,8 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, get_units +from aviary.variable_info.functions import add_aviary_input, get_units, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -23,13 +22,12 @@ def __init__(self, **kwargs): super().__init__(**kwargs) def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Fuselage.NUM_FUSELAGES) + add_aviary_option(self, Aircraft.VerticalTail.NUM_TAILS) def setup(self): nc = 2 - aviary_options: AviaryValues = self.options['aviary_options'] # Wing (Always 1) add_aviary_input(self, Aircraft.Wing.WETTED_AREA, 1.0) @@ -45,9 +43,8 @@ def setup(self): add_aviary_input(self, Aircraft.HorizontalTail.LAMINAR_FLOW_UPPER, 0.0) add_aviary_input(self, Aircraft.HorizontalTail.LAMINAR_FLOW_LOWER, 0.0) - zero_count = (0, None) - # Vertical Tail - num, _ = aviary_options.get_item(Aircraft.VerticalTail.NUM_TAILS, zero_count) + num = self.options[Aircraft.VerticalTail.NUM_TAILS] + self.num_tails = num if num > 0: add_aviary_input(self, Aircraft.VerticalTail.WETTED_AREA, 1.0) @@ -58,7 +55,7 @@ def setup(self): nc += num # Fuselage - num, _ = aviary_options.get_item(Aircraft.Fuselage.NUM_FUSELAGES, zero_count) + num = self.options[Aircraft.Fuselage.NUM_FUSELAGES] self.num_fuselages = num if num > 0: add_aviary_input(self, Aircraft.Fuselage.WETTED_AREA, 1.0) @@ -68,19 +65,21 @@ def setup(self): add_aviary_input(self, Aircraft.Fuselage.LAMINAR_FLOW_LOWER, 0.0) nc += num - num_engines = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] + num_engine_models = len(num_engines) self.num_nacelles = int(sum(num_engines)) + if self.num_nacelles > 0: add_aviary_input(self, Aircraft.Nacelle.WETTED_AREA, - np.zeros(len(num_engines))) + np.zeros(num_engine_models)) add_aviary_input(self, Aircraft.Nacelle.FINENESS, - np.zeros(len(num_engines))) + np.zeros(num_engine_models)) add_aviary_input(self, Aircraft.Nacelle.CHARACTERISTIC_LENGTH, - np.zeros(len(num_engines))) + np.zeros(num_engine_models)) add_aviary_input(self, Aircraft.Nacelle.LAMINAR_FLOW_UPPER, - np.zeros(len(num_engines))) + np.zeros(num_engine_models)) add_aviary_input(self, Aircraft.Nacelle.LAMINAR_FLOW_LOWER, - np.zeros(len(num_engines))) + np.zeros(num_engine_models)) nc += self.num_nacelles self.add_output( @@ -185,8 +184,8 @@ def setup_partials(self): # Nacelle if self.num_nacelles > 0: # derivatives w.r.t vectorized engine inputs have known sparsity pattern - num_engines = self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] + rows = ic + np.arange(self.num_nacelles) cols = [item for sublist in [[i]*j for i, j in enumerate(num_engines)] for item in sublist] @@ -268,7 +267,7 @@ def compute(self, inputs, outputs): ic += self.num_fuselages # Nacelle - num_engines = self.options['aviary_options'].get_val(Aircraft.Engine.NUM_ENGINES) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] wetted_areas = inputs[Aircraft.Nacelle.WETTED_AREA] fineness = inputs[Aircraft.Nacelle.FINENESS] diff --git a/aviary/subsystems/aerodynamics/flops_based/skin_friction.py b/aviary/subsystems/aerodynamics/flops_based/skin_friction.py index 957ad53ac..1e98773ae 100644 --- a/aviary/subsystems/aerodynamics/flops_based/skin_friction.py +++ b/aviary/subsystems/aerodynamics/flops_based/skin_friction.py @@ -1,7 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft, Dynamic @@ -35,27 +35,24 @@ def initialize(self): self.options.declare( 'num_nodes', types=int, default=1, desc='The number of points at which the cross product is computed.') - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Fuselage.NUM_FUSELAGES) + add_aviary_option(self, Aircraft.VerticalTail.NUM_TAILS) def setup(self): nn = self.options['num_nodes'] - aviary_options: AviaryValues = self.options['aviary_options'] - zero_count = (0, None) - num_tails, _ = aviary_options.get_item( - Aircraft.VerticalTail.NUM_TAILS, zero_count) - num_fuselages, _ = aviary_options.get_item( - Aircraft.Fuselage.NUM_FUSELAGES, zero_count) - # TODO does not used vectorized heterogeneous engines. Temp using single engine - num_engines, _ = aviary_options.get_item( - Aircraft.Engine.NUM_ENGINES, zero_count) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] + num_fuselages = self.options[Aircraft.Fuselage.NUM_FUSELAGES] + num_tails = self.options[Aircraft.VerticalTail.NUM_TAILS] + self.nc = nc = 2 + num_tails + num_fuselages + int(sum(num_engines)) # Simulation inputs - self.add_input(Dynamic.Mission.TEMPERATURE, np.ones(nn), units='degR') - self.add_input(Dynamic.Mission.STATIC_PRESSURE, np.ones(nn), units='lbf/ft**2') - self.add_input(Dynamic.Mission.MACH, np.ones(nn), units='unitless') + self.add_input(Dynamic.Atmosphere.TEMPERATURE, np.ones(nn), units='degR') + self.add_input(Dynamic.Atmosphere.STATIC_PRESSURE, + np.ones(nn), units='lbf/ft**2') + self.add_input(Dynamic.Atmosphere.MACH, np.ones(nn), units='unitless') # Aero subsystem inputs self.add_input('characteristic_lengths', np.ones(nc), units='ft') @@ -86,15 +83,45 @@ def setup_partials(self): col = np.arange(nn) cols = np.repeat(col, nc) self.declare_partials( - 'cf_iter', [Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE, Dynamic.Mission.MACH], rows=row_col, cols=cols) + 'cf_iter', + [ + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, + Dynamic.Atmosphere.MACH, + ], + rows=row_col, + cols=cols, + ) self.declare_partials( - 'wall_temp', [Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE, Dynamic.Mission.MACH], rows=row_col, cols=cols) + 'wall_temp', + [ + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, + Dynamic.Atmosphere.MACH, + ], + rows=row_col, + cols=cols, + ) self.declare_partials( - 'Re', [Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE, Dynamic.Mission.MACH], rows=row_col, cols=cols) + 'Re', + [ + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, + Dynamic.Atmosphere.MACH, + ], + rows=row_col, + cols=cols, + ) self.declare_partials( - 'skin_friction_coeff', [Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.STATIC_PRESSURE, Dynamic.Mission.MACH], - rows=row_col, cols=cols) + 'skin_friction_coeff', + [ + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, + Dynamic.Atmosphere.MACH, + ], + rows=row_col, + cols=cols, + ) col = np.arange(nc) cols = np.tile(col, nn) @@ -189,9 +216,9 @@ def linearize(self, inputs, outputs, partials): dreyn_dmach = np.einsum('i,j->ij', RE, length) dreyn_dlen = np.tile(RE * mach, nc).reshape((nc, nn)).T - partials['Re', Dynamic.Mission.STATIC_PRESSURE] = -dreyn_dp.ravel() - partials['Re', Dynamic.Mission.TEMPERATURE] = -dreyn_dT.ravel() - partials['Re', Dynamic.Mission.MACH] = -dreyn_dmach.ravel() + partials['Re', Dynamic.Atmosphere.STATIC_PRESSURE] = -dreyn_dp.ravel() + partials['Re', Dynamic.Atmosphere.TEMPERATURE] = -dreyn_dT.ravel() + partials['Re', Dynamic.Atmosphere.MACH] = -dreyn_dmach.ravel() partials['Re', 'characteristic_lengths'] = -dreyn_dlen.ravel() suth_const = T + 198.72 @@ -228,14 +255,14 @@ def linearize(self, inputs, outputs, partials): -0.5 - 1.5 * self.TAW * np.einsum('i,ij->ij', combined_const, wall_temp ** 2) / (CFL * den ** 2)) - partials['wall_temp', Dynamic.Mission.STATIC_PRESSURE] = ( + partials['wall_temp', Dynamic.Atmosphere.STATIC_PRESSURE] = ( np.einsum('ij,i->ij', dreswt_dcomb, dcomb_dp)).ravel() - partials['wall_temp', Dynamic.Mission.TEMPERATURE] = ( + partials['wall_temp', Dynamic.Atmosphere.TEMPERATURE] = ( np.einsum('ij,i->ij', dreswt_dcomb, dcomb_dT) + dreswt_dCFL * dCFL_dT).ravel() - partials['wall_temp', Dynamic.Mission.MACH] = ( - np.einsum('ij,i->ij', dreswt_dcomb, dcomb_dmach) - + dreswt_dCFL * dCFL_dmach).ravel() + partials['wall_temp', Dynamic.Atmosphere.MACH] = ( + np.einsum('ij,i->ij', dreswt_dcomb, dcomb_dmach) + dreswt_dCFL * dCFL_dmach + ).ravel() partials['wall_temp', 'wall_temp'] = ( dreswt_dCFL * dCFL_dwt + dreswt_dwt).ravel() partials['wall_temp', 'cf_iter'] = (dreswt_dCFL * dCFL_dcf).ravel() @@ -260,20 +287,22 @@ def linearize(self, inputs, outputs, partials): drescf_dRP = -2.0 * fact / (RP * np.log(RP * cf) ** 3) drescf_dcf = -2.0 * fact / (cf * np.log(RP * cf) ** 3) - 1.0 - partials['cf_iter', Dynamic.Mission.STATIC_PRESSURE] = ( + partials['cf_iter', Dynamic.Atmosphere.STATIC_PRESSURE] = ( drescf_dRP * dRP_dp).ravel() - partials['cf_iter', Dynamic.Mission.TEMPERATURE] = (drescf_dRP * dRP_dT).ravel() - partials['cf_iter', Dynamic.Mission.MACH] = (drescf_dRP * dRP_dmach).ravel() + partials['cf_iter', Dynamic.Atmosphere.TEMPERATURE] = ( + drescf_dRP * dRP_dT).ravel() + partials['cf_iter', Dynamic.Atmosphere.MACH] = (drescf_dRP * dRP_dmach).ravel() partials['cf_iter', 'characteristic_lengths'] = (drescf_dRP * dRP_dlen).ravel() partials['cf_iter', 'wall_temp'] = (drescf_dRP * dRP_dwt).ravel() partials['cf_iter', 'cf_iter'] = drescf_dcf.ravel() dskf_dwtr = outputs['cf_iter'] / wall_temp_ratio ** 2 - partials['skin_friction_coeff', Dynamic.Mission.TEMPERATURE] = ( + partials['skin_friction_coeff', Dynamic.Atmosphere.TEMPERATURE] = ( dskf_dwtr * dwtr_dT).ravel() - partials['skin_friction_coeff', Dynamic.Mission.MACH] = np.einsum( - 'ij,i->ij', dskf_dwtr, dwtr_dmach).ravel() + partials['skin_friction_coeff', Dynamic.Atmosphere.MACH] = np.einsum( + 'ij,i->ij', dskf_dwtr, dwtr_dmach + ).ravel() partials['skin_friction_coeff', 'wall_temp'] = np.einsum( 'ij,i->ij', dskf_dwtr, dwtr_dwt).ravel() partials['skin_friction_coeff', 'cf_iter'] = (- 1.0 / wall_temp_ratio).ravel() diff --git a/aviary/subsystems/aerodynamics/flops_based/skin_friction_drag.py b/aviary/subsystems/aerodynamics/flops_based/skin_friction_drag.py index c7a9edd0f..3f377ba6b 100644 --- a/aviary/subsystems/aerodynamics/flops_based/skin_friction_drag.py +++ b/aviary/subsystems/aerodynamics/flops_based/skin_friction_drag.py @@ -1,8 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, get_units +from aviary.variable_info.functions import add_aviary_input, get_units, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -27,23 +26,24 @@ def initialize(self): self.options.declare( 'num_nodes', types=int, default=1, desc='The number of points at which the cross product is computed.') - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - # TODO: Convert these into aviary_options entries. + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Fuselage.NUM_FUSELAGES) + add_aviary_option(self, Aircraft.VerticalTail.NUM_TAILS) + add_aviary_option(self, Aircraft.Wing.AIRFOIL_TECHNOLOGY) + + # TODO: Bring this into the variable hierarchy. self.options.declare( 'excrescences_drag', default=0.06, desc='Drag contribution of excrescences as a percentage.') def setup(self): - aviary_options: AviaryValues = self.options['aviary_options'] nn = self.options['num_nodes'] - zero_count = (0, None) - nvtail, _ = aviary_options.get_item(Aircraft.VerticalTail.NUM_TAILS, zero_count) - nfuse, _ = aviary_options.get_item(Aircraft.Fuselage.NUM_FUSELAGES, zero_count) - num_engines, _ = aviary_options.get_item(Aircraft.Engine.NUM_ENGINES, zero_count) + nvtail = self.options[Aircraft.VerticalTail.NUM_TAILS] + nfuse = self.options[Aircraft.Fuselage.NUM_FUSELAGES] + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] + self.nc = nc = 2 + nvtail + nfuse + int(sum(num_engines)) # Computed by other components in drag group. @@ -96,7 +96,6 @@ def setup_partials(self): def compute(self, inputs, outputs): nc = self.nc - aviary_options: AviaryValues = self.options['aviary_options'] cf = inputs['skin_friction_coeff'] Re = inputs['Re'] @@ -136,7 +135,7 @@ def compute(self, inputs, outputs): # Form factor for surfaces. idx_surf = np.where(fineness <= 0.5)[0] fine = fineness[idx_surf] - airfoil = aviary_options.get_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY) + airfoil = self.options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] FF1 = 1.0 + fine * (F[7] + fine * (F[8] + fine * (F[9] + fine * (F[10] + fine * (F[11] + fine * F[12]))))) @@ -163,7 +162,6 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, partials): nc = self.nc nn = self.options["num_nodes"] - aviary_options: AviaryValues = self.options['aviary_options'] cf = inputs['skin_friction_coeff'] Re = inputs['Re'] @@ -209,7 +207,7 @@ def compute_partials(self, inputs, partials): idx_surf = np.where(fineness <= 0.5)[0] fine = fineness[idx_surf] - airfoil = aviary_options.get_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY) + airfoil = self.options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] FF1 = 1.0 + fine * ( F[7] + fine diff --git a/aviary/subsystems/aerodynamics/flops_based/solved_alpha_group.py b/aviary/subsystems/aerodynamics/flops_based/solved_alpha_group.py index ace5bb457..2e3e058d0 100644 --- a/aviary/subsystems/aerodynamics/flops_based/solved_alpha_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/solved_alpha_group.py @@ -40,8 +40,10 @@ def initialize(self): self.options.declare('structured', types=bool, default=True, desc='Flag that sets if data is a structured grid') - self.options.declare('extrapolate', default=True, desc='Flag that sets if drag ' - 'data can be extrapolated') + self.options.declare( + 'extrapolate', default=True, + desc='Flag that sets if drag ' + 'data can be extrapolated') def setup(self): options = self.options @@ -52,9 +54,14 @@ def setup(self): extrapolate = options['extrapolate'] self.add_subsystem( - 'DynamicPressure', DynamicPressure(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.MACH, Dynamic.Mission.STATIC_PRESSURE], - promotes_outputs=[Dynamic.Mission.DYNAMIC_PRESSURE]) + 'DynamicPressure', + DynamicPressure(num_nodes=nn), + promotes_inputs=[ + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.STATIC_PRESSURE, + ], + promotes_outputs=[Dynamic.Atmosphere.DYNAMIC_PRESSURE], + ) aero = TabularCruiseAero(num_nodes=nn, aero_data=aero_data, @@ -68,12 +75,19 @@ def setup(self): else: extra_promotes = [] - self.add_subsystem("tabular_aero", aero, - promotes_inputs=[Dynamic.Mission.ALTITUDE, Dynamic.Mission.MACH, - Aircraft.Wing.AREA, Dynamic.Mission.MACH, - Dynamic.Mission.DYNAMIC_PRESSURE] - + extra_promotes, - promotes_outputs=['CD', Dynamic.Mission.LIFT, Dynamic.Mission.DRAG]) + self.add_subsystem( + "tabular_aero", + aero, + promotes_inputs=[ + Dynamic.Mission.ALTITUDE, + Dynamic.Atmosphere.MACH, + Aircraft.Wing.AREA, + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + ] + + extra_promotes, + promotes_outputs=['CD', Dynamic.Vehicle.LIFT, Dynamic.Vehicle.DRAG], + ) balance = self.add_subsystem('balance', om.BalanceComp()) balance.add_balance('alpha', val=np.ones(nn), units='deg', res_ref=1.0e6) @@ -81,17 +95,21 @@ def setup(self): self.connect('balance.alpha', 'tabular_aero.alpha') self.connect('needed_lift.lift_resid', 'balance.lhs:alpha') - self.add_subsystem('needed_lift', - om.ExecComp('lift_resid = mass * grav_metric - computed_lift', - grav_metric={'val': grav_metric}, - mass={'units': 'kg', 'shape': nn}, - computed_lift={'units': 'N', 'shape': nn}, - lift_resid={'shape': nn}, - has_diag_partials=True, - ), - promotes_inputs=[('mass', Dynamic.Mission.MASS), - ('computed_lift', Dynamic.Mission.LIFT)] - ) + self.add_subsystem( + 'needed_lift', + om.ExecComp( + 'lift_resid = mass * grav_metric - computed_lift', + grav_metric={'val': grav_metric}, + mass={'units': 'kg', 'shape': nn}, + computed_lift={'units': 'N', 'shape': nn}, + lift_resid={'shape': nn}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('mass', Dynamic.Vehicle.MASS), + ('computed_lift', Dynamic.Vehicle.LIFT), + ], + ) self.linear_solver = om.DirectSolver() newton = self.nonlinear_solver = om.NewtonSolver(solve_subsystems=True) diff --git a/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py index 8d7bb012a..bb6dde476 100644 --- a/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py @@ -4,8 +4,7 @@ from pathlib import Path from aviary.subsystems.aerodynamics.flops_based.drag import TotalDrag as Drag -from aviary.subsystems.aerodynamics.flops_based.lift import \ - LiftEqualsWeight as CL +from aviary.subsystems.aerodynamics.flops_based.lift import LiftEqualsWeight as CL from aviary.utils.csv_data_file import read_data_file from aviary.utils.data_interpolator_builder import build_data_interpolator from aviary.utils.functions import get_path @@ -17,14 +16,21 @@ # spaces are replaced with underscores when data tables are read) # "Repeated" aliases allows variables with different cases to match with desired # all-lowercase name -aliases = {Dynamic.Mission.ALTITUDE: ['h', 'alt', 'altitude'], - Dynamic.Mission.MACH: ['m', 'mach'], - 'lift_coefficient': ['cl', 'coefficient_of_lift', 'lift_coefficient'], - 'lift_dependent_drag_coefficient': ['cdi', 'lift_dependent_drag_coefficient', - 'lift-dependent_drag_coefficient'], - 'zero_lift_drag_coefficient': ['cd0', 'zero_lift_drag_coefficient', - 'zero-lift_drag_coefficient'], - } +aliases = { + Dynamic.Mission.ALTITUDE: ['h', 'alt', 'altitude'], + Dynamic.Atmosphere.MACH: ['m', 'mach'], + 'lift_coefficient': ['cl', 'coefficient_of_lift', 'lift_coefficient'], + 'lift_dependent_drag_coefficient': [ + 'cdi', + 'lift_dependent_drag_coefficient', + 'lift-dependent_drag_coefficient', + ], + 'zero_lift_drag_coefficient': [ + 'cd0', + 'zero_lift_drag_coefficient', + 'zero-lift_drag_coefficient', + ], +} class TabularAeroGroup(om.Group): @@ -50,16 +56,26 @@ def initialize(self): options.declare('num_nodes', types=int) - options.declare('CD0_data', types=(str, Path, NamedValues), - desc='Data file or NamedValues object containing zero-lift drag ' - 'coefficient table.') + options.declare( + 'CD0_data', + types=(str, Path, NamedValues), + desc='Data file or NamedValues object containing zero-lift drag ' + 'coefficient table.', + ) - options.declare('CDI_data', types=(str, Path, NamedValues), - desc='Data file or NamedValues object containing lift-dependent ' - 'drag coefficient table.') + options.declare( + 'CDI_data', + types=(str, Path, NamedValues), + desc='Data file or NamedValues object containing lift-dependent ' + 'drag coefficient table.', + ) - options.declare('structured', types=bool, default=True, - desc='Flag that sets if data is a structured grid.') + options.declare( + 'structured', + types=bool, + default=True, + desc='Flag that sets if data is a structured grid.', + ) options.declare( 'connect_training_data', @@ -113,14 +129,20 @@ def setup(self): # add subsystems self.add_subsystem( - Dynamic.Mission.DYNAMIC_PRESSURE, _DynamicPressure(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.VELOCITY, Dynamic.Mission.DENSITY], - promotes_outputs=[Dynamic.Mission.DYNAMIC_PRESSURE]) + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + _DynamicPressure(num_nodes=nn), + promotes_inputs=[Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.DENSITY], + promotes_outputs=[Dynamic.Atmosphere.DYNAMIC_PRESSURE], + ) self.add_subsystem( - 'lift_coefficient', CL(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.MASS, - Aircraft.Wing.AREA, Dynamic.Mission.DYNAMIC_PRESSURE], + 'lift_coefficient', + CL(num_nodes=nn), + promotes_inputs=[ + Dynamic.Mission.MASS, + Aircraft.Wing.AREA, + Dynamic.Mission.DYNAMIC_PRESSURE, + ], promotes_outputs=[('cl', 'lift_coefficient'), Dynamic.Mission.LIFT]) if connect_training_data: @@ -129,9 +151,12 @@ def setup(self): else: extra_promotes = [] - self.add_subsystem('CD0_interp', CD0_interp, - promotes_inputs=['*'] + extra_promotes, - promotes_outputs=['*']) + self.add_subsystem( + 'CD0_interp', + CD0_interp, + promotes_inputs=['*'] + extra_promotes, + promotes_outputs=['*'], + ) if connect_training_data: extra_promotes = [('lift_dependent_drag_coefficient_train', @@ -139,12 +164,23 @@ def setup(self): else: extra_promotes = [] - self.add_subsystem('CDI_interp', CDI_interp, - promotes_inputs=['*'] + extra_promotes, - promotes_outputs=['*']) + self.add_subsystem( + 'CDI_interp', + CDI_interp, + promotes_inputs=['*'] + extra_promotes, + promotes_outputs=['*'], + ) self.add_subsystem( - Dynamic.Mission.DRAG, + 'CD0_interp', CD0_interp, promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'CDI_interp', CDI_interp, promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + Dynamic.Vehicle.DRAG, Drag(num_nodes=nn), promotes_inputs=[ Aircraft.Design.ZERO_LIFT_DRAG_COEFF_FACTOR, @@ -154,10 +190,10 @@ def setup(self): Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, ('CDI', 'lift_dependent_drag_coefficient'), ('CD0', 'zero_lift_drag_coefficient'), - Dynamic.Mission.MACH, - Dynamic.Mission.DYNAMIC_PRESSURE, + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, ], - promotes_outputs=['CD', Dynamic.Mission.DRAG], + promotes_outputs=['CD', Dynamic.Vehicle.DRAG], ) @@ -173,11 +209,14 @@ def setup(self): nn = self.options['num_nodes'] self.add_input(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') - self.add_input(Dynamic.Mission.DENSITY, val=np.ones(nn), units='kg/m**3') + self.add_input(Dynamic.Atmosphere.DENSITY, val=np.ones(nn), units='kg/m**3') self.add_output( - Dynamic.Mission.DYNAMIC_PRESSURE, val=np.ones(nn), units='N/m**2', - desc='pressure caused by fluid motion') + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + val=np.ones(nn), + units='N/m**2', + desc='pressure caused by fluid motion', + ) def setup_partials(self): nn = self.options['num_nodes'] @@ -185,20 +224,25 @@ def setup_partials(self): rows_cols = np.arange(nn) self.declare_partials( - Dynamic.Mission.DYNAMIC_PRESSURE, [ - Dynamic.Mission.VELOCITY, Dynamic.Mission.DENSITY], - rows=rows_cols, cols=rows_cols) + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + [Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.DENSITY], + rows=rows_cols, + cols=rows_cols, + ) def compute(self, inputs, outputs): TAS = inputs[Dynamic.Mission.VELOCITY] - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] - outputs[Dynamic.Mission.DYNAMIC_PRESSURE] = 0.5 * rho * TAS**2 + outputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] = 0.5 * rho * TAS**2 def compute_partials(self, inputs, partials): TAS = inputs[Dynamic.Mission.VELOCITY] - rho = inputs[Dynamic.Mission.DENSITY] + rho = inputs[Dynamic.Atmosphere.DENSITY] - partials[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.VELOCITY] = rho * TAS - partials[Dynamic.Mission.DYNAMIC_PRESSURE, - Dynamic.Mission.DENSITY] = 0.5 * TAS**2 + partials[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Mission.VELOCITY] = ( + rho * TAS + ) + partials[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.DENSITY] = ( + 0.5 * TAS**2 + ) diff --git a/aviary/subsystems/aerodynamics/flops_based/takeoff_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/takeoff_aero_group.py index 85e2186b0..9d1cde015 100644 --- a/aviary/subsystems/aerodynamics/flops_based/takeoff_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/takeoff_aero_group.py @@ -121,10 +121,13 @@ def setup(self): } inputs = [ - 'angle_of_attack', Dynamic.Mission.ALTITUDE, Dynamic.Mission.FLIGHT_PATH_ANGLE, + 'angle_of_attack', + Dynamic.Mission.ALTITUDE, + Dynamic.Mission.FLIGHT_PATH_ANGLE, ('minimum_drag_coefficient', Mission.Takeoff.DRAG_COEFFICIENT_MIN), - Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.HEIGHT, - Aircraft.Wing.SPAN + Aircraft.Wing.ASPECT_RATIO, + Aircraft.Wing.HEIGHT, + Aircraft.Wing.SPAN, ] self.add_subsystem( @@ -179,8 +182,8 @@ def setup(self): self.connect('ground_effect.drag_coefficient', 'ground_effect_drag') self.connect('climb_drag_coefficient', 'aero_forces.CD') - inputs = [Dynamic.Mission.DYNAMIC_PRESSURE, Aircraft.Wing.AREA] - outputs = [Dynamic.Mission.LIFT, Dynamic.Mission.DRAG] + inputs = [Dynamic.Atmosphere.DYNAMIC_PRESSURE, Aircraft.Wing.AREA] + outputs = [Dynamic.Vehicle.LIFT, Dynamic.Vehicle.DRAG] self.add_subsystem( 'aero_forces', AeroForces(num_nodes=nn), diff --git a/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv b/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv index ebde1eae7..d798dfe0b 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv +++ b/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv @@ -98,7 +98,7 @@ aircraft:wing:aeroelastic_tailoring_factor,0.01,unitless #check aircraft:wing:airfoil_technology,1.01,unitless #check aircraft:wing:area,1480,ft**2 aircraft:wing:aspect_ratio_reference,0.01,unitless #check -aircraft:wing:bending_mass_scaler,1.01,unitless #check +aircraft:wing:BENDING_MATERIAL_MASS_SCALER,1.01,unitless #check aircraft:wing:chord_per_semispan,0.13,0.115,0.06,unitless aircraft:wing:composite_fraction,0.01,unitless #check aircraft:wing:dihedral,-1.0,deg diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_computed_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_computed_aero_group.py index f6d4de0be..53561b65a 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_computed_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_computed_aero_group.py @@ -10,6 +10,7 @@ from aviary.utils.preprocessors import preprocess_options from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems from aviary.validation_cases.validation_tests import get_flops_inputs, get_flops_outputs +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Dynamic, Settings @@ -82,20 +83,24 @@ def test_basic_large_single_aisle_1(self): promotes=['*'] ) + # Set all options + setup_model_options(prob, flops_inputs) + prob.model.set_input_defaults(Aircraft.Engine.SCALE_FACTOR, np.ones(1)) + prob.setup(force_alloc_complex=True) prob.set_solver_print(level=2) # Mission params - prob.set_val(Dynamic.Mission.MACH, val=mach) - prob.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P, units='lbf/ft**2') - prob.set_val(Dynamic.Mission.TEMPERATURE, val=T, units='degR') - prob.set_val(Dynamic.Mission.MASS, val=mass, units='lbm') + prob.set_val(Dynamic.Atmosphere.MACH, val=mach) + prob.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, val=P, units='lbf/ft**2') + prob.set_val(Dynamic.Atmosphere.TEMPERATURE, val=T, units='degR') + prob.set_val(Dynamic.Vehicle.MASS, val=mass, units='lbm') set_aviary_initial_values(prob, flops_inputs) prob.run_model() - D = prob.get_val(Dynamic.Mission.DRAG, 'lbf') + D = prob.get_val(Dynamic.Vehicle.DRAG, 'lbf') CD = D / (Sref * 0.5 * 1.4 * P * mach ** 2) data = np.array([ @@ -194,19 +199,24 @@ def test_n3cc_drag(self): promotes=['*'] ) + # Set all options + setup_model_options(prob, flops_inputs) + + prob.model.set_input_defaults(Aircraft.Engine.SCALE_FACTOR, np.ones(1)) + prob.setup() # Mission params - prob.set_val(Dynamic.Mission.MACH, val=mach) - prob.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P, units='lbf/ft**2') - prob.set_val(Dynamic.Mission.TEMPERATURE, val=T, units='degR') - prob.set_val(Dynamic.Mission.MASS, val=mass, units='lbm') + prob.set_val(Dynamic.Atmosphere.MACH, val=mach) + prob.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, val=P, units='lbf/ft**2') + prob.set_val(Dynamic.Atmosphere.TEMPERATURE, val=T, units='degR') + prob.set_val(Dynamic.Vehicle.MASS, val=mass, units='lbm') set_aviary_initial_values(prob, flops_inputs) prob.run_model() - D = prob.get_val(Dynamic.Mission.DRAG, 'lbf') + D = prob.get_val(Dynamic.Vehicle.DRAG, 'lbf') CD = D / (Sref * 0.5 * 1.4 * P * mach ** 2) data = np.array([ @@ -305,19 +315,24 @@ def test_large_single_aisle_2_drag(self): promotes=['*'] ) + # Set all options + setup_model_options(prob, flops_inputs) + + prob.model.set_input_defaults(Aircraft.Engine.SCALE_FACTOR, np.ones(1)) + prob.setup() # Mission params - prob.set_val(Dynamic.Mission.MACH, val=mach) - prob.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P, units='lbf/ft**2') - prob.set_val(Dynamic.Mission.TEMPERATURE, val=T, units='degR') - prob.set_val(Dynamic.Mission.MASS, val=mass, units='lbm') + prob.set_val(Dynamic.Atmosphere.MACH, val=mach) + prob.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, val=P, units='lbf/ft**2') + prob.set_val(Dynamic.Atmosphere.TEMPERATURE, val=T, units='degR') + prob.set_val(Dynamic.Vehicle.MASS, val=mass, units='lbm') set_aviary_initial_values(prob, flops_inputs) prob.run_model() - D = prob.get_val(Dynamic.Mission.DRAG, 'lbf') + D = prob.get_val(Dynamic.Vehicle.DRAG, 'lbf') CD = D / (Sref * 0.5 * 1.4 * P * mach ** 2) data = np.array([ diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_design.py b/aviary/subsystems/aerodynamics/flops_based/test/test_design.py index 8b9bcb94c..99da39a97 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_design.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_design.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.aerodynamics.flops_based.design import Design -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Aircraft, Mission @@ -17,12 +16,12 @@ def test_derivs_supersonic1(self): model = prob.model options = {} - options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = (1.0, 'unitless') - options[Mission.Constraints.MAX_MACH] = (1.2, 'unitless') + options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = 1.0 + options[Mission.Constraints.MAX_MACH] = 1.2 model.add_subsystem( 'design', - Design(aviary_options=AviaryValues(options)), + Design(**options), promotes_inputs=['*'], promotes_outputs=[Mission.Design.MACH, Mission.Design.LIFT_COEFFICIENT] ) @@ -50,12 +49,12 @@ def test_derivs_subsonic1(self): model = prob.model options = {} - options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = (1.0, 'unitless') - options[Mission.Constraints.MAX_MACH] = (0.9, 'unitless') + options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = 1.0 + options[Mission.Constraints.MAX_MACH] = 0.9 model.add_subsystem( 'design', - Design(aviary_options=AviaryValues(options)), + Design(**options), promotes_inputs=['*'], promotes_outputs=[Mission.Design.MACH, Mission.Design.LIFT_COEFFICIENT], ) @@ -83,12 +82,12 @@ def test_derivs_supersonic2(self): model = prob.model options = {} - options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = (1.0, 'unitless') - options[Mission.Constraints.MAX_MACH] = (1.2, 'unitless') + options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = 1.0 + options[Mission.Constraints.MAX_MACH] = 1.2 model.add_subsystem( 'design', - Design(aviary_options=AviaryValues(options)), + Design(**options), promotes_inputs=['*'], promotes_outputs=[Mission.Design.MACH, Mission.Design.LIFT_COEFFICIENT], ) @@ -116,12 +115,12 @@ def test_derivs_subsonic2(self): model = prob.model options = {} - options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = (1.0, 'unitless') - options[Mission.Constraints.MAX_MACH] = (0.9, 'unitless') + options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = 1.0 + options[Mission.Constraints.MAX_MACH] = 0.9 model.add_subsystem( 'design', - Design(aviary_options=AviaryValues(options)), + Design(**options), promotes_inputs=['*'], promotes_outputs=[Mission.Design.MACH, Mission.Design.LIFT_COEFFICIENT], ) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_drag.py b/aviary/subsystems/aerodynamics/flops_based/test/test_drag.py index 476c5cac3..9fe79ab54 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_drag.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_drag.py @@ -44,14 +44,14 @@ def test_case(self, case_name): # dynamic pressure = 4 digits precision # drag coefficient = 5 digits precision mission_keys = ( - Dynamic.Mission.DYNAMIC_PRESSURE, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, 'CD_prescaled', 'CD', - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, ) # drag = 4 digits precision - outputs_keys = (Dynamic.Mission.DRAG,) + outputs_keys = (Dynamic.Vehicle.DRAG,) # using lowest precision from all available data should "always" work # - will a higher precision comparison work? find a practical tolerance that fits @@ -61,7 +61,7 @@ def test_case(self, case_name): prob = om.Problem() model = prob.model - q, _ = mission_data.get_item(Dynamic.Mission.DYNAMIC_PRESSURE) + q, _ = mission_data.get_item(Dynamic.Atmosphere.DYNAMIC_PRESSURE) nn = len(q) model.add_subsystem('simple_drag', SimpleDrag(num_nodes=nn), promotes=['*']) model.add_subsystem('simple_cd', SimpleCD(num_nodes=nn), promotes=['*']) @@ -95,7 +95,7 @@ def test_case(self, case_name): assert_near_equal(prob.get_val("CD"), mission_simple_CD[case_name], 1e-6) assert_near_equal( - prob.get_val(Dynamic.Mission.DRAG), mission_simple_drag[case_name], 1e-6 + prob.get_val(Dynamic.Vehicle.DRAG), mission_simple_drag[case_name], 1e-6 ) @@ -121,14 +121,14 @@ def test_case(self, case_name): # dynamic pressure = 4 digits precision # drag coefficient = 5 digits precision mission_keys = ( - Dynamic.Mission.DYNAMIC_PRESSURE, - Dynamic.Mission.MACH, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + Dynamic.Atmosphere.MACH, 'CD0', 'CDI', ) # drag = 4 digits precision - outputs_keys = ('CD_prescaled', 'CD', Dynamic.Mission.DRAG) + outputs_keys = ('CD_prescaled', 'CD', Dynamic.Vehicle.DRAG) # using lowest precision from all available data should "always" work # - will a higher precision comparison work? find a practical tolerance that fits @@ -138,7 +138,7 @@ def test_case(self, case_name): prob = om.Problem() model = prob.model - q, _ = mission_data.get_item(Dynamic.Mission.DYNAMIC_PRESSURE) + q, _ = mission_data.get_item(Dynamic.Atmosphere.DYNAMIC_PRESSURE) nn = len(q) model.add_subsystem('total_drag', TotalDrag(num_nodes=nn), promotes=['*']) @@ -171,7 +171,7 @@ def test_case(self, case_name): assert_near_equal(prob.get_val("CD"), mission_total_CD[case_name], 1e-6) assert_near_equal( - prob.get_val(Dynamic.Mission.DRAG), mission_total_drag[case_name], 1e-6 + prob.get_val(Dynamic.Vehicle.DRAG), mission_total_drag[case_name], 1e-6 ) @@ -193,7 +193,7 @@ def test_derivs(self): 'computed_drag', ComputedDrag(num_nodes=nn), promotes_inputs=['*'], - promotes_outputs=['CD', Dynamic.Mission.DRAG], + promotes_outputs=['CD', Dynamic.Vehicle.DRAG], ) prob.setup(force_alloc_complex=True) @@ -202,14 +202,14 @@ def test_derivs(self): prob.set_val('pressure_drag_coeff', 0.01 * cdp) prob.set_val('compress_drag_coeff', 0.01 * cdc) prob.set_val('induced_drag_coeff', 0.01 * cdi) - prob.set_val(Dynamic.Mission.MACH, M) + prob.set_val(Dynamic.Atmosphere.MACH, M) prob.set_val(Aircraft.Design.ZERO_LIFT_DRAG_COEFF_FACTOR, 0.7) prob.set_val(Aircraft.Design.LIFT_DEPENDENT_DRAG_COEFF_FACTOR, 0.3) prob.set_val(Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR, 1.4) prob.set_val(Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, 1.1) prob.set_val(Aircraft.Wing.AREA, 1370, units="ft**2") - prob.set_val(Dynamic.Mission.DYNAMIC_PRESSURE, [206.0, 205.6], 'lbf/ft**2') + prob.set_val(Dynamic.Atmosphere.DYNAMIC_PRESSURE, [206.0, 205.6], 'lbf/ft**2') prob.run_model() @@ -217,7 +217,7 @@ def test_derivs(self): assert_check_partials(derivs, atol=1e-12, rtol=1e-12) assert_near_equal(prob.get_val("CD"), [0.0249732, 0.0297451], 1e-6) - assert_near_equal(prob.get_val(Dynamic.Mission.DRAG), [31350.8, 37268.8], 1e-6) + assert_near_equal(prob.get_val(Dynamic.Vehicle.DRAG), [31350.8, 37268.8], 1e-6) # region - mission test data taken from the baseline FLOPS output for each case @@ -267,19 +267,19 @@ def _add_drag_coefficients( key = 'LargeSingleAisle1FLOPS' mission_test_data[key] = _mission_data = AviaryValues() _mission_data.set_val( - Dynamic.Mission.DYNAMIC_PRESSURE, np.array([206.0, 205.6, 205.4]), 'lbf/ft**2' + Dynamic.Atmosphere.DYNAMIC_PRESSURE, np.array([206.0, 205.6, 205.4]), 'lbf/ft**2' ) _mission_data.set_val( - Dynamic.Mission.MASS, np.array([176751.0, 176400.0, 176185.0]), 'lbm' + Dynamic.Vehicle.MASS, np.array([176751.0, 176400.0, 176185.0]), 'lbm' ) -_mission_data.set_val(Dynamic.Mission.DRAG, np.array([9350.0, 9333.0, 9323.0]), 'lbf') +_mission_data.set_val(Dynamic.Vehicle.DRAG, np.array([9350.0, 9333.0, 9323.0]), 'lbf') M = np.array([0.7750, 0.7750, 0.7750]) CD_scaled = np.array([0.03313, 0.03313, 0.03313]) CD0_scaled = np.array([0.02012, 0.02013, 0.02013]) CDI_scaled = np.array([0.01301, 0.01301, 0.01300]) -_mission_data.set_val(Dynamic.Mission.MACH, M) +_mission_data.set_val(Dynamic.Atmosphere.MACH, M) _add_drag_coefficients(key, _mission_data, M, CD_scaled, CD0_scaled, CDI_scaled) mission_simple_CD[key] = np.array([0.03313, 0.03313, 0.03313]) @@ -290,17 +290,17 @@ def _add_drag_coefficients( key = 'LargeSingleAisle2FLOPS' mission_test_data[key] = _mission_data = AviaryValues() _mission_data.set_val( - Dynamic.Mission.DYNAMIC_PRESSURE, [215.4, 215.4, 215.4], 'lbf/ft**2' + Dynamic.Atmosphere.DYNAMIC_PRESSURE, [215.4, 215.4, 215.4], 'lbf/ft**2' ) -_mission_data.set_val(Dynamic.Mission.MASS, [169730.0, 169200.0, 167400.0], 'lbm') -_mission_data.set_val(Dynamic.Mission.DRAG, [9542.0, 9512.0, 9411.0], 'lbf') +_mission_data.set_val(Dynamic.Vehicle.MASS, [169730.0, 169200.0, 167400.0], 'lbm') +_mission_data.set_val(Dynamic.Vehicle.DRAG, [9542.0, 9512.0, 9411.0], 'lbf') M = np.array([0.7850, 0.7850, 0.7850]) CD_scaled = np.array([0.03304, 0.03293, 0.03258]) CD0_scaled = np.array([0.02016, 0.02016, 0.02016]) CDI_scaled = np.array([0.01288, 0.01277, 0.01242]) -_mission_data.set_val(Dynamic.Mission.MACH, M) +_mission_data.set_val(Dynamic.Atmosphere.MACH, M) _add_drag_coefficients(key, _mission_data, M, CD_scaled, CD0_scaled, CDI_scaled) mission_simple_CD[key] = np.array([0.03304, 0.03293, 0.03258]) @@ -311,17 +311,17 @@ def _add_drag_coefficients( key = 'N3CC' mission_test_data[key] = _mission_data = AviaryValues() _mission_data.set_val( - Dynamic.Mission.DYNAMIC_PRESSURE, [208.4, 288.5, 364.0], 'lbf/ft**2' + Dynamic.Atmosphere.DYNAMIC_PRESSURE, [208.4, 288.5, 364.0], 'lbf/ft**2' ) -_mission_data.set_val(Dynamic.Mission.MASS, [128777.0, 128721.0, 128667.0], 'lbm') -_mission_data.set_val(Dynamic.Mission.DRAG, [5837.0, 6551.0, 7566.0], 'lbf') +_mission_data.set_val(Dynamic.Vehicle.MASS, [128777.0, 128721.0, 128667.0], 'lbm') +_mission_data.set_val(Dynamic.Vehicle.DRAG, [5837.0, 6551.0, 7566.0], 'lbf') M = np.array([0.4522, 0.5321, 0.5985]) CD_scaled = np.array([0.02296, 0.01861, 0.01704]) CD0_scaled = np.array([0.01611, 0.01569, 0.01556]) CDI_scaled = np.array([0.00806, 0.00390, 0.00237]) -_mission_data.set_val(Dynamic.Mission.MACH, M) +_mission_data.set_val(Dynamic.Atmosphere.MACH, M) _add_drag_coefficients(key, _mission_data, M, CD_scaled, CD0_scaled, CDI_scaled) # endregion - mission test data taken from the baseline FLOPS output for each case diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_ground_effect.py b/aviary/subsystems/aerodynamics/flops_based/test/test_ground_effect.py index 2262993a7..d94fa8139 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_ground_effect.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_ground_effect.py @@ -61,17 +61,19 @@ def make_problem(): height = (8., 'ft') span = (34., 'm') - inputs = AviaryValues({ - 'angle_of_attack': (np.array([0., 2., 6]), 'deg'), - Dynamic.Mission.ALTITUDE: (np.array([100.0, 132, 155]), 'm'), - Dynamic.Mission.FLIGHT_PATH_ANGLE: (np.array([0., 0.5, 1.0]), 'deg'), - 'minimum_drag_coefficient': minimum_drag_coefficient, - 'base_lift_coefficient': base_lift_coefficient, - 'base_drag_coefficient': base_drag_coefficient, - Aircraft.Wing.ASPECT_RATIO: aspect_ratio, - Aircraft.Wing.HEIGHT: height, - Aircraft.Wing.SPAN: span - }) + inputs = AviaryValues( + { + 'angle_of_attack': (np.array([0.0, 2.0, 6]), 'deg'), + Dynamic.Mission.ALTITUDE: (np.array([100.0, 132, 155]), 'm'), + Dynamic.Mission.FLIGHT_PATH_ANGLE: (np.array([0.0, 0.5, 1.0]), 'deg'), + 'minimum_drag_coefficient': minimum_drag_coefficient, + 'base_lift_coefficient': base_lift_coefficient, + 'base_drag_coefficient': base_drag_coefficient, + Aircraft.Wing.ASPECT_RATIO: aspect_ratio, + Aircraft.Wing.HEIGHT: height, + Aircraft.Wing.SPAN: span, + } + ) ground_effect = GroundEffect(num_nodes=nn, ground_altitude=ground_altitude) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_induced_drag.py b/aviary/subsystems/aerodynamics/flops_based/test/test_induced_drag.py index 8d5a34d1e..e73ac37c3 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_induced_drag.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_induced_drag.py @@ -5,7 +5,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.aerodynamics.flops_based.induced_drag import InducedDrag -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Aircraft, Dynamic @@ -21,18 +20,18 @@ def test_derivs(self): nn = len(CL) - prob = om.Problem(model=om.Group()) + prob = om.Problem() options = {} - options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] = (False, 'unitless') + options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] = False prob.model.add_subsystem('induced_drag', InducedDrag( - num_nodes=nn, aviary_options=AviaryValues(options)), promotes=['*']) + num_nodes=nn, **options), promotes=['*']) prob.setup(force_alloc_complex=True) - prob.set_val(Dynamic.Mission.MACH, val=mach) - prob.set_val(Dynamic.Mission.LIFT, val=lift) - prob.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P) + prob.set_val(Dynamic.Atmosphere.MACH, val=mach) + prob.set_val(Dynamic.Vehicle.LIFT, val=lift) + prob.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, val=P) prob.set_val(Aircraft.Wing.AREA, val=Sref) prob.set_val(Aircraft.Wing.SWEEP, val=-25.03) prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.278) @@ -60,18 +59,18 @@ def test_derivs_span_eff_redux(self): # High factor - prob = om.Problem(model=om.Group()) + prob = om.Problem() options = {} - options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] = (True, 'unitless') + options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] = True prob.model.add_subsystem('drag', InducedDrag( - num_nodes=nn, aviary_options=AviaryValues(options)), promotes=['*']) + num_nodes=nn, **options), promotes=['*']) prob.setup(force_alloc_complex=True) - prob.set_val(Dynamic.Mission.MACH, val=mach) - prob.set_val(Dynamic.Mission.LIFT, val=lift) - prob.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P) + prob.set_val(Dynamic.Atmosphere.MACH, val=mach) + prob.set_val(Dynamic.Vehicle.LIFT, val=lift) + prob.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, val=P) prob.set_val(Aircraft.Wing.AREA, val=Sref) prob.set_val(Aircraft.Wing.SWEEP, val=-25.10) prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.312) @@ -92,15 +91,15 @@ def test_derivs_span_eff_redux(self): prob = om.Problem(model=om.Group()) options = {} - options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] = (True, 'unitless') + options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] = True prob.model.add_subsystem('drag', InducedDrag( - num_nodes=nn, aviary_options=AviaryValues(options)), promotes=['*']) + num_nodes=nn, **options), promotes=['*']) prob.setup(force_alloc_complex=True) - prob.set_val(Dynamic.Mission.MACH, val=mach) - prob.set_val(Dynamic.Mission.LIFT, val=lift) - prob.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P) + prob.set_val(Dynamic.Atmosphere.MACH, val=mach) + prob.set_val(Dynamic.Vehicle.LIFT, val=lift) + prob.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, val=P) prob.set_val(Aircraft.Wing.AREA, val=Sref) prob.set_val(Aircraft.Wing.SWEEP, val=-25.10) prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.312) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_lift.py b/aviary/subsystems/aerodynamics/flops_based/test/test_lift.py index 65137fec3..790bae080 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_lift.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_lift.py @@ -31,10 +31,10 @@ def test_case(self, case_name): # dynamic pressure = 4 digits precision # lift coefficient = 5 digits precision - mission_keys = (Dynamic.Mission.DYNAMIC_PRESSURE, 'cl') + mission_keys = (Dynamic.Atmosphere.DYNAMIC_PRESSURE, 'cl') # lift = 6 digits precision - outputs_keys = (Dynamic.Mission.LIFT,) + outputs_keys = (Dynamic.Vehicle.LIFT,) # use lowest precision from all available data tol = 1e-4 @@ -42,7 +42,7 @@ def test_case(self, case_name): prob = om.Problem() model = prob.model - q, _ = mission_data.get_item(Dynamic.Mission.DYNAMIC_PRESSURE) + q, _ = mission_data.get_item(Dynamic.Atmosphere.DYNAMIC_PRESSURE) nn = len(q) model.add_subsystem('simple_lift', SimpleLift(num_nodes=nn), promotes=['*']) @@ -74,7 +74,7 @@ def test_case(self, case_name): assert_check_partials(data, atol=2.5e-10, rtol=1e-12) assert_near_equal( - prob.get_val(Dynamic.Mission.LIFT), mission_simple_data[case_name], 1e-6 + prob.get_val(Dynamic.Vehicle.LIFT), mission_simple_data[case_name], 1e-6 ) @@ -91,11 +91,11 @@ def test_case(self, case_name): # dynamic pressure = 4 digits precision # mass = 6 digits precision - mission_keys = (Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MASS) + mission_keys = (Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Vehicle.MASS) # lift coefficient = 5 digits precision # lift = 6 digits precision - outputs_keys = ('cl', Dynamic.Mission.LIFT) + outputs_keys = ('cl', Dynamic.Vehicle.LIFT) # use lowest precision from all available data tol = 1e-4 @@ -103,7 +103,7 @@ def test_case(self, case_name): prob = om.Problem() model = prob.model - q, _ = mission_data.get_item(Dynamic.Mission.DYNAMIC_PRESSURE) + q, _ = mission_data.get_item(Dynamic.Atmosphere.DYNAMIC_PRESSURE) nn = len(q) model.add_subsystem( @@ -138,7 +138,7 @@ def test_case(self, case_name): assert_check_partials(data, atol=2.5e-10, rtol=1e-12) assert_near_equal( - prob.get_val(Dynamic.Mission.LIFT), mission_equal_data[case_name], 1e-6 + prob.get_val(Dynamic.Vehicle.LIFT), mission_equal_data[case_name], 1e-6 ) @@ -152,31 +152,31 @@ def test_case(self, case_name): mission_test_data['LargeSingleAisle1FLOPS'] = _mission_data = AviaryValues() _mission_data.set_val( - Dynamic.Mission.DYNAMIC_PRESSURE, [206.0, 205.6, 205.4], 'lbf/ft**2' + Dynamic.Atmosphere.DYNAMIC_PRESSURE, [206.0, 205.6, 205.4], 'lbf/ft**2' ) _mission_data.set_val('cl', [0.62630, 0.62623, 0.62619]) -_mission_data.set_val(Dynamic.Mission.LIFT, [176751.0, 176400.0, 176185.0], 'lbf') -_mission_data.set_val(Dynamic.Mission.MASS, [176751.0, 176400.0, 176185.0], 'lbm') +_mission_data.set_val(Dynamic.Vehicle.LIFT, [176751.0, 176400.0, 176185.0], 'lbf') +_mission_data.set_val(Dynamic.Vehicle.MASS, [176751.0, 176400.0, 176185.0], 'lbm') mission_simple_data['LargeSingleAisle1FLOPS'] = [786242.68, 784628.29, 783814.96] mission_equal_data['LargeSingleAisle1FLOPS'] = [786227.62, 784666.29, 783709.93] mission_test_data['LargeSingleAisle2FLOPS'] = _mission_data = AviaryValues() _mission_data.set_val( - Dynamic.Mission.DYNAMIC_PRESSURE, [215.4, 215.4, 215.4], 'lbf/ft**2' + Dynamic.Atmosphere.DYNAMIC_PRESSURE, [215.4, 215.4, 215.4], 'lbf/ft**2' ) _mission_data.set_val('cl', [0.58761, 0.58578, 0.57954]) -_mission_data.set_val(Dynamic.Mission.LIFT, [169730.0, 169200.0, 167400.0], 'lbf') -_mission_data.set_val(Dynamic.Mission.MASS, [169730.0, 169200.0, 167400.0], 'lbm') +_mission_data.set_val(Dynamic.Vehicle.LIFT, [169730.0, 169200.0, 167400.0], 'lbf') +_mission_data.set_val(Dynamic.Vehicle.MASS, [169730.0, 169200.0, 167400.0], 'lbm') mission_simple_data['LargeSingleAisle2FLOPS'] = [755005.42, 752654.10, 744636.48] mission_equal_data['LargeSingleAisle2FLOPS'] = [754996.65, 752639.10, 744632.30] mission_test_data['N3CC'] = _mission_data = AviaryValues() _mission_data.set_val( - Dynamic.Mission.DYNAMIC_PRESSURE, [208.4, 288.5, 364.0], 'lbf/ft**2' + Dynamic.Atmosphere.DYNAMIC_PRESSURE, [208.4, 288.5, 364.0], 'lbf/ft**2' ) _mission_data.set_val('cl', [0.50651, 0.36573, 0.28970]) -_mission_data.set_val(Dynamic.Mission.LIFT, [128777.0, 128721.0, 128667.0], 'lbf') -_mission_data.set_val(Dynamic.Mission.MASS, [128777.0, 128721.0, 128667.0], 'lbm') +_mission_data.set_val(Dynamic.Vehicle.LIFT, [128777.0, 128721.0, 128667.0], 'lbf') +_mission_data.set_val(Dynamic.Vehicle.MASS, [128777.0, 128721.0, 128667.0], 'lbm') mission_simple_data['N3CC'] = [572838.22, 572601.72, 572263.60] mission_equal_data['N3CC'] = [572828.63, 572579.53, 572339.33] diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_lift_dependent_drag.py b/aviary/subsystems/aerodynamics/flops_based/test/test_lift_dependent_drag.py index e02606f6d..19fc5c4d0 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_lift_dependent_drag.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_lift_dependent_drag.py @@ -27,9 +27,9 @@ def test_derivs_edge_interp(self): prob.model.add_subsystem('drag', LiftDependentDrag(num_nodes=nn), promotes=['*']) prob.setup(force_alloc_complex=True) - prob.set_val(Dynamic.Mission.MACH, val=mach) - prob.set_val(Dynamic.Mission.LIFT, val=lift) - prob.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P) + prob.set_val(Dynamic.Atmosphere.MACH, val=mach) + prob.set_val(Dynamic.Vehicle.LIFT, val=lift) + prob.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, val=P) prob.set_val(Aircraft.Wing.AREA, val=Sref) prob.set_val(Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, val=1.0) prob.set_val(Aircraft.Wing.SWEEP, val=25.03) @@ -64,9 +64,9 @@ def test_derivs_inner_interp(self): prob.model.add_subsystem('drag', LiftDependentDrag(num_nodes=nn), promotes=['*']) prob.setup(force_alloc_complex=True) - prob.set_val(Dynamic.Mission.MACH, val=mach) - prob.set_val(Dynamic.Mission.LIFT, val=lift) - prob.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P) + prob.set_val(Dynamic.Atmosphere.MACH, val=mach) + prob.set_val(Dynamic.Vehicle.LIFT, val=lift) + prob.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, val=P) prob.set_val(Aircraft.Wing.AREA, val=Sref) prob.set_val(Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, val=1.0) prob.set_val(Aircraft.Wing.SWEEP, val=25.07) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_mux_component.py b/aviary/subsystems/aerodynamics/flops_based/test/test_mux_component.py index e26321f57..592e71d06 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_mux_component.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_mux_component.py @@ -6,7 +6,6 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.subsystems.aerodynamics.flops_based.mux_component import MuxComponent -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Aircraft @@ -16,13 +15,14 @@ def test_mux(self): prob = om.Problem() model = prob.model - aviary_options = AviaryValues() - aviary_options.set_val(Aircraft.VerticalTail.NUM_TAILS, 1) - aviary_options.set_val(Aircraft.Fuselage.NUM_FUSELAGES, 1) - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2])) + aviary_options = { + Aircraft.Engine.NUM_ENGINES: np.array([2]), + Aircraft.Fuselage.NUM_FUSELAGES: 1, + Aircraft.VerticalTail.NUM_TAILS: 1, + } model.add_subsystem( - 'mux', MuxComponent(aviary_options=aviary_options), + 'mux', MuxComponent(**aviary_options), promotes_inputs=['*']) prob.setup(force_alloc_complex=True) @@ -91,13 +91,14 @@ def test_mux_multiengine(self): prob = om.Problem() model = prob.model - aviary_options = AviaryValues() - aviary_options.set_val(Aircraft.VerticalTail.NUM_TAILS, 1) - aviary_options.set_val(Aircraft.Fuselage.NUM_FUSELAGES, 1) - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2, 3])) + aviary_options = { + Aircraft.Engine.NUM_ENGINES: np.array([2, 3]), + Aircraft.Fuselage.NUM_FUSELAGES: 1, + Aircraft.VerticalTail.NUM_TAILS: 1, + } model.add_subsystem( - 'mux', MuxComponent(aviary_options=aviary_options), + 'mux', MuxComponent(**aviary_options), promotes_inputs=['*']) prob.setup(force_alloc_complex=True) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_skinfriction_coef.py b/aviary/subsystems/aerodynamics/flops_based/test/test_skinfriction_coef.py index cbb63666b..e4fd91f5d 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_skinfriction_coef.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_skinfriction_coef.py @@ -5,7 +5,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.aerodynamics.flops_based.skin_friction import SkinFriction -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Aircraft @@ -24,12 +23,12 @@ def test_derivs(self): model = prob.model options = {} - options[Aircraft.VerticalTail.NUM_TAILS] = (0, 'unitless') - options[Aircraft.Fuselage.NUM_FUSELAGES] = (1, 'unitless') - options[Aircraft.Engine.NUM_ENGINES] = ([0], 'unitless') + options[Aircraft.VerticalTail.NUM_TAILS] = 0 + options[Aircraft.Fuselage.NUM_FUSELAGES] = 1 + options[Aircraft.Engine.NUM_ENGINES] = [0] model.add_subsystem( - 'cf', SkinFriction(num_nodes=n, aviary_options=AviaryValues(options)), promotes=['*']) + 'cf', SkinFriction(num_nodes=n, **options), promotes=['*']) prob.setup(force_alloc_complex=True) @@ -122,12 +121,12 @@ def test_derivs_multiengine(self): model = prob.model options = {} - options[Aircraft.VerticalTail.NUM_TAILS] = (0, 'unitless') - options[Aircraft.Fuselage.NUM_FUSELAGES] = (1, 'unitless') - options[Aircraft.Engine.NUM_ENGINES] = ([2, 4], 'unitless') + options[Aircraft.VerticalTail.NUM_TAILS] = 0 + options[Aircraft.Fuselage.NUM_FUSELAGES] = 1 + options[Aircraft.Engine.NUM_ENGINES] = [2, 4] model.add_subsystem( - 'cf', SkinFriction(num_nodes=n, aviary_options=AviaryValues(options)), promotes=['*']) + 'cf', SkinFriction(num_nodes=n, **options), promotes=['*']) prob.setup(force_alloc_complex=True) @@ -281,12 +280,12 @@ def test_skin_friction_algorithm(self): model = prob.model options = {} - options[Aircraft.VerticalTail.NUM_TAILS] = (0, 'unitless') - options[Aircraft.Fuselage.NUM_FUSELAGES] = (1, 'unitless') - options[Aircraft.Engine.NUM_ENGINES] = ([0], 'unitless') + options[Aircraft.VerticalTail.NUM_TAILS] = 0 + options[Aircraft.Fuselage.NUM_FUSELAGES] = 1 + options[Aircraft.Engine.NUM_ENGINES] = [0] model.add_subsystem( - 'cf', SkinFriction(num_nodes=n, aviary_options=AviaryValues(options))) + 'cf', SkinFriction(num_nodes=n, **options)) prob.setup(force_alloc_complex=True) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_skinfriction_drag.py b/aviary/subsystems/aerodynamics/flops_based/test/test_skinfriction_drag.py index 3be06d264..63435d039 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_skinfriction_drag.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_skinfriction_drag.py @@ -6,7 +6,6 @@ from aviary.subsystems.aerodynamics.flops_based.skin_friction_drag import \ SkinFrictionDrag -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Aircraft @@ -28,14 +27,15 @@ def test_derivs(self): prob = om.Problem() model = prob.model - options = AviaryValues() - options.set_val(Aircraft.Fuselage.NUM_FUSELAGES, 1) - options.set_val(Aircraft.Engine.NUM_ENGINES, [2]) - options.set_val(Aircraft.VerticalTail.NUM_TAILS, 1) - options.set_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY, 1.93) + options = { + Aircraft.Fuselage.NUM_FUSELAGES: 1, + Aircraft.Engine.NUM_ENGINES: [2], + Aircraft.VerticalTail.NUM_TAILS: 1, + Aircraft.Wing.AIRFOIL_TECHNOLOGY: 1.93, + } model.add_subsystem( - 'CDf', SkinFrictionDrag(num_nodes=nn, aviary_options=options), + 'CDf', SkinFrictionDrag(num_nodes=nn, **options), promotes_inputs=[Aircraft.Wing.AREA], promotes_outputs=['skin_friction_drag_coeff']) @@ -77,14 +77,15 @@ def test_derivs_multiengine(self): prob = om.Problem() model = prob.model - options = AviaryValues() - options.set_val(Aircraft.Fuselage.NUM_FUSELAGES, 1) - options.set_val(Aircraft.Engine.NUM_ENGINES, [2, 4]) - options.set_val(Aircraft.VerticalTail.NUM_TAILS, 1) - options.set_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY, 1.93) + options = { + Aircraft.Fuselage.NUM_FUSELAGES: 1, + Aircraft.Engine.NUM_ENGINES: [2, 4], + Aircraft.VerticalTail.NUM_TAILS: 1, + Aircraft.Wing.AIRFOIL_TECHNOLOGY: 1.93, + } model.add_subsystem( - 'CDf', SkinFrictionDrag(num_nodes=nn, aviary_options=options), + 'CDf', SkinFrictionDrag(num_nodes=nn, **options), promotes_inputs=[Aircraft.Wing.AREA], promotes_outputs=['skin_friction_drag_coeff']) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py index e85f923d4..1fb1e5845 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py @@ -21,6 +21,7 @@ get_flops_outputs, print_case) from aviary.variable_info.enums import LegacyCode +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings FLOPS = LegacyCode.FLOPS @@ -50,6 +51,8 @@ def setUp(self): promotes_outputs=['*'], ) + setup_model_options(self.prob, aviary_options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case(self): @@ -57,16 +60,15 @@ def test_case(self): # test data from large_single_aisle_2 climb profile # tabular aero was set to large_single_aisle_1, expected value adjusted accordingly self.prob.set_val( - Dynamic.Mission.VELOCITY, - val=115, - units='m/s') # convert from knots to ft/s + Dynamic.Mission.VELOCITY, val=115, units='m/s' + ) # convert from knots to ft/s self.prob.set_val(Dynamic.Mission.ALTITUDE, val=10582, units='m') - self.prob.set_val(Dynamic.Mission.MASS, val=80442, units='kg') - self.prob.set_val(Dynamic.Mission.MACH, val=0.3876, units='unitless') + self.prob.set_val(Dynamic.Vehicle.MASS, val=80442, units='kg') + self.prob.set_val(Dynamic.Atmosphere.MACH, val=0.3876, units='unitless') # 1344.5? 'reference' vs 'calculated'? self.prob.set_val(Aircraft.Wing.AREA, val=1341, units='ft**2') # calculated from online atmospheric table - self.prob.set_val(Dynamic.Mission.DENSITY, val=0.88821, units='kg/m**3') + self.prob.set_val(Dynamic.Atmosphere.DENSITY, val=0.88821, units='kg/m**3') self.prob.run_model() @@ -75,7 +77,7 @@ def test_case(self): tol = .03 assert_near_equal( - self.prob.get_val(Dynamic.Mission.DRAG, units='N'), 53934.78861492, tol + self.prob.get_val(Dynamic.Vehicle.DRAG, units='N'), 53934.78861492, tol ) # check the value of each output # TODO resolve partials wrt gravity (decide on implementation of gravity) @@ -187,6 +189,8 @@ def setUp(self): promotes_outputs=['*'], ) + setup_model_options(self.prob, aviary_options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case(self): @@ -194,16 +198,15 @@ def test_case(self): # test data from large_single_aisle_2 climb profile # tabular aero was set to large_single_aisle_1 data, expected value adjusted accordingly self.prob.set_val( - Dynamic.Mission.VELOCITY, - val=115, - units='m/s') # convert from knots to ft/s + Dynamic.Mission.VELOCITY, val=115, units='m/s' + ) # convert from knots to ft/s self.prob.set_val(Dynamic.Mission.ALTITUDE, val=10582, units='m') - self.prob.set_val(Dynamic.Mission.MASS, val=80442, units='kg') - self.prob.set_val(Dynamic.Mission.MACH, val=0.3876, units='unitless') + self.prob.set_val(Dynamic.Vehicle.MASS, val=80442, units='kg') + self.prob.set_val(Dynamic.Atmosphere.MACH, val=0.3876, units='unitless') # 1344.5? 'reference' vs 'calculated'? self.prob.set_val(Aircraft.Wing.AREA, val=1341, units='ft**2') # calculated from online atmospheric table - self.prob.set_val(Dynamic.Mission.DENSITY, val=0.88821, units='kg/m**3') + self.prob.set_val(Dynamic.Atmosphere.DENSITY, val=0.88821, units='kg/m**3') self.prob.run_model() @@ -212,7 +215,7 @@ def test_case(self): tol = .03 assert_near_equal( - self.prob.get_val(Dynamic.Mission.DRAG, units='N'), 53934.78861492, tol + self.prob.get_val(Dynamic.Vehicle.DRAG, units='N'), 53934.78861492, tol ) # check the value of each output # TODO resolve partials wrt gravity (decide on implementation of gravity) @@ -309,28 +312,28 @@ def test_case(self, case_name): dynamic_inputs.set_val(Dynamic.Mission.VELOCITY, val=vel, units=vel_units) dynamic_inputs.set_val(Dynamic.Mission.ALTITUDE, val=alt, units=alt_units) - dynamic_inputs.set_val(Dynamic.Mission.MASS, val=mass, units=units) + dynamic_inputs.set_val(Dynamic.Vehicle.MASS, val=mass, units=units) prob = _get_computed_aero_data_at_altitude(alt, alt_units) - sos = prob.get_val(Dynamic.Mission.SPEED_OF_SOUND, vel_units) + sos = prob.get_val(Dynamic.Atmosphere.SPEED_OF_SOUND, vel_units) mach = vel / sos - dynamic_inputs.set_val(Dynamic.Mission.MACH, val=mach, units='unitless') + dynamic_inputs.set_val(Dynamic.Atmosphere.MACH, val=mach, units='unitless') - key = Dynamic.Mission.DENSITY + key = Dynamic.Atmosphere.DENSITY units = 'kg/m**3' val = prob.get_val(key, units) dynamic_inputs.set_val(key, val=val, units=units) - key = Dynamic.Mission.TEMPERATURE + key = Dynamic.Atmosphere.TEMPERATURE units = 'degR' val = prob.get_val(key, units) dynamic_inputs.set_val(key, val=val, units=units) - key = Dynamic.Mission.STATIC_PRESSURE + key = Dynamic.Atmosphere.STATIC_PRESSURE units = 'N/m**2' val = prob.get_val(key, units) @@ -338,7 +341,7 @@ def test_case(self, case_name): prob = _run_computed_aero_harness(flops_inputs, dynamic_inputs, 1) - computed_drag = prob.get_val(Dynamic.Mission.DRAG, 'N') + computed_drag = prob.get_val(Dynamic.Vehicle.DRAG, 'N') CDI_data, CD0_data = _computed_aero_drag_data( flops_inputs, *_design_altitudes.get_item(case_name)) @@ -358,6 +361,8 @@ def test_case(self, case_name): promotes_outputs=['*'], ) + setup_model_options(prob, flops_inputs) + prob.setup(check=False, force_alloc_complex=True) for (key, (val, units)) in dynamic_inputs: @@ -371,7 +376,7 @@ def test_case(self, case_name): prob.run_model() - tabular_drag = prob.get_val(Dynamic.Mission.DRAG, 'N') + tabular_drag = prob.get_val(Dynamic.Vehicle.DRAG, 'N') assert_near_equal(tabular_drag, computed_drag, 0.005) @@ -449,7 +454,7 @@ def _default_CD0_data(): CD0_data = NamedValues() CD0_data.set_val(Dynamic.Mission.ALTITUDE, alt_range, 'ft') - CD0_data.set_val(Dynamic.Mission.MACH, mach_range) + CD0_data.set_val(Dynamic.Atmosphere.MACH, mach_range) CD0_data.set_val('zero_lift_drag_coefficient', CD0) return CD0_data @@ -515,7 +520,7 @@ def _default_CDI_data(): # cl_list = np.array(cl_list).flatten() # mach_list = np.array(mach_list).flatten() CDI_data = NamedValues() - CDI_data.set_val(Dynamic.Mission.MACH, mach_range) + CDI_data.set_val(Dynamic.Atmosphere.MACH, mach_range) CDI_data.set_val('lift_coefficient', cl_range) CDI_data.set_val('lift_dependent_drag_coefficient', CDI) @@ -574,8 +579,8 @@ def _computed_aero_drag_data(flops_inputs: AviaryValues, design_altitude, units) # calculate temperature (degR), static pressure (lbf/ft**2), and mass (lbm) at design # altitude from lift coefficients and Mach numbers prob: om.Problem = _get_computed_aero_data_at_altitude(design_altitude, units) - T = prob.get_val(Dynamic.Mission.TEMPERATURE, 'degR') - P = prob.get_val(Dynamic.Mission.STATIC_PRESSURE, 'lbf/ft**2') + T = prob.get_val(Dynamic.Atmosphere.TEMPERATURE, 'degR') + P = prob.get_val(Dynamic.Atmosphere.STATIC_PRESSURE, 'lbf/ft**2') mass = lift = CL * S * 0.5 * 1.4 * P * mach**2 # lbf -> lbm * 1g @@ -584,10 +589,10 @@ def _computed_aero_drag_data(flops_inputs: AviaryValues, design_altitude, units) dynamic_inputs = AviaryValues() - dynamic_inputs.set_val(Dynamic.Mission.MACH, val=mach) - dynamic_inputs.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P, units='lbf/ft**2') - dynamic_inputs.set_val(Dynamic.Mission.TEMPERATURE, val=T, units='degR') - dynamic_inputs.set_val(Dynamic.Mission.MASS, val=mass, units='lbm') + dynamic_inputs.set_val(Dynamic.Atmosphere.MACH, val=mach) + dynamic_inputs.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, val=P, units='lbf/ft**2') + dynamic_inputs.set_val(Dynamic.Atmosphere.TEMPERATURE, val=T, units='degR') + dynamic_inputs.set_val(Dynamic.Vehicle.MASS, val=mass, units='lbm') prob = _run_computed_aero_harness(flops_inputs, dynamic_inputs, nn) @@ -595,7 +600,7 @@ def _computed_aero_drag_data(flops_inputs: AviaryValues, design_altitude, units) CDI = np.reshape(CDI.flatten(), (nsteps, nsteps)) CDI_data = NamedValues() - CDI_data.set_val(Dynamic.Mission.MACH, seed) + CDI_data.set_val(Dynamic.Atmosphere.MACH, seed) CDI_data.set_val('lift_coefficient', seed) CDI_data.set_val('lift_dependent_drag_coefficient', CDI) @@ -608,18 +613,19 @@ def _computed_aero_drag_data(flops_inputs: AviaryValues, design_altitude, units) dynamic_inputs = AviaryValues() - dynamic_inputs.set_val(Dynamic.Mission.MACH, val=mach) - dynamic_inputs.set_val(Dynamic.Mission.MASS, val=mass, units=units) + dynamic_inputs.set_val(Dynamic.Atmosphere.MACH, val=mach) + dynamic_inputs.set_val(Dynamic.Vehicle.MASS, val=mass, units=units) CD0 = [] for h in alt: prob: om.Problem = _get_computed_aero_data_at_altitude(h, 'ft') - T = prob.get_val(Dynamic.Mission.TEMPERATURE, 'degR') - P = prob.get_val(Dynamic.Mission.STATIC_PRESSURE, 'lbf/ft**2') + T = prob.get_val(Dynamic.Atmosphere.TEMPERATURE, 'degR') + P = prob.get_val(Dynamic.Atmosphere.STATIC_PRESSURE, 'lbf/ft**2') - dynamic_inputs.set_val(Dynamic.Mission.STATIC_PRESSURE, val=P, units='lbf/ft**2') - dynamic_inputs.set_val(Dynamic.Mission.TEMPERATURE, val=T, units='degR') + dynamic_inputs.set_val(Dynamic.Atmosphere.STATIC_PRESSURE, + val=P, units='lbf/ft**2') + dynamic_inputs.set_val(Dynamic.Atmosphere.TEMPERATURE, val=T, units='degR') prob = _run_computed_aero_harness(flops_inputs, dynamic_inputs, nn) @@ -629,7 +635,7 @@ def _computed_aero_drag_data(flops_inputs: AviaryValues, design_altitude, units) CD0_data = NamedValues() CD0_data.set_val(Dynamic.Mission.ALTITUDE, alt, 'ft') - CD0_data.set_val(Dynamic.Mission.MACH, seed) + CD0_data.set_val(Dynamic.Atmosphere.MACH, seed) CD0_data.set_val('zero_lift_drag_coefficient', CD0) return (CDI_data, CD0_data) @@ -655,6 +661,8 @@ def _run_computed_aero_harness(flops_inputs, dynamic_inputs, num_nodes): prob = om.Problem( _ComputedAeroHarness(num_nodes=num_nodes, aviary_options=flops_inputs)) + setup_model_options(prob, flops_inputs) + prob.setup() set_aviary_initial_values(prob, dynamic_inputs) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_takeoff_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_takeoff_aero_group.py index ffddd89f0..b57bd73e9 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_takeoff_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_takeoff_aero_group.py @@ -88,7 +88,7 @@ def make_problem(subsystem_options={}): prob.model.add_subsystem( name='atmosphere', subsys=Atmosphere(num_nodes=nn), - promotes=['*', (Dynamic.Mission.DYNAMIC_PRESSURE, 'skip')], + promotes=['*', (Dynamic.Atmosphere.DYNAMIC_PRESSURE, 'skip')], ) aero_builder = CoreAerodynamicsBuilder(code_origin=LegacyCode.FLOPS) @@ -132,22 +132,36 @@ def make_problem(subsystem_options={}): # - last generated 2023 June 8 # - generate new regression data if, and only if, takeoff aero group is updated with a # more trusted implementation -_regression_data = AviaryValues({ - Dynamic.Mission.LIFT: ( - [3028.138891962988, 4072.059743068957, 6240.85493286], _units_lift), - Dynamic.Mission.DRAG: ( - [434.6285684000267, 481.5245555324278, 586.0976806512001], _units_drag)}) +_regression_data = AviaryValues( + { + Dynamic.Vehicle.LIFT: ( + [3028.138891962988, 4072.059743068957, 6240.85493286], + _units_lift, + ), + Dynamic.Vehicle.DRAG: ( + [434.6285684000267, 481.5245555324278, 586.0976806512001], + _units_drag, + ), + } +) # NOTE: # - results from `generate_regression_data_spoiler()` # - last generated 2023 June 8 # - generate new regression data if, and only if, takeoff aero group is updated with a # more trusted implementation -_regression_data_spoiler = AviaryValues({ - Dynamic.Mission.LIFT: ( - [-1367.5937129210124, -323.67286181504335, 1845.1223279759993], _units_lift), - Dynamic.Mission.DRAG: ( - [895.9091503940268, 942.8051375264279, 1047.3782626452], _units_drag)}) +_regression_data_spoiler = AviaryValues( + { + Dynamic.Vehicle.LIFT: ( + [-1367.5937129210124, -323.67286181504335, 1845.1223279759993], + _units_lift, + ), + Dynamic.Vehicle.DRAG: ( + [895.9091503940268, 942.8051375264279, 1047.3782626452], + _units_drag, + ), + } +) def generate_regression_data(): @@ -202,8 +216,8 @@ def _generate_regression_data(subsystem_options={}): prob.run_model() - lift = prob.get_val(Dynamic.Mission.LIFT, _units_lift) - drag = prob.get_val(Dynamic.Mission.DRAG, _units_drag) + lift = prob.get_val(Dynamic.Vehicle.LIFT, _units_lift) + drag = prob.get_val(Dynamic.Vehicle.DRAG, _units_drag) prob.check_partials(compact_print=True, method="cs") diff --git a/aviary/subsystems/aerodynamics/gasp_based/common.py b/aviary/subsystems/aerodynamics/gasp_based/common.py index 8af9801d1..9f34627ba 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/common.py +++ b/aviary/subsystems/aerodynamics/gasp_based/common.py @@ -16,41 +16,52 @@ def setup(self): self.add_input("CL", 1.0, units="unitless", shape=nn, desc="Lift coefficient") self.add_input("CD", 1.0, units="unitless", shape=nn, desc="Drag coefficient") - self.add_input(Dynamic.Mission.DYNAMIC_PRESSURE, 1.0, - units="psf", shape=nn, desc="Dynamic pressure") + self.add_input( + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + 1.0, + units="psf", + shape=nn, + desc="Dynamic pressure", + ) add_aviary_input(self, Aircraft.Wing.AREA, val=1370.3) - self.add_output(Dynamic.Mission.LIFT, units="lbf", shape=nn, desc="Lift force") - self.add_output(Dynamic.Mission.DRAG, units="lbf", shape=nn, desc="Drag force") + self.add_output(Dynamic.Vehicle.LIFT, units="lbf", shape=nn, desc="Lift force") + self.add_output(Dynamic.Vehicle.DRAG, units="lbf", shape=nn, desc="Drag force") def setup_partials(self): nn = self.options["num_nodes"] arange = np.arange(nn) self.declare_partials( - Dynamic.Mission.LIFT, [ - "CL", Dynamic.Mission.DYNAMIC_PRESSURE], rows=arange, cols=arange) - self.declare_partials(Dynamic.Mission.LIFT, [Aircraft.Wing.AREA]) + Dynamic.Vehicle.LIFT, + ["CL", Dynamic.Atmosphere.DYNAMIC_PRESSURE], + rows=arange, + cols=arange, + ) + self.declare_partials(Dynamic.Vehicle.LIFT, [Aircraft.Wing.AREA]) self.declare_partials( - Dynamic.Mission.DRAG, [ - "CD", Dynamic.Mission.DYNAMIC_PRESSURE], rows=arange, cols=arange) - self.declare_partials(Dynamic.Mission.DRAG, [Aircraft.Wing.AREA]) + Dynamic.Vehicle.DRAG, + ["CD", Dynamic.Atmosphere.DYNAMIC_PRESSURE], + rows=arange, + cols=arange, + ) + self.declare_partials(Dynamic.Vehicle.DRAG, [Aircraft.Wing.AREA]) def compute(self, inputs, outputs): CL, CD, q, wing_area = inputs.values() - outputs[Dynamic.Mission.LIFT] = q * CL * wing_area - outputs[Dynamic.Mission.DRAG] = q * CD * wing_area + outputs[Dynamic.Vehicle.LIFT] = q * CL * wing_area + outputs[Dynamic.Vehicle.DRAG] = q * CD * wing_area def compute_partials(self, inputs, J): CL, CD, q, wing_area = inputs.values() - J[Dynamic.Mission.LIFT, "CL"] = q * wing_area - J[Dynamic.Mission.LIFT, Dynamic.Mission.DYNAMIC_PRESSURE] = CL * wing_area - J[Dynamic.Mission.LIFT, Aircraft.Wing.AREA] = q * CL + J[Dynamic.Vehicle.LIFT, "CL"] = q * wing_area + J[Dynamic.Vehicle.LIFT, Dynamic.Atmosphere.DYNAMIC_PRESSURE] = CL * wing_area + J[Dynamic.Vehicle.LIFT, Aircraft.Wing.AREA] = q * CL - J[Dynamic.Mission.DRAG, "CD"] = q * wing_area - J[Dynamic.Mission.DRAG, Dynamic.Mission.DYNAMIC_PRESSURE] = CD * wing_area - J[Dynamic.Mission.DRAG, Aircraft.Wing.AREA] = q * CD + J[Dynamic.Vehicle.DRAG, "CD"] = q * wing_area + J[Dynamic.Vehicle.DRAG, Dynamic.Atmosphere.DYNAMIC_PRESSURE] = CD * wing_area + J[Dynamic.Vehicle.DRAG, Aircraft.Wing.AREA] = q * CD class CLFromLift(om.ExplicitComponent): @@ -62,8 +73,13 @@ def initialize(self): def setup(self): nn = self.options["num_nodes"] self.add_input("lift_req", 1, units="lbf", shape=nn, desc="Lift force") - self.add_input(Dynamic.Mission.DYNAMIC_PRESSURE, 1.0, - units="psf", shape=nn, desc="Dynamic pressure") + self.add_input( + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + 1.0, + units="psf", + shape=nn, + desc="Dynamic pressure", + ) add_aviary_input(self, Aircraft.Wing.AREA, val=1370.3) @@ -72,7 +88,8 @@ def setup(self): def setup_partials(self): ar = np.arange(self.options["num_nodes"]) self.declare_partials( - "CL", ["lift_req", Dynamic.Mission.DYNAMIC_PRESSURE], rows=ar, cols=ar) + "CL", ["lift_req", Dynamic.Atmosphere.DYNAMIC_PRESSURE], rows=ar, cols=ar + ) self.declare_partials("CL", [Aircraft.Wing.AREA]) def compute(self, inputs, outputs): @@ -82,7 +99,7 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): lift_req, q, wing_area = inputs.values() J["CL", "lift_req"] = 1 / (q * wing_area) - J["CL", Dynamic.Mission.DYNAMIC_PRESSURE] = -lift_req / (q**2 * wing_area) + J["CL", Dynamic.Atmosphere.DYNAMIC_PRESSURE] = -lift_req / (q**2 * wing_area) J["CL", Aircraft.Wing.AREA] = -lift_req / (q * wing_area**2) diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/Cl_max.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/Cl_max.py index e9e174aed..81e8b1f38 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/Cl_max.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/Cl_max.py @@ -21,7 +21,7 @@ def setup(self): desc="VLAM8: sensitivity of flap clean wing maximum lift coefficient to wing sweep angle", ) self.add_input( - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.SPEED_OF_SOUND, val=1118.21948771, units="ft/s", desc="SA: speed of sound at sea level", @@ -72,10 +72,16 @@ def setup(self): desc="VLAM7: sensitivity of flap clean wing maximum lift coefficient to wing flap span", ) self.add_input( - "VLAM13", val=1.03512, units='unitless', desc="VLAM13: reynolds number correction factor" + "VLAM13", + val=1.03512, + units='unitless', + desc="VLAM13: reynolds number correction factor", ) self.add_input( - "VLAM14", val=0.99124, units='unitless', desc="VLAM14: mach number correction factor " + "VLAM14", + val=0.99124, + units='unitless', + desc="VLAM14: mach number correction factor ", ) # other inputs @@ -83,7 +89,10 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.LOADING, val=128) self.add_input( - Dynamic.Mission.STATIC_PRESSURE, val=(14.696 * 144), units="lbf/ft**2", desc="P0: static pressure" + Dynamic.Atmosphere.STATIC_PRESSURE, + val=(14.696 * 144), + units="lbf/ft**2", + desc="P0: static pressure", ) add_aviary_input(self, Aircraft.Wing.AVERAGE_CHORD, val=12.61) @@ -114,16 +123,20 @@ def setup(self): units='unitless', desc="VLAM12: sensitivity of slat clean wing maximum lift coefficient to leading edge sweepback", ) - self.add_input("fus_lift", val=0.05498, units='unitless', - desc="DELCLF: fuselage lift increment") self.add_input( - Dynamic.Mission.KINEMATIC_VISCOSITY, + "fus_lift", + val=0.05498, + units='unitless', + desc="DELCLF: fuselage lift increment", + ) + self.add_input( + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, val=0.15723e-03, units="ft**2/s", desc="XKV: kinematic viscosity", ) self.add_input( - Dynamic.Mission.TEMPERATURE, + Dynamic.Atmosphere.TEMPERATURE, val=518.67, units="degR", desc="T0: static temperature of air cross wing", @@ -131,12 +144,21 @@ def setup(self): # outputs - self.add_output("CL_max", val=2.8155, - desc="CLMAX: maximum lift coefficient", units="unitless") - self.add_output(Dynamic.Mission.MACH, val=0.17522, - units='unitless', desc="SMN: mach number") - self.add_output("reynolds", val=157.1111, units='unitless', - desc="RNW: reynolds number") + self.add_output( + "CL_max", + val=2.8155, + desc="CLMAX: maximum lift coefficient", + units="unitless", + ) + self.add_output( + Dynamic.Atmosphere.MACH, + val=0.17522, + units='unitless', + desc="SMN: mach number", + ) + self.add_output( + "reynolds", val=157.1111, units='unitless', desc="RNW: reynolds number" + ) def setup_partials(self): @@ -167,10 +189,10 @@ def setup_partials(self): step=1e-8, ) self.declare_partials( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, [ Aircraft.Wing.LOADING, - Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Atmosphere.STATIC_PRESSURE, Aircraft.Wing.MAX_LIFT_REF, "VLAM1", "VLAM2", @@ -197,10 +219,10 @@ def setup_partials(self): self.declare_partials( "reynolds", [ - Dynamic.Mission.KINEMATIC_VISCOSITY, - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, Aircraft.Wing.AVERAGE_CHORD, - Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Atmosphere.STATIC_PRESSURE, Aircraft.Wing.LOADING, Aircraft.Wing.MAX_LIFT_REF, "VLAM1", @@ -243,11 +265,11 @@ def compute(self, inputs, outputs): VLAM13 = inputs["VLAM13"] VLAM14 = inputs["VLAM14"] - sos = inputs[Dynamic.Mission.SPEED_OF_SOUND] + sos = inputs[Dynamic.Atmosphere.SPEED_OF_SOUND] wing_loading = inputs[Aircraft.Wing.LOADING] - P = inputs[Dynamic.Mission.STATIC_PRESSURE] + P = inputs[Dynamic.Atmosphere.STATIC_PRESSURE] avg_chord = inputs[Aircraft.Wing.AVERAGE_CHORD] - kinematic_viscosity = inputs[Dynamic.Mission.KINEMATIC_VISCOSITY] + kinematic_viscosity = inputs[Dynamic.Atmosphere.KINEMATIC_VISCOSITY] max_lift_reference = inputs[Aircraft.Wing.MAX_LIFT_REF] leading_lift_increment = inputs[Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM] fus_lift = inputs["fus_lift"] @@ -263,7 +285,7 @@ def compute(self, inputs, outputs): Q1 = wing_loading / CL_max - outputs[Dynamic.Mission.MACH] = mach = (Q1 / 0.7 / P) ** 0.5 + outputs[Dynamic.Atmosphere.MACH] = mach = (Q1 / 0.7 / P) ** 0.5 VK = mach * sos outputs["reynolds"] = reynolds = (avg_chord * VK / kinematic_viscosity) / 100000 diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/flaps_model.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/flaps_model.py index 3a4d9ad7d..3dc28dc5f 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/flaps_model.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/flaps_model.py @@ -1,16 +1,20 @@ import openmdao.api as om -from aviary.subsystems.aerodynamics.gasp_based.flaps_model.basic_calculations import \ - BasicFlapsCalculations -from aviary.subsystems.aerodynamics.gasp_based.flaps_model.Cl_max import \ - CLmaxCalculation -from aviary.subsystems.aerodynamics.gasp_based.flaps_model.L_and_D_increments import \ - LiftAndDragIncrements -from aviary.subsystems.aerodynamics.gasp_based.flaps_model.meta_model import \ - MetaModelGroup -from aviary.utils.aviary_values import AviaryValues +from aviary.subsystems.aerodynamics.gasp_based.flaps_model.basic_calculations import ( + BasicFlapsCalculations, +) +from aviary.subsystems.aerodynamics.gasp_based.flaps_model.Cl_max import ( + CLmaxCalculation, +) +from aviary.subsystems.aerodynamics.gasp_based.flaps_model.L_and_D_increments import ( + LiftAndDragIncrements, +) +from aviary.subsystems.aerodynamics.gasp_based.flaps_model.meta_model import ( + MetaModelGroup, +) from aviary.variable_info.enums import FlapType from aviary.variable_info.variables import Aircraft, Dynamic +from aviary.variable_info.functions import add_aviary_option class FlapsGroup(om.Group): @@ -21,10 +25,7 @@ class FlapsGroup(om.Group): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.FLAP_TYPE) # optimum trailing edge flap deflection angle defaults (ADELTO table in GASP) self.optimum_flap_defls = { @@ -39,8 +40,6 @@ def initialize(self): def setup(self): - aviary_options = self.options['aviary_options'] - self.add_subsystem( "BasicFlapsCalculations", BasicFlapsCalculations(), @@ -56,9 +55,9 @@ def setup(self): "CLmaxCalculation", CLmaxCalculation(), promotes_inputs=[ - Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.STATIC_PRESSURE, - Dynamic.Mission.KINEMATIC_VISCOSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.STATIC_PRESSURE, + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, "VLAM1", "VLAM2", "VLAM3", @@ -74,21 +73,21 @@ def setup(self): "VLAM13", "VLAM14", "fus_lift", - Dynamic.Mission.TEMPERATURE, + Dynamic.Atmosphere.TEMPERATURE, ] + ["aircraft:*"], - promotes_outputs=["CL_max", Dynamic.Mission.MACH, "reynolds"], + promotes_outputs=["CL_max", Dynamic.Atmosphere.MACH, "reynolds"], ) self.add_subsystem( "LookupTables", - MetaModelGroup(aviary_options=aviary_options), + MetaModelGroup(), promotes_inputs=[ "flap_defl_ratio", "flap_defl", "slat_defl_ratio", "reynolds", - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, "body_to_span_ratio", "chord_to_body_ratio", ] @@ -146,7 +145,6 @@ def setup(self): # set default trailing edge deflection angle per GASP self.set_input_defaults( Aircraft.Wing.OPTIMUM_FLAP_DEFLECTION, - self.optimum_flap_defls[self.options["aviary_options"].get_val( - Aircraft.Wing.FLAP_TYPE, units='unitless')], + self.optimum_flap_defls[self.options[Aircraft.Wing.FLAP_TYPE]], units="deg", ) diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/meta_model.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/meta_model.py index 5c9e00b4c..484fa8d96 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/meta_model.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/meta_model.py @@ -1,8 +1,8 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import FlapType +from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft, Dynamic @@ -13,15 +13,11 @@ class MetaModelGroup(om.Group): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.FLAP_TYPE) def setup(self): - flap_type = self.options["aviary_options"].get_val( - Aircraft.Wing.FLAP_TYPE, units='unitless') + flap_type = self.options[Aircraft.Wing.FLAP_TYPE] # VDEL1 VDEL1_interp = self.add_subsystem( @@ -782,7 +778,7 @@ def setup(self): "VLAM14_interp", om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, ], promotes_outputs=[ "VLAM14", @@ -790,7 +786,7 @@ def setup(self): ) VLAM14_interp.add_input( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, 0.17522, training_data=[0.0, 0.2, 0.4, 0.6, 0.8, 1.0], units="unitless", diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_Clmax.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_Clmax.py index fbc47559b..f95c1148d 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_Clmax.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_Clmax.py @@ -39,18 +39,22 @@ def setUp(self): self.prob.set_val("VLAM13", 1.03512) self.prob.set_val("VLAM14", 0.99124) - self.prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, 1118.21948771, units="ft/s") # + self.prob.set_val( + Dynamic.Atmosphere.SPEED_OF_SOUND, 1118.21948771, units="ft/s" + ) # self.prob.set_val(Aircraft.Wing.LOADING, 128.0, units="lbf/ft**2") - self.prob.set_val(Dynamic.Mission.STATIC_PRESSURE, - (14.696 * 144), units="lbf/ft**2") + self.prob.set_val( + Dynamic.Atmosphere.STATIC_PRESSURE, (14.696 * 144), units="lbf/ft**2" + ) self.prob.set_val(Aircraft.Wing.AVERAGE_CHORD, 12.61, units="ft") - self.prob.set_val(Dynamic.Mission.KINEMATIC_VISCOSITY, - 0.15723e-3, units="ft**2/s") + self.prob.set_val( + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, 0.15723e-3, units="ft**2/s" + ) self.prob.set_val(Aircraft.Wing.MAX_LIFT_REF, 1.150) self.prob.set_val(Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM, 0.930) self.prob.set_val("fus_lift", 0.05498) self.prob.set_val(Aircraft.Wing.FLAP_LIFT_INCREMENT_OPTIMUM, 1.500) - self.prob.set_val(Dynamic.Mission.TEMPERATURE, 518.7, units="degR") + self.prob.set_val(Dynamic.Atmosphere.TEMPERATURE, 518.7, units="degR") def test_case(self): @@ -63,7 +67,7 @@ def test_case(self): assert_near_equal(ans, reg_data, tol) reg_data = 0.17522 - ans = self.prob[Dynamic.Mission.MACH] + ans = self.prob[Dynamic.Atmosphere.MACH] assert_near_equal(ans, reg_data, tol) reg_data = 157.19864 diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_flaps_group.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_flaps_group.py index b7b78faed..ef008d9eb 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_flaps_group.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_flaps_group.py @@ -5,6 +5,7 @@ from aviary.subsystems.aerodynamics.gasp_based.flaps_model.flaps_model import \ FlapsGroup +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.enums import FlapType from aviary.variable_info.variables import Aircraft, Dynamic @@ -23,12 +24,14 @@ def setUp(self): options.set_val(Aircraft.Wing.FLAP_TYPE, val=FlapType.TRIPLE_SLOTTED, units='unitless') - self.prob.model = FCC = FlapsGroup(aviary_options=options) + self.prob.model = FCC = FlapsGroup() + + setup_model_options(self.prob, options) self.prob.setup() self.prob.set_val(Aircraft.Wing.SWEEP, 25.0, units="deg") - self.prob.set_val(Dynamic.Mission.TEMPERATURE, 518.67, units="degR") + self.prob.set_val(Dynamic.Atmosphere.TEMPERATURE, 518.67, units="degR") self.prob.set_val(Aircraft.Wing.ASPECT_RATIO, 10.13) self.prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, 0.3) self.prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.33) @@ -64,13 +67,17 @@ def setUp(self): self.prob.set_val("VDEL4", 0.93578) self.prob.set_val("VDEL5", 0.90761) - self.prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, 1118.21948771, units="ft/s") + self.prob.set_val( + Dynamic.Atmosphere.SPEED_OF_SOUND, 1118.21948771, units="ft/s" + ) self.prob.set_val(Aircraft.Wing.LOADING, 128.0, units="lbf/ft**2") - self.prob.set_val(Dynamic.Mission.STATIC_PRESSURE, - (14.696 * 144), units="lbf/ft**2") + self.prob.set_val( + Dynamic.Atmosphere.STATIC_PRESSURE, (14.696 * 144), units="lbf/ft**2" + ) self.prob.set_val(Aircraft.Wing.AVERAGE_CHORD, 12.61, units="ft") - self.prob.set_val(Dynamic.Mission.KINEMATIC_VISCOSITY, - 0.15723e-3, units="ft**2/s") + self.prob.set_val( + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, 0.15723e-3, units="ft**2/s" + ) self.prob.set_val(Aircraft.Wing.MAX_LIFT_REF, 1.150) self.prob.set_val(Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM, 0.930) self.prob.set_val("fus_lift", 0.05498) @@ -97,7 +104,7 @@ def test_case(self): assert_near_equal(ans, reg_data, tol) reg_data = 0.17522 - ans = self.prob[Dynamic.Mission.MACH] + ans = self.prob[Dynamic.Atmosphere.MACH] assert_near_equal(ans, reg_data, tol) reg_data = 157.1111 @@ -126,12 +133,14 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Wing.FLAP_TYPE, val=FlapType.SPLIT, units='unitless') - self.prob.model = FCC = FlapsGroup(aviary_options=options) + self.prob.model = FCC = FlapsGroup() + + setup_model_options(self.prob, options) self.prob.setup() self.prob.set_val(Aircraft.Wing.SWEEP, 25.0, units="deg") - self.prob.set_val(Dynamic.Mission.TEMPERATURE, 518.67, units="degR") + self.prob.set_val(Dynamic.Atmosphere.TEMPERATURE, 518.67, units="degR") self.prob.set_val(Aircraft.Wing.ASPECT_RATIO, 10.13) self.prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, 0.3) self.prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.33) @@ -167,13 +176,17 @@ def setUp(self): self.prob.set_val("VDEL4", 0.93578) self.prob.set_val("VDEL5", 0.90761) - self.prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, 1118.21948771, units="ft/s") + self.prob.set_val( + Dynamic.Atmosphere.SPEED_OF_SOUND, 1118.21948771, units="ft/s" + ) self.prob.set_val(Aircraft.Wing.LOADING, 128.0, units="lbf/ft**2") - self.prob.set_val(Dynamic.Mission.STATIC_PRESSURE, - (14.696 * 144), units="lbf/ft**2") + self.prob.set_val( + Dynamic.Atmosphere.STATIC_PRESSURE, (14.696 * 144), units="lbf/ft**2" + ) self.prob.set_val(Aircraft.Wing.AVERAGE_CHORD, 12.61, units="ft") - self.prob.set_val(Dynamic.Mission.KINEMATIC_VISCOSITY, - 0.15723e-3, units="ft**2/s") + self.prob.set_val( + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, 0.15723e-3, units="ft**2/s" + ) self.prob.set_val(Aircraft.Wing.MAX_LIFT_REF, 1.150) self.prob.set_val(Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM, 0.930) self.prob.set_val("fus_lift", 0.05498) @@ -200,7 +213,7 @@ def test_case(self): assert_near_equal(ans, reg_data, tol) reg_data = 0.18368 - ans = self.prob[Dynamic.Mission.MACH] + ans = self.prob[Dynamic.Atmosphere.MACH] assert_near_equal(ans, reg_data, tol) reg_data = 164.78406 @@ -230,12 +243,14 @@ def setUp(self): options.set_val(Aircraft.Wing.FLAP_TYPE, val=FlapType.SINGLE_SLOTTED, units='unitless') - self.prob.model = FCC = FlapsGroup(aviary_options=options) + self.prob.model = FCC = FlapsGroup() + + setup_model_options(self.prob, options) self.prob.setup() self.prob.set_val(Aircraft.Wing.SWEEP, 25.0, units="deg") - self.prob.set_val(Dynamic.Mission.TEMPERATURE, 518.67, units="degR") + self.prob.set_val(Dynamic.Atmosphere.TEMPERATURE, 518.67, units="degR") self.prob.set_val(Aircraft.Wing.ASPECT_RATIO, 10.13) self.prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, 0.3) self.prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.33) @@ -272,13 +287,17 @@ def setUp(self): self.prob.set_val("VDEL4", 0.93578) self.prob.set_val("VDEL5", 0.90761) - self.prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, 1118.21948771, units="ft/s") + self.prob.set_val( + Dynamic.Atmosphere.SPEED_OF_SOUND, 1118.21948771, units="ft/s" + ) self.prob.set_val(Aircraft.Wing.LOADING, 128.0, units="lbf/ft**2") - self.prob.set_val(Dynamic.Mission.STATIC_PRESSURE, - (14.696 * 144), units="lbf/ft**2") + self.prob.set_val( + Dynamic.Atmosphere.STATIC_PRESSURE, (14.696 * 144), units="lbf/ft**2" + ) self.prob.set_val(Aircraft.Wing.AVERAGE_CHORD, 12.61, units="ft") - self.prob.set_val(Dynamic.Mission.KINEMATIC_VISCOSITY, - 0.15723e-3, units="ft**2/s") + self.prob.set_val( + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, 0.15723e-3, units="ft**2/s" + ) self.prob.set_val(Aircraft.Wing.MAX_LIFT_REF, 1.150) self.prob.set_val(Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM, 0.930) self.prob.set_val("fus_lift", 0.05498) @@ -305,7 +324,7 @@ def test_case(self): assert_near_equal(ans, reg_data, tol) reg_data = 0.17522 - ans = self.prob[Dynamic.Mission.MACH] + ans = self.prob[Dynamic.Atmosphere.MACH] assert_near_equal(ans, reg_data, tol) reg_data = 157.1111 @@ -334,12 +353,14 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Wing.FLAP_TYPE, val=FlapType.PLAIN, units='unitless') - self.prob.model = FCC = FlapsGroup(aviary_options=options) + self.prob.model = FCC = FlapsGroup() + + setup_model_options(self.prob, options) self.prob.setup() self.prob.set_val(Aircraft.Wing.SWEEP, 25.0, units="deg") - self.prob.set_val(Dynamic.Mission.TEMPERATURE, 518.67, units="degR") + self.prob.set_val(Dynamic.Atmosphere.TEMPERATURE, 518.67, units="degR") self.prob.set_val(Aircraft.Wing.ASPECT_RATIO, 10.13) self.prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, 0.3) self.prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.33) @@ -375,13 +396,17 @@ def setUp(self): self.prob.set_val("VDEL4", 0.93578) self.prob.set_val("VDEL5", 0.90761) - self.prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, 1118.21948771, units="ft/s") + self.prob.set_val( + Dynamic.Atmosphere.SPEED_OF_SOUND, 1118.21948771, units="ft/s" + ) self.prob.set_val(Aircraft.Wing.LOADING, 128.0, units="lbf/ft**2") - self.prob.set_val(Dynamic.Mission.STATIC_PRESSURE, - (14.696 * 144), units="lbf/ft**2") + self.prob.set_val( + Dynamic.Atmosphere.STATIC_PRESSURE, (14.696 * 144), units="lbf/ft**2" + ) self.prob.set_val(Aircraft.Wing.AVERAGE_CHORD, 12.61, units="ft") - self.prob.set_val(Dynamic.Mission.KINEMATIC_VISCOSITY, - 0.15723e-3, units="ft**2/s") + self.prob.set_val( + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, 0.15723e-3, units="ft**2/s" + ) self.prob.set_val(Aircraft.Wing.MAX_LIFT_REF, 1.150) self.prob.set_val(Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM, 0.930) self.prob.set_val("fus_lift", 0.05498) @@ -408,7 +433,7 @@ def test_case(self): assert_near_equal(ans, reg_data, tol) reg_data = 0.18368 - ans = self.prob[Dynamic.Mission.MACH] + ans = self.prob[Dynamic.Atmosphere.MACH] assert_near_equal(ans, reg_data, tol) reg_data = 164.78406 @@ -437,12 +462,14 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Wing.FLAP_TYPE, val=FlapType.FOWLER, units='unitless') - self.prob.model = FCC = FlapsGroup(aviary_options=options) + self.prob.model = FCC = FlapsGroup() + + setup_model_options(self.prob, options) self.prob.setup() self.prob.set_val(Aircraft.Wing.SWEEP, 25.0, units="deg") - self.prob.set_val(Dynamic.Mission.TEMPERATURE, 518.67, units="degR") + self.prob.set_val(Dynamic.Atmosphere.TEMPERATURE, 518.67, units="degR") self.prob.set_val(Aircraft.Wing.ASPECT_RATIO, 10.13) self.prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, 0.3) self.prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.33) @@ -478,13 +505,17 @@ def setUp(self): self.prob.set_val("VDEL4", 0.93578) self.prob.set_val("VDEL5", 0.90761) - self.prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, 1118.21948771, units="ft/s") + self.prob.set_val( + Dynamic.Atmosphere.SPEED_OF_SOUND, 1118.21948771, units="ft/s" + ) self.prob.set_val(Aircraft.Wing.LOADING, 128.0, units="lbf/ft**2") - self.prob.set_val(Dynamic.Mission.STATIC_PRESSURE, - (14.696 * 144), units="lbf/ft**2") + self.prob.set_val( + Dynamic.Atmosphere.STATIC_PRESSURE, (14.696 * 144), units="lbf/ft**2" + ) self.prob.set_val(Aircraft.Wing.AVERAGE_CHORD, 12.61, units="ft") - self.prob.set_val(Dynamic.Mission.KINEMATIC_VISCOSITY, - 0.15723e-3, units="ft**2/s") + self.prob.set_val( + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, 0.15723e-3, units="ft**2/s" + ) self.prob.set_val(Aircraft.Wing.MAX_LIFT_REF, 1.150) self.prob.set_val(Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM, 0.930) self.prob.set_val("fus_lift", 0.05498) @@ -511,7 +542,7 @@ def test_case(self): assert_near_equal(ans, reg_data, tol) reg_data = 0.17168 - ans = self.prob[Dynamic.Mission.MACH] + ans = self.prob[Dynamic.Atmosphere.MACH] assert_near_equal(ans, reg_data, tol) reg_data = 154.02686 @@ -541,12 +572,14 @@ def setUp(self): options.set_val(Aircraft.Wing.FLAP_TYPE, val=FlapType.DOUBLE_SLOTTED_FOWLER, units='unitless') - self.prob.model = FCC = FlapsGroup(aviary_options=options) + self.prob.model = FCC = FlapsGroup() + + setup_model_options(self.prob, options) self.prob.setup() self.prob.set_val(Aircraft.Wing.SWEEP, 25.0, units="deg") - self.prob.set_val(Dynamic.Mission.TEMPERATURE, 518.67, units="degR") + self.prob.set_val(Dynamic.Atmosphere.TEMPERATURE, 518.67, units="degR") self.prob.set_val(Aircraft.Wing.ASPECT_RATIO, 10.13) self.prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, 0.3) self.prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.33) @@ -582,13 +615,17 @@ def setUp(self): self.prob.set_val("VDEL4", 0.93578) self.prob.set_val("VDEL5", 0.90761) - self.prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, 1118.21948771, units="ft/s") + self.prob.set_val( + Dynamic.Atmosphere.SPEED_OF_SOUND, 1118.21948771, units="ft/s" + ) self.prob.set_val(Aircraft.Wing.LOADING, 128.0, units="lbf/ft**2") - self.prob.set_val(Dynamic.Mission.STATIC_PRESSURE, - (14.696 * 144), units="lbf/ft**2") + self.prob.set_val( + Dynamic.Atmosphere.STATIC_PRESSURE, (14.696 * 144), units="lbf/ft**2" + ) self.prob.set_val(Aircraft.Wing.AVERAGE_CHORD, 12.61, units="ft") - self.prob.set_val(Dynamic.Mission.KINEMATIC_VISCOSITY, - 0.15723e-3, units="ft**2/s") + self.prob.set_val( + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, 0.15723e-3, units="ft**2/s" + ) self.prob.set_val(Aircraft.Wing.MAX_LIFT_REF, 1.150) self.prob.set_val(Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM, 0.930) self.prob.set_val("fus_lift", 0.05498) @@ -615,7 +652,7 @@ def test_case(self): assert_near_equal(ans, reg_data, tol) reg_data = 0.17168 - ans = self.prob[Dynamic.Mission.MACH] + ans = self.prob[Dynamic.Atmosphere.MACH] assert_near_equal(ans, reg_data, tol) reg_data = 154.02686 diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_metamodel.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_metamodel.py index 84581a8ea..cb0f903ec 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_metamodel.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_metamodel.py @@ -20,9 +20,10 @@ class MetaModelTestCasePlain(unittest.TestCase): def setUp(self): self.prob = om.Problem() - options = get_option_defaults() - options.set_val(Aircraft.Wing.FLAP_TYPE, val=FlapType.PLAIN, units='unitless') - self.prob.model = LuTMMa = MetaModelGroup(aviary_options=options) + options = { + Aircraft.Wing.FLAP_TYPE: FlapType.PLAIN, + } + self.prob.model = LuTMMa = MetaModelGroup(**options) self.prob.setup() self.prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, 0.3) @@ -34,7 +35,7 @@ def setUp(self): self.prob.set_val("slat_defl_ratio", 10 / 20) self.prob.set_val(Aircraft.Wing.SLAT_SPAN_RATIO, 0.89761) self.prob.set_val("reynolds", 164.78406) - self.prob.set_val(Dynamic.Mission.MACH, 0.18368) + self.prob.set_val(Dynamic.Atmosphere.MACH, 0.18368) self.prob.set_val(Aircraft.Wing.TAPER_RATIO, 0.33) self.prob.set_val(Aircraft.Wing.SLAT_SPAN_RATIO, 0.89761) self.prob.set_val("body_to_span_ratio", 0.09239) @@ -113,10 +114,10 @@ class MetaModelTestCaseSingleSlotted(unittest.TestCase): def setUp(self): self.prob = om.Problem() - options = get_option_defaults() - options.set_val(Aircraft.Wing.FLAP_TYPE, - val=FlapType.SINGLE_SLOTTED, units='unitless') - self.prob.model = LuTMMb = MetaModelGroup(aviary_options=options) + options = { + Aircraft.Wing.FLAP_TYPE: FlapType.SINGLE_SLOTTED, + } + self.prob.model = LuTMMb = MetaModelGroup(**options) self.prob.setup() self.prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, 0.3) @@ -152,9 +153,10 @@ class MetaModelTestCaseFowler(unittest.TestCase): def setUp(self): self.prob = om.Problem() - options = get_option_defaults() - options.set_val(Aircraft.Wing.FLAP_TYPE, val=FlapType.FOWLER, units='unitless') - self.prob.model = LuTMMc = MetaModelGroup(aviary_options=options) + options = { + Aircraft.Wing.FLAP_TYPE: FlapType.FOWLER, + } + self.prob.model = LuTMMc = MetaModelGroup(**options) self.prob.setup() self.prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, 0.3) diff --git a/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py b/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py index abb839cbe..cd45e5a5c 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py +++ b/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py @@ -5,14 +5,13 @@ from openmdao.utils import cs_safe as cs from aviary.constants import GRAV_ENGLISH_LBM -from aviary.subsystems.aerodynamics.gasp_based.common import (AeroForces, - CLFromLift, - TanhRampComp) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input +from aviary.subsystems.aerodynamics.gasp_based.common import ( + AeroForces, + CLFromLift, + TanhRampComp, +) +from aviary.variable_info.functions import add_aviary_input, add_aviary_option from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.utils.aviary_values import AviaryValues -from aviary.subsystems.aerodynamics.gasp_based.interference import WingFuselageInterferenceMission # @@ -181,14 +180,20 @@ def setup(self): add_aviary_input(self, Aircraft.Fuselage.AVG_DIAMETER, val=0.0) self.add_output( - "hbar", val=0.0, units="unitless", - desc="HBAR: Ratio of HGAP(?) to wing span") + "hbar", + val=0.0, + units="unitless", + desc="HBAR: Ratio of HGAP(?) to wing span", + ) self.add_output( - "bbar", units="unitless", desc="BBAR: Ratio of H tail area to wing area") + "bbar", units="unitless", desc="BBAR: Ratio of H tail area to wing area" + ) self.add_output( - "sbar", units="unitless", desc="SBAR: Ratio of H tail area to wing area") + "sbar", units="unitless", desc="SBAR: Ratio of H tail area to wing area" + ) self.add_output( - "cbar", units="unitless", desc="SBAR: Ratio of H tail chord to wing chord") + "cbar", units="unitless", desc="SBAR: Ratio of H tail chord to wing chord" + ) def setup_partials(self): self.declare_partials( @@ -253,8 +258,13 @@ def setup(self): nn = self.options["num_nodes"] # mission inputs - self.add_input(Dynamic.Mission.MACH, val=0.0, units="unitless", - shape=nn, desc="Mach number") + self.add_input( + Dynamic.Atmosphere.MACH, + val=0.0, + units="unitless", + shape=nn, + desc="Mach number", + ) # stability inputs @@ -276,24 +286,30 @@ def setup(self): # geometry from wing-tail ratios self.add_input( - "sbar", units="unitless", desc="SBAR: Ratio of H tail area to wing area") + "sbar", units="unitless", desc="SBAR: Ratio of H tail area to wing area" + ) self.add_input( - "cbar", units="unitless", desc="CBAR: Ratio of H tail chord to wing chord") + "cbar", units="unitless", desc="CBAR: Ratio of H tail chord to wing chord" + ) self.add_input( - "hbar", units="unitless", desc="HBAR: Ratio of HGAP(?) to wing span") + "hbar", units="unitless", desc="HBAR: Ratio of HGAP(?) to wing span" + ) self.add_input( - "bbar", units="unitless", desc="BBAR: Ratio of H tail area to wing area") + "bbar", units="unitless", desc="BBAR: Ratio of H tail area to wing area" + ) - self.add_output("lift_curve_slope", units="unitless", - shape=nn, desc="Lift-curve slope") + self.add_output( + "lift_curve_slope", units="unitless", shape=nn, desc="Lift-curve slope" + ) self.add_output("lift_ratio", units="unitless", shape=nn, desc="Lift ratio") def setup_partials(self): ar = np.arange(self.options["num_nodes"]) self.declare_partials("lift_ratio", "*", method="cs") - self.declare_partials("lift_ratio", Dynamic.Mission.MACH, - rows=ar, cols=ar, method="cs") + self.declare_partials( + "lift_ratio", Dynamic.Atmosphere.MACH, rows=ar, cols=ar, method="cs" + ) self.declare_partials("lift_curve_slope", "*", method="cs") self.declare_partials( "lift_curve_slope", @@ -310,8 +326,9 @@ def setup_partials(self): ], method="cs", ) - self.declare_partials("lift_curve_slope", Dynamic.Mission.MACH, - rows=ar, cols=ar, method="cs") + self.declare_partials( + "lift_curve_slope", Dynamic.Atmosphere.MACH, rows=ar, cols=ar, method="cs" + ) def compute(self, inputs, outputs): ( @@ -346,9 +363,7 @@ def compute(self, inputs, outputs): eps2 = 1 / np.pi / AR eps3 = cs.abs(xt) / (np.pi * AR * np.sqrt(xt**2 + h**2 + AR**2 / 4)) eps4 = 1 / np.pi / art - eps5 = cs.abs(xt) / ( - np.pi * art * np.sqrt(xt**2 + h**2 + art**2 * cbar**2 / 4) - ) + eps5 = cs.abs(xt) / (np.pi * art * np.sqrt(xt**2 + h**2 + art**2 * cbar**2 / 4)) claw = ( claw0 @@ -375,27 +390,29 @@ class AeroGeom(om.ExplicitComponent): def initialize(self): self.options.declare("num_nodes", default=1, types=int) - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Wing.HAS_STRUT) def setup(self): nn = self.options["num_nodes"] - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) self.add_input( - Dynamic.Mission.MACH, val=0.0, units="unitless", shape=nn, desc="Current Mach number") + Dynamic.Atmosphere.MACH, + val=0.0, + units="unitless", + shape=nn, + desc="Current Mach number", + ) self.add_input( - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.SPEED_OF_SOUND, val=1.0, units="ft/s", shape=nn, desc="Speed of sound at current altitude", ) self.add_input( - Dynamic.Mission.KINEMATIC_VISCOSITY, + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, val=1.0, units="ft**2/s", shape=nn, @@ -411,8 +428,9 @@ def setup(self): add_aviary_input(self, Aircraft.Fuselage.FORM_FACTOR, val=1.25) - add_aviary_input(self, Aircraft.Nacelle.FORM_FACTOR, - val=np.full(num_engine_type, 1.5)) + add_aviary_input( + self, Aircraft.Nacelle.FORM_FACTOR, val=np.full(num_engine_type, 1.5) + ) add_aviary_input(self, Aircraft.VerticalTail.FORM_FACTOR, val=1.25) @@ -454,15 +472,17 @@ def setup(self): add_aviary_input(self, Aircraft.Fuselage.LENGTH, val=0.0) - add_aviary_input(self, Aircraft.Nacelle.AVG_LENGTH, - val=np.zeros(num_engine_type)) + add_aviary_input( + self, Aircraft.Nacelle.AVG_LENGTH, val=np.zeros(num_engine_type) + ) add_aviary_input(self, Aircraft.HorizontalTail.AREA, val=0.0) add_aviary_input(self, Aircraft.Fuselage.WETTED_AREA, val=0.0) - add_aviary_input(self, Aircraft.Nacelle.SURFACE_AREA, - val=np.zeros(num_engine_type)) + add_aviary_input( + self, Aircraft.Nacelle.SURFACE_AREA, val=np.zeros(num_engine_type) + ) add_aviary_input(self, Aircraft.Wing.AREA, val=1370.3) @@ -479,12 +499,16 @@ def setup(self): # outputs for i in range(7): - name = f"SA{i+1}" - self.add_output(name, units="unitless", shape=nn, desc=f"{name}: Drag param") + name = f"SA{i + 1}" + self.add_output( + name, units="unitless", shape=nn, desc=f"{name}: Drag param" + ) self.add_output( - "cf", units="unitless", shape=nn, - desc="CFIN: Skin friction coefficient at Re=1e7" + "cf", + units="unitless", + shape=nn, + desc="CFIN: Skin friction coefficient at Re=1e7", ) def setup_partials(self): @@ -528,21 +552,44 @@ def setup_partials(self): self.declare_partials( "SA4", [Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED], method="cs" ) - self.declare_partials("cf", [Dynamic.Mission.MACH], - rows=ar, cols=ar, method="cs") + self.declare_partials( + "cf", [Dynamic.Atmosphere.MACH], rows=ar, cols=ar, method="cs" + ) # diag partials for SA5-SA7 self.declare_partials( - "SA5", [Dynamic.Mission.MACH, Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.KINEMATIC_VISCOSITY], rows=ar, cols=ar, method="cs" + "SA5", + [ + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, + ], + rows=ar, + cols=ar, + method="cs", ) self.declare_partials( - "SA6", [Dynamic.Mission.MACH, Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.KINEMATIC_VISCOSITY], rows=ar, cols=ar, method="cs" + "SA6", + [ + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, + ], + rows=ar, + cols=ar, + method="cs", ) self.declare_partials( - "SA7", [Dynamic.Mission.MACH, Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.KINEMATIC_VISCOSITY, "ufac"], rows=ar, cols=ar, method="cs" + "SA7", + [ + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, + "ufac", + ], + rows=ar, + cols=ar, + method="cs", ) # dense partials for SA5-SA7 @@ -663,8 +710,7 @@ def compute(self, inputs, outputs): fnre[good_mask] = (np.log10(reli[good_mask] * nac_len) / 7) ** -2.6 fvtre[good_mask] = (np.log10(reli[good_mask] * vtail_chord) / 7) ** -2.6 fhtre[good_mask] = (np.log10(reli[good_mask] * htail_chord) / 7) ** -2.6 - include_strut = self.options["aviary_options"].get_val( - Aircraft.Wing.HAS_STRUT, units='unitless') + include_strut = self.options[Aircraft.Wing.HAS_STRUT] if include_strut: fstrtre = (np.log10(reli[good_mask] * strut_chord) / 7) ** -2.6 @@ -694,13 +740,7 @@ def compute(self, inputs, outputs): fe = few + fef + fevt + feht + fen + feiwf + festrt + cd0_inc * wing_area wfob = cabin_width / wingspan - siwb = ( - 1 - - 0.0088 * wfob - - 1.7364 * wfob**2 - - 2.303 * wfob**3 - + 6.0606 * wfob**4 - ) + siwb = 1 - 0.0088 * wfob - 1.7364 * wfob**2 - 2.303 * wfob**3 + 6.0606 * wfob**4 # wing-free profile drag coefficient cdpo = (fe - few) / wing_area @@ -746,9 +786,6 @@ class AeroSetup(om.Group): def initialize(self): self.options.declare("num_nodes", default=1, types=int) - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') self.options.declare( "input_atmos", default=False, @@ -756,14 +793,9 @@ def initialize(self): desc="Directly input speed of sound and kinematic viscosity instead of " "computing them with an atmospherics component. For testing.", ) - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) def setup(self): nn = self.options["num_nodes"] - aviary_options = self.options['aviary_options'] self.add_subsystem("ratios", WingTailRatios(), promotes=["*"]) self.add_subsystem("xlifts", Xlifts(num_nodes=nn), promotes=["*"]) @@ -777,25 +809,22 @@ def setup(self): self.add_subsystem("interp", interp, promotes=["*"]) self.add_subsystem( - "ufac_calc", - om.ExecComp( + "ufac_calc", om.ExecComp( "ufac=(1 + lift_ratio)**2 / (sigstr*(lift_ratio/bbar)**2 + 2*sigma*lift_ratio/bbar + 1)", lift_ratio={'units': "unitless", "shape": nn}, bbar={'units': "unitless"}, sigma={'units': "unitless"}, sigstr={'units': "unitless"}, ufac={'units': "unitless", "shape": nn}, - has_diag_partials=True - ), - promotes=["*"], - ) + has_diag_partials=True,), + promotes=["*"],) if not self.options["input_atmos"]: # self.add_subsystem( # "atmos", # USatm1976Comp(num_nodes=nn), # promotes_inputs=[("h", Dynamic.Mission.ALTITUDE)], - # promotes_outputs=["rho", Dynamic.Mission.SPEED_OF_SOUND, "viscosity"], + # promotes_outputs=["rho", Dynamic.Atmosphere.SPEED_OF_SOUND, "viscosity"], # ) self.add_subsystem( "kin_visc", @@ -806,12 +835,18 @@ def setup(self): nu={"units": "ft**2/s", "shape": nn}, has_diag_partials=True, ), - promotes=["*", ('rho', Dynamic.Mission.DENSITY), - ('nu', Dynamic.Mission.KINEMATIC_VISCOSITY)], + promotes=[ + "*", + ('rho', Dynamic.Atmosphere.DENSITY), + ('nu', Dynamic.Atmosphere.KINEMATIC_VISCOSITY), + ], ) - self.add_subsystem("geom", AeroGeom( - num_nodes=nn, aviary_options=aviary_options), promotes=["*"]) + self.add_subsystem( + "geom", + AeroGeom(num_nodes=nn), + promotes=["*"] + ) class DragCoef(om.ExplicitComponent): @@ -829,10 +864,16 @@ def setup(self): nn = self.options["num_nodes"] # mission inputs - self.add_input(Dynamic.Mission.ALTITUDE, val=0.0, - units="ft", shape=nn, desc="Altitude") self.add_input( - "CL", val=1.0, units="unitless", shape=nn, desc="Lift coefficient") + Dynamic.Mission.ALTITUDE, + val=0.0, + units="ft", + shape=nn, + desc="Altitude", + ) + self.add_input( + "CL", val=1.0, units="unitless", shape=nn, desc="Lift coefficient" + ) # user inputs @@ -850,19 +891,27 @@ def setup(self): # from flaps self.add_input( - "dCL_flaps_model", val=0.0, units="unitless", - desc="Delta CL from flaps model") + "dCL_flaps_model", + val=0.0, + units="unitless", + desc="Delta CL from flaps model", + ) self.add_input( - "dCD_flaps_model", val=0.0, units="unitless", - desc="Delta CD from flaps model") + "dCD_flaps_model", + val=0.0, + units="unitless", + desc="Delta CD from flaps model", + ) self.add_input( "dCL_flaps_coef", - val=1.0, units="unitless", + val=1.0, + units="unitless", desc="SIGMTO | SIGMLD: Coefficient applied to delta CL from flaps model", ) self.add_input( "CDI_factor", - val=1.0, units="unitless", + val=1.0, + units="unitless", desc="VDEL6T | VDEL6L: Factor applied to induced drag with flaps", ) @@ -876,19 +925,28 @@ def setup(self): # from aero setup self.add_input( - "cf", units="unitless", shape=nn, - desc="CFIN: Skin friction coefficient at Re=1e7") + "cf", + units="unitless", + shape=nn, + desc="CFIN: Skin friction coefficient at Re=1e7", + ) self.add_input("SA5", units="unitless", shape=nn, desc="SA5: Drag param") self.add_input("SA6", units="unitless", shape=nn, desc="SA6: Drag param") self.add_input("SA7", units="unitless", shape=nn, desc="SA7: Drag param") self.add_output("CD_base", units="unitless", shape=nn, desc="Drag coefficient") self.add_output( - "dCD_flaps_full", units="unitless", shape=nn, - desc="CD increment with full flap deflection") + "dCD_flaps_full", + units="unitless", + shape=nn, + desc="CD increment with full flap deflection", + ) self.add_output( - "dCD_gear_full", units="unitless", - shape=nn, desc="CD increment with landing gear down") + "dCD_gear_full", + units="unitless", + shape=nn, + desc="CD increment with landing gear down", + ) def setup_partials(self): # self.declare_coloring(method="cs", show_summary=False) @@ -971,19 +1029,33 @@ def setup(self): nn = self.options["num_nodes"] # mission inputs - self.add_input(Dynamic.Mission.MACH, val=0.0, units="unitless", - shape=nn, desc="Mach number") self.add_input( - "CL", val=1.0, units="unitless", shape=nn, desc="Lift coefficient") + Dynamic.Atmosphere.MACH, + val=0.0, + units="unitless", + shape=nn, + desc="Mach number", + ) + self.add_input( + "CL", val=1.0, units="unitless", shape=nn, desc="Lift coefficient" + ) # user inputs - add_aviary_input(self, Aircraft.Design.SUPERCRITICAL_DIVERGENCE_SHIFT, val=0.033) + add_aviary_input(self, Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR, val=1.0) + add_aviary_input(self, Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, val=1.0) + add_aviary_input( + self, Aircraft.Design.LIFT_DEPENDENT_DRAG_COEFF_FACTOR, val=1.0 + ) + add_aviary_input(self, Aircraft.Design.ZERO_LIFT_DRAG_COEFF_FACTOR, val=1.0) # from aero setup self.add_input( - "cf", units="unitless", shape=nn, - desc="CFIN: Skin friction coefficient at Re=1e7") + "cf", + units="unitless", + shape=nn, + desc="CFIN: Skin friction coefficient at Re=1e7", + ) self.add_input("SA1", units="unitless", shape=nn, desc="SA1: Drag param") self.add_input("SA2", units="unitless", shape=nn, desc="SA2: Drag param") self.add_input("SA5", units="unitless", shape=nn, desc="SA5: Drag param") @@ -997,7 +1069,7 @@ def setup_partials(self): self.declare_partials( "CD", - [Dynamic.Mission.MACH, "CL", "cf", "SA1", "SA2", "SA5", "SA6", "SA7"], + [Dynamic.Atmosphere.MACH, "CL", "cf", "SA1", "SA2", "SA5", "SA6", "SA7"], rows=ar, cols=ar, method="cs", @@ -1007,7 +1079,21 @@ def setup_partials(self): ) def compute(self, inputs, outputs): - mach, CL, div_drag_supercrit, cf, SA1, SA2, SA5, SA6, SA7 = inputs.values() + ( + mach, + CL, + div_drag_supercrit, + subsonic_factor, + supersonic_factor, + lift_factor, + zero_lift_factor, + cf, + SA1, + SA2, + SA5, + SA6, + SA7, + ) = inputs.values() mach_div = SA1 + SA2 * CL + div_drag_supercrit @@ -1023,7 +1109,14 @@ def compute(self, inputs, outputs): # induced drag cdi = SA7 * CL**2 - outputs["CD"] = cd0 + cdi + delcdm + CD = cd0 * zero_lift_factor + cdi * lift_factor + delcdm + + # scale drag + idx_sup = np.where(mach >= 1.0) + CD_scaled = CD * subsonic_factor + CD_scaled[idx_sup] = CD[idx_sup] * supersonic_factor + + outputs["CD"] = CD_scaled class LiftCoeff(om.ExplicitComponent): @@ -1037,10 +1130,16 @@ def setup(self): # mission inputs self.add_input("alpha", val=0.0, units="deg", shape=nn, desc="Angle of attack") - self.add_input(Dynamic.Mission.ALTITUDE, val=0.0, - units="ft", shape=nn, desc="Altitude") - self.add_input("lift_curve_slope", units="unitless", - shape=nn, desc="Lift-curve slope") + self.add_input( + Dynamic.Mission.ALTITUDE, + val=0.0, + units="ft", + shape=nn, + desc="Altitude", + ) + self.add_input( + "lift_curve_slope", units="unitless", shape=nn, desc="Lift-curve slope" + ) self.add_input("lift_ratio", units="unitless", shape=nn, desc="Lift ratio") # user inputs @@ -1065,12 +1164,16 @@ def setup(self): # from flaps self.add_input( - "CL_max_flaps", units="unitless", + "CL_max_flaps", + units="unitless", desc="CLMWTO | CLMWLD: Max lift coefficient from flaps model", ) self.add_input( - "dCL_flaps_model", val=0.0, units="unitless", - desc="Delta CL from flaps model") + "dCL_flaps_model", + val=0.0, + units="unitless", + desc="Delta CL from flaps model", + ) # from sizing @@ -1079,30 +1182,40 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.SPAN, val=0.0) self.add_output( - "CL_base", units="unitless", shape=nn, desc="Base lift coefficient") + "CL_base", units="unitless", shape=nn, desc="Base lift coefficient" + ) self.add_output( - "dCL_flaps_full", units="unitless", shape=nn, - desc="CL increment with full flap deflection" + "dCL_flaps_full", + units="unitless", + shape=nn, + desc="CL increment with full flap deflection", ) self.add_output( "alpha_stall", units="deg", shape=nn, desc="Stall angle of attack" ) self.add_output( - "CL_max", units="unitless", shape=nn, desc="Max lift coefficient") + "CL_max", units="unitless", shape=nn, desc="Max lift coefficient" + ) def setup_partials(self): # self.declare_coloring(method="cs", show_summary=False) self.declare_partials("*", "*", dependent=False) ar = np.arange(self.options["num_nodes"]) - dynvars = ["alpha", Dynamic.Mission.ALTITUDE, "lift_curve_slope", "lift_ratio"] + dynvars = [ + "alpha", + Dynamic.Mission.ALTITUDE, + "lift_curve_slope", + "lift_ratio", + ] self.declare_partials("CL_base", ["*"], method="cs") self.declare_partials("CL_base", dynvars, rows=ar, cols=ar, method="cs") self.declare_partials("dCL_flaps_full", ["dCL_flaps_model"], method="cs") self.declare_partials( - "dCL_flaps_full", ["lift_ratio"], rows=ar, cols=ar, method="cs") + "dCL_flaps_full", ["lift_ratio"], rows=ar, cols=ar, method="cs" + ) self.declare_partials("alpha_stall", ["*"], method="cs") self.declare_partials("alpha_stall", dynvars, rows=ar, cols=ar, method="cs") @@ -1149,13 +1262,14 @@ def compute(self, inputs, outputs): ) kclge = np.clip(kclge, 1.0, None) - outputs["CL_base"] = kclge * lift_curve_slope * \ - deg2rad(alpha - alpha0) * (1 + lift_ratio) + outputs["CL_base"] = ( + kclge * lift_curve_slope * deg2rad(alpha - alpha0) * (1 + lift_ratio) + ) outputs["dCL_flaps_full"] = dCL_flaps_model * (1 + lift_ratio) outputs["alpha_stall"] = ( - rad2deg((CL_max_flaps - dCL_flaps_model) / - (kclge * lift_curve_slope)) + alpha0 + rad2deg((CL_max_flaps - dCL_flaps_model) / (kclge * lift_curve_slope)) + + alpha0 ) outputs["CL_max"] = CL_max_flaps * (1 + lift_ratio) @@ -1180,16 +1294,19 @@ def setup(self): "alpha", val=0.0, units="deg", shape=nn, desc="Angle of attack" ) self.add_input( - "CL", val=1.0, units="unitless", shape=nn, desc="Lift coefficient") + "CL", val=1.0, units="unitless", shape=nn, desc="Lift coefficient" + ) else: self.add_input( "alpha", val=0.0, units="deg", shape=nn, desc="Angle of attack" ) self.add_output( - "CL", val=1.0, units="unitless", shape=nn, desc="Lift coefficient") + "CL", val=1.0, units="unitless", shape=nn, desc="Lift coefficient" + ) - self.add_input("lift_curve_slope", units="unitless", - shape=nn, desc="Lift-curve slope") + self.add_input( + "lift_curve_slope", units="unitless", shape=nn, desc="Lift-curve slope" + ) self.add_input("lift_ratio", units="unitless", shape=nn, desc="Lift ratio") add_aviary_input(self, Aircraft.Wing.ZERO_LIFT_ANGLE, val=-1.2) @@ -1198,7 +1315,8 @@ def setup(self): self.add_output("alpha_stall", shape=nn, desc="Stall angle of attack") self.add_output( - "CL_max", units="unitless", shape=nn, desc="Max lift coefficient") + "CL_max", units="unitless", shape=nn, desc="Max lift coefficient" + ) def setup_partials(self): # self.declare_coloring(method="cs", show_summary=False) @@ -1207,17 +1325,26 @@ def setup_partials(self): if self.options["output_alpha"]: self.declare_partials( - "alpha", ["CL", "lift_ratio", "lift_curve_slope"], rows=ar, cols=ar, method="cs" + "alpha", + ["CL", "lift_ratio", "lift_curve_slope"], + rows=ar, + cols=ar, + method="cs", ) self.declare_partials("alpha", [Aircraft.Wing.ZERO_LIFT_ANGLE], method="cs") else: self.declare_partials( - "CL", ["lift_curve_slope", "alpha", "lift_ratio"], rows=ar, cols=ar, method="cs" + "CL", + ["lift_curve_slope", "alpha", "lift_ratio"], + rows=ar, + cols=ar, + method="cs", ) self.declare_partials("CL", [Aircraft.Wing.ZERO_LIFT_ANGLE], method="cs") self.declare_partials( - "alpha_stall", ["lift_curve_slope"], rows=ar, cols=ar, method="cs") + "alpha_stall", ["lift_curve_slope"], rows=ar, cols=ar, method="cs" + ) self.declare_partials( "alpha_stall", [ @@ -1240,7 +1367,9 @@ def compute(self, inputs, outputs): outputs["alpha"] = rad2deg(clw / lift_curve_slope) + alpha0 else: alpha = inputs["alpha"] - outputs["CL"] = lift_curve_slope * deg2rad(alpha - alpha0) * (1 + lift_ratio) + outputs["CL"] = ( + lift_curve_slope * deg2rad(alpha - alpha0) * (1 + lift_ratio) + ) outputs["alpha_stall"] = rad2deg(CL_max_flaps / lift_curve_slope) + alpha0 outputs["CL_max"] = CL_max_flaps * (1 + lift_ratio) @@ -1251,9 +1380,6 @@ class CruiseAero(om.Group): def initialize(self): self.options.declare("num_nodes", default=1, types=int) - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') self.options.declare( "output_alpha", @@ -1268,18 +1394,15 @@ def initialize(self): desc="Directly input speed of sound and kinematic viscosity instead of " "computing them with an atmospherics component. For testing.", ) - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) def setup(self): nn = self.options["num_nodes"] - aviary_options = self.options["aviary_options"] self.add_subsystem( "aero_setup", - AeroSetup(num_nodes=nn, aviary_options=aviary_options, - input_atmos=self.options["input_atmos"]), + AeroSetup( + num_nodes=nn, + input_atmos=self.options["input_atmos"], + ), promotes=["*"], ) if self.options["output_alpha"]: @@ -1299,9 +1422,6 @@ class LowSpeedAero(om.Group): def initialize(self): self.options.declare("num_nodes", default=1, types=int) - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') self.options.declare( "retract_gear", default=True, @@ -1330,39 +1450,45 @@ def initialize(self): desc="Directly input speed of sound and kinematic viscosity instead of " "computing them with an atmospherics component. For testing.", ) - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) def setup(self): nn = self.options["num_nodes"] output_alpha = self.options["output_alpha"] - aviary_options = self.options["aviary_options"] self.add_subsystem( "aero_setup", - AeroSetup(num_nodes=nn, aviary_options=aviary_options, - input_atmos=self.options["input_atmos"]), + AeroSetup( + num_nodes=nn, + input_atmos=self.options["input_atmos"], + ), promotes=["*"], ) aero_ramps = TanhRampComp(time_units='s', num_nodes=nn) - aero_ramps.add_ramp('flap_factor', output_units='unitless', - initial_val=1.0 if self.options['retract_flaps'] else 0.0, - final_val=0.0 if self.options['retract_flaps'] else 1.0) - aero_ramps.add_ramp('gear_factor', output_units='unitless', - initial_val=1.0 if self.options['retract_gear'] else 0.0, - final_val=0.0 if self.options['retract_gear'] else 1.0) - - self.add_subsystem("aero_ramps", - aero_ramps, - promotes_inputs=[("time", "t_curr"), - ("flap_factor:t_init", "t_init_flaps"), - ("flap_factor:t_duration", "dt_flaps"), - ("gear_factor:t_init", "t_init_gear"), - ("gear_factor:t_duration", "dt_gear")], - promotes_outputs=['flap_factor', - 'gear_factor']) + aero_ramps.add_ramp( + 'flap_factor', + output_units='unitless', + initial_val=1.0 if self.options['retract_flaps'] else 0.0, + final_val=0.0 if self.options['retract_flaps'] else 1.0, + ) + aero_ramps.add_ramp( + 'gear_factor', + output_units='unitless', + initial_val=1.0 if self.options['retract_gear'] else 0.0, + final_val=0.0 if self.options['retract_gear'] else 1.0, + ) + + self.add_subsystem( + "aero_ramps", + aero_ramps, + promotes_inputs=[ + ("time", "t_curr"), + ("flap_factor:t_init", "t_init_flaps"), + ("flap_factor:t_duration", "dt_flaps"), + ("gear_factor:t_init", "t_init_gear"), + ("gear_factor:t_duration", "dt_gear"), + ], + promotes_outputs=['flap_factor', 'gear_factor'], + ) if output_alpha: # lift_req -> CL @@ -1380,7 +1506,7 @@ def setup(self): "lift_coef", LiftCoeff(num_nodes=nn), promotes_inputs=["*"], - promotes_outputs=["*"] + promotes_outputs=["*"], ) self.add_subsystem( @@ -1397,7 +1523,7 @@ def setup(self): # dCL_flaps=dict(shape=nn, units='unitless'), flap_factor=dict(shape=nn, units='unitless'), dCL_flaps_full=dict(shape=nn, units='unitless'), - has_diag_partials=True + has_diag_partials=True, ), promotes=["*"], ) @@ -1426,7 +1552,7 @@ def setup(self): gear_factor=dict(shape=nn, units='unitless'), dCD_gear_full=dict(shape=nn, units='unitless'), dCD_flaps_full=dict(shape=nn, units='unitless'), - has_diag_partials=True + has_diag_partials=True, ), promotes=["*"], ) diff --git a/aviary/subsystems/aerodynamics/gasp_based/interference.py b/aviary/subsystems/aerodynamics/gasp_based/interference.py index 2a1fb74ad..4169849f5 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/interference.py +++ b/aviary/subsystems/aerodynamics/gasp_based/interference.py @@ -307,10 +307,9 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.FORM_FACTOR, 1.25) add_aviary_input(self, Aircraft.Wing.AVERAGE_CHORD) - add_aviary_input(self, Dynamic.Mission.MACH, shape=nn) - add_aviary_input(self, Dynamic.Mission.TEMPERATURE, shape=nn) - add_aviary_input(self, Dynamic.Mission.KINEMATIC_VISCOSITY, - shape=nn) + add_aviary_input(self, Dynamic.Atmosphere.MACH, shape=nn) + add_aviary_input(self, Dynamic.Atmosphere.TEMPERATURE, shape=nn) + add_aviary_input(self, Dynamic.Atmosphere.KINEMATIC_VISCOSITY, shape=nn) self.add_input('interference_independent_of_shielded_area') self.add_input('drag_loss_due_to_shielded_wing_area') @@ -321,11 +320,15 @@ def setup_partials(self): nn = self.options["num_nodes"] arange = np.arange(nn) self.declare_partials( - 'wing_fuselage_interference_flat_plate_equivalent', [ - Dynamic.Mission.MACH, - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.KINEMATIC_VISCOSITY], - rows=arange, cols=arange) + 'wing_fuselage_interference_flat_plate_equivalent', + [ + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, + ], + rows=arange, + cols=arange, + ) self.declare_partials( 'wing_fuselage_interference_flat_plate_equivalent', [ Aircraft.Wing.FORM_FACTOR, @@ -368,16 +371,54 @@ def compute_partials(self, inputs, J): J['wing_fuselage_interference_flat_plate_equivalent', Aircraft.Wing.AVERAGE_CHORD] = \ 2.6*CDWI * CKW * ((np.log10(RELI * CBARW)/7.)**(-3.6))*AREASHIELDWF \ * 1/(np.log(10)*(CBARW)*7) - J['wing_fuselage_interference_flat_plate_equivalent', Dynamic.Mission.MACH] = -CKW * AREASHIELDWF * (((np.log10(RELI * CBARW)/7.)**(-2.6)) * ( - FCFWC*FCFWT * dCFIN_dEM) + CFIN*(-2.6*((np.log10(RELI * CBARW)/7.)**(-3.6)) / (np.log(10)*(RELI)*7)*(dRELI_dEM))) - J['wing_fuselage_interference_flat_plate_equivalent', Dynamic.Mission.TEMPERATURE] = \ - -CDWI * CKW * -2.6*((np.log10(RELI * CBARW)/7.)**(-3.6))*AREASHIELDWF \ - * 1/(np.log(10)*(RELI)*7) * np.sqrt(1.4*GRAV_ENGLISH_GASP*53.32) \ - * EM * .5/(XKV*np.sqrt(T0)) - J['wing_fuselage_interference_flat_plate_equivalent', Dynamic.Mission.KINEMATIC_VISCOSITY] = \ - CDWI * CKW * -2.6*((np.log10(RELI * CBARW)/7.)**(-3.6))*AREASHIELDWF \ - * 1/(np.log(10)*(RELI)*7) * np.sqrt(1.4*GRAV_ENGLISH_GASP*53.32) \ - * EM * np.sqrt(T0) / XKV**2 + J[ + 'wing_fuselage_interference_flat_plate_equivalent', Dynamic.Atmosphere.MACH + ] = ( + -CKW + * AREASHIELDWF + * ( + ((np.log10(RELI * CBARW) / 7.0) ** (-2.6)) * (FCFWC * FCFWT * dCFIN_dEM) + + CFIN + * ( + -2.6 + * ((np.log10(RELI * CBARW) / 7.0) ** (-3.6)) + / (np.log(10) * (RELI) * 7) + * (dRELI_dEM) + ) + ) + ) + J[ + 'wing_fuselage_interference_flat_plate_equivalent', + Dynamic.Atmosphere.TEMPERATURE, + ] = ( + -CDWI + * CKW + * -2.6 + * ((np.log10(RELI * CBARW) / 7.0) ** (-3.6)) + * AREASHIELDWF + * 1 + / (np.log(10) * (RELI) * 7) + * np.sqrt(1.4 * GRAV_ENGLISH_GASP * 53.32) + * EM + * 0.5 + / (XKV * np.sqrt(T0)) + ) + J[ + 'wing_fuselage_interference_flat_plate_equivalent', + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, + ] = ( + CDWI + * CKW + * -2.6 + * ((np.log10(RELI * CBARW) / 7.0) ** (-3.6)) + * AREASHIELDWF + * 1 + / (np.log(10) * (RELI) * 7) + * np.sqrt(1.4 * GRAV_ENGLISH_GASP * 53.32) + * EM + * np.sqrt(T0) + / XKV**2 + ) J['wing_fuselage_interference_flat_plate_equivalent', 'interference_independent_of_shielded_area'] = \ -CDWI * CKW * ((np.log10(RELI * CBARW)/7.)**(-2.6)) diff --git a/aviary/subsystems/aerodynamics/gasp_based/premission_aero.py b/aviary/subsystems/aerodynamics/gasp_based/premission_aero.py index 213b10b9d..d3ebf67a9 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/premission_aero.py +++ b/aviary/subsystems/aerodynamics/gasp_based/premission_aero.py @@ -8,7 +8,6 @@ from aviary.subsystems.atmosphere.atmosphere import Atmosphere from aviary.subsystems.aerodynamics.gasp_based.flaps_model import FlapsGroup -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.variable_info.enums import SpeedType from aviary.subsystems.aerodynamics.gasp_based.gasp_aero_coeffs import AeroFormfactors @@ -21,16 +20,8 @@ class PreMissionAero(om.Group): """Takeoff and landing flaps modeling""" - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): - aviary_options = self.options['aviary_options'] - self.add_subsystem("wing_fus_interference_premission", WingFuselageInterferencePremission(), promotes_inputs=["aircraft:*"], @@ -60,14 +51,16 @@ def setup(self): rho={"units": "slug/ft**3"}, kinematic_viscosity={"units": "ft**2/s"}, ), - promotes=["viscosity", - ("kinematic_viscosity", Dynamic.Mission.KINEMATIC_VISCOSITY), - ("rho", Dynamic.Mission.DENSITY)], + promotes=[ + "viscosity", + ("kinematic_viscosity", Dynamic.Atmosphere.KINEMATIC_VISCOSITY), + ("rho", Dynamic.Atmosphere.DENSITY), + ], ) self.add_subsystem( "flaps_up", - FlapsGroup(aviary_options=aviary_options), + FlapsGroup(), promotes_inputs=[ "*", ("flap_defl", "flap_defl_up"), @@ -77,10 +70,13 @@ def setup(self): ) self.add_subsystem( "flaps_takeoff", - FlapsGroup(aviary_options=aviary_options), + FlapsGroup(), # slat deflection same for takeoff and landing - promotes_inputs=["*", ("flap_defl", Aircraft.Wing.FLAP_DEFLECTION_TAKEOFF), - ("slat_defl", Aircraft.Wing.MAX_SLAT_DEFLECTION_TAKEOFF)], + promotes_inputs=[ + "*", + ("flap_defl", Aircraft.Wing.FLAP_DEFLECTION_TAKEOFF), + ("slat_defl", Aircraft.Wing.MAX_SLAT_DEFLECTION_TAKEOFF), + ], promotes_outputs=[ ("CL_max", Mission.Takeoff.LIFT_COEFFICIENT_MAX), ( @@ -95,9 +91,12 @@ def setup(self): ) self.add_subsystem( "flaps_landing", - FlapsGroup(aviary_options=aviary_options), - promotes_inputs=["*", ("flap_defl", Aircraft.Wing.FLAP_DEFLECTION_LANDING), - ("slat_defl", Aircraft.Wing.MAX_SLAT_DEFLECTION_LANDING)], + FlapsGroup(), + promotes_inputs=[ + "*", + ("flap_defl", Aircraft.Wing.FLAP_DEFLECTION_LANDING), + ("slat_defl", Aircraft.Wing.MAX_SLAT_DEFLECTION_LANDING), + ], promotes_outputs=[ ("CL_max", Mission.Landing.LIFT_COEFFICIENT_MAX), ( diff --git a/aviary/subsystems/aerodynamics/gasp_based/table_based.py b/aviary/subsystems/aerodynamics/gasp_based/table_based.py index 670dfb0f9..5c0d33a5c 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/table_based.py +++ b/aviary/subsystems/aerodynamics/gasp_based/table_based.py @@ -19,16 +19,17 @@ # spaces are replaced with underscores when data tables are read) # "Repeated" aliases allows variables with different cases to match with desired # all-lowercase name -aliases = {Dynamic.Mission.ALTITUDE: ['h', 'alt', 'altitude'], - Dynamic.Mission.MACH: ['m', 'mach'], - 'angle_of_attack': ['alpha', 'angle_of_attack', 'AoA'], - 'flap_deflection': ['flap_deflection'], - 'hob': ['hob'], - 'lift_coefficient': ['cl', 'lift_coefficient'], - 'drag_coefficient': ['cd', 'drag_coefficient'], - 'delta_lift_coefficient': ['delta_cl', 'dcl'], - 'delta_drag_coefficient': ['delta_cd', 'dcd'] - } +aliases = { + Dynamic.Mission.ALTITUDE: ['h', 'alt', 'altitude'], + Dynamic.Atmosphere.MACH: ['m', 'mach'], + 'angle_of_attack': ['alpha', 'angle_of_attack', 'AoA'], + 'flap_deflection': ['flap_deflection'], + 'hob': ['hob'], + 'lift_coefficient': ['cl', 'lift_coefficient'], + 'drag_coefficient': ['cd', 'drag_coefficient'], + 'delta_lift_coefficient': ['delta_cl', 'dcl'], + 'delta_drag_coefficient': ['delta_cd', 'dcd'], +} class TabularCruiseAero(om.Group): @@ -71,17 +72,21 @@ def setup(self): structured=structured, extrapolate=extrapolate) - self.add_subsystem('free_aero_interp', - subsys=interp_comp, - promotes_inputs=[Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, - ('angle_of_attack', 'alpha')] - + extra_promotes, - promotes_outputs=[('lift_coefficient', 'CL'), ('drag_coefficient', 'CD')]) + self.add_subsystem( + 'free_aero_interp', + subsys=interp_comp, + promotes_inputs=[ + Dynamic.Mission.ALTITUDE, + Dynamic.Atmosphere.MACH, + ('angle_of_attack', 'alpha'), + ] + + extra_promotes, + promotes_outputs=[('lift_coefficient', 'CL'), ('drag_coefficient', 'CD')], + ) self.add_subsystem("forces", AeroForces(num_nodes=nn), promotes=["*"]) - self.set_input_defaults(Dynamic.Mission.MACH, np.zeros(nn)) + self.set_input_defaults(Dynamic.Atmosphere.MACH, np.zeros(nn)) class TabularLowSpeedAero(om.Group): @@ -168,8 +173,11 @@ def setup(self): self.add_subsystem( "interp_free", free_aero_interp, - promotes_inputs=[Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, ('angle_of_attack', 'alpha')], + promotes_inputs=[ + Dynamic.Mission.ALTITUDE, + Dynamic.Atmosphere.MACH, + ('angle_of_attack', 'alpha'), + ], promotes_outputs=[ ("lift_coefficient", "CL_free"), ("drag_coefficient", "CD_free"), @@ -186,8 +194,11 @@ def setup(self): self.add_subsystem( "interp_flaps", flaps_aero_interp, - promotes_inputs=[('flap_deflection', 'flap_defl'), - Dynamic.Mission.MACH, ('angle_of_attack', 'alpha')], + promotes_inputs=[ + ('flap_deflection', 'flap_defl'), + Dynamic.Atmosphere.MACH, + ('angle_of_attack', 'alpha'), + ], promotes_outputs=[ ("delta_lift_coefficient", "dCL_flaps_full"), ("delta_drag_coefficient", "dCD_flaps_full"), @@ -204,7 +215,11 @@ def setup(self): self.add_subsystem( "interp_ground", ground_aero_interp, - promotes_inputs=[Dynamic.Mission.MACH, ('angle_of_attack', 'alpha'), 'hob'], + promotes_inputs=[ + Dynamic.Atmosphere.MACH, + ('angle_of_attack', 'alpha'), + 'hob', + ], promotes_outputs=[ ("delta_lift_coefficient", "dCL_ground"), ("delta_drag_coefficient", "dCD_ground"), @@ -290,10 +305,10 @@ def setup(self): promotes_inputs=[ "CL", "CD", - Dynamic.Mission.DYNAMIC_PRESSURE, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, ] + ["aircraft:*"], - promotes_outputs=[Dynamic.Mission.LIFT, Dynamic.Mission.DRAG], + promotes_outputs=[Dynamic.Vehicle.LIFT, Dynamic.Vehicle.DRAG], ) if self.options["retract_gear"]: @@ -313,7 +328,7 @@ def setup(self): # TODO default flap duration for landing? self.set_input_defaults(Dynamic.Mission.ALTITUDE, np.zeros(nn)) - self.set_input_defaults(Dynamic.Mission.MACH, np.zeros(nn)) + self.set_input_defaults(Dynamic.Atmosphere.MACH, np.zeros(nn)) class GearDragIncrement(om.ExplicitComponent): @@ -396,8 +411,11 @@ def _build_free_aero_interp(num_nodes=0, aero_data=None, connect_training_data=F interp_data = _structure_special_grid(interp_data) - required_inputs = {Dynamic.Mission.ALTITUDE, Dynamic.Mission.MACH, - 'angle_of_attack'} + required_inputs = { + Dynamic.Mission.ALTITUDE, + Dynamic.Atmosphere.MACH, + 'angle_of_attack', + } required_outputs = {'lift_coefficient', 'drag_coefficient'} missing_variables = [] @@ -439,10 +457,13 @@ def _build_free_aero_interp(num_nodes=0, aero_data=None, connect_training_data=F meta_1d = om.MetaModelStructuredComp(method='1D-lagrange2', vec_size=num_nodes, extrapolate=extrapolate) - meta_1d.add_input(Dynamic.Mission.MACH, 0.0, units="unitless", - shape=num_nodes, - training_data=interp_data.get_val(Dynamic.Mission.MACH, - 'unitless')) + meta_1d.add_input( + Dynamic.Atmosphere.MACH, + 0.0, + units="unitless", + shape=num_nodes, + training_data=interp_data.get_val(Dynamic.Atmosphere.MACH, 'unitless'), + ) meta_1d.add_output('lift_coefficient_max', units="unitless", shape=num_nodes, training_data=cl_max) @@ -468,7 +489,7 @@ def _build_flaps_aero_interp(num_nodes=0, aero_data=None, connect_training_data= interp_data = _structure_special_grid(interp_data) - required_inputs = {'flap_deflection', Dynamic.Mission.MACH, 'angle_of_attack'} + required_inputs = {'flap_deflection', Dynamic.Atmosphere.MACH, 'angle_of_attack'} required_outputs = {'delta_lift_coefficient', 'delta_drag_coefficient'} missing_variables = [] @@ -487,7 +508,7 @@ def _build_flaps_aero_interp(num_nodes=0, aero_data=None, connect_training_data= ) # units don't matter, not using values alpha = np.unique(interp_data.get_val('angle_of_attack', 'deg') ) # units don't matter, not using values - mach = np.unique(interp_data.get_val(Dynamic.Mission.MACH, 'unitless')) + mach = np.unique(interp_data.get_val(Dynamic.Atmosphere.MACH, 'unitless')) dcl_max = np.zeros_like(dcl) shape = (defl.size, mach.size, alpha.size) @@ -522,7 +543,7 @@ def _build_ground_aero_interp(num_nodes=0, aero_data=None, connect_training_data # aero_data is modified in-place, deepcopy required interp_data = aero_data.deepcopy() - required_inputs = {'hob', Dynamic.Mission.MACH, 'angle_of_attack'} + required_inputs = {'hob', Dynamic.Atmosphere.MACH, 'angle_of_attack'} required_outputs = {'delta_lift_coefficient', 'delta_drag_coefficient'} missing_variables = [] @@ -539,7 +560,7 @@ def _build_ground_aero_interp(num_nodes=0, aero_data=None, connect_training_data dcl = interp_data.get_val('delta_lift_coefficient', 'unitless') alpha = np.unique(interp_data.get_val('angle_of_attack', 'deg') ) # units don't matter, not using values - mach = np.unique(interp_data.get_val(Dynamic.Mission.MACH, 'unitless')) + mach = np.unique(interp_data.get_val(Dynamic.Atmosphere.MACH, 'unitless')) hob = np.unique(interp_data.get_val('hob', 'unitless')) dcl_max = np.zeros_like(dcl) diff --git a/aviary/subsystems/aerodynamics/gasp_based/test/test_common.py b/aviary/subsystems/aerodynamics/gasp_based/test/test_common.py index 3ccd22329..674c41ce3 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/test/test_common.py +++ b/aviary/subsystems/aerodynamics/gasp_based/test/test_common.py @@ -21,13 +21,13 @@ def testAeroForces(self): prob.set_val("CL", [1.0, 0.9, 0.8]) prob.set_val("CD", [1.0, 0.95, 0.85]) - prob.set_val(Dynamic.Mission.DYNAMIC_PRESSURE, 1, units="psf") + prob.set_val(Dynamic.Atmosphere.DYNAMIC_PRESSURE, 1, units="psf") prob.set_val(Aircraft.Wing.AREA, 1370.3, units="ft**2") prob.run_model() - lift = prob.get_val(Dynamic.Mission.LIFT) - drag = prob.get_val(Dynamic.Mission.DRAG) + lift = prob.get_val(Dynamic.Vehicle.LIFT) + drag = prob.get_val(Dynamic.Vehicle.DRAG) assert_near_equal(lift, [1370.3, 1233.27, 1096.24]) assert_near_equal(drag, [1370.3, 1301.785, 1164.755]) diff --git a/aviary/subsystems/aerodynamics/gasp_based/test/test_gaspaero.py b/aviary/subsystems/aerodynamics/gasp_based/test/test_gaspaero.py index 9e97710a3..ed962e8ed 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/test/test_gaspaero.py +++ b/aviary/subsystems/aerodynamics/gasp_based/test/test_gaspaero.py @@ -29,7 +29,9 @@ class GASPAeroTest(unittest.TestCase): def test_cruise(self): prob = om.Problem() prob.model.add_subsystem( - "aero", CruiseAero(num_nodes=2, aviary_options=get_option_defaults(), input_atmos=True), promotes=["*"] + "aero", + CruiseAero(num_nodes=2, input_atmos=True), + promotes=["*"], ) prob.setup(check=False, force_alloc_complex=True) @@ -48,10 +50,10 @@ def test_cruise(self): with self.subTest(alt=alt, mach=mach, alpha=alpha): # prob.set_val(Dynamic.Mission.ALTITUDE, alt) - prob.set_val(Dynamic.Mission.MACH, mach) + prob.set_val(Dynamic.Atmosphere.MACH, mach) prob.set_val("alpha", alpha) - prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, row["sos"]) - prob.set_val(Dynamic.Mission.KINEMATIC_VISCOSITY, row["nu"]) + prob.set_val(Dynamic.Atmosphere.SPEED_OF_SOUND, row["sos"]) + prob.set_val(Dynamic.Atmosphere.KINEMATIC_VISCOSITY, row["nu"]) prob.run_model() @@ -65,7 +67,12 @@ def test_cruise(self): def test_ground(self): prob = om.Problem() prob.model.add_subsystem( - "aero", LowSpeedAero(num_nodes=2, aviary_options=get_option_defaults(), input_atmos=True), promotes=["*"] + "aero", + LowSpeedAero( + num_nodes=2, + input_atmos=True, + ), + promotes=["*"], ) prob.setup(check=False, force_alloc_complex=True) @@ -85,11 +92,11 @@ def test_ground(self): alpha = row["alpha"] with self.subTest(ilift=ilift, alt=alt, mach=mach, alpha=alpha): - prob.set_val(Dynamic.Mission.MACH, mach) + prob.set_val(Dynamic.Atmosphere.MACH, mach) prob.set_val(Dynamic.Mission.ALTITUDE, alt) prob.set_val("alpha", alpha) - prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, row["sos"]) - prob.set_val(Dynamic.Mission.KINEMATIC_VISCOSITY, row["nu"]) + prob.set_val(Dynamic.Atmosphere.SPEED_OF_SOUND, row["sos"]) + prob.set_val(Dynamic.Atmosphere.KINEMATIC_VISCOSITY, row["nu"]) # note we're just letting the time ramps for flaps/gear default to the # takeoff config such that the default times correspond to full flap and @@ -100,8 +107,8 @@ def test_ground(self): prob.set_val("CL_max_flaps", setup_data["clmwto"]) prob.set_val("dCL_flaps_model", setup_data["dclto"]) prob.set_val("dCD_flaps_model", setup_data["dcdto"]) - prob.set_val("aero_ramps.flap_factor:final_val", 1.) - prob.set_val("aero_ramps.gear_factor:final_val", 1.) + prob.set_val("aero_ramps.flap_factor:final_val", 1.0) + prob.set_val("aero_ramps.gear_factor:final_val", 1.0) else: # landing flaps config prob.set_val("flap_defl", setup_data["delfld"]) @@ -122,14 +129,14 @@ def test_ground_alpha_out(self): prob = om.Problem() prob.model.add_subsystem( "alpha_in", - LowSpeedAero(aviary_options=get_option_defaults()), + LowSpeedAero(), promotes_inputs=["*", ("alpha", "alpha_in")], - promotes_outputs=[(Dynamic.Mission.LIFT, "lift_req")], + promotes_outputs=[(Dynamic.Vehicle.LIFT, "lift_req")], ) prob.model.add_subsystem( "alpha_out", - LowSpeedAero(aviary_options=get_option_defaults(), output_alpha=True), + LowSpeedAero(output_alpha=True), promotes_inputs=["*", "lift_req"], ) @@ -144,7 +151,7 @@ def test_ground_alpha_out(self): prob.set_val(Aircraft.Wing.FLAP_CHORD_RATIO, setup_data["cfoc"]) prob.set_val(Mission.Design.GROSS_MASS, setup_data["wgto"]) - prob.set_val(Dynamic.Mission.MACH, 0.1) + prob.set_val(Dynamic.Atmosphere.MACH, 0.1) prob.set_val(Dynamic.Mission.ALTITUDE, 10) prob.set_val("alpha_in", 5) prob.run_model() diff --git a/aviary/subsystems/aerodynamics/gasp_based/test/test_interference.py b/aviary/subsystems/aerodynamics/gasp_based/test/test_interference.py index 06a532520..e301f8524 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/test/test_interference.py +++ b/aviary/subsystems/aerodynamics/gasp_based/test/test_interference.py @@ -147,7 +147,7 @@ def test_complete_group(self): USatm1976Comp(num_nodes=nn), promotes_inputs=[("h", Dynamic.Mission.ALTITUDE)], promotes_outputs=['rho', "viscosity", - ("temp", Dynamic.Mission.TEMPERATURE)], + ("temp", Dynamic.Atmosphere.TEMPERATURE)], ) prob.model.add_subsystem( "kin_visc", @@ -158,7 +158,7 @@ def test_complete_group(self): nu={"units": "ft**2/s", "shape": nn}, has_diag_partials=True, ), - promotes=["*", ('nu', Dynamic.Mission.KINEMATIC_VISCOSITY)], + promotes=["*", ('nu', Dynamic.Atmosphere.KINEMATIC_VISCOSITY)], ) prob.model.add_subsystem( "comp", WingFuselageInterferenceMission(num_nodes=nn), @@ -167,7 +167,7 @@ def test_complete_group(self): prob.set_val(Aircraft.Wing.FORM_FACTOR, 1.25) prob.set_val(Aircraft.Wing.AVERAGE_CHORD, 12) - prob.set_val(Dynamic.Mission.MACH, (.6, .65)) + prob.set_val(Dynamic.Atmosphere.MACH, (.6, .65)) prob.set_val(Dynamic.Mission.ALTITUDE, (30000, 30000)) prob.set_val('interference_independent_of_shielded_area', 0.35794891) prob.set_val('drag_loss_due_to_shielded_wing_area', 83.53366) diff --git a/aviary/subsystems/aerodynamics/gasp_based/test/test_table_based.py b/aviary/subsystems/aerodynamics/gasp_based/test/test_table_based.py index cfa949f19..3d9ad91cb 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/test/test_table_based.py +++ b/aviary/subsystems/aerodynamics/gasp_based/test/test_table_based.py @@ -25,12 +25,13 @@ def test_climb(self): prob.setup(force_alloc_complex=True) prob.set_val( - Dynamic.Mission.MACH, [ - 0.381, 0.384, 0.391, 0.399, 0.8, 0.8, 0.8, 0.8]) + Dynamic.Atmosphere.MACH, [0.381, 0.384, 0.391, 0.399, 0.8, 0.8, 0.8, 0.8] + ) prob.set_val("alpha", [5.19, 5.19, 5.19, 5.18, 3.58, 3.81, 4.05, 4.18]) prob.set_val( - Dynamic.Mission.ALTITUDE, [ - 500, 1000, 2000, 3000, 35000, 36000, 37000, 37500]) + Dynamic.Mission.ALTITUDE, + [500, 1000, 2000, 3000, 35000, 36000, 37000, 37500], + ) prob.run_model() cl_exp = np.array( @@ -55,7 +56,7 @@ def test_cruise(self): prob.model = TabularCruiseAero(num_nodes=2, aero_data=fp) prob.setup(force_alloc_complex=True) - prob.set_val(Dynamic.Mission.MACH, [0.8, 0.8]) + prob.set_val(Dynamic.Atmosphere.MACH, [0.8, 0.8]) prob.set_val("alpha", [4.216, 3.146]) prob.set_val(Dynamic.Mission.ALTITUDE, [37500, 37500]) prob.run_model() @@ -101,7 +102,7 @@ def test_groundroll(self): prob.set_val("t_curr", [0.0, 1.0, 2.0, 3.0]) prob.set_val(Dynamic.Mission.ALTITUDE, 0) - prob.set_val(Dynamic.Mission.MACH, [0.0, 0.009, 0.018, 0.026]) + prob.set_val(Dynamic.Atmosphere.MACH, [0.0, 0.009, 0.018, 0.026]) prob.set_val("alpha", 0) # TODO set q if we want to test lift/drag forces @@ -143,8 +144,9 @@ def test_takeoff(self): alts = [44.2, 62.7, 84.6, 109.7, 373.0, 419.4, 465.3, 507.8] prob.set_val(Dynamic.Mission.ALTITUDE, alts) prob.set_val( - Dynamic.Mission.MACH, [ - 0.257, 0.260, 0.263, 0.265, 0.276, 0.277, 0.279, 0.280]) + Dynamic.Atmosphere.MACH, + [0.257, 0.260, 0.263, 0.265, 0.276, 0.277, 0.279, 0.280], + ) prob.set_val("alpha", [8.94, 8.74, 8.44, 8.24, 6.45, 6.34, 6.76, 7.59]) # TODO set q if we want to test lift/drag forces diff --git a/aviary/subsystems/atmosphere/atmosphere.py b/aviary/subsystems/atmosphere/atmosphere.py index 2e47e5974..efefcb4b2 100644 --- a/aviary/subsystems/atmosphere/atmosphere.py +++ b/aviary/subsystems/atmosphere/atmosphere.py @@ -21,7 +21,7 @@ def initialize(self): self.options.declare( 'h_def', values=('geopotential', 'geodetic'), - default='geopotential', + default='geodetic', desc='The definition of altitude provided as input to the component. If ' '"geodetic", it will be converted to geopotential based on Equation 19 in ' 'the original standard.', @@ -57,10 +57,10 @@ def setup(self): promotes_inputs=[('h', Dynamic.Mission.ALTITUDE)], promotes_outputs=[ '*', - ('sos', Dynamic.Mission.SPEED_OF_SOUND), - ('rho', Dynamic.Mission.DENSITY), - ('temp', Dynamic.Mission.TEMPERATURE), - ('pres', Dynamic.Mission.STATIC_PRESSURE), + ('sos', Dynamic.Atmosphere.SPEED_OF_SOUND), + ('rho', Dynamic.Atmosphere.DENSITY), + ('temp', Dynamic.Atmosphere.TEMPERATURE), + ('pres', Dynamic.Atmosphere.STATIC_PRESSURE), ], ) diff --git a/aviary/subsystems/atmosphere/flight_conditions.py b/aviary/subsystems/atmosphere/flight_conditions.py index 66b12a217..a83d535d5 100644 --- a/aviary/subsystems/atmosphere/flight_conditions.py +++ b/aviary/subsystems/atmosphere/flight_conditions.py @@ -27,20 +27,20 @@ def setup(self): arange = np.arange(self.options["num_nodes"]) self.add_input( - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, val=np.zeros(nn), units="slug/ft**3", desc="density of air", ) self.add_input( - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.SPEED_OF_SOUND, val=np.zeros(nn), units="ft/s", desc="speed of sound", ) self.add_output( - Dynamic.Mission.DYNAMIC_PRESSURE, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, val=np.zeros(nn), units="lbf/ft**2", desc="dynamic pressure", @@ -60,27 +60,27 @@ def setup(self): desc="equivalent air speed", ) self.add_output( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, val=np.zeros(nn), units="unitless", desc="mach number", ) self.declare_partials( - Dynamic.Mission.DYNAMIC_PRESSURE, - [Dynamic.Mission.DENSITY, Dynamic.Mission.VELOCITY], + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + [Dynamic.Atmosphere.DENSITY, Dynamic.Mission.VELOCITY], rows=arange, cols=arange, ) self.declare_partials( - Dynamic.Mission.MACH, - [Dynamic.Mission.SPEED_OF_SOUND, Dynamic.Mission.VELOCITY], + Dynamic.Atmosphere.MACH, + [Dynamic.Atmosphere.SPEED_OF_SOUND, Dynamic.Mission.VELOCITY], rows=arange, cols=arange, ) self.declare_partials( "EAS", - [Dynamic.Mission.VELOCITY, Dynamic.Mission.DENSITY], + [Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.DENSITY], rows=arange, cols=arange, ) @@ -98,37 +98,37 @@ def setup(self): desc="true air speed", ) self.add_output( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, val=np.zeros(nn), units="unitless", desc="mach number", ) self.declare_partials( - Dynamic.Mission.DYNAMIC_PRESSURE, - [Dynamic.Mission.DENSITY, "EAS"], + Dynamic.Atmosphere.DYNAMIC_PRESSURE, + [Dynamic.Atmosphere.DENSITY, "EAS"], rows=arange, cols=arange, ) self.declare_partials( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, [ - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.SPEED_OF_SOUND, "EAS", - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.DENSITY, ], rows=arange, cols=arange, ) self.declare_partials( Dynamic.Mission.VELOCITY, - [Dynamic.Mission.DENSITY, "EAS"], + [Dynamic.Atmosphere.DENSITY, "EAS"], rows=arange, cols=arange, ) elif in_type is SpeedType.MACH: self.add_input( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, val=np.zeros(nn), units="unitless", desc="mach number", @@ -147,27 +147,27 @@ def setup(self): ) self.declare_partials( - Dynamic.Mission.DYNAMIC_PRESSURE, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, [ - Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.MACH, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.DENSITY, ], rows=arange, cols=arange, ) self.declare_partials( Dynamic.Mission.VELOCITY, - [Dynamic.Mission.SPEED_OF_SOUND, Dynamic.Mission.MACH], + [Dynamic.Atmosphere.SPEED_OF_SOUND, Dynamic.Atmosphere.MACH], rows=arange, cols=arange, ) self.declare_partials( "EAS", [ - Dynamic.Mission.SPEED_OF_SOUND, - Dynamic.Mission.MACH, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.DENSITY, ], rows=arange, cols=arange, @@ -177,50 +177,54 @@ def compute(self, inputs, outputs): in_type = self.options["input_speed_type"] - rho = inputs[Dynamic.Mission.DENSITY] - sos = inputs[Dynamic.Mission.SPEED_OF_SOUND] + rho = inputs[Dynamic.Atmosphere.DENSITY] + sos = inputs[Dynamic.Atmosphere.SPEED_OF_SOUND] if in_type is SpeedType.TAS: TAS = inputs[Dynamic.Mission.VELOCITY] - outputs[Dynamic.Mission.MACH] = mach = TAS / sos + outputs[Dynamic.Atmosphere.MACH] = mach = TAS / sos outputs["EAS"] = TAS * (rho / constants.RHO_SEA_LEVEL_ENGLISH) ** 0.5 - outputs[Dynamic.Mission.DYNAMIC_PRESSURE] = 0.5 * rho * TAS**2 + outputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] = 0.5 * rho * TAS**2 elif in_type is SpeedType.EAS: EAS = inputs["EAS"] outputs[Dynamic.Mission.VELOCITY] = TAS = ( EAS / (rho / constants.RHO_SEA_LEVEL_ENGLISH) ** 0.5 ) - outputs[Dynamic.Mission.MACH] = mach = TAS / sos - outputs[Dynamic.Mission.DYNAMIC_PRESSURE] = ( + outputs[Dynamic.Atmosphere.MACH] = mach = TAS / sos + outputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] = ( 0.5 * EAS**2 * constants.RHO_SEA_LEVEL_ENGLISH ) elif in_type is SpeedType.MACH: - mach = inputs[Dynamic.Mission.MACH] + mach = inputs[Dynamic.Atmosphere.MACH] outputs[Dynamic.Mission.VELOCITY] = TAS = sos * mach outputs["EAS"] = TAS * (rho / constants.RHO_SEA_LEVEL_ENGLISH) ** 0.5 - outputs[Dynamic.Mission.DYNAMIC_PRESSURE] = 0.5 * rho * sos**2 * mach**2 + outputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] = 0.5 * rho * sos**2 * mach**2 def compute_partials(self, inputs, J): in_type = self.options["input_speed_type"] - rho = inputs[Dynamic.Mission.DENSITY] - sos = inputs[Dynamic.Mission.SPEED_OF_SOUND] + rho = inputs[Dynamic.Atmosphere.DENSITY] + sos = inputs[Dynamic.Atmosphere.SPEED_OF_SOUND] if in_type is SpeedType.TAS: TAS = inputs[Dynamic.Mission.VELOCITY] - J[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.VELOCITY] = rho * TAS - J[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.DENSITY] = 0.5 * TAS**2 + J[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Mission.VELOCITY] = rho * TAS + J[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.DENSITY] = ( + 0.5 * TAS**2 + ) - J[Dynamic.Mission.MACH, Dynamic.Mission.VELOCITY] = 1 / sos - J[Dynamic.Mission.MACH, Dynamic.Mission.SPEED_OF_SOUND] = -TAS / sos**2 + J[Dynamic.Atmosphere.MACH, Dynamic.Mission.VELOCITY] = 1 / sos + J[Dynamic.Atmosphere.MACH, Dynamic.Atmosphere.SPEED_OF_SOUND] = ( + -TAS / sos**2 + ) J["EAS", Dynamic.Mission.VELOCITY] = ( rho / constants.RHO_SEA_LEVEL_ENGLISH ) ** 0.5 - J["EAS", Dynamic.Mission.DENSITY] = ( + J["EAS", Dynamic.Atmosphere.DENSITY] = ( TAS * 0.5 * (rho ** (-0.5) / constants.RHO_SEA_LEVEL_ENGLISH**0.5) ) @@ -231,36 +235,38 @@ def compute_partials(self, inputs, J): dTAS_dRho = -0.5 * EAS * constants.RHO_SEA_LEVEL_ENGLISH**0.5 / rho**1.5 dTAS_dEAS = 1 / (rho / constants.RHO_SEA_LEVEL_ENGLISH) ** 0.5 - J[Dynamic.Mission.DYNAMIC_PRESSURE, "EAS"] = ( + J[Dynamic.Atmosphere.DYNAMIC_PRESSURE, "EAS"] = ( EAS * constants.RHO_SEA_LEVEL_ENGLISH ) - J[Dynamic.Mission.MACH, "EAS"] = dTAS_dEAS / sos - J[Dynamic.Mission.MACH, Dynamic.Mission.DENSITY] = dTAS_dRho / sos - J[Dynamic.Mission.MACH, Dynamic.Mission.SPEED_OF_SOUND] = -TAS / sos**2 - J[Dynamic.Mission.VELOCITY, Dynamic.Mission.DENSITY] = dTAS_dRho + J[Dynamic.Atmosphere.MACH, "EAS"] = dTAS_dEAS / sos + J[Dynamic.Atmosphere.MACH, Dynamic.Atmosphere.DENSITY] = dTAS_dRho / sos + J[Dynamic.Atmosphere.MACH, Dynamic.Atmosphere.SPEED_OF_SOUND] = ( + -TAS / sos**2 + ) + J[Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.DENSITY] = dTAS_dRho J[Dynamic.Mission.VELOCITY, "EAS"] = dTAS_dEAS elif in_type is SpeedType.MACH: - mach = inputs[Dynamic.Mission.MACH] + mach = inputs[Dynamic.Atmosphere.MACH] TAS = sos * mach - J[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.SPEED_OF_SOUND] = ( - rho * sos * mach**2 - ) - J[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH] = ( + J[ + Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.SPEED_OF_SOUND + ] = (rho * sos * mach**2) + J[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.MACH] = ( rho * sos**2 * mach ) - J[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.DENSITY] = ( + J[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.DENSITY] = ( 0.5 * sos**2 * mach**2 ) - J[Dynamic.Mission.VELOCITY, Dynamic.Mission.SPEED_OF_SOUND] = mach - J[Dynamic.Mission.VELOCITY, Dynamic.Mission.MACH] = sos - J["EAS", Dynamic.Mission.SPEED_OF_SOUND] = ( + J[Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.SPEED_OF_SOUND] = mach + J[Dynamic.Mission.VELOCITY, Dynamic.Atmosphere.MACH] = sos + J["EAS", Dynamic.Atmosphere.SPEED_OF_SOUND] = ( mach * (rho / constants.RHO_SEA_LEVEL_ENGLISH) ** 0.5 ) - J["EAS", Dynamic.Mission.MACH] = ( + J["EAS", Dynamic.Atmosphere.MACH] = ( sos * (rho / constants.RHO_SEA_LEVEL_ENGLISH) ** 0.5 ) - J["EAS", Dynamic.Mission.DENSITY] = ( + J["EAS", Dynamic.Atmosphere.DENSITY] = ( TAS * (1 / constants.RHO_SEA_LEVEL_ENGLISH) ** 0.5 * 0.5 * rho ** (-0.5) ) diff --git a/aviary/subsystems/atmosphere/test/test_flight_conditions.py b/aviary/subsystems/atmosphere/test/test_flight_conditions.py index 4cfc41c09..e4b6b8ce1 100644 --- a/aviary/subsystems/atmosphere/test/test_flight_conditions.py +++ b/aviary/subsystems/atmosphere/test/test_flight_conditions.py @@ -21,10 +21,10 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Dynamic.Mission.DENSITY, val=1.22 * np.ones(2), units="kg/m**3" + Dynamic.Atmosphere.DENSITY, val=1.22 * np.ones(2), units="kg/m**3" ) self.prob.model.set_input_defaults( - Dynamic.Mission.SPEED_OF_SOUND, val=344 * np.ones(2), units="m/s" + Dynamic.Atmosphere.SPEED_OF_SOUND, val=344 * np.ones(2), units="m/s" ) self.prob.model.set_input_defaults( Dynamic.Mission.VELOCITY, val=344 * np.ones(2), units="m/s" @@ -37,9 +37,9 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.DYNAMIC_PRESSURE], 1507.6 * np.ones(2), tol + self.prob[Dynamic.Atmosphere.DYNAMIC_PRESSURE], 1507.6 * np.ones(2), tol ) - assert_near_equal(self.prob[Dynamic.Mission.MACH], np.ones(2), tol) + assert_near_equal(self.prob[Dynamic.Atmosphere.MACH], np.ones(2), tol) assert_near_equal( self.prob.get_val("EAS", units="m/s"), 343.3 * np.ones(2), tol ) @@ -60,10 +60,10 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Dynamic.Mission.DENSITY, val=1.05 * np.ones(2), units="kg/m**3" + Dynamic.Atmosphere.DENSITY, val=1.05 * np.ones(2), units="kg/m**3" ) self.prob.model.set_input_defaults( - Dynamic.Mission.SPEED_OF_SOUND, val=344 * np.ones(2), units="m/s" + Dynamic.Atmosphere.SPEED_OF_SOUND, val=344 * np.ones(2), units="m/s" ) self.prob.model.set_input_defaults( "EAS", val=318.4821143 * np.ones(2), units="m/s" @@ -76,12 +76,12 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.DYNAMIC_PRESSURE], 1297.54 * np.ones(2), tol + self.prob[Dynamic.Atmosphere.DYNAMIC_PRESSURE], 1297.54 * np.ones(2), tol ) assert_near_equal( self.prob[Dynamic.Mission.VELOCITY], 1128.61 * np.ones(2), tol ) - assert_near_equal(self.prob[Dynamic.Mission.MACH], np.ones(2), tol) + assert_near_equal(self.prob[Dynamic.Atmosphere.MACH], np.ones(2), tol) partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) @@ -98,13 +98,13 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Dynamic.Mission.DENSITY, val=1.05 * np.ones(2), units="kg/m**3" + Dynamic.Atmosphere.DENSITY, val=1.05 * np.ones(2), units="kg/m**3" ) self.prob.model.set_input_defaults( - Dynamic.Mission.SPEED_OF_SOUND, val=344 * np.ones(2), units="m/s" + Dynamic.Atmosphere.SPEED_OF_SOUND, val=344 * np.ones(2), units="m/s" ) self.prob.model.set_input_defaults( - Dynamic.Mission.MACH, val=np.ones(2), units="unitless" + Dynamic.Atmosphere.MACH, val=np.ones(2), units="unitless" ) self.prob.setup(check=False, force_alloc_complex=True) @@ -114,7 +114,7 @@ def test_case1(self): self.prob.run_model() assert_near_equal( - self.prob[Dynamic.Mission.DYNAMIC_PRESSURE], 1297.54 * np.ones(2), tol + self.prob[Dynamic.Atmosphere.DYNAMIC_PRESSURE], 1297.54 * np.ones(2), tol ) assert_near_equal( self.prob[Dynamic.Mission.VELOCITY], 1128.61 * np.ones(2), tol diff --git a/aviary/subsystems/energy/battery_builder.py b/aviary/subsystems/energy/battery_builder.py index eede97a15..8a8012e18 100644 --- a/aviary/subsystems/energy/battery_builder.py +++ b/aviary/subsystems/energy/battery_builder.py @@ -19,9 +19,9 @@ class BatteryBuilder(SubsystemBuilderBase): get_mass_names(self) -> list: Returns the name of variable Aircraft.Battery.MASS as a list get_states(self) -> dict: - Returns a dictionary of the subsystem's states, where the keys are the names - of the state variables, and the values are dictionaries that contain the units - for the state variable and any additional keyword arguments required by OpenMDAO + Returns a dictionary of the subsystem's states, where the keys are the names + of the state variables, and the values are dictionaries that contain the units + for the state variable and any additional keyword arguments required by OpenMDAO for the state variable. get_constraints(self) -> dict: Returns a dictionary of constraints for the battery subsystem. @@ -39,22 +39,37 @@ def get_mass_names(self): def build_mission(self, num_nodes, aviary_inputs=None) -> om.Group: battery_group = om.Group() # Here, the efficiency variable is used as an overall efficiency for the battery - soc = om.ExecComp('state_of_charge = (energy_capacity - (cumulative_electric_energy_used/efficiency)) / energy_capacity', - state_of_charge={'val': np.zeros( - num_nodes), 'units': 'unitless'}, - energy_capacity={'val': 10.0, 'units': 'kJ'}, - cumulative_electric_energy_used={ - 'val': np.zeros(num_nodes), 'units': 'kJ'}, - efficiency={'val': 0.95, 'units': 'unitless'}, - has_diag_partials=True) - - battery_group.add_subsystem('state_of_charge', - subsys=soc, - promotes_inputs=[('energy_capacity', Aircraft.Battery.ENERGY_CAPACITY), - ('cumulative_electric_energy_used', - Dynamic.Mission.CUMULATIVE_ELECTRIC_ENERGY_USED), - ('efficiency', Aircraft.Battery.EFFICIENCY)], - promotes_outputs=[('state_of_charge', Dynamic.Mission.BATTERY_STATE_OF_CHARGE)]) + soc = om.ExecComp( + 'state_of_charge = (energy_capacity - (cumulative_electric_energy_used/efficiency)) / energy_capacity', + state_of_charge={ + 'val': np.zeros(num_nodes), + 'units': 'unitless'}, + energy_capacity={ + 'val': 10.0, + 'units': 'kJ'}, + cumulative_electric_energy_used={ + 'val': np.zeros(num_nodes), + 'units': 'kJ'}, + efficiency={ + 'val': 0.95, + 'units': 'unitless'}, + has_diag_partials=True) + + battery_group.add_subsystem( + 'state_of_charge', + subsys=soc, + promotes_inputs=[ + ('energy_capacity', Aircraft.Battery.ENERGY_CAPACITY), + ( + 'cumulative_electric_energy_used', + Dynamic.Vehicle.CUMULATIVE_ELECTRIC_ENERGY_USED, + ), + ('efficiency', Aircraft.Battery.EFFICIENCY), + ], + promotes_outputs=[ + ('state_of_charge', Dynamic.Vehicle.BATTERY_STATE_OF_CHARGE) + ], + ) return battery_group @@ -63,25 +78,25 @@ def get_states(self): # to issue where non aircraft or mission variables are not fully promoted # TODO fix this by not promoting only 'aircraft:*' and 'mission:*' state_dict = { - Dynamic.Mission.CUMULATIVE_ELECTRIC_ENERGY_USED: { + Dynamic.Vehicle.CUMULATIVE_ELECTRIC_ENERGY_USED: { 'fix_initial': True, 'fix_final': False, 'lower': 0.0, 'ref': 1e4, 'defect_ref': 1e6, 'units': 'kJ', - 'rate_source': Dynamic.Mission.ELECTRIC_POWER_IN_TOTAL, + 'rate_source': Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN_TOTAL, 'input_initial': 0.0, - 'targets': f'{self.name}.{Dynamic.Mission.CUMULATIVE_ELECTRIC_ENERGY_USED}', - } - } + 'targets': f'{self.name}.{Dynamic.Vehicle.CUMULATIVE_ELECTRIC_ENERGY_USED}', + }} return state_dict def get_constraints(self): constraint_dict = { - # Can add constraints here; state of charge is a common one in many battery applications - f'{self.name}.{Dynamic.Mission.BATTERY_STATE_OF_CHARGE}': { + # Can add constraints here; state of charge is a common one in many + # battery applications + f'{self.name}.{Dynamic.Vehicle.BATTERY_STATE_OF_CHARGE}': { 'type': 'boundary', 'loc': 'final', 'lower': 0.2, @@ -90,17 +105,11 @@ def get_constraints(self): return constraint_dict def get_parameters(self, aviary_inputs=None, phase_info=None): + params = { Aircraft.Battery.ENERGY_CAPACITY: { 'val': 0.0, 'units': 'kJ', - 'static_target': True, - }, - Aircraft.Battery.EFFICIENCY: { - 'val': 0.0, - 'units': 'unitless', - 'static_target': True, }, } - return params diff --git a/aviary/subsystems/energy/test/test_battery.py b/aviary/subsystems/energy/test/test_battery.py index 8d6ad7245..307335bc0 100644 --- a/aviary/subsystems/energy/test/test_battery.py +++ b/aviary/subsystems/energy/test/test_battery.py @@ -54,15 +54,18 @@ def test_battery_mission(self): av.Aircraft.Battery.ENERGY_CAPACITY, 10_000, units='kJ') prob.model.set_input_defaults( av.Aircraft.Battery.EFFICIENCY, efficiency, units='unitless') - prob.model.set_input_defaults(av.Dynamic.Mission.CUMULATIVE_ELECTRIC_ENERGY_USED, [ - 0, 2_000, 5_000, 9_500], units='kJ') + prob.model.set_input_defaults( + av.Dynamic.Vehicle.CUMULATIVE_ELECTRIC_ENERGY_USED, + [0, 2_000, 5_000, 9_500], + units='kJ', + ) prob.setup(force_alloc_complex=True) prob.run_model() soc_expected = np.array([1., 0.7894736842105263, 0.4736842105263159, 0.]) - soc = prob.get_val(av.Dynamic.Mission.BATTERY_STATE_OF_CHARGE, 'unitless') + soc = prob.get_val(av.Dynamic.Vehicle.BATTERY_STATE_OF_CHARGE, 'unitless') assert_near_equal(soc, soc_expected, tolerance=1e-10) diff --git a/aviary/subsystems/geometry/combined_geometry.py b/aviary/subsystems/geometry/combined_geometry.py index f9f21c070..c4403dc95 100644 --- a/aviary/subsystems/geometry/combined_geometry.py +++ b/aviary/subsystems/geometry/combined_geometry.py @@ -18,11 +18,6 @@ class CombinedGeometry(om.Group): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - self.options.declare('code_origin_to_prioritize', values=[GASP, FLOPS, None], default=None, @@ -31,18 +26,17 @@ def initialize(self): ) def setup(self): - aviary_inputs = self.options['aviary_options'] self.add_subsystem( 'gasp_based_geom', - SizeGroup(aviary_options=aviary_inputs,), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=["aircraft:*"], ) self.add_subsystem( 'flops_based_geom', - PrepGeom(aviary_options=aviary_inputs), + PrepGeom(), promotes_inputs=['*'], promotes_outputs=['*'] ) diff --git a/aviary/subsystems/geometry/flops_based/characteristic_lengths.py b/aviary/subsystems/geometry/flops_based/characteristic_lengths.py index 92148f338..ef9ce92dc 100644 --- a/aviary/subsystems/geometry/flops_based/characteristic_lengths.py +++ b/aviary/subsystems/geometry/flops_based/characteristic_lengths.py @@ -2,8 +2,7 @@ import openmdao.api as om from aviary.subsystems.geometry.flops_based.utils import Names -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -14,13 +13,11 @@ class CharacteristicLengths(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) self.add_input(Names.CROOT, 0.0, units='unitless') @@ -36,7 +33,7 @@ def setup(self): add_aviary_input(self, Aircraft.Fuselage.LENGTH, 0.0) add_aviary_input(self, Aircraft.HorizontalTail.AREA, 0.0) - add_aviary_input(self, Aircraft.HorizontalTail.ASPECT_RATIO, 0.0) + add_aviary_input(self, Aircraft.HorizontalTail.ASPECT_RATIO, 4.75) # add_aviary_input(self, Aircraft.HorizontalTail.LAMINAR_FLOW_LOWER, 0.0) # add_aviary_input(self, Aircraft.HorizontalTail.LAMINAR_FLOW_UPPER, 0.0) add_aviary_input(self, Aircraft.HorizontalTail.THICKNESS_TO_CHORD, 0.0) @@ -93,9 +90,8 @@ def setup_partials(self): self._setup_partials_nacelles() self._setup_partials_canard() - def compute( - self, inputs, outputs, discrete_inputs=None, discrete_outputs=None - ): + def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): + self._compute_wing(inputs, outputs, discrete_inputs, discrete_outputs) self._compute_horizontal_tail( @@ -141,9 +137,7 @@ def _setup_partials_wing(self): Aircraft.Wing.GLOVE_AND_BAT, ] - aviary_options: AviaryValues = self.options['aviary_options'] - - if aviary_options.get_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION): + if self.options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION]: wrt = [ Names.CROOT, Aircraft.Wing.TAPER_RATIO, @@ -199,8 +193,7 @@ def _setup_partials_fuselage(self): def _setup_partials_nacelles(self): # derivatives w.r.t vectorized engine inputs have known sparsity pattern - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) shape = np.arange(num_engine_type) self.declare_partials( @@ -239,9 +232,7 @@ def _compute_wing( length = ((area - glove_and_bat) / aspect_ratio)**0.5 - aviary_options: AviaryValues = self.options['aviary_options'] - - if aviary_options.get_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION): + if self.options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION]: taper_ratio = inputs[Aircraft.Wing.TAPER_RATIO] CROOT = inputs[Names.CROOT] @@ -310,7 +301,7 @@ def _compute_nacelles( ): # TODO do all engines support nacelles? If not, is this deliberate, or # just an artifact of the implementation? - num_eng = self.options['aviary_options'].get_val(Aircraft.Engine.NUM_ENGINES) + num_eng = self.options[Aircraft.Engine.NUM_ENGINES] avg_diam = inputs[Aircraft.Nacelle.AVG_DIAMETER] avg_length = inputs[Aircraft.Nacelle.AVG_LENGTH] @@ -411,9 +402,8 @@ def _compute_canard( outputs[Aircraft.Canard.FINENESS] = thickness_to_chord def _compute_partials_wing(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - if aviary_options.get_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION): + if self.options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION]: taper_ratio = inputs[Aircraft.Wing.TAPER_RATIO] CROOT = inputs[Names.CROOT] @@ -518,7 +508,7 @@ def _compute_partials_fuselage(self, inputs, J, discrete_inputs=None): ] = -length / avg_diam**2.0 def _compute_partials_nacelles(self, inputs, J, discrete_inputs=None): - num_eng = self.options['aviary_options'].get_val(Aircraft.Engine.NUM_ENGINES) + num_eng = self.options[Aircraft.Engine.NUM_ENGINES] avg_diam = inputs[Aircraft.Nacelle.AVG_DIAMETER] avg_length = inputs[Aircraft.Nacelle.AVG_LENGTH] diff --git a/aviary/subsystems/geometry/flops_based/fuselage.py b/aviary/subsystems/geometry/flops_based/fuselage.py index ff2f87c48..2b73da704 100644 --- a/aviary/subsystems/geometry/flops_based/fuselage.py +++ b/aviary/subsystems/geometry/flops_based/fuselage.py @@ -4,7 +4,6 @@ import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft @@ -16,11 +15,6 @@ class FuselagePrelim(om.ExplicitComponent): Aircraft.Fuselage.PLANFORM_AREA = length * max_width """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Fuselage.LENGTH, val=0.0) add_aviary_input(self, Aircraft.Fuselage.MAX_HEIGHT, val=0.0) diff --git a/aviary/subsystems/geometry/flops_based/nacelle.py b/aviary/subsystems/geometry/flops_based/nacelle.py index a2f0d58ba..c8c9adf97 100644 --- a/aviary/subsystems/geometry/flops_based/nacelle.py +++ b/aviary/subsystems/geometry/flops_based/nacelle.py @@ -1,8 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -15,13 +14,10 @@ class Nacelles(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Nacelle.AVG_DIAMETER, val=np.zeros(num_engine_type)) add_aviary_input(self, Aircraft.Nacelle.AVG_LENGTH, @@ -35,8 +31,7 @@ def setup(self): def setup_partials(self): # derivatives w.r.t vectorized engine inputs have known sparsity pattern - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) shape = np.arange(num_engine_type) self.declare_partials( @@ -59,9 +54,9 @@ def setup_partials(self): def compute( self, inputs, outputs, discrete_inputs=None, discrete_outputs=None ): - aviary_options: AviaryValues = self.options['aviary_options'] # how many of each unique engine type are on the aircraft (array) - num_engines = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] + # how many unique engine types are there (int) num_engine_type = len(num_engines) @@ -82,8 +77,7 @@ def compute( outputs[Aircraft.Nacelle.TOTAL_WETTED_AREA] = total_wetted_area def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - num_engines = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] avg_diam = inputs[Aircraft.Nacelle.AVG_DIAMETER] avg_length = inputs[Aircraft.Nacelle.AVG_LENGTH] diff --git a/aviary/subsystems/geometry/flops_based/prep_geom.py b/aviary/subsystems/geometry/flops_based/prep_geom.py index 89b68b36f..37cf27e1b 100644 --- a/aviary/subsystems/geometry/flops_based/prep_geom.py +++ b/aviary/subsystems/geometry/flops_based/prep_geom.py @@ -5,9 +5,10 @@ TODO: blended-wing-body support TODO: multiple engine model support ''' -import openmdao.api as om from numpy import pi +import openmdao.api as om + from aviary.subsystems.geometry.flops_based.canard import Canard from aviary.subsystems.geometry.flops_based.characteristic_lengths import \ CharacteristicLengths @@ -18,8 +19,7 @@ d_calc_fuselage_adjustment, thickness_to_chord_scaler) from aviary.subsystems.geometry.flops_based.wetted_area_total import TotalWettedArea from aviary.subsystems.geometry.flops_based.wing import WingPrelim -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -28,33 +28,27 @@ class PrepGeom(om.Group): Prepare derived values of aircraft geometry for aerodynamics analysis. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): - aviary_options = self.options['aviary_options'] self.add_subsystem( - 'fuselage_prelim', FuselagePrelim(aviary_options=aviary_options), + 'fuselage_prelim', FuselagePrelim(), promotes_inputs=['*'], promotes_outputs=['*'] ) self.add_subsystem( - 'wing_prelim', WingPrelim(aviary_options=aviary_options), + 'wing_prelim', WingPrelim(), promotes_inputs=['*'], promotes_outputs=['*'] ) self.add_subsystem( - 'prelim', _Prelim(aviary_options=aviary_options), + 'prelim', _Prelim(), promotes_inputs=['*'], ) self.add_subsystem( - 'wing', _Wing(aviary_options=aviary_options), + 'wing', _Wing(), promotes_inputs=['aircraft*'], promotes_outputs=['*'] ) @@ -65,7 +59,7 @@ def setup(self): self.connect(f'prelim.{Names.XMULT}', f'wing.{Names.XMULT}') self.add_subsystem( - 'tail', _Tail(aviary_options=aviary_options), + 'tail', _Tail(), promotes_inputs=['aircraft*'], promotes_outputs=['*'] ) @@ -74,7 +68,7 @@ def setup(self): self.connect(f'prelim.{Names.XMULTV}', f'tail.{Names.XMULTV}') self.add_subsystem( - 'fuselage', _Fuselage(aviary_options=aviary_options), + 'fuselage', _Fuselage(), promotes_inputs=['aircraft*'], promotes_outputs=['*'] ) @@ -84,20 +78,20 @@ def setup(self): self.connect(f'prelim.{Names.CRTHTB}', f'fuselage.{Names.CRTHTB}') self.add_subsystem( - 'nacelles', Nacelles(aviary_options=aviary_options), + 'nacelles', Nacelles(), promotes_inputs=['aircraft*'], promotes_outputs=['*'] ) self.add_subsystem( - 'canard', Canard(aviary_options=aviary_options), + 'canard', Canard(), promotes_inputs=['aircraft*'], promotes_outputs=['*'] ) self.add_subsystem( 'characteristic_lengths', - CharacteristicLengths(aviary_options=aviary_options), + CharacteristicLengths(), promotes_inputs=['aircraft*'], promotes_outputs=['*'] ) @@ -107,7 +101,7 @@ def setup(self): ) self.add_subsystem( - 'total_wetted_area', TotalWettedArea(aviary_options=aviary_options), + 'total_wetted_area', TotalWettedArea(), promotes_inputs=['*'], promotes_outputs=['*'] ) @@ -119,17 +113,17 @@ class _Prelim(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION) def setup(self): add_aviary_input(self, Aircraft.Fuselage.AVG_DIAMETER, 0.0) add_aviary_input(self, Aircraft.Fuselage.MAX_WIDTH, 0.0) add_aviary_input(self, Aircraft.HorizontalTail.AREA, 0.0) - add_aviary_input(self, Aircraft.HorizontalTail.ASPECT_RATIO, 0.0) - add_aviary_input(self, Aircraft.HorizontalTail.TAPER_RATIO, 0.0) + add_aviary_input(self, Aircraft.HorizontalTail.ASPECT_RATIO, + 4.75, units="unitless") + add_aviary_input(self, Aircraft.HorizontalTail.TAPER_RATIO, + 0.352, units="unitless") add_aviary_input(self, Aircraft.HorizontalTail.THICKNESS_TO_CHORD, 0.0) add_aviary_input(self, Aircraft.VerticalTail.AREA, 0.0) @@ -477,9 +471,8 @@ def fuselage_var(self): Define the variable name associated with XDX. ''' value = Aircraft.Fuselage.AVG_DIAMETER - aviary_options: AviaryValues = self.options['aviary_options'] - if aviary_options.get_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION): + if self.options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION]: value = Aircraft.Fuselage.MAX_WIDTH return value @@ -491,9 +484,7 @@ class _Wing(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Fuselage.NUM_FUSELAGES) def setup(self): self.add_input(Names.CROOT, 0.0, units='unitless') @@ -518,8 +509,7 @@ def setup_partials(self): def compute( self, inputs, outputs, discrete_inputs=None, discrete_outputs=None ): - aviary_options: AviaryValues = self.options['aviary_options'] - num_fuselage = aviary_options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) + num_fuselage = self.options[Aircraft.Fuselage.NUM_FUSELAGES] area = inputs[Aircraft.Wing.AREA] CROOT = inputs[Names.CROOT] @@ -536,8 +526,7 @@ def compute( outputs[Aircraft.Wing.WETTED_AREA] = wetted_area def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - num_fuselage = aviary_options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) + num_fuselage = self.options[Aircraft.Fuselage.NUM_FUSELAGES] area = inputs[Aircraft.Wing.AREA] CROOT = inputs[Names.CROOT] @@ -571,9 +560,8 @@ class _Tail(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + add_aviary_option(self, Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION) def setup(self): self.add_input(Names.XMULTH, 0.0, units='unitless') @@ -610,8 +598,7 @@ def setup_partials(self): ] ) - aviary_options: AviaryValues = self.options['aviary_options'] - redux = aviary_options.get_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION) + redux = self.options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] if not redux: self.declare_partials( @@ -629,12 +616,11 @@ def compute( wetted_area = scaler * XMULTH * area - aviary_options: AviaryValues = self.options['aviary_options'] - redux = aviary_options.get_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION) + redux = self.options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] if not redux: num_fuselage_engines = \ - aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + self.options[Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES] vertical_tail_fraction = \ inputs[Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION] @@ -656,8 +642,7 @@ def compute( outputs[Aircraft.VerticalTail.WETTED_AREA] = wetted_area def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - redux = aviary_options.get_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION) + redux = self.options[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] # horizontal tail XMULTH = inputs[Names.XMULTH] @@ -665,8 +650,8 @@ def compute_partials(self, inputs, J, discrete_inputs=None): scaler = inputs[Aircraft.HorizontalTail.WETTED_AREA_SCALER] if not redux: - num_fuselage_engines = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + num_fuselage_engines = \ + self.options[Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES] vertical_tail_fraction = \ inputs[Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION] @@ -734,9 +719,8 @@ class _Fuselage(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION) + add_aviary_option(self, Aircraft.Fuselage.NUM_FUSELAGES) def setup(self): self.add_input(Names.CROOTB, 0.0, units='unitless') @@ -808,8 +792,7 @@ def setup_partials(self): def compute( self, inputs, outputs, discrete_inputs=None, discrete_outputs=None ): - aviary_options: AviaryValues = self.options['aviary_options'] - num_fuselages = aviary_options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) + num_fuselages = self.options[Aircraft.Fuselage.NUM_FUSELAGES] area = inputs[Aircraft.Wing.AREA] aspect_ratio = inputs[Aircraft.Wing.ASPECT_RATIO] @@ -867,8 +850,7 @@ def compute( outputs[Aircraft.Fuselage.WETTED_AREA] = wetted_area def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - num_fuselages = aviary_options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) + num_fuselages = self.options[Aircraft.Fuselage.NUM_FUSELAGES] area = inputs[Aircraft.Wing.AREA] aspect_ratio = inputs[Aircraft.Wing.ASPECT_RATIO] diff --git a/aviary/subsystems/geometry/flops_based/test/test_characteristic_lengths.py b/aviary/subsystems/geometry/flops_based/test/test_characteristic_lengths.py index f4fe31abe..a5f47faaa 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_characteristic_lengths.py +++ b/aviary/subsystems/geometry/flops_based/test/test_characteristic_lengths.py @@ -20,13 +20,16 @@ def test_case_multiengine(self): # test with multiple engine types prob = self.prob - aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2, 2, 3])) - aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 7) + aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') + + aviary_options = { + Aircraft.Engine.NUM_ENGINES: np.array([2, 2, 3]), + Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION: aviary_inputs.get_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION), + } prob.model.add_subsystem( 'char_lengths', - CharacteristicLengths(aviary_options=aviary_options), + CharacteristicLengths(**aviary_options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -52,7 +55,7 @@ def test_case_multiengine(self): (Aircraft.Wing.THICKNESS_TO_CHORD, 'unitless') ] for var, units in input_list: - prob.set_val(var, aviary_options.get_val(var, units)) + prob.set_val(var, aviary_inputs.get_val(var, units)) # this is another component's output prob.set_val(Aircraft.Fuselage.AVG_DIAMETER, val=12.75) diff --git a/aviary/subsystems/geometry/flops_based/test/test_nacelle.py b/aviary/subsystems/geometry/flops_based/test/test_nacelle.py index 61f2ebbaf..1ca18d748 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_nacelle.py +++ b/aviary/subsystems/geometry/flops_based/test/test_nacelle.py @@ -6,7 +6,6 @@ from aviary.subsystems.geometry.flops_based.nacelle import Nacelles from aviary.utils.test_utils.variable_test import assert_match_varnames -from aviary.validation_cases.validation_tests import get_flops_inputs from aviary.variable_info.variables import Aircraft @@ -22,13 +21,13 @@ def test_case_multiengine(self): # test with multiple engine types prob = self.prob - aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2, 2, 3])) - aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 7) + options = { + Aircraft.Engine.NUM_ENGINES: np.array([2, 2, 3]), + } prob.model.add_subsystem( 'nacelles', - Nacelles(aviary_options=aviary_options), + Nacelles(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py b/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py index 58a239103..66ebf3098 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py +++ b/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py @@ -55,9 +55,7 @@ def initialize(self): desc='collection of Aircraft/Mission specific options') def setup(self): - aviary_options = self.options['aviary_options'] - - self.add_subsystem('prep_geom', PrepGeom(aviary_options=aviary_options), + self.add_subsystem('prep_geom', PrepGeom(), promotes=['*']) def configure(self): @@ -65,15 +63,19 @@ def configure(self): override_aviary_vars(self, aviary_options) - options = get_flops_data(case_name, preprocess=True, - keys=[ - Aircraft.Fuselage.NUM_FUSELAGES, - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES, - Aircraft.VerticalTail.NUM_TAILS, - Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, - Aircraft.Engine.NUM_ENGINES, - Aircraft.Propulsion.TOTAL_NUM_ENGINES, - ]) + keys = [ + Aircraft.Fuselage.NUM_FUSELAGES, + Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES, + Aircraft.VerticalTail.NUM_TAILS, + Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, + Aircraft.Engine.NUM_ENGINES, + Aircraft.Propulsion.TOTAL_NUM_ENGINES, + ] + + options = get_flops_data(case_name, preprocess=True, keys=keys) + model_options = {} + for key in keys: + model_options[key] = options.get_item(key)[0] prob = self.prob @@ -81,6 +83,8 @@ def configure(self): 'premission', PreMission(aviary_options=options), promotes=['*'] ) + prob.model_options['*'] = model_options + prob.setup(check=False, force_alloc_complex=True) output_keys = [Aircraft.Fuselage.AVG_DIAMETER, @@ -206,10 +210,15 @@ def test_case(self, case_name): prob = self.prob + keys = [Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION] + flops_inputs = get_flops_inputs(case_name, keys=keys) + options = {} + for key in keys: + options[key] = flops_inputs.get_item(key)[0] + prob.model.add_subsystem( 'prelim', - _Prelim(aviary_options=get_flops_inputs(case_name, - keys=[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION])), + _Prelim(**options), promotes=['*'] ) @@ -264,10 +273,15 @@ def test_case(self, case_name): prob = self.prob + keys = [Aircraft.Fuselage.NUM_FUSELAGES] + flops_inputs = get_flops_inputs(case_name, keys=keys) + options = {} + for key in keys: + options[key] = flops_inputs.get_item(key)[0] + prob.model.add_subsystem( 'wings', - _Wing(aviary_options=get_flops_inputs(case_name, - keys=[Aircraft.Fuselage.NUM_FUSELAGES])), + _Wing(**options), promotes=['*']) prob.setup(check=False, force_alloc_complex=True) @@ -303,11 +317,16 @@ def test_case(self, case_name): prob = self.prob + keys = [Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, + Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES] + flops_inputs = get_flops_data(case_name, keys=keys) + options = {} + for key in keys: + options[key] = flops_inputs.get_item(key)[0] + prob.model.add_subsystem( 'tails', - _Tail(aviary_options=get_flops_inputs(case_name, preprocess=True, - keys=[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES])), + _Tail(**options), promotes=['*']) prob.setup(check=False, force_alloc_complex=True) @@ -345,10 +364,15 @@ def test_case(self, case_name): prob = self.prob + keys = [Aircraft.Fuselage.NUM_FUSELAGES] + flops_inputs = get_flops_inputs(case_name, keys=keys) + options = {} + for key in keys: + options[key] = flops_inputs.get_item(key)[0] + prob.model.add_subsystem( 'fuse', - _Fuselage(aviary_options=get_flops_inputs(case_name, - keys=[Aircraft.Fuselage.NUM_FUSELAGES])), + _Fuselage(**options), promotes=['*']) prob.setup(check=False, force_alloc_complex=True) @@ -401,14 +425,15 @@ def test_case(self, case_name): prob = self.prob - flops_inputs = get_flops_inputs(case_name, preprocess=True, - keys=[Aircraft.Engine.NUM_ENGINES, - Aircraft.Fuselage.NUM_FUSELAGES, - ]) + keys = [Aircraft.Engine.NUM_ENGINES] + flops_inputs = get_flops_inputs(case_name, keys=keys) + options = {} + for key in keys: + options[key] = flops_inputs.get_item(key)[0] prob.model.add_subsystem( 'nacelles', - Nacelles(aviary_options=flops_inputs), + Nacelles(**options), promotes=['*']) prob.setup(check=False, force_alloc_complex=True) @@ -438,7 +463,7 @@ def test_case(self): prob.model.add_subsystem( 'canard', - Canard(aviary_options=AviaryValues()), + Canard(), promotes=['*']) prob.setup(check=False, force_alloc_complex=True) @@ -471,16 +496,16 @@ def test_case(self, case_name): prob = self.prob - flops_inputs = get_flops_inputs(case_name, preprocess=True, - keys=[Aircraft.Engine.NUM_ENGINES, - Aircraft.Fuselage.NUM_FUSELAGES, - Aircraft.VerticalTail.NUM_TAILS, - Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, - ]) + keys = [Aircraft.Engine.NUM_ENGINES, + Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION,] + flops_inputs = get_flops_inputs(case_name, keys=keys) + options = {} + for key in keys: + options[key] = flops_inputs.get_item(key)[0] prob.model.add_subsystem( 'characteristic_lengths', - CharacteristicLengths(aviary_options=flops_inputs), + CharacteristicLengths(**options), promotes=['*'] ) diff --git a/aviary/subsystems/geometry/flops_based/wetted_area_total.py b/aviary/subsystems/geometry/flops_based/wetted_area_total.py index 4bb08d3e8..63b2a4fab 100644 --- a/aviary/subsystems/geometry/flops_based/wetted_area_total.py +++ b/aviary/subsystems/geometry/flops_based/wetted_area_total.py @@ -1,6 +1,5 @@ import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft @@ -11,11 +10,6 @@ class TotalWettedArea(om.ExplicitComponent): It is simple enought to skip unit test """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Canard.WETTED_AREA, 0.0) add_aviary_input(self, Aircraft.Fuselage.WETTED_AREA, 0.0) diff --git a/aviary/subsystems/geometry/flops_based/wing.py b/aviary/subsystems/geometry/flops_based/wing.py index 7eb02513c..f6c7c09e2 100644 --- a/aviary/subsystems/geometry/flops_based/wing.py +++ b/aviary/subsystems/geometry/flops_based/wing.py @@ -4,7 +4,6 @@ import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft @@ -14,11 +13,6 @@ class WingPrelim(om.ExplicitComponent): preliminary calculations of wing aspect ratio """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Wing.AREA, val=0.0) add_aviary_input(self, Aircraft.Wing.GLOVE_AND_BAT, val=0.0) diff --git a/aviary/subsystems/geometry/gasp_based/electric.py b/aviary/subsystems/geometry/gasp_based/electric.py index 3196bb92b..07d423edd 100644 --- a/aviary/subsystems/geometry/gasp_based/electric.py +++ b/aviary/subsystems/geometry/gasp_based/electric.py @@ -1,8 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -12,16 +11,10 @@ class CableSize(om.ExplicitComponent): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) def setup(self): - aviary_options = self.options['aviary_options'] - total_num_wing_engines = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) + total_num_wing_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES] add_aviary_input(self, Aircraft.Engine.WING_LOCATIONS, val=np.full(int(total_num_wing_engines/2), 0.35)) diff --git a/aviary/subsystems/geometry/gasp_based/empennage.py b/aviary/subsystems/geometry/gasp_based/empennage.py index c0133bc54..5cdb6aa03 100644 --- a/aviary/subsystems/geometry/gasp_based/empennage.py +++ b/aviary/subsystems/geometry/gasp_based/empennage.py @@ -1,8 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input +from aviary.variable_info.functions import add_aviary_input, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -17,10 +16,6 @@ class TailVolCoef(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) self.options.declare( "vertical", default=False, @@ -93,13 +88,6 @@ class TailSize(om.ExplicitComponent): to tail moment arm and the wing span are input. """ - def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): # defaults here for Large Single Aisle 1 horizontal tail self.add_input( @@ -207,10 +195,8 @@ class EmpennageSize(om.Group): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF) + add_aviary_option(self, Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF) def setup(self): # TODO: For cruciform/T-tail configurations, GASP checks to make sure the V tail @@ -220,8 +206,6 @@ def setup(self): # overrides the H tail aspect ratio. H tail taper ratio is used in landing gear # mass calculation. - aviary_options = self.options['aviary_options'] - # higher inputs that are input to groups other than this one, or calculated in groups other than this one higher_level_inputs_htail_vc = [ ("cab_w", Aircraft.Fuselage.AVG_DIAMETER), @@ -288,24 +272,24 @@ def setup(self): ("vol_coef", Aircraft.VerticalTail.VOLUME_COEFFICIENT), ] - if self.options["aviary_options"].get_val(Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF, units='unitless'): + if self.options[Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF]: self.add_subsystem( "htail_vc", - TailVolCoef(aviary_options=aviary_options), + TailVolCoef(), promotes_inputs=higher_level_inputs_htail_vc + ["aircraft:*"], promotes_outputs=connected_outputs_htail_vc, ) - if self.options["aviary_options"].get_val(Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, units='unitless'): + if self.options[Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF]: self.add_subsystem( "vtail_vc", - TailVolCoef(aviary_options=aviary_options, vertical=True), + TailVolCoef(vertical=True), promotes_inputs=higher_level_inputs_vtail_vc + ["aircraft:*"], promotes_outputs=connected_outputs_vtail_vc, ) self.add_subsystem( "htail", - TailSize(aviary_options=aviary_options,), + TailSize(), promotes_inputs=higher_level_inputs_htail + rename_inputs_htail + connected_inputs_htail @@ -315,7 +299,7 @@ def setup(self): self.add_subsystem( "vtail", - TailSize(aviary_options=aviary_options,), + TailSize(), promotes_inputs=higher_level_inputs_vtail + rename_inputs_vtail + connected_inputs_vtail diff --git a/aviary/subsystems/geometry/gasp_based/engine.py b/aviary/subsystems/geometry/gasp_based/engine.py index b39c7f836..545427ac7 100644 --- a/aviary/subsystems/geometry/gasp_based/engine.py +++ b/aviary/subsystems/geometry/gasp_based/engine.py @@ -1,8 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -13,15 +12,10 @@ class EngineSize(om.ExplicitComponent): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Engine.REFERENCE_DIAMETER, np.full(num_engine_type, 5.8)) @@ -39,8 +33,7 @@ def setup(self): def setup_partials(self): # derivatives w.r.t vectorized engine inputs have known sparsity pattern - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) shape = np.arange(num_engine_type) innames = [ diff --git a/aviary/subsystems/geometry/gasp_based/fuselage.py b/aviary/subsystems/geometry/gasp_based/fuselage.py index 3e27a1b5a..f525118f1 100644 --- a/aviary/subsystems/geometry/gasp_based/fuselage.py +++ b/aviary/subsystems/geometry/gasp_based/fuselage.py @@ -1,9 +1,8 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import Verbosity -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Settings @@ -25,11 +24,13 @@ class FuselageParameters(om.ExplicitComponent): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) + add_aviary_option(self, Aircraft.Fuselage.AISLE_WIDTH, units='inch') + add_aviary_option(self, Aircraft.Fuselage.NUM_AISLES) + add_aviary_option(self, Aircraft.Fuselage.NUM_SEATS_ABREAST) + add_aviary_option(self, Aircraft.Fuselage.SEAT_PITCH, units='inch') + add_aviary_option(self, Aircraft.Fuselage.SEAT_WIDTH, units='inch') + add_aviary_option(self, Settings.VERBOSITY) def setup(self): @@ -55,15 +56,15 @@ def setup(self): ) def compute(self, inputs, outputs): - verbosity = self.options['aviary_options'].get_val(Settings.VERBOSITY) - aviary_options: AviaryValues = self.options['aviary_options'] - seats_abreast = aviary_options.get_val(Aircraft.Fuselage.NUM_SEATS_ABREAST) - seat_width = aviary_options.get_val(Aircraft.Fuselage.SEAT_WIDTH, units='inch') - num_aisle = aviary_options.get_val(Aircraft.Fuselage.NUM_AISLES) - aisle_width = aviary_options.get_val(Aircraft.Fuselage.AISLE_WIDTH, units='inch') - PAX = self.options['aviary_options'].get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') - seat_pitch = aviary_options.get_val(Aircraft.Fuselage.SEAT_PITCH, units='inch') + options = self.options + verbosity = options[Settings.VERBOSITY] + seats_abreast = options[Aircraft.Fuselage.NUM_SEATS_ABREAST] + seat_width, _ = options[Aircraft.Fuselage.SEAT_WIDTH] + num_aisle = options[Aircraft.Fuselage.NUM_AISLES] + aisle_width, _ = options[Aircraft.Fuselage.AISLE_WIDTH] + PAX = options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] + seat_pitch, _ = options[Aircraft.Fuselage.SEAT_PITCH] + delta_diameter = inputs[Aircraft.Fuselage.DELTA_DIAMETER] cabin_width = seats_abreast * seat_width + num_aisle * aisle_width + 12 @@ -95,8 +96,8 @@ def compute(self, inputs, outputs): nose_height_b*sigX(100*(seats_abreast-1.5)) def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - seats_abreast = aviary_options.get_val(Aircraft.Fuselage.NUM_SEATS_ABREAST) + options = self.options + seats_abreast = options[Aircraft.Fuselage.NUM_SEATS_ABREAST] J["nose_height", Aircraft.Fuselage.DELTA_DIAMETER] = sigX( 100*(seats_abreast-1.5))*(-1) @@ -107,16 +108,9 @@ def compute_partials(self, inputs, J): class FuselageSize(om.ExplicitComponent): """ Computation of fuselage length, fuselage wetted area, and cabin length - for the tail boom fuselage. + for the tail boom fuselage. """ - def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): add_aviary_input(self, Aircraft.Fuselage.NOSE_FINENESS, val=1) @@ -255,32 +249,21 @@ class FuselageGroup(om.Group): Group to pull together FuselageParameters and FuselageSize. """ - def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): - aviary_options = self.options['aviary_options'] - # outputs from parameters that are used in size but not outside of this group connected_input_outputs = ["cabin_height", "cabin_len", "nose_height"] parameters = self.add_subsystem( "parameters", - FuselageParameters( - aviary_options=aviary_options, - ), + FuselageParameters(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"] + connected_input_outputs, ) size = self.add_subsystem( "size", - FuselageSize(aviary_options=aviary_options,), + FuselageSize(), promotes_inputs=connected_input_outputs + ["aircraft:*"], promotes_outputs=["aircraft:*"], ) diff --git a/aviary/subsystems/geometry/gasp_based/non_dimensional_conversion.py b/aviary/subsystems/geometry/gasp_based/non_dimensional_conversion.py index bfd3fad10..c8da2494b 100644 --- a/aviary/subsystems/geometry/gasp_based/non_dimensional_conversion.py +++ b/aviary/subsystems/geometry/gasp_based/non_dimensional_conversion.py @@ -1,7 +1,6 @@ import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -11,15 +10,13 @@ class StrutCalcs(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED) + add_aviary_option(self, Aircraft.Wing.HAS_STRUT) def setup(self): add_aviary_input(self, Aircraft.Wing.SPAN, val=0) - if self.options["aviary_options"].get_val(Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, units='unitless'): + if self.options[Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED]: add_aviary_input(self, Aircraft.Strut.ATTACHMENT_LOCATION, val=0) add_aviary_output( self, Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, val=0) @@ -30,7 +27,7 @@ def setup(self): def setup_partials(self): - if self.options["aviary_options"].get_val(Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, units='unitless'): + if self.options[Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED]: self.declare_partials( Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, [Aircraft.Strut.ATTACHMENT_LOCATION, Aircraft.Wing.SPAN]) else: @@ -41,8 +38,8 @@ def compute(self, inputs, outputs): wing_span = inputs[Aircraft.Wing.SPAN] strut_loc_name = Aircraft.Strut.ATTACHMENT_LOCATION - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): - if self.options["aviary_options"].get_val(Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, units='unitless'): + if self.options[Aircraft.Wing.HAS_STRUT]: + if self.options[Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED]: strut_x = inputs[strut_loc_name] outputs[strut_loc_name+"_dimensionless"] = strut_x / wing_span else: @@ -53,8 +50,8 @@ def compute_partials(self, inputs, partials): wing_span = inputs[Aircraft.Wing.SPAN] strut_loc_name = Aircraft.Strut.ATTACHMENT_LOCATION - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): - if self.options["aviary_options"].get_val(Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, units='unitless'): + if self.options[Aircraft.Wing.HAS_STRUT]: + if self.options[Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED]: partials[strut_loc_name+"_dimensionless", strut_loc_name] = 1 / wing_span partials[strut_loc_name+"_dimensionless", Aircraft.Wing.SPAN] = - inputs[strut_loc_name] / wing_span**2 @@ -70,16 +67,13 @@ class FoldCalcs(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED) def setup(self): add_aviary_input(self, Aircraft.Wing.SPAN, val=0) - if self.options["aviary_options"].get_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, units='unitless'): - add_aviary_input(self, Aircraft.Wing.FOLDED_SPAN, val=0) + if self.options[Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED]: + add_aviary_input(self, Aircraft.Wing.FOLDED_SPAN, val=25) add_aviary_output(self, Aircraft.Wing.FOLDED_SPAN_DIMENSIONLESS, val=0) else: add_aviary_input(self, Aircraft.Wing.FOLDED_SPAN_DIMENSIONLESS, val=0) @@ -87,7 +81,7 @@ def setup(self): def setup_partials(self): - if self.options["aviary_options"].get_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, units='unitless'): + if self.options[Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED]: self.declare_partials( Aircraft.Wing.FOLDED_SPAN_DIMENSIONLESS, [Aircraft.Wing.FOLDED_SPAN, Aircraft.Wing.SPAN]) else: @@ -98,7 +92,7 @@ def compute(self, inputs, outputs): wing_span = inputs[Aircraft.Wing.SPAN] folded_span_name = Aircraft.Wing.FOLDED_SPAN - if self.options["aviary_options"].get_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, units='unitless'): + if self.options[Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED]: fold_y = inputs[folded_span_name] outputs[folded_span_name+"_dimensionless"] = fold_y / wing_span else: @@ -109,7 +103,7 @@ def compute_partials(self, inputs, partials): wing_span = inputs[Aircraft.Wing.SPAN] folded_span_name = Aircraft.Wing.FOLDED_SPAN - if self.options["aviary_options"].get_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, units='unitless'): + if self.options[Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED]: partials[folded_span_name+"_dimensionless", folded_span_name] = 1 / wing_span partials[folded_span_name+"_dimensionless", Aircraft.Wing.SPAN] = - \ inputs[folded_span_name] / (wing_span**2) @@ -125,28 +119,23 @@ class DimensionalNonDimensionalInterchange(om.Group): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.HAS_FOLD) + add_aviary_option(self, Aircraft.Wing.HAS_STRUT) def setup(self): - aviary_options = self.options['aviary_options'] - - if aviary_options.get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): + if self.options[Aircraft.Wing.HAS_STRUT]: self.add_subsystem( "strut_calcs", - StrutCalcs(aviary_options=aviary_options,), + StrutCalcs(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"], ) - if aviary_options.get_val(Aircraft.Wing.HAS_FOLD, units='unitless'): + if self.options[Aircraft.Wing.HAS_FOLD]: self.add_subsystem( "fold_calcs", - FoldCalcs(aviary_options=aviary_options,), + FoldCalcs(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"], ) diff --git a/aviary/subsystems/geometry/gasp_based/size_group.py b/aviary/subsystems/geometry/gasp_based/size_group.py index c17acae03..bb061764c 100644 --- a/aviary/subsystems/geometry/gasp_based/size_group.py +++ b/aviary/subsystems/geometry/gasp_based/size_group.py @@ -5,61 +5,50 @@ from aviary.subsystems.geometry.gasp_based.engine import EngineSize from aviary.subsystems.geometry.gasp_based.fuselage import FuselageGroup from aviary.subsystems.geometry.gasp_based.wing import WingGroup -from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft class SizeGroup(om.Group): - """ Group to pull together all the different components and subgroups of the SIZE subroutine - """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Electrical.HAS_HYBRID_SYSTEM) def setup(self): - aviary_options = self.options['aviary_options'] self.add_subsystem( "fuselage", - FuselageGroup( - aviary_options=aviary_options, - ), + FuselageGroup(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"], ) self.add_subsystem( "wing", - WingGroup( - aviary_options=aviary_options, - ), + WingGroup(), promotes=["aircraft:*", "mission:*"], ) self.add_subsystem( "empennage", - EmpennageSize(aviary_options=aviary_options,), + EmpennageSize(), promotes=["aircraft:*"], ) self.add_subsystem( "engine", - EngineSize(aviary_options=aviary_options,), + EngineSize(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"], ) - if self.options["aviary_options"].get_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, units='unitless'): + if self.options[Aircraft.Electrical.HAS_HYBRID_SYSTEM]: self.add_subsystem( "cable", - CableSize(aviary_options=aviary_options,), + CableSize(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"], ) diff --git a/aviary/subsystems/geometry/gasp_based/strut.py b/aviary/subsystems/geometry/gasp_based/strut.py index c6443cc4d..2c3fd83f0 100644 --- a/aviary/subsystems/geometry/gasp_based/strut.py +++ b/aviary/subsystems/geometry/gasp_based/strut.py @@ -3,7 +3,6 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft @@ -13,12 +12,6 @@ class StrutGeom(om.ExplicitComponent): Computation of strut length, strut area, and strut chord for GASP-based geometry. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): add_aviary_input(self, Aircraft.Wing.AREA, val=150) diff --git a/aviary/subsystems/geometry/gasp_based/test/test_electric.py b/aviary/subsystems/geometry/gasp_based/test/test_electric.py index 05ac0bd71..9116a4dc7 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_electric.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_electric.py @@ -5,6 +5,7 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.geometry.gasp_based.electric import CableSize +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft from aviary.utils.aviary_values import AviaryValues @@ -17,8 +18,7 @@ def setUp(self): aviary_options = AviaryValues() aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 2) - self.prob.model.add_subsystem("cable", CableSize( - aviary_options=aviary_options), promotes=["*"]) + self.prob.model.add_subsystem("cable", CableSize(), promotes=["*"]) self.prob.model.set_input_defaults( Aircraft.Engine.WING_LOCATIONS, 0.35, units="unitless" @@ -30,6 +30,8 @@ def setUp(self): Aircraft.Fuselage.AVG_DIAMETER, 10, units="ft" ) # not actual GASP value + setup_model_options(self.prob, aviary_options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -53,8 +55,7 @@ def test_case_multiengine(self): # aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2, 4])) aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 6) - prob.model.add_subsystem("cable", CableSize( - aviary_options=aviary_options), promotes=["*"]) + prob.model.add_subsystem("cable", CableSize(), promotes=["*"]) prob.model.set_input_defaults( Aircraft.Engine.WING_LOCATIONS, np.array([0.35, 0.2, 0.6]), units="unitless" @@ -66,6 +67,8 @@ def test_case_multiengine(self): Aircraft.Fuselage.AVG_DIAMETER, 10, units="ft" ) + setup_model_options(prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) prob.run_model() diff --git a/aviary/subsystems/geometry/gasp_based/test/test_empennage.py b/aviary/subsystems/geometry/gasp_based/test/test_empennage.py index d5eb4e813..aa77dbeab 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_empennage.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_empennage.py @@ -7,6 +7,7 @@ from aviary.subsystems.geometry.gasp_based.empennage import (EmpennageSize, TailSize, TailVolCoef) +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft @@ -158,7 +159,6 @@ def setUp(self): ) def test_large_sinle_aisle_1_defaults(self): - self.prob.model.emp.options["aviary_options"] = get_option_defaults() self.prob.setup(check=False, force_alloc_complex=True) @@ -193,7 +193,9 @@ def test_large_sinle_aisle_1_calc_volcoefs(self): val=True, units='unitless') options.set_val(Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, val=True, units='unitless') - self.prob.model.emp.options["aviary_options"] = options + + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) self.prob.set_val( diff --git a/aviary/subsystems/geometry/gasp_based/test/test_engine.py b/aviary/subsystems/geometry/gasp_based/test/test_engine.py index 5e9538972..09fbe365e 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_engine.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_engine.py @@ -5,6 +5,7 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.geometry.gasp_based.engine import EngineSize +from aviary.variable_info.functions import setup_model_options, extract_options from aviary.variable_info.variables import Aircraft from aviary.utils.aviary_values import AviaryValues @@ -18,8 +19,7 @@ def setUp(self): aviary_options = AviaryValues() aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2])) - self.prob.model.add_subsystem("engsz", EngineSize( - aviary_options=aviary_options), promotes=["*"]) + self.prob.model.add_subsystem("engsz", EngineSize(), promotes=["*"]) self.prob.model.set_input_defaults( Aircraft.Engine.REFERENCE_DIAMETER, 5.8, units="ft") @@ -31,6 +31,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Nacelle.FINENESS, 2, units="unitless") + setup_model_options(self.prob, aviary_options) + self.prob.setup(check=False, force_alloc_complex=True) def test_large_sinle_aisle_1_defaults(self): @@ -52,8 +54,7 @@ def test_case_multiengine(self): aviary_options = AviaryValues() aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2, 4])) - prob.model.add_subsystem("cable", EngineSize( - aviary_options=aviary_options), promotes=["*"]) + prob.model.add_subsystem("cable", EngineSize(), promotes=["*"]) prob.model.set_input_defaults( Aircraft.Engine.REFERENCE_DIAMETER, np.array([5.8, 8.2]), units="ft") @@ -65,6 +66,8 @@ def test_case_multiengine(self): prob.model.set_input_defaults( Aircraft.Nacelle.FINENESS, np.array([2, 2.21]), units="unitless") + prob.model_options['*'] = extract_options(aviary_options) + prob.setup(check=False, force_alloc_complex=True) prob.run_model() diff --git a/aviary/subsystems/geometry/gasp_based/test/test_fuselage.py b/aviary/subsystems/geometry/gasp_based/test/test_fuselage.py index b40f34f9d..efd6a29d8 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_fuselage.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_fuselage.py @@ -6,6 +6,7 @@ from aviary.subsystems.geometry.gasp_based.fuselage import (FuselageGroup, FuselageParameters, FuselageSize) +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft @@ -18,7 +19,7 @@ class FuselageParametersTestCase1(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, val=180) options.set_val(Aircraft.Fuselage.AISLE_WIDTH, 24, units="inch") options.set_val(Aircraft.Fuselage.NUM_AISLES, 1) options.set_val(Aircraft.Fuselage.NUM_SEATS_ABREAST, 6) @@ -28,7 +29,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "parameters", - FuselageParameters(aviary_options=options), + FuselageParameters(), promotes=["*"], ) @@ -37,6 +38,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, 9.5, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -57,7 +60,8 @@ class FuselageParametersTestCase2(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=30, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=30, units='unitless') options.set_val(Aircraft.Fuselage.AISLE_WIDTH, 24, units="inch") options.set_val(Aircraft.Fuselage.NUM_AISLES, 1) options.set_val(Aircraft.Fuselage.NUM_SEATS_ABREAST, 1) @@ -67,7 +71,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "parameters", - FuselageParameters(aviary_options=options), + FuselageParameters(), promotes=["*"], ) @@ -76,6 +80,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, 9.5, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case2(self): @@ -93,16 +99,14 @@ def test_case2(self): class FuselageSizeTestCase1(unittest.TestCase): - """ + """ this is the GASP test case, input and output values based on large single aisle 1 v3 without bug fix """ def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem( - "size", FuselageSize(aviary_options=get_option_defaults()), promotes=["*"] - ) + self.prob.model.add_subsystem("size", FuselageSize(), promotes=["*"]) self.prob.model.set_input_defaults( Aircraft.Fuselage.NOSE_FINENESS, 1, units="unitless") @@ -144,7 +148,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "parameters", FuselageSize(aviary_options=options), promotes=["*"] + "parameters", FuselageSize(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -159,6 +163,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Fuselage.WETTED_AREA_SCALER, 1, units="unitless") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case2(self): @@ -186,7 +192,8 @@ class FuselageGroupTestCase1( def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.Fuselage.AISLE_WIDTH, 24, units="inch") options.set_val(Aircraft.Fuselage.NUM_AISLES, 1) options.set_val(Aircraft.Fuselage.NUM_SEATS_ABREAST, 6) @@ -196,7 +203,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - FuselageGroup(aviary_options=options), + FuselageGroup(), promotes=["*"], ) @@ -211,6 +218,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, 9.5, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -235,7 +244,8 @@ class FuselageGroupTestCase2(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.Fuselage.AISLE_WIDTH, 24, units="inch") # not actual GASP value options.set_val(Aircraft.Fuselage.NUM_AISLES, 1) # not actual GASP value @@ -248,7 +258,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - FuselageGroup(aviary_options=options), + FuselageGroup(), promotes=["*"], ) @@ -267,6 +277,8 @@ def setUp(self): Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, 9.5, units="ft" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -295,7 +307,8 @@ class FuselageGroupTestCase3(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=30, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=30, units='unitless') options.set_val(Aircraft.Fuselage.AISLE_WIDTH, 24, units="inch") # not actual GASP value options.set_val(Aircraft.Fuselage.NUM_AISLES, 1) # not actual GASP value @@ -308,7 +321,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - FuselageGroup(aviary_options=options), + FuselageGroup(), promotes=["*"], ) @@ -327,6 +340,8 @@ def setUp(self): Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, 9.5, units="ft" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -355,7 +370,8 @@ class FuselageGroupTestCase4(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=30, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=30, units='unitless') options.set_val(Aircraft.Fuselage.AISLE_WIDTH, 24, units="inch") # not actual GASP value options.set_val(Aircraft.Fuselage.NUM_AISLES, 1) # not actual GASP value @@ -368,7 +384,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - FuselageGroup(aviary_options=options), + FuselageGroup(), promotes=["*"], ) @@ -387,6 +403,8 @@ def setUp(self): Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, 9.5, units="ft" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): diff --git a/aviary/subsystems/geometry/gasp_based/test/test_non_dimensional_conversion.py b/aviary/subsystems/geometry/gasp_based/test/test_non_dimensional_conversion.py index adc7f6963..7aaf3a7c5 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_non_dimensional_conversion.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_non_dimensional_conversion.py @@ -8,6 +8,7 @@ from aviary.variable_info.variables import Aircraft from aviary.subsystems.geometry.gasp_based.non_dimensional_conversion import DimensionalNonDimensionalInterchange +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults @@ -20,8 +21,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem("dimensionless_calcs", - DimensionalNonDimensionalInterchange( - aviary_options=options), + DimensionalNonDimensionalInterchange(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"] ) @@ -33,6 +33,8 @@ def setUp(self): Aircraft.Wing.FOLDED_SPAN, val=118.0, units="ft" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -55,8 +57,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem("dimensionless_calcs", - DimensionalNonDimensionalInterchange( - aviary_options=options), + DimensionalNonDimensionalInterchange(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"] ) @@ -68,6 +69,8 @@ def setUp(self): Aircraft.Wing.FOLDED_SPAN_DIMENSIONLESS, val=0.5, units="unitless" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -90,8 +93,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem("dimensionless_calcs", - DimensionalNonDimensionalInterchange( - aviary_options=options), + DimensionalNonDimensionalInterchange(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"] ) @@ -103,6 +105,8 @@ def setUp(self): Aircraft.Strut.ATTACHMENT_LOCATION, val=118.0, units="ft" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -125,8 +129,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem("dimensionless_calcs", - DimensionalNonDimensionalInterchange( - aviary_options=options), + DimensionalNonDimensionalInterchange(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"] ) @@ -138,6 +141,8 @@ def setUp(self): Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, val=0.5, units="unitless" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -163,8 +168,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem("dimensionless_calcs", - DimensionalNonDimensionalInterchange( - aviary_options=options), + DimensionalNonDimensionalInterchange(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"] ) @@ -179,6 +183,8 @@ def setUp(self): Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, val=0.5, units="unitless" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -207,8 +213,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem("dimensionless_calcs", - DimensionalNonDimensionalInterchange( - aviary_options=options), + DimensionalNonDimensionalInterchange(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"] ) @@ -223,6 +228,8 @@ def setUp(self): Aircraft.Strut.ATTACHMENT_LOCATION, val=90.0, units="ft" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -251,8 +258,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem("dimensionless_calcs", - DimensionalNonDimensionalInterchange( - aviary_options=options), + DimensionalNonDimensionalInterchange(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"] ) @@ -267,6 +273,8 @@ def setUp(self): Aircraft.Strut.ATTACHMENT_LOCATION, val=108.0, units="ft" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): diff --git a/aviary/subsystems/geometry/gasp_based/test/test_override.py b/aviary/subsystems/geometry/gasp_based/test/test_override.py index 2b7973093..e26311714 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_override.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_override.py @@ -10,6 +10,7 @@ from aviary.subsystems.aerodynamics.gasp_based.gaspaero import AeroGeom from aviary.utils.process_input_decks import create_vehicle from aviary.utils.preprocessors import preprocess_propulsion +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData import warnings @@ -53,6 +54,8 @@ def test_case1(self): self.aviary_inputs.set_val( Aircraft.Fuselage.WETTED_AREA, val=4000.0, units="ft**2") + setup_model_options(prob, self.aviary_inputs) + with warnings.catch_warnings(): warnings.simplefilter("ignore", om.PromotionWarning) prob.setup() @@ -67,6 +70,8 @@ def test_case2(self): # self.aviary_inputs.set_val(Aircraft.Fuselage.WETTED_AREA, val=4000, units="ft**2") + setup_model_options(prob, self.aviary_inputs) + with warnings.catch_warnings(): warnings.simplefilter("ignore", om.PromotionWarning) prob.setup() @@ -83,6 +88,8 @@ def test_case3(self): self.aviary_inputs.set_val( Aircraft.Fuselage.WETTED_AREA_SCALER, val=0.5, units="unitless") + setup_model_options(prob, self.aviary_inputs) + with warnings.catch_warnings(): warnings.simplefilter("ignore", om.PromotionWarning) prob.setup() @@ -100,6 +107,8 @@ def test_case4(self): self.aviary_inputs.set_val( Aircraft.Fuselage.WETTED_AREA_SCALER, val=0.5, units="unitless") + setup_model_options(prob, self.aviary_inputs) + with warnings.catch_warnings(): warnings.simplefilter("ignore", om.PromotionWarning) prob.setup() @@ -114,10 +123,11 @@ def test_case_aero_coeffs(self): Also checks non-overriden (wing) and default (strut) """ prob = self.prob - prob.model.add_subsystem("geom", AeroGeom( - aviary_options=self.aviary_inputs), promotes=["*"]) + prob.model.add_subsystem("geom", AeroGeom(), promotes=["*"]) self.aviary_inputs.set_val(Aircraft.HorizontalTail.FORM_FACTOR, val=1.5) + setup_model_options(prob, self.aviary_inputs) + with warnings.catch_warnings(): warnings.simplefilter("ignore", om.PromotionWarning) prob.setup() diff --git a/aviary/subsystems/geometry/gasp_based/test/test_size_group.py b/aviary/subsystems/geometry/gasp_based/test/test_size_group.py index 0a9530218..90ad3170a 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_size_group.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_size_group.py @@ -5,6 +5,7 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.geometry.gasp_based.size_group import SizeGroup +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission @@ -17,7 +18,8 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.Fuselage.AISLE_WIDTH, 24, units="inch") options.set_val(Aircraft.Fuselage.NUM_AISLES, 1) options.set_val(Aircraft.Fuselage.NUM_SEATS_ABREAST, 6) @@ -27,9 +29,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes=["*"], ) @@ -97,6 +97,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Nacelle.FINENESS, 2, units="unitless") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -164,7 +166,8 @@ def setUp(self): options.set_val(Aircraft.Wing.HAS_STRUT, val=True, units='unitless') options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') options.set_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, val=True, units='unitless') @@ -179,9 +182,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes=["*"], ) @@ -252,6 +253,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Nacelle.FINENESS, 2, units="unitless") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -384,7 +387,8 @@ def setUp(self): val=True, units='unitless') options.set_val(Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, val=True, units='unitless') - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, val=True, units='unitless') options.set_val(Aircraft.Fuselage.AISLE_WIDTH, 24, units="inch") @@ -396,9 +400,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes=["*"], ) @@ -475,6 +477,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Nacelle.FINENESS, 2, units="unitless") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -607,7 +611,8 @@ def setUp(self): val=False, units='unitless') options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.Fuselage.AISLE_WIDTH, 24, units="inch") options.set_val(Aircraft.Fuselage.NUM_AISLES, 1) options.set_val(Aircraft.Fuselage.NUM_SEATS_ABREAST, 1) @@ -617,9 +622,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes=["*"], ) @@ -696,6 +699,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Nacelle.FINENESS, 2, units="unitless") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): diff --git a/aviary/subsystems/geometry/gasp_based/test/test_strut.py b/aviary/subsystems/geometry/gasp_based/test/test_strut.py index d2c14daa8..e3eaf569b 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_strut.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_strut.py @@ -12,8 +12,7 @@ class SizeGroupTestCase1(unittest.TestCase): def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem("strut", StrutGeom( - aviary_options=get_option_defaults()), promotes=["*"]) + self.prob.model.add_subsystem("strut", StrutGeom(), promotes=["*"]) self.prob.model.set_input_defaults( Aircraft.Strut.AREA_RATIO, val=.2, units=None diff --git a/aviary/subsystems/geometry/gasp_based/test/test_wing.py b/aviary/subsystems/geometry/gasp_based/test/test_wing.py index 0bbd89fbc..5cb91f101 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_wing.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_wing.py @@ -6,6 +6,7 @@ from aviary.subsystems.geometry.gasp_based.wing import (WingFold, WingGroup, WingParameters, WingSize) +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission @@ -71,7 +72,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "parameters", WingParameters(aviary_options=get_option_defaults()), promotes=["*"] + "parameters", WingParameters(), promotes=["*"] ) self.prob.model.set_input_defaults(Aircraft.Wing.AREA, 1370.3, units="ft**2") @@ -121,7 +122,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "parameters", WingParameters(aviary_options=options), promotes=["*"] + "parameters", WingParameters(), promotes=["*"] ) self.prob.model.set_input_defaults(Aircraft.Wing.AREA, 1370.3, units="ft**2") @@ -141,6 +142,8 @@ def setUp(self): Aircraft.Wing.THICKNESS_TO_CHORD_TIP, 0.12, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -170,9 +173,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - WingFold( - aviary_options=options, - ), + WingFold(), promotes=["*"], ) @@ -195,6 +196,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, 0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -236,9 +239,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - WingFold( - aviary_options=options - ), + WingFold(), promotes=["*"], ) @@ -261,6 +262,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, 0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -299,7 +302,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "group", WingGroup(aviary_options=get_option_defaults()), promotes=["*"] + "group", WingGroup(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -371,9 +374,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - WingGroup( - aviary_options=options, - ), + WingGroup(), promotes=["*"], ) @@ -410,6 +411,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, 0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -473,9 +476,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - WingGroup( - aviary_options=options, - ), + WingGroup(), promotes=["*"], ) @@ -508,6 +509,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, 0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -567,9 +570,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - WingGroup( - aviary_options=options, - ), + WingGroup(), promotes=["*"], ) @@ -580,6 +581,8 @@ def setUp(self): Aircraft.Strut.ATTACHMENT_LOCATION, val=0, units="ft" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -623,9 +626,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - WingGroup( - aviary_options=options, - ), + WingGroup(), promotes=["*"], ) @@ -668,6 +669,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, 0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): diff --git a/aviary/subsystems/geometry/gasp_based/wing.py b/aviary/subsystems/geometry/gasp_based/wing.py index 122938c2d..85ce6cf1b 100644 --- a/aviary/subsystems/geometry/gasp_based/wing.py +++ b/aviary/subsystems/geometry/gasp_based/wing.py @@ -5,9 +5,8 @@ from aviary.subsystems.geometry.gasp_based.non_dimensional_conversion import \ DimensionalNonDimensionalInterchange from aviary.subsystems.geometry.gasp_based.strut import StrutGeom -from aviary.utils.aviary_values import AviaryValues from aviary.utils.conflict_checks import check_fold_location_definition -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -16,12 +15,6 @@ class WingSize(om.ExplicitComponent): Computation of wing area and wing span for GASP-based aerodynamics. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): add_aviary_input(self, Mission.Design.GROSS_MASS, val=152000) @@ -86,11 +79,7 @@ class WingParameters(om.ExplicitComponent): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.HAS_FOLD) def setup(self): @@ -103,7 +92,7 @@ def setup(self): add_aviary_input(self, Aircraft.Fuselage.AVG_DIAMETER, val=10) add_aviary_input(self, Aircraft.Wing.THICKNESS_TO_CHORD_TIP, val=0.1) - if not self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless'): + if not self.options[Aircraft.Wing.HAS_FOLD]: add_aviary_input(self, Aircraft.Fuel.WING_FUEL_FRACTION, val=0.6) add_aviary_output(self, Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, val=0) @@ -214,7 +203,7 @@ def compute(self, inputs, outputs): outputs[Aircraft.Wing.ROOT_CHORD] = root_chord outputs[Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED] = tc_ratio_avg - if not self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless'): + if not self.options[Aircraft.Wing.HAS_FOLD]: fuel_vol_frac = inputs[Aircraft.Fuel.WING_FUEL_FRACTION] geometric_fuel_vol = ( @@ -430,7 +419,7 @@ def compute_partials(self, inputs, J): np.pi * AR**2 * trp1**2 / denom / 180 / np.cos(swprad) ** 2 ) - if not self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless'): + if not self.options[Aircraft.Wing.HAS_FOLD]: fuel_vol_frac = inputs[Aircraft.Fuel.WING_FUEL_FRACTION] geometric_fuel_vol = ( fuel_vol_frac @@ -523,15 +512,11 @@ class WingFold(om.ExplicitComponent): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.CHOOSE_FOLD_LOCATION) def setup(self): - if not self.options["aviary_options"].get_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, units='unitless'): + if not self.options[Aircraft.Wing.CHOOSE_FOLD_LOCATION]: self.add_input( "strut_y", val=25, @@ -639,7 +624,7 @@ def compute(self, inputs, outputs): tc_ratio_tip = inputs[Aircraft.Wing.THICKNESS_TO_CHORD_TIP] fuel_vol_frac = inputs[Aircraft.Fuel.WING_FUEL_FRACTION] - if not self.options["aviary_options"].get_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, units='unitless'): + if not self.options[Aircraft.Wing.CHOOSE_FOLD_LOCATION]: strut_y = inputs["strut_y"] location = strut_y @@ -692,7 +677,7 @@ def compute_partials(self, inputs, J): tc_ratio_tip = inputs[Aircraft.Wing.THICKNESS_TO_CHORD_TIP] fuel_vol_frac = inputs[Aircraft.Fuel.WING_FUEL_FRACTION] - if not self.options["aviary_options"].get_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, units='unitless'): + if not self.options[Aircraft.Wing.CHOOSE_FOLD_LOCATION]: strut_y = inputs["strut_y"] location = strut_y @@ -971,60 +956,56 @@ class WingGroup(om.Group): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.CHOOSE_FOLD_LOCATION) + add_aviary_option(self, Aircraft.Wing.HAS_FOLD) + add_aviary_option(self, Aircraft.Wing.HAS_STRUT) def setup(self): - aviary_options = self.options['aviary_options'] + has_fold = self.options[Aircraft.Wing.HAS_FOLD] + has_strut = self.options[Aircraft.Wing.HAS_STRUT] size = self.add_subsystem( "size", - WingSize(aviary_options=aviary_options,), + WingSize(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=["aircraft:*"], ) - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless') or self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): + if has_fold or has_strut: self.add_subsystem( "dimensionless_calcs", - DimensionalNonDimensionalInterchange(aviary_options=aviary_options), + DimensionalNonDimensionalInterchange(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"] ) parameters = self.add_subsystem( "parameters", - WingParameters(aviary_options=aviary_options,), + WingParameters(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"], ) - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): + if has_strut: strut = self.add_subsystem( "strut", - StrutGeom( - aviary_options=aviary_options, - ), + StrutGeom(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"], ) - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless'): + if has_fold: fold = self.add_subsystem( "fold", - WingFold( - aviary_options=aviary_options, - ), + WingFold(), promotes_inputs=["aircraft:*"], promotes_outputs=["aircraft:*"], ) - if not self.options["aviary_options"].get_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, units='unitless'): - check_fold_location_definition(None, aviary_options) + choose_fold_location = self.options[Aircraft.Wing.CHOOSE_FOLD_LOCATION] + if not choose_fold_location: + check_fold_location_definition(choose_fold_location, has_strut) self.promotes("strut", outputs=["strut_y"]) self.promotes("fold", inputs=["strut_y"]) diff --git a/aviary/subsystems/geometry/geometry_builder.py b/aviary/subsystems/geometry/geometry_builder.py index 04f87d4b9..37c3b7358 100644 --- a/aviary/subsystems/geometry/geometry_builder.py +++ b/aviary/subsystems/geometry/geometry_builder.py @@ -90,15 +90,16 @@ def build_pre_mission(self, aviary_inputs): geom_group = None if both_geom: - geom_group = CombinedGeometry(aviary_options=aviary_inputs, - code_origin_to_prioritize=code_origin_to_prioritize) + geom_group = CombinedGeometry( + code_origin_to_prioritize=code_origin_to_prioritize + ) elif code_origin is GASP: - geom_group = SizeGroup(aviary_options=aviary_inputs) + geom_group = SizeGroup() geom_group.manual_overrides = None elif code_origin is FLOPS: - geom_group = PrepGeom(aviary_options=aviary_inputs) + geom_group = PrepGeom() geom_group.manual_overrides = None return geom_group @@ -111,10 +112,11 @@ def get_parameters(self, aviary_inputs=None, phase_info=None): params = {} for entry in Aircraft.Nacelle.__dict__: - var = getattr(Aircraft.Nacelle, entry) - if var in aviary_inputs: - if 'total' not in var: - params[var] = {'shape': (num_engine_type), 'static_target': True} + if entry != "__dict__": # cannot get attribute from mappingproxy + var = getattr(Aircraft.Nacelle, entry) + if var in aviary_inputs: + if 'total' not in var: + params[var] = {'shape': (num_engine_type), 'static_target': True} return params diff --git a/aviary/subsystems/geometry/test/test_flops_geom_builder.py b/aviary/subsystems/geometry/test/test_flops_geom_builder.py new file mode 100644 index 000000000..fa2fd4bb4 --- /dev/null +++ b/aviary/subsystems/geometry/test/test_flops_geom_builder.py @@ -0,0 +1,87 @@ +import unittest + +import numpy as np +import openmdao.api as om + +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal + +from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder +from aviary.variable_info.enums import LegacyCode +from aviary.variable_info.variables import Aircraft +from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData +import aviary.api as av + +FLOPS = LegacyCode.FLOPS + + +class TestFLOPSGeomBuilder(av.TestSubsystemBuilderBase): + """ + That class inherits from TestSubsystemBuilder. So all the test functions are + within that inherited class. The setUp() method prepares the class and is run + before the test methods; then the test methods are run. + """ + + def setUp(self): + self.subsystem_builder = CoreGeometryBuilder( + 'core_geometry', + BaseMetaData, + use_both_geometries=False, + code_origin=FLOPS, + code_origin_to_prioritize=FLOPS) + self.aviary_values = av.AviaryValues() + self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') + self.aviary_values.set_val( + Aircraft.Electrical.HAS_HYBRID_SYSTEM, False, units='unitless') + self.aviary_values.set_val(Aircraft.Wing.HAS_FOLD, True, units='unitless') + self.aviary_values.set_val(Aircraft.Wing.HAS_STRUT, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.CHOOSE_FOLD_LOCATION, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, True, units='unitless') + + +class TestFLOPSGeomBuilderHybrid(av.TestSubsystemBuilderBase): + """ + That class inherits from TestSubsystemBuilder. So all the test functions are + within that inherited class. The setUp() method prepares the class and is run + before the test methods; then the test methods are run. + """ + + def setUp(self): + self.subsystem_builder = CoreGeometryBuilder( + 'core_geometry', + BaseMetaData, + use_both_geometries=True, + code_origin_to_prioritize=FLOPS) + self.aviary_values = av.AviaryValues() + self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') + self.aviary_values.set_val( + Aircraft.Electrical.HAS_HYBRID_SYSTEM, True, units='unitless') + self.aviary_values.set_val(Aircraft.Wing.HAS_FOLD, True, units='unitless') + self.aviary_values.set_val(Aircraft.Wing.HAS_STRUT, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.CHOOSE_FOLD_LOCATION, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 2, units='unitless') + + +if __name__ == '__main__': + unittest.main() diff --git a/aviary/subsystems/geometry/test/test_gasp_geom_builder.py b/aviary/subsystems/geometry/test/test_gasp_geom_builder.py new file mode 100644 index 000000000..bc0e33c0c --- /dev/null +++ b/aviary/subsystems/geometry/test/test_gasp_geom_builder.py @@ -0,0 +1,87 @@ +import unittest + +import numpy as np +import openmdao.api as om + +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal + +from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder +from aviary.variable_info.enums import LegacyCode +from aviary.variable_info.variables import Aircraft +from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData +import aviary.api as av + +GASP = LegacyCode.GASP + + +class TestGASPGeomBuilder(av.TestSubsystemBuilderBase): + """ + That class inherits from TestSubsystemBuilder. So all the test functions are + within that inherited class. The setUp() method prepares the class and is run + before the test methods; then the test methods are run. + """ + + def setUp(self): + self.subsystem_builder = CoreGeometryBuilder( + 'core_geometry', + BaseMetaData, + use_both_geometries=False, + code_origin=GASP, + code_origin_to_prioritize=GASP) + self.aviary_values = av.AviaryValues() + self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') + self.aviary_values.set_val( + Aircraft.Electrical.HAS_HYBRID_SYSTEM, False, units='unitless') + self.aviary_values.set_val(Aircraft.Wing.HAS_FOLD, True, units='unitless') + self.aviary_values.set_val(Aircraft.Wing.HAS_STRUT, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.CHOOSE_FOLD_LOCATION, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, True, units='unitless') + + +class TestGASPGeomBuilderHybrid(av.TestSubsystemBuilderBase): + """ + That class inherits from TestSubsystemBuilder. So all the test functions are + within that inherited class. The setUp() method prepares the class and is run + before the test methods; then the test methods are run. + """ + + def setUp(self): + self.subsystem_builder = CoreGeometryBuilder( + 'core_geometry', + BaseMetaData, + use_both_geometries=True, + code_origin_to_prioritize=GASP) + self.aviary_values = av.AviaryValues() + self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') + self.aviary_values.set_val( + Aircraft.Electrical.HAS_HYBRID_SYSTEM, True, units='unitless') + self.aviary_values.set_val(Aircraft.Wing.HAS_FOLD, True, units='unitless') + self.aviary_values.set_val(Aircraft.Wing.HAS_STRUT, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.CHOOSE_FOLD_LOCATION, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, True, units='unitless') + self.aviary_values.set_val( + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 2, units='unitless') + + +if __name__ == '__main__': + unittest.main() diff --git a/aviary/subsystems/mass/flops_based/air_conditioning.py b/aviary/subsystems/mass/flops_based/air_conditioning.py index 98605525e..4e2db1cfe 100644 --- a/aviary/subsystems/mass/flops_based/air_conditioning.py +++ b/aviary/subsystems/mass/flops_based/air_conditioning.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import ( distributed_engine_count_factor, distributed_thrust_factor) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -16,9 +15,8 @@ class TransportAirCondMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) + add_aviary_option(self, Mission.Constraints.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.AirConditioning.MASS_SCALER, val=1.0) @@ -35,30 +33,26 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - pax = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] scaler = inputs[Aircraft.AirConditioning.MASS_SCALER] avionics_wt = inputs[Aircraft.Avionics.MASS] * GRAV_ENGLISH_LBM height = inputs[Aircraft.Fuselage.MAX_HEIGHT] planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] outputs[Aircraft.AirConditioning.MASS] = \ ((3.2 * (planform * height)**0.6 + 9 * pax**0.83) * max_mach + 0.075 * avionics_wt) * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - pax = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] scaler = inputs[Aircraft.AirConditioning.MASS_SCALER] avionics_wt = inputs[Aircraft.Avionics.MASS] * GRAV_ENGLISH_LBM height = inputs[Aircraft.Fuselage.MAX_HEIGHT] planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] planform_exp = planform**0.6 height_exp = height**0.6 @@ -86,9 +80,7 @@ class AltAirCondMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) def setup(self): add_aviary_input(self, Aircraft.AirConditioning.MASS_SCALER, val=1.0) @@ -99,9 +91,7 @@ def setup_partials(self): self.declare_partials(of=Aircraft.AirConditioning.MASS, wrt='*') def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - num_pax = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + num_pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] scaler = inputs[Aircraft.AirConditioning.MASS_SCALER] @@ -109,9 +99,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): 26.0 * num_pax * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_pax = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + num_pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] J[Aircraft.AirConditioning.MASS, Aircraft.AirConditioning.MASS_SCALER] = \ 26.0 * num_pax / GRAV_ENGLISH_LBM diff --git a/aviary/subsystems/mass/flops_based/anti_icing.py b/aviary/subsystems/mass/flops_based/anti_icing.py index 779fc3ca0..9d7a485da 100644 --- a/aviary/subsystems/mass/flops_based/anti_icing.py +++ b/aviary/subsystems/mass/flops_based/anti_icing.py @@ -6,8 +6,7 @@ distributed_engine_count_factor, distributed_nacelle_diam_factor, distributed_nacelle_diam_factor_deriv) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -18,13 +17,11 @@ class AntiIcingMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.AntiIcing.MASS_SCALER, val=1.0) @@ -43,9 +40,8 @@ def setup_partials(self): self.declare_partials("*", "*") def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - total_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) - num_engines = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + total_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] scaler = inputs[Aircraft.AntiIcing.MASS_SCALER] max_width = inputs[Aircraft.Fuselage.MAX_WIDTH] @@ -61,9 +57,8 @@ def compute(self, inputs, outputs): + 3.8 * f_nacelle * count_factor + 1.5 * max_width) * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - total_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) - num_engines = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + total_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] scaler = inputs[Aircraft.AntiIcing.MASS_SCALER] max_width = inputs[Aircraft.Fuselage.MAX_WIDTH] diff --git a/aviary/subsystems/mass/flops_based/apu.py b/aviary/subsystems/mass/flops_based/apu.py index c4858be1f..d71b2ac38 100644 --- a/aviary/subsystems/mass/flops_based/apu.py +++ b/aviary/subsystems/mass/flops_based/apu.py @@ -1,8 +1,7 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -13,9 +12,7 @@ class TransportAPUMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) def setup(self): add_aviary_input(self, Aircraft.APU.MASS_SCALER, val=1.0) @@ -28,9 +25,7 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - pax = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] scaler = inputs[Aircraft.APU.MASS_SCALER] planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] @@ -38,9 +33,7 @@ def compute(self, inputs, outputs): 54.0 * planform ** 0.3 + 5.4 * pax ** 0.9) * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - pax = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] scaler = inputs[Aircraft.APU.MASS_SCALER] planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] diff --git a/aviary/subsystems/mass/flops_based/avionics.py b/aviary/subsystems/mass/flops_based/avionics.py index 0c6e54522..1f7e75f7d 100644 --- a/aviary/subsystems/mass/flops_based/avionics.py +++ b/aviary/subsystems/mass/flops_based/avionics.py @@ -1,8 +1,7 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -14,9 +13,7 @@ class TransportAvionicsMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.NUM_FLIGHT_CREW) def setup(self): add_aviary_input(self, Aircraft.Avionics.MASS_SCALER, val=1.0) @@ -31,8 +28,7 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - crew = aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) + crew = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] scaler = inputs[Aircraft.Avionics.MASS_SCALER] planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] des_range = inputs[Mission.Design.RANGE] @@ -41,8 +37,7 @@ def compute(self, inputs, outputs): 15.8 * des_range**0.1 * crew**0.7 * planform**0.43 * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - crew = aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) + crew = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] scaler = inputs[Aircraft.Avionics.MASS_SCALER] planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] des_range = inputs[Mission.Design.RANGE] diff --git a/aviary/subsystems/mass/flops_based/canard.py b/aviary/subsystems/mass/flops_based/canard.py index 9223872f1..e40b374d3 100644 --- a/aviary/subsystems/mass/flops_based/canard.py +++ b/aviary/subsystems/mass/flops_based/canard.py @@ -1,7 +1,6 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft, Mission @@ -12,11 +11,6 @@ class CanardMass(om.ExplicitComponent): equations, modified to output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Mission.Design.GROSS_MASS, val=0.0) add_aviary_input(self, Aircraft.Canard.AREA, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/cargo.py b/aviary/subsystems/mass/flops_based/cargo.py index 8ac83f493..dd388e067 100644 --- a/aviary/subsystems/mass/flops_based/cargo.py +++ b/aviary/subsystems/mass/flops_based/cargo.py @@ -5,8 +5,7 @@ ''' import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -17,9 +16,10 @@ class CargoMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, + units='lbm') + add_aviary_option(self, Aircraft.CrewPayload.MASS_PER_PASSENGER, units='lbm') + add_aviary_option(self, Aircraft.CrewPayload.NUM_PASSENGERS) def setup(self): add_aviary_output(self, Aircraft.CrewPayload.PASSENGER_MASS, 0.) @@ -54,14 +54,9 @@ def setup_partials(self): def compute( self, inputs, outputs, discrete_inputs=None, discrete_outputs=None ): - aviary_options: AviaryValues = self.options['aviary_options'] - passenger_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) - - mass_per_passenger = aviary_options.get_val( - Aircraft.CrewPayload.MASS_PER_PASSENGER, units='lbm') - - baggage_mass_per_passenger = aviary_options.get_val( - Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 'lbm') + passenger_count = self.options[Aircraft.CrewPayload.NUM_PASSENGERS] + mass_per_passenger, _ = self.options[Aircraft.CrewPayload.MASS_PER_PASSENGER] + baggage_mass_per_passenger, _ = self.options[Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER] outputs[Aircraft.CrewPayload.PASSENGER_MASS] = \ mass_per_passenger * passenger_count diff --git a/aviary/subsystems/mass/flops_based/cargo_containers.py b/aviary/subsystems/mass/flops_based/cargo_containers.py index df0967439..18460dcaf 100644 --- a/aviary/subsystems/mass/flops_based/cargo_containers.py +++ b/aviary/subsystems/mass/flops_based/cargo_containers.py @@ -2,7 +2,6 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft @@ -14,11 +13,6 @@ class TransportCargoContainersMass(om.ExplicitComponent): the FLOPS weight equations, modified to output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input( self, Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, val=1.0) diff --git a/aviary/subsystems/mass/flops_based/crew.py b/aviary/subsystems/mass/flops_based/crew.py index 60030710b..924840101 100644 --- a/aviary/subsystems/mass/flops_based/crew.py +++ b/aviary/subsystems/mass/flops_based/crew.py @@ -4,8 +4,7 @@ ''' import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -15,9 +14,8 @@ class NonFlightCrewMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS) + add_aviary_option(self, Aircraft.CrewPayload.NUM_GALLEY_CREW) def setup(self): add_aviary_input( @@ -34,11 +32,8 @@ def setup_partials(self): def compute( self, inputs, outputs, discrete_inputs=None, discrete_outputs=None ): - aviary_options: AviaryValues = self.options['aviary_options'] - flight_attendants_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS) - galley_crew_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_GALLEY_CREW) + flight_attendants_count = self.options[Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS] + galley_crew_count = self.options[Aircraft.CrewPayload.NUM_GALLEY_CREW] mass_per_flight_attendant = self._mass_per_flight_attendant mass_per_galley_crew = self._mass_per_galley_crew @@ -52,11 +47,8 @@ def compute( ) * mass_scaler def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - flight_attendants_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS) - galley_crew_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_GALLEY_CREW) + flight_attendants_count = self.options[Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS] + galley_crew_count = self.options[Aircraft.CrewPayload.NUM_GALLEY_CREW] mass_per_flight_attendant = self._mass_per_flight_attendant mass_per_galley_crew = self._mass_per_galley_crew @@ -79,9 +71,8 @@ class FlightCrewMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.NUM_FLIGHT_CREW) + add_aviary_option(self, Aircraft.LandingGear.CARRIER_BASED) def setup(self): add_aviary_input( @@ -98,9 +89,7 @@ def setup_partials(self): def compute( self, inputs, outputs, discrete_inputs=None, discrete_outputs=None ): - aviary_options: AviaryValues = self.options['aviary_options'] - flight_crew_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) + flight_crew_count = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] mass_per_flight_crew = self._mass_per_flight_crew(inputs) @@ -110,9 +99,7 @@ def compute( flight_crew_count * mass_per_flight_crew * mass_scaler def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - flight_crew_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) + flight_crew_count = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] mass_per_flight_crew = self._mass_per_flight_crew(inputs) @@ -126,11 +113,10 @@ def _mass_per_flight_crew(self, inputs): Return the mass, in pounds, of one member of the flight crew and their baggage. ''' - aviary_options: AviaryValues = self.options['aviary_options'] mass_per_flight_crew = 225.0 # lbm # account for machine precision error - if 0.9 <= aviary_options.get_val(Aircraft.LandingGear.CARRIER_BASED): + if self.options[Aircraft.LandingGear.CARRIER_BASED]: mass_per_flight_crew -= 35.0 # lbm return mass_per_flight_crew diff --git a/aviary/subsystems/mass/flops_based/electrical.py b/aviary/subsystems/mass/flops_based/electrical.py index d3b6e13ff..7ba6ee967 100644 --- a/aviary/subsystems/mass/flops_based/electrical.py +++ b/aviary/subsystems/mass/flops_based/electrical.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import \ distributed_engine_count_factor -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -15,9 +14,10 @@ class ElectricalMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.NUM_FLIGHT_CREW) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) + add_aviary_option(self, Aircraft.Fuselage.NUM_FUSELAGES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) def setup(self): add_aviary_input(self, Aircraft.Fuselage.LENGTH, 0.0) @@ -30,13 +30,13 @@ def setup_partials(self): self.declare_partials(of='*', wrt='*') def compute(self, inputs, outputs): - options: AviaryValues = self.options['aviary_options'] - nfuse = options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) - ncrew = options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) - npass = options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + nfuse = self.options[Aircraft.Fuselage.NUM_FUSELAGES] + ncrew = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] + npass = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] + length = inputs[Aircraft.Fuselage.LENGTH] width = inputs[Aircraft.Fuselage.MAX_WIDTH] - num_eng = options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_engines_factor = distributed_engine_count_factor(num_eng) mass_scaler = inputs[Aircraft.Electrical.MASS_SCALER] @@ -45,13 +45,13 @@ def compute(self, inputs, outputs): * (1.0 + 0.044 * ncrew + 0.0015 * npass) * mass_scaler / GRAV_ENGLISH_LBM) def compute_partials(self, inputs, J): - options: AviaryValues = self.options['aviary_options'] - nfuse = options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) - ncrew = options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) - npass = options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + nfuse = self.options[Aircraft.Fuselage.NUM_FUSELAGES] + ncrew = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] + npass = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] + length = inputs[Aircraft.Fuselage.LENGTH] width = inputs[Aircraft.Fuselage.MAX_WIDTH] - num_eng = options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_engines_factor = distributed_engine_count_factor(num_eng) mass_scaler = inputs[Aircraft.Electrical.MASS_SCALER] @@ -78,9 +78,7 @@ class AltElectricalMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) def setup(self): add_aviary_input(self, Aircraft.Electrical.MASS_SCALER, 1.0) @@ -91,18 +89,14 @@ def setup_partials(self): self.declare_partials(of='*', wrt='*') def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - npass = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + npass = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] mass_scaler = inputs[Aircraft.Electrical.MASS_SCALER] outputs[Aircraft.Electrical.MASS] = 16.3 * \ npass * mass_scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - npass = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + npass = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] J[Aircraft.Electrical.MASS, Aircraft.Electrical.MASS_SCALER] = \ 16.3 * npass / GRAV_ENGLISH_LBM diff --git a/aviary/subsystems/mass/flops_based/empty_margin.py b/aviary/subsystems/mass/flops_based/empty_margin.py index 4c4b5cf33..43fca2b20 100644 --- a/aviary/subsystems/mass/flops_based/empty_margin.py +++ b/aviary/subsystems/mass/flops_based/empty_margin.py @@ -1,6 +1,5 @@ import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft @@ -10,11 +9,6 @@ class EmptyMassMargin(om.ExplicitComponent): Calculates the empty mass margin. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Propulsion.MASS, val=0.) diff --git a/aviary/subsystems/mass/flops_based/engine.py b/aviary/subsystems/mass/flops_based/engine.py index 34c792f6c..93740cccb 100644 --- a/aviary/subsystems/mass/flops_based/engine.py +++ b/aviary/subsystems/mass/flops_based/engine.py @@ -1,13 +1,12 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft # TODO should additional misc mass be separated out into a separate component? - +# TODO include estimation for baseline (unscaled) mass if not provided (NTRS paper on FLOPS equations pg. 30) class EngineMass(om.ExplicitComponent): ''' @@ -16,13 +15,14 @@ class EngineMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.ADDITIONAL_MASS_FRACTION) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Engine.REFERENCE_MASS, units='lbm') + add_aviary_option(self, Aircraft.Engine.REFERENCE_SLS_THRUST, units='lbf') + add_aviary_option(self, Aircraft.Engine.SCALE_MASS) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Engine.SCALED_SLS_THRUST, val=np.zeros(num_engine_type)) @@ -36,17 +36,12 @@ def setup(self): add_aviary_output(self, Aircraft.Propulsion.TOTAL_ENGINE_MASS, val=0.0) def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - - # cast to numpy arrays to ensure values are always correct type - num_engines = np.array(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) - scale_mass = np.array(aviary_options.get_val(Aircraft.Engine.SCALE_MASS)) - addtl_mass_fraction = np.array(aviary_options.get_val( - Aircraft.Engine.ADDITIONAL_MASS_FRACTION)) - ref_engine_mass = np.array(aviary_options.get_val( - Aircraft.Engine.REFERENCE_MASS, units='lbm')) - ref_sls_thrust = np.array(aviary_options.get_val( - Aircraft.Engine.REFERENCE_SLS_THRUST, units='lbf')) + options = self.options + num_engines = options[Aircraft.Engine.NUM_ENGINES] + scale_mass = options[Aircraft.Engine.SCALE_MASS] + addtl_mass_fraction = options[Aircraft.Engine.ADDITIONAL_MASS_FRACTION] + ref_engine_mass, _ = options[Aircraft.Engine.REFERENCE_MASS] + ref_sls_thrust, _ = options[Aircraft.Engine.REFERENCE_SLS_THRUST] scaled_sls_thrust = np.array(inputs[Aircraft.Engine.SCALED_SLS_THRUST]) scaling_parameter = np.array(inputs[Aircraft.Engine.MASS_SCALER]) @@ -76,8 +71,7 @@ def compute(self, inputs, outputs): outputs[Aircraft.Engine.ADDITIONAL_MASS] = addtl_mass def setup_partials(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) shape = np.arange(num_engine_type) self.declare_partials(Aircraft.Engine.MASS, @@ -92,17 +86,14 @@ def setup_partials(self): ['*']) def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_engine_type = len(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) - - num_engines = np.array(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) - scale_mass = np.array(aviary_options.get_val(Aircraft.Engine.SCALE_MASS)) - addtl_mass_fraction = np.array(aviary_options.get_val( - Aircraft.Engine.ADDITIONAL_MASS_FRACTION)) - ref_engine_mass = np.array(aviary_options.get_val( - Aircraft.Engine.REFERENCE_MASS, units='lbm')) - ref_sls_thrust = np.array(aviary_options.get_val( - Aircraft.Engine.REFERENCE_SLS_THRUST, units='lbf')) + options = self.options + num_engines = options[Aircraft.Engine.NUM_ENGINES] + num_engine_type = len(num_engines) + + scale_mass = options[Aircraft.Engine.SCALE_MASS] + addtl_mass_fraction = options[Aircraft.Engine.ADDITIONAL_MASS_FRACTION] + ref_engine_mass, _ = options[Aircraft.Engine.REFERENCE_MASS] + ref_sls_thrust, _ = options[Aircraft.Engine.REFERENCE_SLS_THRUST] scaled_sls_thrust = np.array(inputs[Aircraft.Engine.SCALED_SLS_THRUST]) scaling_parameter = np.array(inputs[Aircraft.Engine.MASS_SCALER]) diff --git a/aviary/subsystems/mass/flops_based/engine_controls.py b/aviary/subsystems/mass/flops_based/engine_controls.py index c17868c1f..17058a821 100644 --- a/aviary/subsystems/mass/flops_based/engine_controls.py +++ b/aviary/subsystems/mass/flops_based/engine_controls.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import ( distributed_engine_count_factor, distributed_thrust_factor) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -25,9 +24,7 @@ class TransportEngineCtrlsMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) def setup(self): add_aviary_input( @@ -41,9 +38,7 @@ def setup_partials(self): [Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST]) def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - - num_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_engines_factor = distributed_engine_count_factor(num_engines) max_sls_thrust = inputs[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST] @@ -55,9 +50,7 @@ def compute(self, inputs, outputs): total_controls_weight / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - - num_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] max_sls_thrust = inputs[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST] thrust_factor = distributed_thrust_factor(max_sls_thrust, num_engines) diff --git a/aviary/subsystems/mass/flops_based/engine_oil.py b/aviary/subsystems/mass/flops_based/engine_oil.py index 79cfde263..14fc7f429 100644 --- a/aviary/subsystems/mass/flops_based/engine_oil.py +++ b/aviary/subsystems/mass/flops_based/engine_oil.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import ( distributed_engine_count_factor, distributed_thrust_factor) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -22,9 +21,7 @@ class TransportEngineOilMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) def setup(self): add_aviary_input(self, Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER, val=1.0) @@ -37,9 +34,8 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] scaler = inputs[Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER] - num_eng = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_eng_fact = distributed_engine_count_factor(num_eng) max_sls_thrust = inputs[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST] thrust_factor = distributed_thrust_factor(max_sls_thrust, num_eng) @@ -48,9 +44,8 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): 0.082 * num_eng_fact * thrust_factor**0.65 * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] scaler = inputs[Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER] - num_eng = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_eng_fact = distributed_engine_count_factor(num_eng) max_sls_thrust = inputs[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST] thrust_factor = distributed_thrust_factor(max_sls_thrust, num_eng) @@ -72,9 +67,7 @@ class AltEngineOilMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) def setup(self): add_aviary_input(self, Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER, val=1.0) @@ -85,9 +78,7 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - pax = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] scaler = inputs[Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER] @@ -95,9 +86,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): 240.0 * ((pax + 39) // 40) * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - pax = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] J[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS, Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER diff --git a/aviary/subsystems/mass/flops_based/engine_pod.py b/aviary/subsystems/mass/flops_based/engine_pod.py index 256c26d26..c1c262481 100644 --- a/aviary/subsystems/mass/flops_based/engine_pod.py +++ b/aviary/subsystems/mass/flops_based/engine_pod.py @@ -2,8 +2,7 @@ import openmdao.api as om from aviary.subsystems.mass.flops_based.distributed_prop import nacelle_count_factor -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -18,13 +17,10 @@ class EnginePodMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Electrical.MASS, val=0.0) add_aviary_input(self, Aircraft.Fuel.FUEL_SYSTEM_MASS, val=0.0) @@ -46,8 +42,7 @@ def setup_partials(self): self.declare_partials('*', '*') # derivatives w.r.t vectorized engine inputs have known sparsity pattern - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) shape = np.arange(num_engine_type) self.declare_partials(Aircraft.Engine.POD_MASS, @@ -67,8 +62,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): # BUG this methodology completely ignores miscellaneous mass. There is a discrepency between this calculation # and miscellaneous mass. Engine control, starter, and additional mass have a scaler applied to them, and # if their calculated values are used directly this scaler is skipped - aviary_options: AviaryValues = self.options['aviary_options'] - num_eng = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + num_eng = self.options[Aircraft.Engine.NUM_ENGINES] nacelle_count = nacelle_count_factor(num_eng) eng_thrust = inputs[Aircraft.Engine.SCALED_SLS_THRUST] @@ -113,8 +107,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): outputs[Aircraft.Engine.POD_MASS] = pod_mass def compute_partials(self, inputs, partials, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - num_eng = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + num_eng = self.options[Aircraft.Engine.NUM_ENGINES] count_factor = nacelle_count_factor(num_eng) m_start = inputs[Aircraft.Propulsion.TOTAL_STARTER_MASS] diff --git a/aviary/subsystems/mass/flops_based/fin.py b/aviary/subsystems/mass/flops_based/fin.py index 989ee1ee2..b4e9f79ab 100644 --- a/aviary/subsystems/mass/flops_based/fin.py +++ b/aviary/subsystems/mass/flops_based/fin.py @@ -1,8 +1,7 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -13,9 +12,7 @@ class FinMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Fins.NUM_FINS) def setup(self): add_aviary_input(self, Mission.Design.GROSS_MASS, val=0.0) @@ -29,8 +26,7 @@ def setup_partials(self): self.declare_partials("*", "*") def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - num_fins = aviary_options.get_val(Aircraft.Fins.NUM_FINS) + num_fins = self.options[Aircraft.Fins.NUM_FINS] if num_fins > 0: togw = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM area = inputs[Aircraft.Fins.AREA] @@ -41,8 +37,7 @@ def compute(self, inputs, outputs): inputs[Aircraft.Fins.MASS_SCALER] / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_fins = aviary_options.get_val(Aircraft.Fins.NUM_FINS) + num_fins = self.options[Aircraft.Fins.NUM_FINS] if num_fins > 0: area = inputs[Aircraft.Fins.AREA] taper_ratio = inputs[Aircraft.Fins.TAPER_RATIO] diff --git a/aviary/subsystems/mass/flops_based/fuel_capacity.py b/aviary/subsystems/mass/flops_based/fuel_capacity.py index 98d50b2e9..d1d2009b6 100644 --- a/aviary/subsystems/mass/flops_based/fuel_capacity.py +++ b/aviary/subsystems/mass/flops_based/fuel_capacity.py @@ -1,6 +1,5 @@ import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft @@ -10,17 +9,11 @@ class FuelCapacityGroup(om.Group): Compute the maximum fuel that can be carried. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): - aviary_options = self.options['aviary_options'] self.add_subsystem( 'wing_fuel_capacity', - WingFuelCapacity(aviary_options=aviary_options), + WingFuelCapacity(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( @@ -126,11 +119,6 @@ class WingFuelCapacity(om.ExplicitComponent): Compute the maximum fuel that can be carried in the wing's enclosed space. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Fuel.DENSITY_RATIO, 1.0) add_aviary_input(self, Aircraft.Fuel.WING_REF_CAPACITY, 0.0) diff --git a/aviary/subsystems/mass/flops_based/fuel_system.py b/aviary/subsystems/mass/flops_based/fuel_system.py index a78851fe2..78dfe92bc 100644 --- a/aviary/subsystems/mass/flops_based/fuel_system.py +++ b/aviary/subsystems/mass/flops_based/fuel_system.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import \ distributed_engine_count_factor -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -16,9 +15,8 @@ class TransportFuelSystemMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) + add_aviary_option(self, Mission.Constraints.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, val=1.0) @@ -31,24 +29,22 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] scaler = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER] capacity = inputs[Aircraft.Fuel.TOTAL_CAPACITY] - num_eng = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_eng_fact = distributed_engine_count_factor(num_eng) - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] outputs[Aircraft.Fuel.FUEL_SYSTEM_MASS] = ( 1.07 * capacity**0.58 * num_eng_fact**0.43 * max_mach**0.34 * scaler) / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] scaler = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER] capacity = inputs[Aircraft.Fuel.TOTAL_CAPACITY] - num_eng = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_eng_fact = distributed_engine_count_factor(num_eng) - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] J[Aircraft.Fuel.FUEL_SYSTEM_MASS, Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER] = ( 1.07 * capacity**0.58 * num_eng_fact**0.43 * max_mach**0.34 / GRAV_ENGLISH_LBM) @@ -66,9 +62,7 @@ class AltFuelSystemMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Fuel.NUM_TANKS) def setup(self): add_aviary_input(self, Aircraft.Fuel.TOTAL_CAPACITY, val=0.0) @@ -81,8 +75,7 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - number_of_fuel_tanks = aviary_options.get_val(Aircraft.Fuel.NUM_TANKS) + number_of_fuel_tanks = self.options[Aircraft.Fuel.NUM_TANKS] total_fuel_capacity = inputs[Aircraft.Fuel.TOTAL_CAPACITY] scaler = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER] @@ -97,8 +90,7 @@ def compute(self, inputs, outputs): fuel_sys_weight / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - number_of_fuel_tanks = aviary_options.get_val(Aircraft.Fuel.NUM_TANKS) + number_of_fuel_tanks = self.options[Aircraft.Fuel.NUM_TANKS] total_fuel_capacity = inputs[Aircraft.Fuel.TOTAL_CAPACITY] scaler = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER] diff --git a/aviary/subsystems/mass/flops_based/furnishings.py b/aviary/subsystems/mass/flops_based/furnishings.py index 62fd9f7bf..edba25346 100644 --- a/aviary/subsystems/mass/flops_based/furnishings.py +++ b/aviary/subsystems/mass/flops_based/furnishings.py @@ -2,8 +2,7 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -14,9 +13,11 @@ class TransportFurnishingsGroupMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS) + add_aviary_option(self, Aircraft.CrewPayload.NUM_FLIGHT_CREW) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_FIRST_CLASS) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS) + add_aviary_option(self, Aircraft.Fuselage.NUM_FUSELAGES) def setup(self): add_aviary_input(self, Aircraft.Furnishings.MASS_SCALER, val=1.0) @@ -32,21 +33,14 @@ def setup(self): def setup_partials(self): self.declare_partials(of=Aircraft.Furnishings.MASS, wrt='*') - def compute( - self, inputs, outputs, discrete_inputs=None, discrete_outputs=None - ): - aviary_options: AviaryValues = self.options['aviary_options'] - - flight_crew_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) - first_class_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS) - - business_class_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_BUSINESS_CLASS) + def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - tourist_class_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_TOURIST_CLASS) + flight_crew_count = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] + first_class_count = self.options[Aircraft.CrewPayload.Design.NUM_FIRST_CLASS] + business_class_count = self.options[Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS] + tourist_class_count = self.options[Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS] - fuse_count = aviary_options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) + fuse_count = self.options[Aircraft.Fuselage.NUM_FUSELAGES] scaler = inputs[Aircraft.Furnishings.MASS_SCALER] @@ -64,18 +58,12 @@ def compute( ) * scaler def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] + flight_crew_count = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] + first_class_count = self.options[Aircraft.CrewPayload.Design.NUM_FIRST_CLASS] + business_class_count = self.options[Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS] + tourist_class_count = self.options[Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS] - flight_crew_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) - first_class_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS) - - business_class_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_BUSINESS_CLASS) - - tourist_class_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_TOURIST_CLASS) - - fuse_count = aviary_options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) + fuse_count = self.options[Aircraft.Fuselage.NUM_FUSELAGES] scaler = inputs[Aircraft.Furnishings.MASS_SCALER] fuse_max_width = inputs[Aircraft.Fuselage.MAX_WIDTH] @@ -107,9 +95,12 @@ class BWBFurnishingsGroupMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.BWB.NUM_BAYS) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS) + add_aviary_option(self, Aircraft.CrewPayload.NUM_FLIGHT_CREW) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_FIRST_CLASS) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS) + add_aviary_option(self, Aircraft.Fuselage.MILITARY_CARGO_FLOOR) def setup(self): add_aviary_input(self, Aircraft.Furnishings.MASS_SCALER, val=1.0) @@ -129,19 +120,12 @@ def setup(self): def setup_partials(self): self.declare_partials(of=Aircraft.Furnishings.MASS, wrt='*') - def compute( - self, inputs, outputs, discrete_inputs=None, discrete_outputs=None - ): - aviary_options: AviaryValues = self.options['aviary_options'] - - flight_crew_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) - first_class_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS) + def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - business_class_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_BUSINESS_CLASS) - - tourist_class_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_TOURIST_CLASS) + flight_crew_count = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] + first_class_count = self.options[Aircraft.CrewPayload.Design.NUM_FIRST_CLASS] + business_class_count = self.options[Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS] + tourist_class_count = self.options[Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS] scaler = inputs[Aircraft.Furnishings.MASS_SCALER] fuse_max_width = inputs[Aircraft.Fuselage.MAX_WIDTH] @@ -153,9 +137,9 @@ def compute( ) # outputs[Aircraft.Furnishings.MASS] = weight / GRAV_ENGLISH_LBM - if not aviary_options.get_val(Aircraft.Fuselage.MILITARY_CARGO_FLOOR): + if not self.options[Aircraft.Fuselage.MILITARY_CARGO_FLOOR]: acabin = inputs[Aircraft.BWB.CABIN_AREA] - nbay = aviary_options.get_val(Aircraft.BWB.NUM_BAYS) + nbay = self.options[Aircraft.BWB.NUM_BAYS] cos = np.cos( np.pi/180*(inputs[Aircraft.BWB.PASSENGER_LEADING_EDGE_SWEEP]) @@ -170,16 +154,10 @@ def compute( outputs[Aircraft.Furnishings.MASS] = weight * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - - flight_crew_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) - first_class_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS) - - business_class_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_BUSINESS_CLASS) - - tourist_class_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_TOURIST_CLASS) + flight_crew_count = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] + first_class_count = self.options[Aircraft.CrewPayload.Design.NUM_FIRST_CLASS] + business_class_count = self.options[Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS] + tourist_class_count = self.options[Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS] scaler = inputs[Aircraft.Furnishings.MASS_SCALER] @@ -188,7 +166,7 @@ def compute_partials(self, inputs, J): + 78.0 * business_class_count + 44.0 * tourist_class_count ) / GRAV_ENGLISH_LBM - if aviary_options.get_val(Aircraft.Fuselage.MILITARY_CARGO_FLOOR): + if self.options[Aircraft.Fuselage.MILITARY_CARGO_FLOOR]: J[Aircraft.Furnishings.MASS, Aircraft.BWB.CABIN_AREA] = 0.0 J[Aircraft.Furnishings.MASS, Aircraft.Fuselage.MAX_WIDTH] = 0.0 @@ -206,7 +184,7 @@ def compute_partials(self, inputs, J): tan = np.tan(d2r) acabin = inputs[Aircraft.BWB.CABIN_AREA] - nbay = aviary_options.get_val(Aircraft.BWB.NUM_BAYS) + nbay = self.options[Aircraft.BWB.NUM_BAYS] fuse_max_width = inputs[Aircraft.Fuselage.MAX_WIDTH] fuse_max_height = inputs[Aircraft.Fuselage.MAX_HEIGHT] cabin_area = inputs[Aircraft.BWB.CABIN_AREA] @@ -258,9 +236,7 @@ class AltFurnishingsGroupMassBase(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) def setup(self): add_aviary_input(self, Aircraft.Furnishings.MASS_SCALER, val=1.0) @@ -273,18 +249,14 @@ def setup_partials(self): def compute( self, inputs, outputs, discrete_inputs=None, discrete_outputs=None ): - aviary_options: AviaryValues = self.options['aviary_options'] - pax_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + pax_count = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] scaler = inputs[Aircraft.Furnishings.MASS_SCALER] outputs[Aircraft.Furnishings.MASS_BASE] = \ (82.15 * pax_count + 3600.0) * scaler def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - pax_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + pax_count = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] J[ Aircraft.Furnishings.MASS_BASE, @@ -299,11 +271,6 @@ class AltFurnishingsGroupMass(om.ExplicitComponent): equations, modified to output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Furnishings.MASS_BASE, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/fuselage.py b/aviary/subsystems/mass/flops_based/fuselage.py index 6b349ec20..dc0ad71ec 100644 --- a/aviary/subsystems/mass/flops_based/fuselage.py +++ b/aviary/subsystems/mass/flops_based/fuselage.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import \ distributed_engine_count_factor -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -16,9 +15,9 @@ class TransportFuselageMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Fuselage.MILITARY_CARGO_FLOOR) + add_aviary_option(self, Aircraft.Fuselage.NUM_FUSELAGES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) def setup(self): add_aviary_input(self, Aircraft.Fuselage.LENGTH, val=0.0) @@ -33,16 +32,15 @@ def setup_partials(self): self.declare_partials(Aircraft.Fuselage.MASS, "*") def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] length = inputs[Aircraft.Fuselage.LENGTH] scaler = inputs[Aircraft.Fuselage.MASS_SCALER] avg_diameter = inputs[Aircraft.Fuselage.AVG_DIAMETER] - num_fuse = aviary_options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) - num_fuse_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + num_fuse = self.options[Aircraft.Fuselage.NUM_FUSELAGES] + num_fuse_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES] + num_fuse_eng_fact = distributed_engine_count_factor(num_fuse_eng) - military_cargo = aviary_options.get_val(Aircraft.Fuselage.MILITARY_CARGO_FLOOR) + military_cargo = self.options[Aircraft.Fuselage.MILITARY_CARGO_FLOOR] mil_factor = 1.38 if military_cargo else 1.0 @@ -52,15 +50,13 @@ def compute(self, inputs, outputs): ) def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] length = inputs[Aircraft.Fuselage.LENGTH] scaler = inputs[Aircraft.Fuselage.MASS_SCALER] avg_diameter = inputs[Aircraft.Fuselage.AVG_DIAMETER] - num_fuse = aviary_options.get_val(Aircraft.Fuselage.NUM_FUSELAGES) - num_fuse_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + num_fuse = self.options[Aircraft.Fuselage.NUM_FUSELAGES] + num_fuse_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES] num_fuse_eng_fact = distributed_engine_count_factor(num_fuse_eng) - military_cargo = aviary_options.get_val(Aircraft.Fuselage.MILITARY_CARGO_FLOOR) + military_cargo = self.options[Aircraft.Fuselage.MILITARY_CARGO_FLOOR] # avg_diameter = (max_height + max_width) / 2. avg_diameter_exp = avg_diameter ** 1.28 @@ -84,11 +80,6 @@ class AltFuselageMass(om.ExplicitComponent): of weight. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Fuselage.MASS_SCALER, 1.0) diff --git a/aviary/subsystems/mass/flops_based/horizontal_tail.py b/aviary/subsystems/mass/flops_based/horizontal_tail.py index c775a52b8..a647ebd8f 100644 --- a/aviary/subsystems/mass/flops_based/horizontal_tail.py +++ b/aviary/subsystems/mass/flops_based/horizontal_tail.py @@ -1,7 +1,6 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft, Mission @@ -12,15 +11,10 @@ class HorizontalTailMass(om.ExplicitComponent): equations, modified to output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.HorizontalTail.AREA, val=0.0) - add_aviary_input(self, Aircraft.HorizontalTail.TAPER_RATIO, val=0.0) + add_aviary_input(self, Aircraft.HorizontalTail.TAPER_RATIO, val=0.352) add_aviary_input(self, Mission.Design.GROSS_MASS, val=0.0) @@ -70,11 +64,6 @@ class AltHorizontalTailMass(om.ExplicitComponent): output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.HorizontalTail.AREA, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/hydraulics.py b/aviary/subsystems/mass/flops_based/hydraulics.py index aed93313f..e2f5ca58c 100644 --- a/aviary/subsystems/mass/flops_based/hydraulics.py +++ b/aviary/subsystems/mass/flops_based/hydraulics.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import \ distributed_engine_count_factor -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission # TODO: update non-transport components to new standard to remove these variables @@ -23,9 +22,9 @@ class TransportHydraulicsGroupMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) + add_aviary_option(self, Mission.Constraints.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.Fuselage.PLANFORM_AREA, val=0.0) @@ -44,11 +43,8 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - num_wing_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) - num_fuse_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + num_wing_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES] + num_fuse_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES] num_wing_eng_fact = distributed_engine_count_factor(num_wing_eng) num_fuse_eng_fact = distributed_engine_count_factor(num_fuse_eng) @@ -57,7 +53,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): scaler = inputs[Aircraft.Hydraulics.MASS_SCALER] area = inputs[Aircraft.Wing.AREA] var_sweep = inputs[Aircraft.Wing.VAR_SWEEP_MASS_PENALTY] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] outputs[Aircraft.Hydraulics.MASS] = ( 0.57 * (planform + 0.27 * area) @@ -66,11 +62,8 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): * scaler / GRAV_ENGLISH_LBM) def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_wing_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) - num_fuse_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + num_wing_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES] + num_fuse_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES] num_wing_eng_fact = distributed_engine_count_factor(num_wing_eng) num_fuse_eng_fact = distributed_engine_count_factor(num_fuse_eng) @@ -79,7 +72,7 @@ def compute_partials(self, inputs, J): scaler = inputs[Aircraft.Hydraulics.MASS_SCALER] area = inputs[Aircraft.Wing.AREA] var_sweep = inputs[Aircraft.Wing.VAR_SWEEP_MASS_PENALTY] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] term1 = (planform + 0.27 * area) term2 = (1.0 + 0.03 * num_wing_eng_fact + 0.05 * num_fuse_eng_fact) @@ -111,11 +104,6 @@ class AltHydraulicsGroupMass(om.ExplicitComponent): output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Wing.AREA, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/instruments.py b/aviary/subsystems/mass/flops_based/instruments.py index 3b0c50f84..04bcda862 100644 --- a/aviary/subsystems/mass/flops_based/instruments.py +++ b/aviary/subsystems/mass/flops_based/instruments.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import \ distributed_engine_count_factor -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -18,9 +17,10 @@ class TransportInstrumentMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.NUM_FLIGHT_CREW) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) + add_aviary_option(self, Mission.Constraints.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.Fuselage.PLANFORM_AREA, 0.0) @@ -31,17 +31,14 @@ def setup(self): self.declare_partials("*", "*") def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - num_crew = aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) - num_wing_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) - num_fuse_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + num_crew = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] + num_wing_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES] + num_fuse_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES] num_wing_eng_fact = distributed_engine_count_factor(num_wing_eng) num_fuse_eng_fact = distributed_engine_count_factor(num_fuse_eng) fuse_area = inputs[Aircraft.Fuselage.PLANFORM_AREA] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] mass_scaler = inputs[Aircraft.Instruments.MASS_SCALER] instrument_weight = ( @@ -53,17 +50,14 @@ def compute(self, inputs, outputs): mass_scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_crew = aviary_options.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) - num_wing_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) - num_fuse_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES) + num_crew = self.options[Aircraft.CrewPayload.NUM_FLIGHT_CREW] + num_wing_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES] + num_fuse_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES] num_wing_eng_fact = distributed_engine_count_factor(num_wing_eng) num_fuse_eng_fact = distributed_engine_count_factor(num_fuse_eng) fuse_area = inputs[Aircraft.Fuselage.PLANFORM_AREA] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] mass_scaler = inputs[Aircraft.Instruments.MASS_SCALER] fact = (10.0 + 2.5 * num_crew + num_wing_eng_fact + 1.5 * num_fuse_eng_fact) diff --git a/aviary/subsystems/mass/flops_based/landing_gear.py b/aviary/subsystems/mass/flops_based/landing_gear.py index db87a4aee..97f03615f 100644 --- a/aviary/subsystems/mass/flops_based/landing_gear.py +++ b/aviary/subsystems/mass/flops_based/landing_gear.py @@ -4,8 +4,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import ( distributed_nacelle_diam_factor, distributed_nacelle_diam_factor_deriv) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission DEG2RAD = np.pi / 180.0 @@ -19,11 +18,6 @@ class LandingGearMass(om.ExplicitComponent): # TODO: add in aircraft type and carrier factors as options and modify # equations - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.LandingGear.MAIN_GEAR_OLEO_LENGTH, val=0.0) @@ -136,11 +130,6 @@ class AltLandingGearMass(om.ExplicitComponent): to output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.LandingGear.MAIN_GEAR_OLEO_LENGTH, val=0.0) @@ -255,11 +244,6 @@ class NoseGearLength(om.ExplicitComponent): NOSE_GEAR_OLEO_LENGTH = 0.7 * MAIN_GEAR_OLEO_LENGTH """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.LandingGear.MAIN_GEAR_OLEO_LENGTH, val=0.0) add_aviary_output(self, Aircraft.LandingGear.NOSE_GEAR_OLEO_LENGTH, val=0.0) @@ -280,22 +264,23 @@ class MainGearLength(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Engine.NUM_WING_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) - num_wing_engines = self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_WING_ENGINES) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) + num_wing_engines = self.options[Aircraft.Engine.NUM_WING_ENGINES] add_aviary_input(self, Aircraft.Fuselage.LENGTH, val=0.0) add_aviary_input(self, Aircraft.Fuselage.MAX_WIDTH, val=0.0) add_aviary_input(self, Aircraft.Nacelle.AVG_DIAMETER, val=np.zeros(num_engine_type)) - add_aviary_input(self, Aircraft.Engine.WING_LOCATIONS, - val=np.zeros((num_engine_type, int(num_wing_engines[0]/2)))) + if any(num_wing_engines) > 0: + add_aviary_input(self, Aircraft.Engine.WING_LOCATIONS, val=np.zeros( + (num_engine_type, int(num_wing_engines[0] / 2)))) + else: + add_aviary_input(self, Aircraft.Engine.WING_LOCATIONS, + val=[[0.0]]) add_aviary_input(self, Aircraft.Wing.DIHEDRAL, val=0.0) add_aviary_input(self, Aircraft.Wing.SPAN, val=0.0) @@ -305,10 +290,10 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - options: AviaryValues = self.options['aviary_options'] + num_eng = self.options[Aircraft.Engine.NUM_ENGINES][0] + # TODO temp using first engine, heterogeneous engines not supported - num_eng = options.get_val(Aircraft.Engine.NUM_ENGINES)[0] - num_wing_eng = options.get_val(Aircraft.Engine.NUM_WING_ENGINES)[0] + num_wing_eng = self.options[Aircraft.Engine.NUM_WING_ENGINES][0] y_eng_fore = inputs[Aircraft.Engine.WING_LOCATIONS][0][0] @@ -345,10 +330,9 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): outputs[Aircraft.LandingGear.MAIN_GEAR_OLEO_LENGTH] = cmlg def compute_partials(self, inputs, partials, discrete_inputs=None): - options: AviaryValues = self.options['aviary_options'] # TODO temp using first engine, heterogeneous engines not supported - num_eng = options.get_val(Aircraft.Engine.NUM_ENGINES)[0] - num_wing_eng = options.get_val(Aircraft.Engine.NUM_WING_ENGINES)[0] + num_eng = self.options[Aircraft.Engine.NUM_ENGINES][0] + num_wing_eng = self.options[Aircraft.Engine.NUM_WING_ENGINES][0] y_eng_fore = inputs[Aircraft.Engine.WING_LOCATIONS][0][0] y_eng_aft = 0 diff --git a/aviary/subsystems/mass/flops_based/landing_group.py b/aviary/subsystems/mass/flops_based/landing_group.py index 13978daf8..468e1efad 100644 --- a/aviary/subsystems/mass/flops_based/landing_group.py +++ b/aviary/subsystems/mass/flops_based/landing_group.py @@ -4,8 +4,8 @@ AltLandingGearMass, LandingGearMass, MainGearLength, NoseGearLength) from aviary.subsystems.mass.flops_based.landing_mass import ( LandingMass, LandingTakeoffMassRatio) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Aircraft +from aviary.variable_info.functions import add_aviary_option +from aviary.variable_info.variables import Aircraft, Mission class LandingMassGroup(om.Group): @@ -15,35 +15,32 @@ class LandingMassGroup(om.Group): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Design.USE_ALT_MASS) def setup(self): - aviary_options: AviaryValues = self.options['aviary_options'] - alt_mass = aviary_options.get_val(Aircraft.Design.USE_ALT_MASS) + alt_mass = self.options[Aircraft.Design.USE_ALT_MASS] self.add_subsystem('landing_to_takeoff_mass_ratio', - LandingTakeoffMassRatio(aviary_options=aviary_options), + LandingTakeoffMassRatio(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem('main_landing_gear_length', - MainGearLength(aviary_options=aviary_options), + MainGearLength(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem('nose_landing_gear_length', - NoseGearLength(aviary_options=aviary_options), + NoseGearLength(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem('landing_mass', - LandingMass(aviary_options=aviary_options), + LandingMass(), promotes_inputs=['*'], promotes_outputs=['*']) if alt_mass: self.add_subsystem('landing_gear', - AltLandingGearMass(aviary_options=aviary_options), + AltLandingGearMass(), promotes_inputs=['*'], promotes_outputs=['*']) else: self.add_subsystem('landing_gear', - LandingGearMass(aviary_options=aviary_options), + LandingGearMass(), promotes_inputs=['*'], promotes_outputs=['*']) diff --git a/aviary/subsystems/mass/flops_based/landing_mass.py b/aviary/subsystems/mass/flops_based/landing_mass.py index c34686fbe..b809b51dc 100644 --- a/aviary/subsystems/mass/flops_based/landing_mass.py +++ b/aviary/subsystems/mass/flops_based/landing_mass.py @@ -1,7 +1,6 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft, Mission @@ -11,11 +10,6 @@ class LandingTakeoffMassRatio(om.ExplicitComponent): Calculate the ratio of maximum landing mass to maximum takeoff gross mass. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Mission.Summary.CRUISE_MACH, val=0.0) @@ -58,11 +52,6 @@ class LandingMass(om.ExplicitComponent): Maximum landing mass is maximum takeoff gross mass times the ratio of landing/takeoff mass. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Mission.Design.GROSS_MASS, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/mass_premission.py b/aviary/subsystems/mass/flops_based/mass_premission.py index b60b2ebd3..c477b562c 100644 --- a/aviary/subsystems/mass/flops_based/mass_premission.py +++ b/aviary/subsystems/mass/flops_based/mass_premission.py @@ -45,7 +45,7 @@ from aviary.subsystems.mass.flops_based.vertical_tail import ( AltVerticalTailMass, VerticalTailMass) from aviary.subsystems.mass.flops_based.wing_group import WingMassGroup -from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -57,249 +57,241 @@ class MassPremission(om.Group): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Design.USE_ALT_MASS) def setup(self): - aviary_options: AviaryValues = self.options['aviary_options'] - alt_mass = aviary_options.get_val(Aircraft.Design.USE_ALT_MASS) + alt_mass = self.options[Aircraft.Design.USE_ALT_MASS] self.add_subsystem( 'cargo', - CargoMass(aviary_options=aviary_options), + CargoMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'cargo_containers', - TransportCargoContainersMass( - aviary_options=aviary_options), + TransportCargoContainersMass(), promotes_inputs=['*', ], promotes_outputs=['*', ]) self.add_subsystem( 'engine_controls', - TransportEngineCtrlsMass(aviary_options=aviary_options), + TransportEngineCtrlsMass(), promotes_inputs=['*', ], promotes_outputs=['*', ]) self.add_subsystem( 'avionics', - TransportAvionicsMass(aviary_options=aviary_options), + TransportAvionicsMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'fuel_capacity_group', - FuelCapacityGroup(aviary_options=aviary_options), + FuelCapacityGroup(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'engine_mass', - EngineMass(aviary_options=aviary_options), + EngineMass(), promotes_inputs=['*'], promotes_outputs=['*']) if alt_mass: self.add_subsystem( 'fuel_system', - AltFuelSystemMass(aviary_options=aviary_options), + AltFuelSystemMass(), promotes_inputs=['*', ], promotes_outputs=['*', ]) self.add_subsystem( 'AC', - AltAirCondMass(aviary_options=aviary_options), + AltAirCondMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'engine_oil', - AltEngineOilMass(aviary_options=aviary_options), + AltEngineOilMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'furnishing_base', - AltFurnishingsGroupMassBase( - aviary_options=aviary_options), + AltFurnishingsGroupMassBase(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'furnishings', - AltFurnishingsGroupMass(aviary_options=aviary_options), + AltFurnishingsGroupMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'hydraulics', - AltHydraulicsGroupMass(aviary_options=aviary_options), + AltHydraulicsGroupMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'pass_service', - AltPassengerServiceMass( - aviary_options=aviary_options), + AltPassengerServiceMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'unusable_fuel', - AltUnusableFuelMass(aviary_options=aviary_options), + AltUnusableFuelMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'electrical', - AltElectricalMass(aviary_options=aviary_options), + AltElectricalMass(), promotes_inputs=['*'], promotes_outputs=['*']) else: self.add_subsystem( 'fuel_system', - TransportFuelSystemMass(aviary_options=aviary_options), + TransportFuelSystemMass(), promotes_inputs=['*', ], promotes_outputs=['*', ]) self.add_subsystem( 'AC', - TransportAirCondMass(aviary_options=aviary_options), + TransportAirCondMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'engine_oil', - TransportEngineOilMass(aviary_options=aviary_options), + TransportEngineOilMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'furnishings', - TransportFurnishingsGroupMass( - aviary_options=aviary_options), + TransportFurnishingsGroupMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'hydraulics', - TransportHydraulicsGroupMass( - aviary_options=aviary_options), + TransportHydraulicsGroupMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'pass_service', - PassengerServiceMass(aviary_options=aviary_options), + PassengerServiceMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'unusable_fuel', - TransportUnusableFuelMass(aviary_options=aviary_options), + TransportUnusableFuelMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'electrical', - ElectricalMass(aviary_options=aviary_options), + ElectricalMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'starter', - TransportStarterMass(aviary_options=aviary_options), + TransportStarterMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'anti_icing', - AntiIcingMass(aviary_options=aviary_options), + AntiIcingMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'apu', - TransportAPUMass(aviary_options=aviary_options), + TransportAPUMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'nonflight_crew', - NonFlightCrewMass(aviary_options=aviary_options), + NonFlightCrewMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'flight_crew', - FlightCrewMass(aviary_options=aviary_options), + FlightCrewMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'instruments', - TransportInstrumentMass(aviary_options=aviary_options), + TransportInstrumentMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'misc_engine', - EngineMiscMass(aviary_options=aviary_options), + EngineMiscMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'nacelle', - NacelleMass(aviary_options=aviary_options), + NacelleMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'paint', - PaintMass(aviary_options=aviary_options), + PaintMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'thrust_rev', - ThrustReverserMass(aviary_options=aviary_options), + ThrustReverserMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'landing_group', - LandingMassGroup(aviary_options=aviary_options), + LandingMassGroup(), promotes_inputs=['*'], promotes_outputs=['*']) if alt_mass: self.add_subsystem( 'surf_ctrl', - AltSurfaceControlMass(aviary_options=aviary_options), + AltSurfaceControlMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'fuselage', - AltFuselageMass(aviary_options=aviary_options), + AltFuselageMass(), promotes_inputs=['*', ], promotes_outputs=['*', ]) self.add_subsystem( 'htail', - AltHorizontalTailMass(aviary_options=aviary_options), + AltHorizontalTailMass(), promotes_inputs=['*', ], promotes_outputs=['*', ]) self.add_subsystem( 'vert_tail', - AltVerticalTailMass(aviary_options=aviary_options), + AltVerticalTailMass(), promotes_inputs=['*'], promotes_outputs=['*']) else: self.add_subsystem( 'surf_ctrl', - SurfaceControlMass(aviary_options=aviary_options), + SurfaceControlMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'fuselage', - TransportFuselageMass(aviary_options=aviary_options), + TransportFuselageMass(), promotes_inputs=['*', ], promotes_outputs=['*', ]) self.add_subsystem( 'htail', - HorizontalTailMass(aviary_options=aviary_options), + HorizontalTailMass(), promotes_inputs=['*', ], promotes_outputs=['*', ]) self.add_subsystem( 'vert_tail', - VerticalTailMass(aviary_options=aviary_options), + VerticalTailMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'canard', - CanardMass(aviary_options=aviary_options), + CanardMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'fin', - FinMass(aviary_options=aviary_options), + FinMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'wing_group', - WingMassGroup(aviary_options=aviary_options), + WingMassGroup(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'total_mass', - MassSummation(aviary_options=aviary_options), + MassSummation(), promotes_inputs=['*'], promotes_outputs=['*']) diff --git a/aviary/subsystems/mass/flops_based/mass_summation.py b/aviary/subsystems/mass/flops_based/mass_summation.py index d1294985e..2a3ae8103 100644 --- a/aviary/subsystems/mass/flops_based/mass_summation.py +++ b/aviary/subsystems/mass/flops_based/mass_summation.py @@ -3,8 +3,7 @@ import openmdao.api as om from aviary.subsystems.mass.flops_based.empty_margin import EmptyMassMargin -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -19,73 +18,67 @@ class MassSummation(om.Group): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Design.USE_ALT_MASS) def setup(self): - aviary_options: AviaryValues = self.options['aviary_options'] - alt_mass = aviary_options.get_val(Aircraft.Design.USE_ALT_MASS) + alt_mass = self.options[Aircraft.Design.USE_ALT_MASS] self.add_subsystem( - 'structure_mass', StructureMass(aviary_options=aviary_options), + 'structure_mass', StructureMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( - 'propulsion_mass', PropulsionMass(aviary_options=aviary_options), + 'propulsion_mass', PropulsionMass(), promotes_inputs=['*'], promotes_outputs=['*']) if alt_mass: self.add_subsystem( 'system_equip_mass_base', - AltSystemsEquipMassBase(aviary_options=aviary_options), + AltSystemsEquipMassBase(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( 'system_equip_mass', - AltSystemsEquipMass(aviary_options=aviary_options), + AltSystemsEquipMass(), promotes_inputs=['*'], promotes_outputs=['*']) else: self.add_subsystem( - 'system_equip_mass', SystemsEquipMass(aviary_options=aviary_options), + 'system_equip_mass', SystemsEquipMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( - 'empty_mass_margin', EmptyMassMargin(aviary_options=aviary_options), + 'empty_mass_margin', EmptyMassMargin(), promotes_inputs=['*'], promotes_outputs=['*']) if alt_mass: self.add_subsystem( - 'empty_mass', AltEmptyMass(aviary_options=aviary_options), + 'empty_mass', AltEmptyMass(), promotes_inputs=['*'], promotes_outputs=['*']) else: - self.add_subsystem('empty_mass', EmptyMass(aviary_options=aviary_options), + self.add_subsystem('empty_mass', EmptyMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( - 'operating_mass', OperatingMass(aviary_options=aviary_options), + 'operating_mass', OperatingMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( - 'zero_fuel_mass', ZeroFuelMass(aviary_options=aviary_options), + 'zero_fuel_mass', ZeroFuelMass(), promotes_inputs=['*'], promotes_outputs=['*']) - self.add_subsystem('fuel_mass', FuelMass(aviary_options=aviary_options), + self.add_subsystem('fuel_mass', FuelMass(), promotes_inputs=['*'], promotes_outputs=['*']) class StructureMass(om.ExplicitComponent): def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Canard.MASS, val=0.0) add_aviary_input(self, Aircraft.Fins.MASS, val=0.0) @@ -101,8 +94,7 @@ def setup(self): add_aviary_output(self, Aircraft.Design.STRUCTURE_MASS, val=0.0) def setup_partials(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) self.declare_partials(Aircraft.Design.STRUCTURE_MASS, '*', val=1) self.declare_partials(Aircraft.Design.STRUCTURE_MASS, Aircraft.Nacelle.MASS, @@ -127,11 +119,6 @@ def compute(self, inputs, outputs): class PropulsionMass(om.ExplicitComponent): - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Fuel.FUEL_SYSTEM_MASS, val=0.0) add_aviary_input(self, Aircraft.Propulsion.TOTAL_MISC_MASS, val=0.0) @@ -162,11 +149,6 @@ def compute(self, inputs, outputs): class SystemsEquipMass(om.ExplicitComponent): - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.AirConditioning.MASS, val=0.0) add_aviary_input(self, Aircraft.AntiIcing.MASS, val=0.0) @@ -204,11 +186,6 @@ def compute(self, inputs, outputs): class AltSystemsEquipMassBase(om.ExplicitComponent): - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.AirConditioning.MASS, val=0.0) add_aviary_input(self, Aircraft.AntiIcing.MASS, val=0.0) @@ -246,11 +223,6 @@ def compute(self, inputs, outputs): class AltSystemsEquipMass(om.ExplicitComponent): - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Design.SYSTEMS_EQUIP_MASS_BASE, val=0.0) add_aviary_input(self, Aircraft.Design.STRUCTURE_MASS, val=0.0) @@ -283,11 +255,6 @@ def compute(self, inputs, outputs): class EmptyMass(om.ExplicitComponent): - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Design.EMPTY_MASS_MARGIN, val=0.0) add_aviary_input(self, Aircraft.Design.STRUCTURE_MASS, val=0.0) @@ -311,11 +278,6 @@ def compute(self, inputs, outputs): class AltEmptyMass(om.ExplicitComponent): - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Design.EMPTY_MASS_MARGIN, val=0.0) add_aviary_input(self, Aircraft.Design.STRUCTURE_MASS, val=0.0) @@ -346,11 +308,6 @@ def compute(self, inputs, outputs): class OperatingMass(om.ExplicitComponent): - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.CrewPayload.CARGO_CONTAINER_MASS, val=0.0) add_aviary_input(self, Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS, val=0.0) @@ -381,11 +338,6 @@ def compute(self, inputs, outputs): class ZeroFuelMass(om.ExplicitComponent): - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.CrewPayload.PASSENGER_MASS, val=0.0) add_aviary_input(self, Aircraft.CrewPayload.BAGGAGE_MASS, val=0.0) @@ -409,11 +361,6 @@ def compute(self, inputs, outputs): class FuelMass(om.ExplicitComponent): - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Mission.Design.GROSS_MASS, val=0.0) add_aviary_input(self, Aircraft.Design.ZERO_FUEL_MASS, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/misc_engine.py b/aviary/subsystems/mass/flops_based/misc_engine.py index dba079072..a77ca24c9 100644 --- a/aviary/subsystems/mass/flops_based/misc_engine.py +++ b/aviary/subsystems/mass/flops_based/misc_engine.py @@ -1,9 +1,8 @@ import numpy as np + import openmdao.api as om -import numpy as np -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -20,13 +19,10 @@ class EngineMiscMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input( self, Aircraft.Engine.ADDITIONAL_MASS, val=np.zeros(num_engine_type)) @@ -48,8 +44,7 @@ def setup(self): def compute(self, inputs, outputs): # TODO temporarily using engine-level additional mass and multiplying # by num_engines to get propulsion-level additional mass - options: AviaryValues = self.options['aviary_options'] - num_engines = options.get_val(Aircraft.Engine.NUM_ENGINES) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] addtl_mass = sum(inputs[Aircraft.Engine.ADDITIONAL_MASS] * num_engines) ctrl_mass = inputs[Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS] @@ -63,8 +58,7 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): # TODO temporarily using engine-level additional mass and multiplying # by num_engines to get propulsion-level additional mass - options: AviaryValues = self.options['aviary_options'] - num_engines = options.get_val(Aircraft.Engine.NUM_ENGINES) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] addtl_mass = inputs[Aircraft.Engine.ADDITIONAL_MASS] * num_engines ctrl_mass = inputs[Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS] diff --git a/aviary/subsystems/mass/flops_based/nacelle.py b/aviary/subsystems/mass/flops_based/nacelle.py index 398d8f0af..7ec531053 100644 --- a/aviary/subsystems/mass/flops_based/nacelle.py +++ b/aviary/subsystems/mass/flops_based/nacelle.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import nacelle_count_factor -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -21,13 +20,10 @@ class NacelleMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Nacelle.AVG_DIAMETER, val=np.zeros(num_engine_type)) @@ -45,8 +41,7 @@ def setup(self): def setup_partials(self): # derivatives w.r.t vectorized engine inputs have known sparsity pattern - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) shape = np.arange(num_engine_type) self.declare_partials(Aircraft.Nacelle.MASS, Aircraft.Nacelle.AVG_DIAMETER, @@ -59,8 +54,7 @@ def setup_partials(self): rows=shape, cols=shape, val=1.0) def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - num_eng = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + num_eng = self.options[Aircraft.Engine.NUM_ENGINES] avg_diam = inputs[Aircraft.Nacelle.AVG_DIAMETER] avg_length = inputs[Aircraft.Nacelle.AVG_LENGTH] scaler = inputs[Aircraft.Nacelle.MASS_SCALER] @@ -73,8 +67,7 @@ def compute(self, inputs, outputs): avg_diam * avg_length * thrust**0.36 * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_eng = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + num_eng = self.options[Aircraft.Engine.NUM_ENGINES] avg_diam = inputs[Aircraft.Nacelle.AVG_DIAMETER] avg_length = inputs[Aircraft.Nacelle.AVG_LENGTH] scaler = inputs[Aircraft.Nacelle.MASS_SCALER] diff --git a/aviary/subsystems/mass/flops_based/paint.py b/aviary/subsystems/mass/flops_based/paint.py index 7e1df471a..4781a13e6 100644 --- a/aviary/subsystems/mass/flops_based/paint.py +++ b/aviary/subsystems/mass/flops_based/paint.py @@ -1,6 +1,5 @@ import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft @@ -10,11 +9,6 @@ class PaintMass(om.ExplicitComponent): Calculates the mass of paint based on total wetted area. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Design.TOTAL_WETTED_AREA, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/passenger_service.py b/aviary/subsystems/mass/flops_based/passenger_service.py index 21c5a5ae2..f333b4011 100644 --- a/aviary/subsystems/mass/flops_based/passenger_service.py +++ b/aviary/subsystems/mass/flops_based/passenger_service.py @@ -5,8 +5,7 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -18,9 +17,10 @@ class PassengerServiceMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_FIRST_CLASS) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS) + add_aviary_option(self, Mission.Constraints.MAX_MACH) def setup(self): add_aviary_input( @@ -45,16 +45,12 @@ def setup_partials(self): self.declare_partials('*', '*') def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - first_class_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS) + first_class_count = self.options[Aircraft.CrewPayload.Design.NUM_FIRST_CLASS] + business_class_count = self.options[Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS] + tourist_class_count = self.options[Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS] - business_class_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS) - - tourist_class_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS) design_range = inputs[Mission.Design.RANGE] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] passenger_service_mass_scaler = \ inputs[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER] @@ -71,16 +67,12 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): passenger_service_weight / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - first_class_count = aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS) - - business_class_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS) + first_class_count = self.options[Aircraft.CrewPayload.Design.NUM_FIRST_CLASS] + business_class_count = self.options[Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS] + tourist_class_count = self.options[Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS] - tourist_class_count = \ - aviary_options.get_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS) design_range = inputs[Mission.Design.RANGE] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] passenger_service_mass_scaler = \ inputs[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER] @@ -114,9 +106,7 @@ class AltPassengerServiceMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) def setup(self): add_aviary_input( @@ -130,9 +120,7 @@ def setup_partials(self): def compute( self, inputs, outputs, discrete_inputs=None, discrete_outputs=None ): - aviary_options: AviaryValues = self.options['aviary_options'] - passenger_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + passenger_count = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] passenger_service_mass_scaler = \ inputs[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER] @@ -144,9 +132,7 @@ def compute( passenger_service_weight / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J, discrete_inputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - passenger_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + passenger_count = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] J[ Aircraft.CrewPayload.PASSENGER_SERVICE_MASS, diff --git a/aviary/subsystems/mass/flops_based/starter.py b/aviary/subsystems/mass/flops_based/starter.py index e7b06a4d9..2bf04fb07 100644 --- a/aviary/subsystems/mass/flops_based/starter.py +++ b/aviary/subsystems/mass/flops_based/starter.py @@ -1,11 +1,11 @@ -import openmdao.api as om import numpy as np +import openmdao.api as om + from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import ( distributed_engine_count_factor, distributed_nacelle_diam_factor) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -17,13 +17,12 @@ class TransportStarterMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) + add_aviary_option(self, Mission.Constraints.MAX_MACH) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Nacelle.AVG_DIAMETER, val=np.zeros(num_engine_type)) @@ -34,12 +33,11 @@ def setup_partials(self): self.declare_partials("*", "*") def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - total_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) - num_engines = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + total_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] + max_mach = self.options[Mission.Constraints.MAX_MACH] d_nacelle = inputs[Aircraft.Nacelle.AVG_DIAMETER] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) num_engines_factor = distributed_engine_count_factor(total_engines) f_nacelle = distributed_nacelle_diam_factor(d_nacelle, num_engines) @@ -47,13 +45,12 @@ def compute(self, inputs, outputs): 11.0 * num_engines_factor * max_mach**0.32 * f_nacelle**1.6) / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - total_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) - num_engines = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + total_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] + max_mach = self.options[Mission.Constraints.MAX_MACH] d_nacelle = inputs[Aircraft.Nacelle.AVG_DIAMETER] eng_count_factor = distributed_engine_count_factor(total_engines) - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) d_avg = sum(d_nacelle * num_engines) / total_engines diff --git a/aviary/subsystems/mass/flops_based/surface_controls.py b/aviary/subsystems/mass/flops_based/surface_controls.py index 441a7fcde..fb109e427 100644 --- a/aviary/subsystems/mass/flops_based/surface_controls.py +++ b/aviary/subsystems/mass/flops_based/surface_controls.py @@ -1,8 +1,7 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -13,9 +12,7 @@ class SurfaceControlMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Mission.Constraints.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, val=1.0) @@ -31,9 +28,8 @@ def setup(self): Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO, Aircraft.Wing.AREA]) def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] scaler = inputs[Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] gross_weight = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM flap_ratio = inputs[Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO] wing_area = inputs[Aircraft.Wing.AREA] @@ -49,9 +45,8 @@ def compute(self, inputs, outputs): GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] scaler = inputs[Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER] - max_mach = aviary_options.get_val(Mission.Constraints.MAX_MACH) + max_mach = self.options[Mission.Constraints.MAX_MACH] gross_weight = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM flap_ratio = inputs[Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO] wing_area = inputs[Aircraft.Wing.AREA] @@ -93,11 +88,6 @@ class AltSurfaceControlMass(om.ExplicitComponent): output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, val=1.0) add_aviary_input(self, Aircraft.Wing.AREA, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/test/test_air_conditioning.py b/aviary/subsystems/mass/flops_based/test/test_air_conditioning.py index a168955a5..929bd0a12 100644 --- a/aviary/subsystems/mass/flops_based/test/test_air_conditioning.py +++ b/aviary/subsystems/mass/flops_based/test/test_air_conditioning.py @@ -10,7 +10,7 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -28,11 +28,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "air_cond", - TransportAirCondMass(aviary_options=get_flops_inputs(case_name)), + TransportAirCondMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -43,7 +45,7 @@ def test_case(self, case_name): Aircraft.Fuselage.MAX_HEIGHT, Aircraft.Fuselage.PLANFORM_AREA], output_keys=Aircraft.AirConditioning.MASS, - aviary_option_keys=[Aircraft.CrewPayload.NUM_PASSENGERS], + aviary_option_keys=[Aircraft.CrewPayload.Design.NUM_PASSENGERS], version=Version.TRANSPORT, tol=3.0e-4, atol=1e-11) @@ -67,12 +69,16 @@ def tearDown(self): def test_case(self): prob = om.Problem() + prob.model.add_subsystem( "air_cond", - TransportAirCondMass(aviary_options=get_flops_inputs("N3CC")), + TransportAirCondMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + prob.model_options['*'] = get_flops_options("N3CC") + prob.model.set_input_defaults( Aircraft.AirConditioning.MASS_SCALER, val=0.98094, units="unitless") prob.model.set_input_defaults( @@ -81,6 +87,7 @@ def test_case(self): Aircraft.Fuselage.MAX_HEIGHT, val=13., units="ft") prob.model.set_input_defaults( Aircraft.Fuselage.PLANFORM_AREA, val=1537.5, units="ft**2") + prob.setup(check=False, force_alloc_complex=True) partial_data = prob.check_partials(out_stream=None, method="cs") @@ -103,11 +110,13 @@ def test_case(self, case_name): prob.model.add_subsystem( 'air_cond', - AltAirCondMass(aviary_options=get_flops_inputs(case_name)), + AltAirCondMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -115,7 +124,7 @@ def test_case(self, case_name): case_name, input_keys=Aircraft.AirConditioning.MASS_SCALER, output_keys=Aircraft.AirConditioning.MASS, - aviary_option_keys=Aircraft.CrewPayload.NUM_PASSENGERS, + aviary_option_keys=Aircraft.CrewPayload.Design.NUM_PASSENGERS, version=Version.ALTERNATE) def test_IO(self): @@ -137,12 +146,16 @@ def tearDown(self): def test_case(self): prob = om.Problem() + prob.model.add_subsystem( 'air_cond', - AltAirCondMass(aviary_options=get_flops_inputs("N3CC")), + AltAirCondMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + prob.model_options['*'] = get_flops_options("N3CC") + prob.model.set_input_defaults( Aircraft.AirConditioning.MASS_SCALER, val=0.98094, units="unitless") prob.setup(check=False, force_alloc_complex=True) diff --git a/aviary/subsystems/mass/flops_based/test/test_anti_icing.py b/aviary/subsystems/mass/flops_based/test/test_anti_icing.py index b02844208..3cf156548 100644 --- a/aviary/subsystems/mass/flops_based/test/test_anti_icing.py +++ b/aviary/subsystems/mass/flops_based/test/test_anti_icing.py @@ -11,6 +11,7 @@ from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -28,11 +29,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "anti_icing", - AntiIcingMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), + AntiIcingMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -50,17 +53,19 @@ def test_case_2(self): # test with more than four engines prob = self.prob - aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([5])) - aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 5) + options = get_flops_options('LargeSingleAisle1FLOPS') + options[Aircraft.Engine.NUM_ENGINES] = np.array([5]) + options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] = 5 prob.model.add_subsystem( "anti_icing", - AntiIcingMass(aviary_options=aviary_options), + AntiIcingMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = options + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.AntiIcing.MASS_SCALER, 1.0) @@ -83,17 +88,19 @@ def test_case_3(self): # test with multiple engine types prob = self.prob - aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2, 2, 4])) - aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 8) + options = get_flops_options('LargeSingleAisle1FLOPS') + options[Aircraft.Engine.NUM_ENGINES] = np.array([2, 2, 4]) + options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] = 8 prob.model.add_subsystem( "anti_icing", - AntiIcingMass(aviary_options=aviary_options), + AntiIcingMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = options + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.AntiIcing.MASS_SCALER, 1.0) @@ -132,15 +139,20 @@ def tearDown(self): def test_case_2(self): prob = om.Problem() - aviary_options = get_flops_inputs('N3CC') - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([5])) - aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 5) + + options = get_flops_options('N3CC') + options[Aircraft.Engine.NUM_ENGINES] = np.array([5]) + options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] = 5 + prob.model.add_subsystem( "anti_icing", - AntiIcingMass(aviary_options=aviary_options), + AntiIcingMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + prob.model_options['*'] = options + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.AntiIcing.MASS_SCALER, 1.0) prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 12.33, 'ft') diff --git a/aviary/subsystems/mass/flops_based/test/test_apu.py b/aviary/subsystems/mass/flops_based/test/test_apu.py index e9050e459..f0706f3fb 100644 --- a/aviary/subsystems/mass/flops_based/test/test_apu.py +++ b/aviary/subsystems/mass/flops_based/test/test_apu.py @@ -8,7 +8,7 @@ from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -26,11 +26,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "apu", - TransportAPUMass(aviary_options=get_flops_inputs(case_name)), + TransportAPUMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -62,10 +64,13 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "apu", - TransportAPUMass(aviary_options=get_flops_inputs("N3CC")), + TransportAPUMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.Fuselage.PLANFORM_AREA, 100.0, 'ft**2') diff --git a/aviary/subsystems/mass/flops_based/test/test_avionics.py b/aviary/subsystems/mass/flops_based/test/test_avionics.py index 3ce67ff86..084afb5ce 100644 --- a/aviary/subsystems/mass/flops_based/test/test_avionics.py +++ b/aviary/subsystems/mass/flops_based/test/test_avionics.py @@ -8,7 +8,7 @@ from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft, Mission @@ -29,12 +29,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "avionics", - TransportAvionicsMass(aviary_options=get_flops_inputs( - case_name, preprocess=True)), + TransportAvionicsMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -68,11 +69,13 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "avionics", - TransportAvionicsMass(aviary_options=get_flops_inputs( - "N3CC", preprocess=True)), + TransportAvionicsMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.Fuselage.PLANFORM_AREA, 1500.0, 'ft**2') prob.set_val(Mission.Design.RANGE, 3500.0, 'nmi') diff --git a/aviary/subsystems/mass/flops_based/test/test_cargo.py b/aviary/subsystems/mass/flops_based/test/test_cargo.py index 7d388fc1c..7b6ea15b3 100644 --- a/aviary/subsystems/mass/flops_based/test/test_cargo.py +++ b/aviary/subsystems/mass/flops_based/test/test_cargo.py @@ -6,17 +6,14 @@ from aviary.subsystems.mass.flops_based.cargo import CargoMass from aviary.utils.aviary_values import AviaryValues from aviary.utils.test_utils.variable_test import assert_match_varnames -from aviary.validation_cases.validation_tests import do_validation_test, print_case +from aviary.validation_cases.validation_tests import do_validation_test, print_case, get_flops_options from aviary.variable_info.variables import Aircraft cargo_test_data = {} cargo_test_data['1'] = AviaryValues({ - Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER: (50, 'lbm'), Aircraft.CrewPayload.MISC_CARGO: (2000., 'lbm'), # custom - Aircraft.CrewPayload.MASS_PER_PASSENGER: (180., 'lbm'), Aircraft.CrewPayload.WING_CARGO: (1000., 'lbm'), # custom Aircraft.CrewPayload.BAGGAGE_MASS: (9200., 'lbm'), # custom - Aircraft.CrewPayload.NUM_PASSENGERS: (184, 'unitless'), # custom Aircraft.CrewPayload.PASSENGER_MASS: (33120., 'lbm'), # custom Aircraft.CrewPayload.CARGO_MASS: (3000., 'lbm'), # custom Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS: (45320., 'lbm') # custom @@ -38,11 +35,17 @@ def test_case(self, case_name): prob.model.add_subsystem( 'cargo_passenger', - CargoMass(aviary_options=validation_data), + CargoMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = { + Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER: (50, 'lbm'), + Aircraft.CrewPayload.MASS_PER_PASSENGER: (180., 'lbm'), + Aircraft.CrewPayload.NUM_PASSENGERS: 184, # custom + } + prob.setup(check=False, force_alloc_complex=True) do_validation_test(prob, diff --git a/aviary/subsystems/mass/flops_based/test/test_cargo_containers.py b/aviary/subsystems/mass/flops_based/test/test_cargo_containers.py index 9b5c303c9..35eca64a4 100644 --- a/aviary/subsystems/mass/flops_based/test/test_cargo_containers.py +++ b/aviary/subsystems/mass/flops_based/test/test_cargo_containers.py @@ -9,7 +9,7 @@ from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -27,12 +27,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "cargo_containers", - TransportCargoContainersMass( - aviary_options=get_flops_inputs(case_name)), + TransportCargoContainersMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -67,12 +68,13 @@ def test_case(self): prob.model.add_subsystem( "cargo_containers", - TransportCargoContainersMass( - aviary_options=get_flops_inputs("N3CC")), + TransportCargoContainersMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.CrewPayload.BAGGAGE_MASS, 5000.0, 'lbm') diff --git a/aviary/subsystems/mass/flops_based/test/test_crew.py b/aviary/subsystems/mass/flops_based/test/test_crew.py index bcd0dc2ce..e4800e0a7 100644 --- a/aviary/subsystems/mass/flops_based/test/test_crew.py +++ b/aviary/subsystems/mass/flops_based/test/test_crew.py @@ -7,7 +7,7 @@ from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -25,12 +25,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "non_flight_crew", - NonFlightCrewMass(aviary_options=get_flops_inputs( - case_name, preprocess=True)), + NonFlightCrewMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -57,11 +58,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "flight_crew", - FlightCrewMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), + FlightCrewMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( diff --git a/aviary/subsystems/mass/flops_based/test/test_electrical.py b/aviary/subsystems/mass/flops_based/test/test_electrical.py index f9abb531a..42567dbb9 100644 --- a/aviary/subsystems/mass/flops_based/test/test_electrical.py +++ b/aviary/subsystems/mass/flops_based/test/test_electrical.py @@ -10,7 +10,7 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -28,7 +28,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "electric_test", - ElectricalMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), + ElectricalMass(), promotes_outputs=[ Aircraft.Electrical.MASS, ], @@ -39,6 +39,8 @@ def test_case(self, case_name): ] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -65,7 +67,7 @@ def test_case(self): prob.model.add_subsystem( "electric_test", - ElectricalMass(aviary_options=get_flops_inputs("N3CC", preprocess=True)), + ElectricalMass(), promotes_outputs=[ Aircraft.Electrical.MASS, ], @@ -76,6 +78,8 @@ def test_case(self): ] ) + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -106,7 +110,7 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "electric_test", - ElectricalMass(aviary_options=get_flops_inputs("N3CC", preprocess=True)), + ElectricalMass(), promotes_outputs=[ Aircraft.Electrical.MASS, ], @@ -116,6 +120,9 @@ def test_case(self): Aircraft.Electrical.MASS_SCALER ] ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.Fuselage.LENGTH, 100.0, 'ft') prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 12.0, 'ft') @@ -137,8 +144,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "electric_test", - AltElectricalMass(aviary_options=get_flops_inputs( - case_name, preprocess=True)), + AltElectricalMass(), promotes_outputs=[ Aircraft.Electrical.MASS, ], @@ -147,6 +153,8 @@ def test_case(self, case_name): ] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( diff --git a/aviary/subsystems/mass/flops_based/test/test_empty_margin.py b/aviary/subsystems/mass/flops_based/test/test_empty_margin.py index 29b45f3fb..20ca3cad3 100644 --- a/aviary/subsystems/mass/flops_based/test/test_empty_margin.py +++ b/aviary/subsystems/mass/flops_based/test/test_empty_margin.py @@ -7,7 +7,7 @@ from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -25,11 +25,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "margin", - EmptyMassMargin(aviary_options=get_flops_inputs(case_name)), + EmptyMassMargin(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( diff --git a/aviary/subsystems/mass/flops_based/test/test_engine.py b/aviary/subsystems/mass/flops_based/test/test_engine.py index 8f249a162..94ba9732e 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine.py @@ -13,7 +13,7 @@ from aviary.utils.functions import get_path from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft, Settings @@ -26,16 +26,17 @@ def setUp(self): @parameterized.expand(get_flops_case_names(), name_func=print_case) def test_case(self, case_name): - prob = self.prob prob.model.add_subsystem( "engine_mass", - EngineMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), + EngineMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -81,8 +82,18 @@ def test_case_2(self): engine3 = EngineDeck(name='engine3', options=options) preprocess_propulsion(options, [engine, engine2, engine3]) - prob.model.add_subsystem('engine_mass', EngineMass( - aviary_options=options), promotes=['*']) + prob.model.add_subsystem('engine_mass', EngineMass(), promotes=['*']) + + opts = { + Aircraft.Engine.ADDITIONAL_MASS_FRACTION: options.get_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION), + Aircraft.Engine.NUM_ENGINES: options.get_val(Aircraft.Engine.NUM_ENGINES), + Aircraft.Engine.REFERENCE_MASS: options.get_item(Aircraft.Engine.REFERENCE_MASS), + Aircraft.Engine.REFERENCE_SLS_THRUST: options.get_item(Aircraft.Engine.REFERENCE_SLS_THRUST), + Aircraft.Engine.SCALE_MASS: options.get_val(Aircraft.Engine.SCALE_MASS), + } + + prob.model_options['*'] = opts + prob.setup(force_alloc_complex=True) prob.set_val(Aircraft.Engine.SCALED_SLS_THRUST, diff --git a/aviary/subsystems/mass/flops_based/test/test_engine_controls.py b/aviary/subsystems/mass/flops_based/test/test_engine_controls.py index 9df3af152..63cb871ed 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine_controls.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine_controls.py @@ -9,7 +9,7 @@ from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -25,17 +25,18 @@ def setUp(self): @parameterized.expand(get_flops_case_names(omit='N3CC'), name_func=print_case) def test_case(self, case_name): - flops_inputs = get_flops_inputs(case_name, preprocess=True) prob = self.prob prob.model.add_subsystem( 'engine_ctrls', - TransportEngineCtrlsMass(aviary_options=flops_inputs), + TransportEngineCtrlsMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(force_alloc_complex=True) flops_validation_test( @@ -64,14 +65,17 @@ def tearDown(self): control.GRAV_ENGLISH_LBM = 1.0 def test_case(self): - flops_inputs = get_flops_inputs("LargeSingleAisle1FLOPS", preprocess=True) prob = om.Problem() prob.model.add_subsystem( 'engine_ctrls', - TransportEngineCtrlsMass(aviary_options=flops_inputs), + TransportEngineCtrlsMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) + + prob.model_options['*'] = get_flops_options("LargeSingleAisle1FLOPS", + preprocess=True) + prob.setup(force_alloc_complex=True) prob.set_val(Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, 50000.0, 'lbf') diff --git a/aviary/subsystems/mass/flops_based/test/test_engine_oil.py b/aviary/subsystems/mass/flops_based/test/test_engine_oil.py index 8ec123917..6b3157175 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine_oil.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine_oil.py @@ -10,6 +10,7 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, + get_flops_options, get_flops_inputs, print_case) from aviary.variable_info.variables import Aircraft @@ -29,16 +30,19 @@ def test_case(self, case_name): prob = self.prob - options = get_flops_inputs(case_name) - options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 2) + options = { + Aircraft.Propulsion.TOTAL_NUM_ENGINES: 2, + } prob.model.add_subsystem( 'engine_oil', - TransportEngineOilMass(aviary_options=options), + TransportEngineOilMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) + prob.model_options['*'] = options + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -69,12 +73,14 @@ def tearDown(self): def test_case(self): prob = om.Problem() - options = get_flops_inputs("N3CC") - options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 2) + + options = { + Aircraft.Propulsion.TOTAL_NUM_ENGINES: 2, + } prob.model.add_subsystem( 'engine_oil', - TransportEngineOilMass(aviary_options=options), + TransportEngineOilMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -99,16 +105,21 @@ def test_case(self, case_name): prob = self.prob - options = get_flops_inputs(case_name) - options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 2) + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.CrewPayload.Design.NUM_PASSENGERS: inputs.get_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS), + } prob.model.add_subsystem( 'engine_oil', - AltEngineOilMass(aviary_options=options), + AltEngineOilMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) + prob.model_options['*'] = options + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -137,11 +148,16 @@ def tearDown(self): def test_case(self): prob = om.Problem() - options = get_flops_inputs("N3CC") - options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 2) + + inputs = get_flops_inputs("N3CC", preprocess=True) + + options = { + Aircraft.CrewPayload.Design.NUM_PASSENGERS: inputs.get_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS), + } + prob.model.add_subsystem( 'engine_oil', - AltEngineOilMass(aviary_options=options), + AltEngineOilMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_engine_pod.py b/aviary/subsystems/mass/flops_based/test/test_engine_pod.py index 7882b7178..a813abc69 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine_pod.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine_pod.py @@ -30,13 +30,21 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + } + prob.model.add_subsystem( 'engine_pod', - EnginePodMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), + EnginePodMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) + prob.model_options['*'] = options + prob.setup(check=False, force_alloc_complex=True) # Tol not that tight, but it is unclear where the pod mass values in files come from, @@ -62,13 +70,13 @@ def test_case_multiengine(self): # test with multiple engine types prob = self.prob - aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2, 2, 3])) - aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 7) + options = { + Aircraft.Engine.NUM_ENGINES: np.array([2, 2, 3]), + } prob.model.add_subsystem( 'engine_pod', - EnginePodMass(aviary_options=aviary_options), + EnginePodMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_fin.py b/aviary/subsystems/mass/flops_based/test/test_fin.py index 095ce75c2..fb75e20a9 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fin.py +++ b/aviary/subsystems/mass/flops_based/test/test_fin.py @@ -36,9 +36,12 @@ def test_case(self, case_name): validation_data = fin_test_data[case_name] prob = self.prob + options = { + Aircraft.Fins.NUM_FINS: 1, + } prob.model.add_subsystem( "fin", - FinMass(aviary_options=validation_data), + FinMass(**options), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -73,11 +76,14 @@ def tearDown(self): fin.GRAV_ENGLISH_LBM = 1.0 def test_case(self): - validation_data = fin_test_data["1"] prob = om.Problem() + + options = { + Aircraft.Fins.NUM_FINS: 1, + } prob.model.add_subsystem( "fin", - FinMass(aviary_options=validation_data), + FinMass(**options), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_fuel_capacity.py b/aviary/subsystems/mass/flops_based/test/test_fuel_capacity.py index 1e2b94ad3..d9e7aff1d 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fuel_capacity.py +++ b/aviary/subsystems/mass/flops_based/test/test_fuel_capacity.py @@ -31,11 +31,10 @@ def initialize(self): desc='Aircraft options dictionary') def setup(self): - aviary_options = self.options['aviary_options'] self.add_subsystem( 'fuel_capacity_group', - FuelCapacityGroup(aviary_options=aviary_options), + FuelCapacityGroup(), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_fuel_system.py b/aviary/subsystems/mass/flops_based/test/test_fuel_system.py index c1c0f9dd8..7aa2ad9cc 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fuel_system.py +++ b/aviary/subsystems/mass/flops_based/test/test_fuel_system.py @@ -12,7 +12,7 @@ get_flops_case_names, get_flops_inputs, print_case) -from aviary.variable_info.variables import Aircraft +from aviary.variable_info.variables import Aircraft, Mission class AltFuelSystemTest(unittest.TestCase): @@ -26,10 +26,15 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Fuel.NUM_TANKS: inputs.get_val(Aircraft.Fuel.NUM_TANKS), + } + prob.model.add_subsystem( "alt_fuel_sys_test", - AltFuelSystemMass(aviary_options=get_flops_inputs( - case_name, preprocess=True)), + AltFuelSystemMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -63,10 +68,16 @@ def tearDown(self): def test_case(self): prob = om.Problem() + + inputs = get_flops_inputs("N3CC", preprocess=True) + + options = { + Aircraft.Fuel.NUM_TANKS: inputs.get_val(Aircraft.Fuel.NUM_TANKS), + } + prob.model.add_subsystem( "alt_fuel_sys_test", - AltFuelSystemMass(aviary_options=get_flops_inputs( - "N3CC", preprocess=True)), + AltFuelSystemMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -88,10 +99,16 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Propulsion.TOTAL_NUM_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES), + Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + } + prob.model.add_subsystem( "transport_fuel_sys_test", - TransportFuelSystemMass( - aviary_options=get_flops_inputs(case_name, preprocess=True)), + TransportFuelSystemMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -126,10 +143,17 @@ def tearDown(self): def test_case(self): prob = om.Problem() + + inputs = get_flops_inputs("N3CC", preprocess=True) + + options = { + Aircraft.Propulsion.TOTAL_NUM_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES), + Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + } + prob.model.add_subsystem( "transport_fuel_sys_test", - TransportFuelSystemMass( - aviary_options=get_flops_inputs("N3CC", preprocess=True)), + TransportFuelSystemMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_furnishings.py b/aviary/subsystems/mass/flops_based/test/test_furnishings.py index b6885b17b..7dab4cc72 100644 --- a/aviary/subsystems/mass/flops_based/test/test_furnishings.py +++ b/aviary/subsystems/mass/flops_based/test/test_furnishings.py @@ -11,6 +11,7 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, + get_flops_options, get_flops_inputs, print_case) from aviary.variable_info.variables import Aircraft, Mission @@ -32,12 +33,13 @@ def test_case(self, case_name): prob.model.add_subsystem( 'furnishings', - TransportFurnishingsGroupMass( - aviary_options=get_flops_inputs(case_name, preprocess=True)), + TransportFurnishingsGroupMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -68,18 +70,25 @@ def test_case(self, case_name): prob = self.prob flops_inputs = get_flops_inputs(case_name, preprocess=True) - flops_inputs.update({ - Aircraft.Fuselage.MILITARY_CARGO_FLOOR: (False, 'unitless'), - Aircraft.BWB.NUM_BAYS: (5, 'unitless') - }) + + opts = { + Aircraft.BWB.NUM_BAYS: 5, + Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS: flops_inputs.get_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS), + Aircraft.CrewPayload.NUM_FLIGHT_CREW: flops_inputs.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW), + Aircraft.CrewPayload.Design.NUM_FIRST_CLASS: flops_inputs.get_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS), + Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS: flops_inputs.get_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS), + Aircraft.Fuselage.MILITARY_CARGO_FLOOR: False, + } prob.model.add_subsystem( 'furnishings', - BWBFurnishingsGroupMass(aviary_options=flops_inputs), + BWBFurnishingsGroupMass(**opts), promotes_outputs=['*'], promotes_inputs=['*'] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) # TODO: add FLOPS tests cases with BWB furnishings mass calculations @@ -124,14 +133,21 @@ def tearDown(self): def test_case(self): prob = om.Problem() + flops_inputs = get_flops_inputs("N3CC", preprocess=True) - flops_inputs.update({ - Aircraft.Fuselage.MILITARY_CARGO_FLOOR: (False, 'unitless'), - Aircraft.BWB.NUM_BAYS: (5, 'unitless') - }) + + opts = { + Aircraft.BWB.NUM_BAYS: 5, + Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS: flops_inputs.get_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS), + Aircraft.CrewPayload.NUM_FLIGHT_CREW: flops_inputs.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW), + Aircraft.CrewPayload.Design.NUM_FIRST_CLASS: flops_inputs.get_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS), + Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS: flops_inputs.get_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS), + Aircraft.Fuselage.MILITARY_CARGO_FLOOR: False, + } + prob.model.add_subsystem( 'furnishings', - BWBFurnishingsGroupMass(aviary_options=flops_inputs), + BWBFurnishingsGroupMass(**opts), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -157,12 +173,13 @@ def test_case(self, case_name): prob.model.add_subsystem( 'furnishings', - AltFurnishingsGroupMassBase( - aviary_options=get_flops_inputs(case_name, preprocess=True)), + AltFurnishingsGroupMassBase(), promotes_outputs=['*'], promotes_inputs=['*'] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -192,12 +209,13 @@ def test_case(self, case_name): prob.model.add_subsystem( 'furnishings', - AltFurnishingsGroupMass( - aviary_options=get_flops_inputs(case_name, preprocess=True)), + AltFurnishingsGroupMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( diff --git a/aviary/subsystems/mass/flops_based/test/test_fuselage.py b/aviary/subsystems/mass/flops_based/test/test_fuselage.py index e9bda3a9d..554ae7284 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fuselage.py +++ b/aviary/subsystems/mass/flops_based/test/test_fuselage.py @@ -10,7 +10,7 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -28,12 +28,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "fuselage", - TransportFuselageMass(aviary_options=get_flops_inputs( - case_name, preprocess=True)), + TransportFuselageMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -67,11 +68,13 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "fuselage", - TransportFuselageMass(aviary_options=get_flops_inputs( - "N3CC", preprocess=True)), + TransportFuselageMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.Fuselage.LENGTH, 100.0, 'ft') prob.set_val(Aircraft.Fuselage.AVG_DIAMETER, 10.0, 'ft') @@ -93,7 +96,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "fuselage", - AltFuselageMass(aviary_options=get_flops_inputs(case_name)), + AltFuselageMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -131,7 +134,7 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "fuselage", - AltFuselageMass(aviary_options=get_flops_inputs("N3CC")), + AltFuselageMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_horizontail_tail.py b/aviary/subsystems/mass/flops_based/test/test_horizontail_tail.py index 2269d0aec..ca45ce0fb 100644 --- a/aviary/subsystems/mass/flops_based/test/test_horizontail_tail.py +++ b/aviary/subsystems/mass/flops_based/test/test_horizontail_tail.py @@ -10,7 +10,6 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, - get_flops_inputs, print_case) from aviary.variable_info.variables import Aircraft, Mission @@ -28,7 +27,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "horizontal_tail", - HorizontalTailMass(aviary_options=get_flops_inputs(case_name)), + HorizontalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -67,7 +66,7 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "horizontal_tail", - HorizontalTailMass(aviary_options=get_flops_inputs("N3CC")), + HorizontalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -93,7 +92,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "horizontal_tail", - AltHorizontalTailMass(aviary_options=get_flops_inputs(case_name)), + AltHorizontalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -129,7 +128,7 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "horizontal_tail", - AltHorizontalTailMass(aviary_options=get_flops_inputs("N3CC")), + AltHorizontalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_hydraulics.py b/aviary/subsystems/mass/flops_based/test/test_hydraulics.py index 2ce70522d..f17d1f252 100644 --- a/aviary/subsystems/mass/flops_based/test/test_hydraulics.py +++ b/aviary/subsystems/mass/flops_based/test/test_hydraulics.py @@ -29,10 +29,17 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + } + prob.model.add_subsystem( 'hydraulics', - TransportHydraulicsGroupMass( - aviary_options=get_flops_inputs(case_name, preprocess=True)), + TransportHydraulicsGroupMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -70,10 +77,18 @@ def tearDown(self): def test_case(self): prob = om.Problem() + + inputs = get_flops_inputs("N3CC", preprocess=True) + + options = { + Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + } + prob.model.add_subsystem( 'hydraulics', - TransportHydraulicsGroupMass( - aviary_options=get_flops_inputs("N3CC", preprocess=True)), + TransportHydraulicsGroupMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -102,8 +117,7 @@ def test_case(self, case_name): prob.model.add_subsystem( 'hydraulics', - AltHydraulicsGroupMass( - aviary_options=get_flops_inputs(case_name, preprocess=True)), + AltHydraulicsGroupMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -142,8 +156,7 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( 'hydraulics', - AltHydraulicsGroupMass( - aviary_options=get_flops_inputs("N3CC", preprocess=True)), + AltHydraulicsGroupMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_instruments.py b/aviary/subsystems/mass/flops_based/test/test_instruments.py index b8b5fabca..5a0521b5e 100644 --- a/aviary/subsystems/mass/flops_based/test/test_instruments.py +++ b/aviary/subsystems/mass/flops_based/test/test_instruments.py @@ -24,10 +24,18 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.CrewPayload.NUM_FLIGHT_CREW: inputs.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW), + Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + } + prob.model.add_subsystem( "instruments_tests", - TransportInstrumentMass( - aviary_options=get_flops_inputs(case_name, preprocess=True)), + TransportInstrumentMass(**options), promotes_outputs=[ Aircraft.Instruments.MASS, ], @@ -66,10 +74,19 @@ def tearDown(self): def test_case(self): prob = om.Problem() + + inputs = get_flops_inputs("N3CC", preprocess=True) + + options = { + Aircraft.CrewPayload.NUM_FLIGHT_CREW: inputs.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW), + Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + } + prob.model.add_subsystem( "instruments_tests", - TransportInstrumentMass( - aviary_options=get_flops_inputs("N3CC", preprocess=True)), + TransportInstrumentMass(**options), promotes_outputs=[ Aircraft.Instruments.MASS, ], diff --git a/aviary/subsystems/mass/flops_based/test/test_landing_gear.py b/aviary/subsystems/mass/flops_based/test/test_landing_gear.py index a02d8b923..6f67d9ffd 100644 --- a/aviary/subsystems/mass/flops_based/test/test_landing_gear.py +++ b/aviary/subsystems/mass/flops_based/test/test_landing_gear.py @@ -1,3 +1,5 @@ +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.preprocessors import preprocess_options import unittest import openmdao.api as om @@ -28,7 +30,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "landing_gear", - LandingGearMass(aviary_options=get_flops_inputs(case_name)), + LandingGearMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -66,7 +68,7 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "landing_gear", - LandingGearMass(aviary_options=get_flops_inputs("N3CC")), + LandingGearMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -92,7 +94,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "landing_gear_alt", - AltLandingGearMass(aviary_options=get_flops_inputs(case_name)), + AltLandingGearMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -130,7 +132,7 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "landing_gear_alt", - AltLandingGearMass(aviary_options=get_flops_inputs("N3CC")), + AltLandingGearMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -156,12 +158,18 @@ def setUp(self): def test_derivs(self, case_name): prob = self.prob model = prob.model - flops_inputs = get_flops_inputs(case_name) + + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + Aircraft.Engine.NUM_WING_ENGINES: inputs.get_val(Aircraft.Engine.NUM_WING_ENGINES), + } model.add_subsystem( - 'main', MainGearLength(aviary_options=flops_inputs), promotes=['*']) + 'main', MainGearLength(**options), promotes=['*']) model.add_subsystem( - 'nose', NoseGearLength(aviary_options=flops_inputs), promotes=['*']) + 'nose', NoseGearLength(), promotes=['*']) prob.setup(force_alloc_complex=True) diff --git a/aviary/subsystems/mass/flops_based/test/test_landing_mass.py b/aviary/subsystems/mass/flops_based/test/test_landing_mass.py index 0493c022a..60764ce66 100644 --- a/aviary/subsystems/mass/flops_based/test/test_landing_mass.py +++ b/aviary/subsystems/mass/flops_based/test/test_landing_mass.py @@ -7,7 +7,6 @@ from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, - get_flops_inputs, print_case) from aviary.variable_info.variables import Aircraft, Mission @@ -24,7 +23,7 @@ def test_case(self, case_name): prob = self.prob prob.model.add_subsystem( "landing_mass", - LandingMass(aviary_options=get_flops_inputs(case_name)), + LandingMass(), promotes=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_mass_summation.py b/aviary/subsystems/mass/flops_based/test/test_mass_summation.py index dbb14b121..4d85dfa7e 100644 --- a/aviary/subsystems/mass/flops_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/flops_based/test/test_mass_summation.py @@ -30,7 +30,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "tot", - MassSummation(aviary_options=get_flops_inputs(case_name, preprocess=True)), + MassSummation(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -99,9 +99,15 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Design.USE_ALT_MASS: inputs.get_val(Aircraft.Design.USE_ALT_MASS), + } + prob.model.add_subsystem( "tot", - MassSummation(aviary_options=get_flops_inputs(case_name, preprocess=True)), + MassSummation(**options), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -180,8 +186,12 @@ def test_case_multiengine(self): preprocess_propulsion(options, [engineModel1, engineModel2, engineModel3]) - prob.model.add_subsystem('structure_mass', StructureMass( - aviary_options=options), promotes=['*']) + comp_options = { + Aircraft.Engine.NUM_ENGINES: options.get_val(Aircraft.Engine.NUM_ENGINES), + } + + prob.model.add_subsystem('structure_mass', StructureMass(**comp_options), + promotes=['*']) prob.setup(force_alloc_complex=True) prob.set_val(Aircraft.Canard.MASS, val=10.0, units='lbm') diff --git a/aviary/subsystems/mass/flops_based/test/test_misc_engine.py b/aviary/subsystems/mass/flops_based/test/test_misc_engine.py index dc90b0b99..65f582752 100644 --- a/aviary/subsystems/mass/flops_based/test/test_misc_engine.py +++ b/aviary/subsystems/mass/flops_based/test/test_misc_engine.py @@ -28,9 +28,15 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + } + prob.model.add_subsystem( "misc_mass", - EngineMiscMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), + EngineMiscMass(**options), promotes_inputs=['*'], promotes_outputs=['*'] ) @@ -65,9 +71,15 @@ def test_case_multiengine(self): preprocess_propulsion(options, [engineModel1, engineModel2, engineModel3]) - prob.model.add_subsystem('misc_engine_mass', EngineMiscMass( - aviary_options=options), promotes=['*']) + comp_options = { + Aircraft.Engine.NUM_ENGINES: options.get_val(Aircraft.Engine.NUM_ENGINES), + } + + prob.model.add_subsystem('misc_engine_mass', EngineMiscMass(**comp_options), + promotes=['*']) + prob.setup(force_alloc_complex=True) + prob.set_val(Aircraft.Engine.ADDITIONAL_MASS, np.array([100, 26, 30]), units='lbm') prob.set_val(Aircraft.Propulsion.MISC_MASS_SCALER, 1.02, units='unitless') diff --git a/aviary/subsystems/mass/flops_based/test/test_nacelle.py b/aviary/subsystems/mass/flops_based/test/test_nacelle.py index 975abc97e..9534dfb84 100644 --- a/aviary/subsystems/mass/flops_based/test/test_nacelle.py +++ b/aviary/subsystems/mass/flops_based/test/test_nacelle.py @@ -28,9 +28,15 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + } + prob.model.add_subsystem( "nacelle", - NacelleMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), + NacelleMass(**options), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -66,9 +72,15 @@ def test_case_multiengine(self): preprocess_propulsion(options, [engineModel1, engineModel2, engineModel3]) - prob.model.add_subsystem('nacelle_mass', NacelleMass( - aviary_options=options), promotes=['*']) + comp_options = { + Aircraft.Engine.NUM_ENGINES: options.get_val(Aircraft.Engine.NUM_ENGINES), + } + + prob.model.add_subsystem('nacelle_mass', NacelleMass(**comp_options), + promotes=['*']) + prob.setup(force_alloc_complex=True) + prob.set_val(Aircraft.Nacelle.AVG_DIAMETER, np.array([5.0, 3.0, 8.0]), units='ft') prob.set_val(Aircraft.Nacelle.AVG_LENGTH, @@ -104,9 +116,16 @@ def tearDown(self): def test_case(self): prob = om.Problem() + + inputs = get_flops_inputs("N3CC", preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + } + prob.model.add_subsystem( "nacelle", - NacelleMass(aviary_options=get_flops_inputs("N3CC", preprocess=True)), + NacelleMass(**options), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -130,10 +149,18 @@ def test_case_multiengine(self): options.set_val(Aircraft.Engine.NUM_ENGINES, 2) engineModel2 = EngineDeck(options=options) engineModel3 = EngineDeck(options=options) + preprocess_propulsion(options, [engineModel1, engineModel2, engineModel3]) - prob.model.add_subsystem('nacelle_mass', NacelleMass( - aviary_options=options), promotes=['*']) + + comp_options = { + Aircraft.Engine.NUM_ENGINES: options.get_val(Aircraft.Engine.NUM_ENGINES), + } + + prob.model.add_subsystem('nacelle_mass', NacelleMass(**comp_options), + promotes=['*']) + prob.setup(force_alloc_complex=True) + prob.set_val(Aircraft.Nacelle.AVG_DIAMETER, np.array([5.0, 3.0, 8.0]), units='ft') prob.set_val(Aircraft.Nacelle.AVG_LENGTH, diff --git a/aviary/subsystems/mass/flops_based/test/test_paint.py b/aviary/subsystems/mass/flops_based/test/test_paint.py index bb434b136..046c4e33e 100644 --- a/aviary/subsystems/mass/flops_based/test/test_paint.py +++ b/aviary/subsystems/mass/flops_based/test/test_paint.py @@ -7,7 +7,6 @@ from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, - get_flops_inputs, print_case) from aviary.variable_info.variables import Aircraft @@ -24,7 +23,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "paint", - PaintMass(aviary_options=get_flops_inputs(case_name)), + PaintMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_passenger_service.py b/aviary/subsystems/mass/flops_based/test/test_passenger_service.py index 448eb8532..31cc6e115 100644 --- a/aviary/subsystems/mass/flops_based/test/test_passenger_service.py +++ b/aviary/subsystems/mass/flops_based/test/test_passenger_service.py @@ -10,7 +10,7 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft, Mission @@ -28,11 +28,13 @@ def test_case(self, case_name): prob.model.add_subsystem( 'passenger_service_weight', - PassengerServiceMass(aviary_options=get_flops_inputs(case_name)), + PassengerServiceMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -65,10 +67,13 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( 'passenger_service_weight', - PassengerServiceMass(aviary_options=get_flops_inputs("N3CC")), + PassengerServiceMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Mission.Design.RANGE, 3500.0, 'nmi') @@ -89,11 +94,13 @@ def test_case(self, case_name): prob.model.add_subsystem( 'alternate_passenger_service_weight', - AltPassengerServiceMass(aviary_options=get_flops_inputs(case_name)), + AltPassengerServiceMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -124,10 +131,13 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( 'alternate_passenger_service_weight', - AltPassengerServiceMass(aviary_options=get_flops_inputs("N3CC")), + AltPassengerServiceMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) partial_data = prob.check_partials(out_stream=None, method="cs") diff --git a/aviary/subsystems/mass/flops_based/test/test_starter.py b/aviary/subsystems/mass/flops_based/test/test_starter.py index 426afa6bb..a8577c19d 100644 --- a/aviary/subsystems/mass/flops_based/test/test_starter.py +++ b/aviary/subsystems/mass/flops_based/test/test_starter.py @@ -25,10 +25,17 @@ def test_case_1(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES), + Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + } + prob.model.add_subsystem( "starter_test", - TransportStarterMass(aviary_options=get_flops_inputs( - case_name, preprocess=True)), + TransportStarterMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -45,14 +52,15 @@ def test_case_2(self): # test with more than 4 engines prob = self.prob - aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([5])) - aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 5) - aviary_options.set_val(Mission.Constraints.MAX_MACH, 0.785) + options = { + Aircraft.Engine.NUM_ENGINES: np.array([5]), + Aircraft.Propulsion.TOTAL_NUM_ENGINES: 5, + Mission.Constraints.MAX_MACH: 0.785, + } prob.model.add_subsystem( "starter_test", - TransportStarterMass(aviary_options=aviary_options), + TransportStarterMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -90,13 +98,16 @@ def tearDown(self): def test_case_2(self): prob = om.Problem() - aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([5])) - aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 5) - aviary_options.set_val(Mission.Constraints.MAX_MACH, 0.785) + + options = { + Aircraft.Engine.NUM_ENGINES: np.array([5]), + Aircraft.Propulsion.TOTAL_NUM_ENGINES: 5, + Mission.Constraints.MAX_MACH: 0.785, + } + prob.model.add_subsystem( "starter_test", - TransportStarterMass(aviary_options=aviary_options), + TransportStarterMass(**options), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_surface_controls.py b/aviary/subsystems/mass/flops_based/test/test_surface_controls.py index 0e96f7dc3..961f46502 100644 --- a/aviary/subsystems/mass/flops_based/test/test_surface_controls.py +++ b/aviary/subsystems/mass/flops_based/test/test_surface_controls.py @@ -10,7 +10,7 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft, Mission @@ -28,10 +28,12 @@ def test_case(self, case_name): prob.model.add_subsystem( "surf_ctrl", - SurfaceControlMass(aviary_options=get_flops_inputs(case_name)), + SurfaceControlMass(), promotes=['*'] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -69,9 +71,12 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "surf_ctrl", - SurfaceControlMass(aviary_options=get_flops_inputs("N3CC")), + SurfaceControlMass(), promotes=['*'] ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Mission.Design.GROSS_MASS, 130000, 'lbm') prob.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO, 1, 'unitless') @@ -93,10 +98,12 @@ def test_case(self, case_name): prob.model.add_subsystem( "surf_ctrl", - AltSurfaceControlMass(aviary_options=get_flops_inputs(case_name)), + AltSurfaceControlMass(), promotes=['*'] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -133,9 +140,12 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "surf_ctrl", - AltSurfaceControlMass(aviary_options=get_flops_inputs("N3CC")), + AltSurfaceControlMass(), promotes=['*'] ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.Wing.AREA, 1000, 'ft**2') prob.set_val(Aircraft.HorizontalTail.WETTED_AREA, 100, 'ft**2') diff --git a/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py b/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py index e77408cf6..aa09a187a 100644 --- a/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py +++ b/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py @@ -28,10 +28,15 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + } + prob.model.add_subsystem( "thrust_rev", - ThrustReverserMass(aviary_options=get_flops_inputs( - case_name, preprocess=True)), + ThrustReverserMass(**options), promotes=['*'] ) @@ -63,8 +68,12 @@ def test_case_multiengine(self): preprocess_propulsion(aviary_options, [engineModel1, engineModel2, engineModel3]) - prob.model.add_subsystem('thrust_reverser_mass', ThrustReverserMass( - aviary_options=aviary_options), promotes=['*']) + options = { + Aircraft.Engine.NUM_ENGINES: aviary_options.get_val(Aircraft.Engine.NUM_ENGINES), + } + + prob.model.add_subsystem('thrust_reverser_mass', ThrustReverserMass(**options), + promotes=['*']) prob.setup(force_alloc_complex=True) @@ -110,10 +119,16 @@ def tearDown(self): def test_case(self): prob = om.Problem() + + inputs = get_flops_inputs("N3CC", preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + } + prob.model.add_subsystem( "thrust_rev", - ThrustReverserMass(aviary_options=get_flops_inputs( - "N3CC", preprocess=True)), + ThrustReverserMass(**options), promotes=['*'] ) prob.setup(check=False, force_alloc_complex=True) diff --git a/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py b/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py index f479b7488..85f79aaf2 100644 --- a/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py +++ b/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py @@ -10,7 +10,7 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft @@ -28,15 +28,16 @@ def setUp(self): def test_case(self, case_name): prob = self.prob - flops_inputs = get_flops_inputs(case_name, preprocess=True) prob.model.add_subsystem( 'unusable_fuel', - TransportUnusableFuelMass(aviary_options=flops_inputs), + TransportUnusableFuelMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -72,13 +73,16 @@ def tearDown(self): def test_case(self): prob = om.Problem() - flops_inputs = get_flops_inputs("N3CC", preprocess=True) + prob.model.add_subsystem( 'unusable_fuel', - TransportUnusableFuelMass(aviary_options=flops_inputs), + TransportUnusableFuelMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.Fuel.TOTAL_CAPACITY, 30000.0, 'lbm') prob.set_val(Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, 40000.0, 'lbf') @@ -104,7 +108,7 @@ def test_case(self, case_name): prob.model.add_subsystem( 'unusable_fuel', - AltUnusableFuelMass(aviary_options=get_flops_inputs(case_name)), + AltUnusableFuelMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -141,7 +145,7 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( 'unusable_fuel', - AltUnusableFuelMass(aviary_options=get_flops_inputs("N3CC")), + AltUnusableFuelMass(), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_vertical_tail.py b/aviary/subsystems/mass/flops_based/test/test_vertical_tail.py index fc9801613..9df1f1748 100644 --- a/aviary/subsystems/mass/flops_based/test/test_vertical_tail.py +++ b/aviary/subsystems/mass/flops_based/test/test_vertical_tail.py @@ -10,7 +10,7 @@ from aviary.validation_cases.validation_tests import (Version, flops_validation_test, get_flops_case_names, - get_flops_inputs, + get_flops_options, print_case) from aviary.variable_info.variables import Aircraft, Mission @@ -28,11 +28,13 @@ def test_case(self, case_name): prob.model.add_subsystem( "vertical_tail", - VerticalTailMass(aviary_options=get_flops_inputs(case_name)), + VerticalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + prob.setup(check=False, force_alloc_complex=True) flops_validation_test( @@ -66,10 +68,13 @@ def test_case(self): prob = om.Problem() prob.model.add_subsystem( "vertical_tail", - VerticalTailMass(aviary_options=get_flops_inputs("N3CC")), + VerticalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + prob.model_options['*'] = get_flops_options("N3CC", preprocess=True) + prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.VerticalTail.AREA, 100, 'ft**2') prob.set_val(Mission.Design.GROSS_MASS, 1000.0, 'lbm') @@ -91,7 +96,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "vertical_tail", - AltVerticalTailMass(aviary_options=get_flops_inputs(case_name)), + AltVerticalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_wing_common.py b/aviary/subsystems/mass/flops_based/test/test_wing_common.py index 69134fa47..5652de62c 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_common.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_common.py @@ -6,7 +6,6 @@ from aviary.subsystems.mass.flops_based.wing_common import ( WingBendingMass, WingMiscMass, WingShearControlMass) -from aviary.variable_info.options import get_option_defaults from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import (flops_validation_test, get_flops_case_names, @@ -141,9 +140,14 @@ def test_case(self): class WingBendingMassTest(unittest.TestCase): def setUp(self): prob = self.prob = om.Problem() + + opts = { + Aircraft.Fuselage.NUM_FUSELAGES: 1, + } + prob.model.add_subsystem( "wing", - WingBendingMass(aviary_options=get_option_defaults()), + WingBendingMass(**opts), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -159,24 +163,27 @@ def test_case(self, case_name): flops_validation_test( prob, case_name, - input_keys=[Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, - Aircraft.Wing.BENDING_FACTOR, - Aircraft.Wing.BENDING_MASS_SCALER, - Aircraft.Wing.COMPOSITE_FRACTION, - Aircraft.Wing.ENG_POD_INERTIA_FACTOR, - Mission.Design.GROSS_MASS, - Aircraft.Wing.LOAD_FRACTION, - Aircraft.Wing.MISC_MASS, - Aircraft.Wing.MISC_MASS_SCALER, - Aircraft.Wing.SHEAR_CONTROL_MASS, - Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER, - Aircraft.Wing.SPAN, - Aircraft.Wing.SWEEP, - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, - Aircraft.Wing.VAR_SWEEP_MASS_PENALTY], - output_keys=Aircraft.Wing.BENDING_MASS, + input_keys=[ + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, + Aircraft.Wing.BENDING_MATERIAL_FACTOR, + Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, + Aircraft.Wing.COMPOSITE_FRACTION, + Aircraft.Wing.ENG_POD_INERTIA_FACTOR, + Mission.Design.GROSS_MASS, + Aircraft.Wing.LOAD_FRACTION, + Aircraft.Wing.MISC_MASS, + Aircraft.Wing.MISC_MASS_SCALER, + Aircraft.Wing.SHEAR_CONTROL_MASS, + Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER, + Aircraft.Wing.SPAN, + Aircraft.Wing.SWEEP, + Aircraft.Wing.ULTIMATE_LOAD_FACTOR, + Aircraft.Wing.VAR_SWEEP_MASS_PENALTY, + ], + output_keys=Aircraft.Wing.BENDING_MATERIAL_MASS, atol=1e-11, - rtol=1e-11) + rtol=1e-11, + ) def test_IO(self): assert_match_varnames(self.prob.model) @@ -198,15 +205,16 @@ def tearDown(self): def test_case(self): prob = om.Problem() + prob.model.add_subsystem( "wing", - WingBendingMass(aviary_options=get_option_defaults()), + WingBendingMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, 0.333, 'unitless') - prob.set_val(Aircraft.Wing.BENDING_FACTOR, 10, 'unitless') + prob.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 10, 'unitless') prob.set_val(Aircraft.Wing.COMPOSITE_FRACTION, 0.333, 'unitless') prob.set_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 1, 'unitless') prob.set_val(Mission.Design.GROSS_MASS, 100000, 'lbm') diff --git a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py index 075fd3261..a7f21d840 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -25,16 +25,30 @@ def setUp(self): self.prob = om.Problem() # Skip model that doesn't use detailed wing. - @parameterized.expand(get_flops_case_names(omit=['LargeSingleAisle2FLOPS', 'LargeSingleAisle2FLOPSalt']), - name_func=print_case) + @parameterized.expand( + get_flops_case_names( + omit=[ + 'LargeSingleAisle2FLOPS', + 'LargeSingleAisle2FLOPSalt']), + name_func=print_case) def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + Aircraft.Engine.NUM_WING_ENGINES: inputs.get_val(Aircraft.Engine.NUM_WING_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + Aircraft.Wing.INPUT_STATION_DIST: inputs.get_val(Aircraft.Wing.INPUT_STATION_DIST), + Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL: inputs.get_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL), + Aircraft.Wing.NUM_INTEGRATION_STATIONS: inputs.get_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS), + } + self.prob.model.add_subsystem( "wing", - DetailedWingBendingFact( - aviary_options=get_flops_inputs(case_name, preprocess=True)), + DetailedWingBendingFact(**options), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -43,23 +57,28 @@ def test_case(self, case_name): flops_validation_test( prob, case_name, - input_keys=[Aircraft.Wing.LOAD_PATH_SWEEP_DIST, - Aircraft.Wing.THICKNESS_TO_CHORD_DIST, - Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, - Mission.Design.GROSS_MASS, - Aircraft.Engine.POD_MASS, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.ASPECT_RATIO_REF, - Aircraft.Wing.STRUT_BRACING_FACTOR, - Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.Wing.THICKNESS_TO_CHORD, - Aircraft.Wing.THICKNESS_TO_CHORD_REF], - output_keys=[Aircraft.Wing.BENDING_FACTOR, - Aircraft.Wing.ENG_POD_INERTIA_FACTOR], + input_keys=[ + Aircraft.Wing.LOAD_PATH_SWEEP_DIST, + Aircraft.Wing.THICKNESS_TO_CHORD_DIST, + Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, + Mission.Design.GROSS_MASS, + Aircraft.Engine.POD_MASS, + Aircraft.Wing.ASPECT_RATIO, + Aircraft.Wing.ASPECT_RATIO_REF, + Aircraft.Wing.STRUT_BRACING_FACTOR, + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, + Aircraft.Engine.WING_LOCATIONS, + Aircraft.Wing.THICKNESS_TO_CHORD, + Aircraft.Wing.THICKNESS_TO_CHORD_REF, + ], + output_keys=[ + Aircraft.Wing.BENDING_MATERIAL_FACTOR, + Aircraft.Wing.ENG_POD_INERTIA_FACTOR, + ], method='fd', atol=1e-3, - rtol=1e-5) + rtol=1e-5, + ) def test_case_multiengine(self): prob = self.prob @@ -79,8 +98,17 @@ def test_case_multiengine(self): preprocess_propulsion(aviary_options, [engineModel1, engineModel2, engineModel3]) - prob.model.add_subsystem('detailed_wing', DetailedWingBendingFact( - aviary_options=aviary_options), promotes=['*']) + options = { + Aircraft.Engine.NUM_ENGINES: aviary_options.get_val(Aircraft.Engine.NUM_ENGINES), + Aircraft.Engine.NUM_WING_ENGINES: aviary_options.get_val(Aircraft.Engine.NUM_WING_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + Aircraft.Wing.INPUT_STATION_DIST: aviary_options.get_val(Aircraft.Wing.INPUT_STATION_DIST), + Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL: aviary_options.get_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL), + Aircraft.Wing.NUM_INTEGRATION_STATIONS: aviary_options.get_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS), + } + + prob.model.add_subsystem('detailed_wing', DetailedWingBendingFact(**options), + promotes=['*']) prob.setup(force_alloc_complex=True) @@ -110,20 +138,165 @@ def test_case_multiengine(self): prob.run_model() - bending_factor = prob.get_val(Aircraft.Wing.BENDING_FACTOR) + BENDING_MATERIAL_FACTOR = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) pod_inertia = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) - # manual computation of expected thrust reverser mass - bending_factor_expected = 11.59165669761 + BENDING_MATERIAL_FACTOR_expected = 11.59165669761 # 0.9600334354133278 if the factors are additive pod_inertia_expected = 0.9604608395586276 - assert_near_equal(bending_factor, bending_factor_expected, tolerance=1e-10) + assert_near_equal( + BENDING_MATERIAL_FACTOR, BENDING_MATERIAL_FACTOR_expected, tolerance=1e-10 + ) assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-10) partial_data = prob.check_partials( - out_stream=None, compact_print=True, show_only_incorrect=True, form='central', method="fd") + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method="fd") assert_check_partials(partial_data, atol=1e-5, rtol=1e-5) + def test_case_fuselage_engines(self): + prob = self.prob + + aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') + + engine_options = AviaryValues() + engine_options.set_val(Settings.VERBOSITY, 0) + engine_options.set_val(Aircraft.Engine.DATA_FILE, + 'models/engines/turbofan_28k.deck') + engine_options.set_val(Aircraft.Engine.NUM_ENGINES, 2) + engine_options.set_val(Aircraft.Engine.NUM_WING_ENGINES, 0) + engine_options.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 2) + engineModel = EngineDeck(options=engine_options) + + preprocess_propulsion(aviary_options, [engineModel]) + + options = { + Aircraft.Engine.NUM_ENGINES: aviary_options.get_val(Aircraft.Engine.NUM_ENGINES), + Aircraft.Engine.NUM_WING_ENGINES: aviary_options.get_val(Aircraft.Engine.NUM_WING_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + Aircraft.Wing.INPUT_STATION_DIST: aviary_options.get_val(Aircraft.Wing.INPUT_STATION_DIST), + Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL: aviary_options.get_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL), + Aircraft.Wing.NUM_INTEGRATION_STATIONS: aviary_options.get_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS), + } + + prob.model.add_subsystem( + 'detailed_wing', + DetailedWingBendingFact(**options), + promotes=['*'], + ) + + prob.setup(force_alloc_complex=True) + + input_keys = [Aircraft.Wing.LOAD_PATH_SWEEP_DIST, + Aircraft.Wing.THICKNESS_TO_CHORD_DIST, + Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, + Mission.Design.GROSS_MASS, + Aircraft.Wing.ASPECT_RATIO, + Aircraft.Wing.ASPECT_RATIO_REF, + Aircraft.Wing.STRUT_BRACING_FACTOR, + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, + Aircraft.Wing.THICKNESS_TO_CHORD, + Aircraft.Wing.THICKNESS_TO_CHORD_REF] + + for key in input_keys: + val, units = aviary_options.get_item(key) + prob.set_val(key, val, units) + + prob.set_val(Aircraft.Engine.POD_MASS, np.array([0]), units='lbm') + + wing_location = np.zeros(0) + wing_location = np.append(wing_location, [0.0]) + + prob.set_val(Aircraft.Engine.WING_LOCATIONS, wing_location) + + prob.run_model() + + BENDING_MATERIAL_FACTOR = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) + pod_inertia = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) + + BENDING_MATERIAL_FACTOR_expected = 11.59165669761 + pod_inertia_expected = 0.84 + assert_near_equal( + BENDING_MATERIAL_FACTOR, BENDING_MATERIAL_FACTOR_expected, tolerance=1e-10 + ) + assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-10) + + def test_case_fuselage_multiengine(self): + prob = self.prob + + aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') + + engine_options = AviaryValues() + engine_options.set_val(Aircraft.Engine.DATA_FILE, + 'models/engines/turbofan_28k.deck') + engine_options.set_val(Aircraft.Engine.NUM_ENGINES, 2) + engine_options.set_val(Aircraft.Engine.NUM_WING_ENGINES, 2) + engine_options.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 0) + engineModel1 = EngineDeck(options=engine_options) + + engine_options.set_val(Aircraft.Engine.DATA_FILE, + 'models/engines/turbofan_22k.deck') + engine_options.set_val(Aircraft.Engine.NUM_ENGINES, 2) + engine_options.set_val(Aircraft.Engine.NUM_WING_ENGINES, 0) + engine_options.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 2) + engineModel2 = EngineDeck(options=engine_options) + + preprocess_propulsion(aviary_options, [engineModel1, engineModel2]) + + options = { + Aircraft.Engine.NUM_ENGINES: aviary_options.get_val(Aircraft.Engine.NUM_ENGINES), + Aircraft.Engine.NUM_WING_ENGINES: aviary_options.get_val(Aircraft.Engine.NUM_WING_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + Aircraft.Wing.INPUT_STATION_DIST: aviary_options.get_val(Aircraft.Wing.INPUT_STATION_DIST), + Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL: aviary_options.get_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL), + Aircraft.Wing.NUM_INTEGRATION_STATIONS: aviary_options.get_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS), + } + + prob.model.add_subsystem( + 'detailed_wing', + DetailedWingBendingFact(**options), + promotes=['*'], + ) + + prob.setup(force_alloc_complex=True) + + input_keys = [Aircraft.Wing.LOAD_PATH_SWEEP_DIST, + Aircraft.Wing.THICKNESS_TO_CHORD_DIST, + Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, + Mission.Design.GROSS_MASS, + Aircraft.Wing.ASPECT_RATIO, + Aircraft.Wing.ASPECT_RATIO_REF, + Aircraft.Wing.STRUT_BRACING_FACTOR, + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, + Aircraft.Wing.THICKNESS_TO_CHORD, + Aircraft.Wing.THICKNESS_TO_CHORD_REF] + + for key in input_keys: + val, units = aviary_options.get_item(key) + prob.set_val(key, val, units) + + prob.set_val(Aircraft.Engine.POD_MASS, np.array([1130, 0]), units='lbm') + + wing_locations = np.zeros(0) + wing_locations = np.append(wing_locations, [0.5]) + + prob.set_val(Aircraft.Engine.WING_LOCATIONS, wing_locations) + + prob.run_model() + + BENDING_MATERIAL_FACTOR = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) + pod_inertia = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) + + BENDING_MATERIAL_FACTOR_expected = 11.59165669761 + pod_inertia_expected = 0.84 + assert_near_equal( + BENDING_MATERIAL_FACTOR, BENDING_MATERIAL_FACTOR_expected, tolerance=1e-10 + ) + assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-10) + def test_extreme_engine_loc(self): aviary_options = get_flops_inputs('LargeSingleAisle1FLOPS') @@ -140,9 +313,18 @@ def test_extreme_engine_loc(self): preprocess_propulsion(aviary_options, [engineModel]) + options = { + Aircraft.Engine.NUM_ENGINES: aviary_options.get_val(Aircraft.Engine.NUM_ENGINES), + Aircraft.Engine.NUM_WING_ENGINES: aviary_options.get_val(Aircraft.Engine.NUM_WING_ENGINES), + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + Aircraft.Wing.INPUT_STATION_DIST: aviary_options.get_val(Aircraft.Wing.INPUT_STATION_DIST), + Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL: aviary_options.get_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL), + Aircraft.Wing.NUM_INTEGRATION_STATIONS: aviary_options.get_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS), + } + self.prob.model.add_subsystem( "wing", - DetailedWingBendingFact(aviary_options=aviary_options), + DetailedWingBendingFact(**options), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -188,4 +370,4 @@ def test_IO(self): # test = DetailedWingBendingTest() # test.setUp() # test.test_case(case_name='LargeSingleAisle1FLOPS') - # test.test_extreme_engine_loc() + # test.test_case_multiengine() diff --git a/aviary/subsystems/mass/flops_based/test/test_wing_simple.py b/aviary/subsystems/mass/flops_based/test/test_wing_simple.py index da5d4148b..cdb3fed54 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_simple.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_simple.py @@ -23,10 +23,15 @@ def test_case(self, case_name): prob = self.prob + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES: inputs.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES), + } + prob.model.add_subsystem( "wing", - SimpleWingBendingFact(aviary_options=get_flops_inputs( - case_name, preprocess=True)), + SimpleWingBendingFact(**options), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -36,18 +41,23 @@ def test_case(self, case_name): flops_validation_test( prob, case_name, - input_keys=[Aircraft.Wing.AREA, - Aircraft.Wing.SPAN, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD, - Aircraft.Wing.STRUT_BRACING_FACTOR, - Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP], - output_keys=[Aircraft.Wing.BENDING_FACTOR, - Aircraft.Wing.ENG_POD_INERTIA_FACTOR], + input_keys=[ + Aircraft.Wing.AREA, + Aircraft.Wing.SPAN, + Aircraft.Wing.TAPER_RATIO, + Aircraft.Wing.THICKNESS_TO_CHORD, + Aircraft.Wing.STRUT_BRACING_FACTOR, + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, + Aircraft.Wing.ASPECT_RATIO, + Aircraft.Wing.SWEEP, + ], + output_keys=[ + Aircraft.Wing.BENDING_MATERIAL_FACTOR, + Aircraft.Wing.ENG_POD_INERTIA_FACTOR, + ], atol=1e-11, - rtol=1e-11) + rtol=1e-11, + ) def test_IO(self): assert_match_varnames(self.prob.model) diff --git a/aviary/subsystems/mass/flops_based/thrust_reverser.py b/aviary/subsystems/mass/flops_based/thrust_reverser.py index 028c2969c..6821f182b 100644 --- a/aviary/subsystems/mass/flops_based/thrust_reverser.py +++ b/aviary/subsystems/mass/flops_based/thrust_reverser.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import nacelle_count_factor -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -23,13 +22,10 @@ class ThrustReverserMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input( self, Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, val=np.zeros(num_engine_type)) @@ -43,8 +39,7 @@ def setup(self): def setup_partials(self): # derivatives w.r.t vectorized engine inputs have known sparsity pattern - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) shape = np.arange(num_engine_type) self.declare_partials(Aircraft.Engine.THRUST_REVERSERS_MASS, @@ -64,8 +59,7 @@ def setup_partials(self): val=1.0) def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - num_eng = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + num_eng = self.options[Aircraft.Engine.NUM_ENGINES] scaler = inputs[Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER] max_thrust = inputs[Aircraft.Engine.SCALED_SLS_THRUST] nac_count = nacelle_count_factor(num_eng) @@ -76,8 +70,7 @@ def compute(self, inputs, outputs): thrust_reverser_mass) def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_eng = aviary_options.get_val(Aircraft.Engine.NUM_ENGINES) + num_eng = self.options[Aircraft.Engine.NUM_ENGINES] scaler = inputs[Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER] max_thrust = inputs[Aircraft.Engine.SCALED_SLS_THRUST] nac_count = nacelle_count_factor(num_eng) diff --git a/aviary/subsystems/mass/flops_based/unusable_fuel.py b/aviary/subsystems/mass/flops_based/unusable_fuel.py index 6b994718a..8913549ee 100644 --- a/aviary/subsystems/mass/flops_based/unusable_fuel.py +++ b/aviary/subsystems/mass/flops_based/unusable_fuel.py @@ -3,8 +3,7 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import ( distributed_engine_count_factor, distributed_thrust_factor) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -21,9 +20,8 @@ class TransportUnusableFuelMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Fuel.NUM_TANKS) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) def setup(self): add_aviary_input( @@ -55,12 +53,11 @@ def setup_partials(self): Aircraft.Fuel.TOTAL_CAPACITY, Aircraft.Fuel.DENSITY_RATIO]) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - aviary_options: AviaryValues = self.options['aviary_options'] - tank_count = aviary_options.get_val(Aircraft.Fuel.NUM_TANKS) + tank_count = self.options[Aircraft.Fuel.NUM_TANKS] scaler = inputs[Aircraft.Fuel.UNUSABLE_FUEL_MASS_SCALER] density_ratio = inputs[Aircraft.Fuel.DENSITY_RATIO] total_capacity = inputs[Aircraft.Fuel.TOTAL_CAPACITY] - num_eng = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_eng_fact = distributed_engine_count_factor(num_eng) max_sls_thrust = inputs[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST] thrust_factor = distributed_thrust_factor(max_sls_thrust, num_eng) @@ -74,12 +71,11 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): total_capacity**0.28) * density_ratio) * scaler / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - tank_count = aviary_options.get_val(Aircraft.Fuel.NUM_TANKS) + tank_count = self.options[Aircraft.Fuel.NUM_TANKS] scaler = inputs[Aircraft.Fuel.UNUSABLE_FUEL_MASS_SCALER] density_ratio = inputs[Aircraft.Fuel.DENSITY_RATIO] total_capacity = inputs[Aircraft.Fuel.TOTAL_CAPACITY] - num_eng = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_eng_fact = distributed_engine_count_factor(num_eng) max_sls_thrust = inputs[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST] thrust_factor = distributed_thrust_factor(max_sls_thrust, num_eng) @@ -120,11 +116,6 @@ class AltUnusableFuelMass(om.ExplicitComponent): to output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.Fuel.UNUSABLE_FUEL_MASS_SCALER, val=1.0) diff --git a/aviary/subsystems/mass/flops_based/vertical_tail.py b/aviary/subsystems/mass/flops_based/vertical_tail.py index 68df78b73..0f95fb3da 100644 --- a/aviary/subsystems/mass/flops_based/vertical_tail.py +++ b/aviary/subsystems/mass/flops_based/vertical_tail.py @@ -1,8 +1,7 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -13,9 +12,7 @@ class VerticalTailMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.VerticalTail.NUM_TAILS) def setup(self): add_aviary_input(self, Aircraft.VerticalTail.AREA, val=0.0) @@ -32,8 +29,7 @@ def setup_partials(self): self.declare_partials("*", "*") def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - num_tails = aviary_options.get_val(Aircraft.VerticalTail.NUM_TAILS) + num_tails = self.options[Aircraft.VerticalTail.NUM_TAILS] area = inputs[Aircraft.VerticalTail.AREA] taper_ratio = inputs[Aircraft.VerticalTail.TAPER_RATIO] @@ -45,8 +41,7 @@ def compute(self, inputs, outputs): num_tails ** 0.7 / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_tails = aviary_options.get_val(Aircraft.VerticalTail.NUM_TAILS) + num_tails = self.options[Aircraft.VerticalTail.NUM_TAILS] area = inputs[Aircraft.VerticalTail.AREA] gross_weight = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM @@ -81,11 +76,6 @@ class AltVerticalTailMass(om.ExplicitComponent): output mass instead of weight. ''' - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): add_aviary_input(self, Aircraft.VerticalTail.AREA, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/wing_common.py b/aviary/subsystems/mass/flops_based/wing_common.py index e810dad45..a932a4e49 100644 --- a/aviary/subsystems/mass/flops_based/wing_common.py +++ b/aviary/subsystems/mass/flops_based/wing_common.py @@ -2,8 +2,7 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -14,15 +13,13 @@ class WingBendingMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Fuselage.NUM_FUSELAGES) def setup(self): add_aviary_input(self, Mission.Design.GROSS_MASS, val=0.0) add_aviary_input(self, Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, val=0.0) - add_aviary_input(self, Aircraft.Wing.BENDING_FACTOR, val=0.0) - add_aviary_input(self, Aircraft.Wing.BENDING_MASS_SCALER, val=1.0) + add_aviary_input(self, Aircraft.Wing.BENDING_MATERIAL_FACTOR, val=0.0) + add_aviary_input(self, Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, val=1.0) add_aviary_input(self, Aircraft.Wing.COMPOSITE_FRACTION, val=0.0) add_aviary_input(self, Aircraft.Wing.ENG_POD_INERTIA_FACTOR, val=0.0) add_aviary_input(self, Aircraft.Wing.LOAD_FRACTION, val=0.0) @@ -35,7 +32,7 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.ULTIMATE_LOAD_FACTOR, val=3.75) add_aviary_input(self, Aircraft.Wing.VAR_SWEEP_MASS_PENALTY, val=0.0) - add_aviary_output(self, Aircraft.Wing.BENDING_MASS, val=0.0) + add_aviary_output(self, Aircraft.Wing.BENDING_MATERIAL_MASS, val=0.0) self.A1 = 8.80 self.A2 = 6.25 @@ -44,7 +41,7 @@ def setup_partials(self): self.declare_partials("*", "*") def compute(self, inputs, outputs): - bt = inputs[Aircraft.Wing.BENDING_FACTOR] + bt = inputs[Aircraft.Wing.BENDING_MATERIAL_FACTOR] ulf = inputs[Aircraft.Wing.ULTIMATE_LOAD_FACTOR] span = inputs[Aircraft.Wing.SPAN] comp_frac = inputs[Aircraft.Wing.COMPOSITE_FRACTION] @@ -54,10 +51,9 @@ def compute(self, inputs, outputs): sweep = inputs[Aircraft.Wing.SWEEP] gross_weight = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM CAYE = inputs[Aircraft.Wing.ENG_POD_INERTIA_FACTOR] - scaler = inputs[Aircraft.Wing.BENDING_MASS_SCALER] + scaler = inputs[Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER] - num_fuse = self.options['aviary_options'].get_val( - Aircraft.Fuselage.NUM_FUSELAGES) + num_fuse = self.options[Aircraft.Fuselage.NUM_FUSELAGES] # Note: Calculation requires weights prior to being scaled, so we need to divide # by the scale factor. @@ -72,12 +68,14 @@ def compute(self, inputs, outputs): W1NIR = self.A1 * bt * (1.0 + (self.A2 / span)**0.5) * ulf * span * \ (1.0 - 0.4 * comp_frac) * (1.0 - 0.1 * faert) * cayf * vfact * pctl * 1.0e-6 - outputs[Aircraft.Wing.BENDING_MASS] = ( - (gross_weight * CAYE * W1NIR + W2 + W3) / (1.0 + W1NIR) - W2 - W3) \ - * scaler / GRAV_ENGLISH_LBM + outputs[Aircraft.Wing.BENDING_MATERIAL_MASS] = ( + ((gross_weight * CAYE * W1NIR + W2 + W3) / (1.0 + W1NIR) - W2 - W3) + * scaler + / GRAV_ENGLISH_LBM + ) def compute_partials(self, inputs, J): - bt = inputs[Aircraft.Wing.BENDING_FACTOR] + bt = inputs[Aircraft.Wing.BENDING_MATERIAL_FACTOR] ulf = inputs[Aircraft.Wing.ULTIMATE_LOAD_FACTOR] span = inputs[Aircraft.Wing.SPAN] comp_frac = inputs[Aircraft.Wing.COMPOSITE_FRACTION] @@ -91,10 +89,9 @@ def compute_partials(self, inputs, J): W3 = inputs[Aircraft.Wing.MISC_MASS] * GRAV_ENGLISH_LBM W2scale = inputs[Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER] W3scale = inputs[Aircraft.Wing.MISC_MASS_SCALER] - scaler = inputs[Aircraft.Wing.BENDING_MASS_SCALER] + scaler = inputs[Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER] - num_fuse = self.options['aviary_options'].get_val( - Aircraft.Fuselage.NUM_FUSELAGES) + num_fuse = self.options[Aircraft.Fuselage.NUM_FUSELAGES] deg2rad = np.pi / 180. term = 0.96 / np.cos(deg2rad * sweep) @@ -136,50 +133,69 @@ def compute_partials(self, inputs, J): fact2 = 1.0 / (1.0 + W1NIR) dbend_w1nir = scaler * (gross_weight * CAYE * fact2 - fact1 * fact2**2) - J[Aircraft.Wing.BENDING_MASS, Mission.Design.GROSS_MASS] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Mission.Design.GROSS_MASS] = ( CAYE * W1NIR * fact2 * scaler + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.ENG_POD_INERTIA_FACTOR] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.ENG_POD_INERTIA_FACTOR] = ( gross_weight * W1NIR * fact2 * scaler / GRAV_ENGLISH_LBM + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.SHEAR_CONTROL_MASS] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.SHEAR_CONTROL_MASS] = ( (fact2 - 1.0) * scaler / W2scale + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER] = \ - -(fact2 - 1.0) * scaler * W2 / W2scale ** 2 / GRAV_ENGLISH_LBM + J[ + Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER + ] = (-(fact2 - 1.0) * scaler * W2 / W2scale**2 / GRAV_ENGLISH_LBM) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.MISC_MASS] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.MISC_MASS] = ( (fact2 - 1.0) * scaler / W3scale + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.MISC_MASS_SCALER] = \ - -(fact2 - 1.0) * scaler * W3 / W3scale ** 2 / GRAV_ENGLISH_LBM + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.MISC_MASS_SCALER] = ( + -(fact2 - 1.0) * scaler * W3 / W3scale**2 / GRAV_ENGLISH_LBM + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.BENDING_MASS_SCALER] = \ - (fact1 * fact2 - W2/W2scale - W3/W3scale) / GRAV_ENGLISH_LBM + J[ + Aircraft.Wing.BENDING_MATERIAL_MASS, + Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, + ] = (fact1 * fact2 - W2 / W2scale - W3 / W3scale) / GRAV_ENGLISH_LBM - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.BENDING_FACTOR] = \ - dbend_w1nir * dW1NIR_bt / GRAV_ENGLISH_LBM + J[ + Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.BENDING_MATERIAL_FACTOR + ] = (dbend_w1nir * dW1NIR_bt / GRAV_ENGLISH_LBM) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.ULTIMATE_LOAD_FACTOR] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.ULTIMATE_LOAD_FACTOR] = ( dbend_w1nir * dW1NIR_ulf / GRAV_ENGLISH_LBM + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.LOAD_FRACTION] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.LOAD_FRACTION] = ( dbend_w1nir * dW1NIR_pctl / GRAV_ENGLISH_LBM + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.COMPOSITE_FRACTION] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.COMPOSITE_FRACTION] = ( dbend_w1nir * dW1NIR_compfrac / GRAV_ENGLISH_LBM + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR] = \ + J[ + Aircraft.Wing.BENDING_MATERIAL_MASS, + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, + ] = ( dbend_w1nir * dW1NIR_faert / GRAV_ENGLISH_LBM + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.VAR_SWEEP_MASS_PENALTY] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.VAR_SWEEP_MASS_PENALTY] = ( dbend_w1nir * dW1NIR_varswp / GRAV_ENGLISH_LBM + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.SWEEP] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.SWEEP] = ( dbend_w1nir * dW1NIR_sweep / GRAV_ENGLISH_LBM + ) - J[Aircraft.Wing.BENDING_MASS, Aircraft.Wing.SPAN] = \ + J[Aircraft.Wing.BENDING_MATERIAL_MASS, Aircraft.Wing.SPAN] = ( dbend_w1nir * dW1NIR_span / GRAV_ENGLISH_LBM + ) class WingShearControlMass(om.ExplicitComponent): @@ -189,10 +205,6 @@ class WingShearControlMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - self.options.declare( 'aircraft_type', default='Transport', @@ -270,10 +282,6 @@ class WingMiscMass(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - self.options.declare( 'aircraft_type', default='Transport', @@ -330,13 +338,8 @@ class WingTotalMass(om.ExplicitComponent): Computation of wing mass using FLOPS-based detailed wing mass equations. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - def setup(self): - add_aviary_input(self, Aircraft.Wing.BENDING_MASS, val=0.0) + add_aviary_input(self, Aircraft.Wing.BENDING_MATERIAL_MASS, val=0.0) add_aviary_input(self, Aircraft.Wing.SHEAR_CONTROL_MASS, val=0.0) @@ -352,7 +355,7 @@ def setup_partials(self): self.declare_partials("*", "*") def compute(self, inputs, outputs): - m1 = inputs[Aircraft.Wing.BENDING_MASS] + m1 = inputs[Aircraft.Wing.BENDING_MATERIAL_MASS] m2 = inputs[Aircraft.Wing.SHEAR_CONTROL_MASS] m3 = inputs[Aircraft.Wing.MISC_MASS] m4 = inputs[Aircraft.Wing.BWB_AFTBODY_MASS] @@ -361,13 +364,13 @@ def compute(self, inputs, outputs): outputs[Aircraft.Wing.MASS] = (m1 + m2 + m3 + m4) * m_scaler def compute_partials(self, inputs, J): - m1 = inputs[Aircraft.Wing.BENDING_MASS] + m1 = inputs[Aircraft.Wing.BENDING_MATERIAL_MASS] m2 = inputs[Aircraft.Wing.SHEAR_CONTROL_MASS] m3 = inputs[Aircraft.Wing.MISC_MASS] m4 = inputs[Aircraft.Wing.BWB_AFTBODY_MASS] m_scaler = inputs[Aircraft.Wing.MASS_SCALER] - J[Aircraft.Wing.MASS, Aircraft.Wing.BENDING_MASS] = m_scaler + J[Aircraft.Wing.MASS, Aircraft.Wing.BENDING_MATERIAL_MASS] = m_scaler J[Aircraft.Wing.MASS, Aircraft.Wing.SHEAR_CONTROL_MASS] = m_scaler J[Aircraft.Wing.MASS, Aircraft.Wing.MISC_MASS] = m_scaler J[Aircraft.Wing.MASS, Aircraft.Wing.BWB_AFTBODY_MASS] = m_scaler diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index c6f825bd8..ba7a01c48 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -3,8 +3,7 @@ import openmdao.api as om from openmdao.components.interp_util.interp import InterpND -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -15,17 +14,18 @@ class DetailedWingBendingFact(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Engine.NUM_WING_ENGINES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) + add_aviary_option(self, Aircraft.Wing.INPUT_STATION_DIST) + add_aviary_option(self, Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL) + add_aviary_option(self, Aircraft.Wing.NUM_INTEGRATION_STATIONS) def setup(self): - aviary_options: AviaryValues = self.options['aviary_options'] - input_station_dist = aviary_options.get_val(Aircraft.Wing.INPUT_STATION_DIST) + input_station_dist = self.options[Aircraft.Wing.INPUT_STATION_DIST] num_input_stations = len(input_station_dist) - total_num_wing_engines = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) - num_engine_type = len(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) + total_num_wing_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES] + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) # wing locations are different for each engine type - ragged array! # this "tricks" numpy into allowing a ragged array, with limitations (each index @@ -33,14 +33,23 @@ def setup(self): # wing_location_default = np.empty(num_engine_type, object) # wing_location_default[:] = [np.array([0]*int(num)) for num in num_wing_engines/2] - add_aviary_input(self, Aircraft.Wing.LOAD_PATH_SWEEP_DIST, - val=np.zeros(num_input_stations - 1)) + add_aviary_input( + self, + Aircraft.Wing.LOAD_PATH_SWEEP_DIST, + val=np.zeros(num_input_stations - 1), + ) - add_aviary_input(self, Aircraft.Wing.THICKNESS_TO_CHORD_DIST, - val=np.zeros(num_input_stations)) + add_aviary_input( + self, + Aircraft.Wing.THICKNESS_TO_CHORD_DIST, + val=np.zeros(num_input_stations), + ) - add_aviary_input(self, Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, - val=np.zeros(num_input_stations)) + add_aviary_input( + self, + Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, + val=np.zeros(num_input_stations), + ) add_aviary_input(self, Mission.Design.GROSS_MASS, val=0.0) @@ -54,14 +63,20 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, val=0.0) - add_aviary_input(self, Aircraft.Engine.WING_LOCATIONS, - val=np.zeros(int(total_num_wing_engines/2))) + if total_num_wing_engines > 0: + add_aviary_input( + self, + Aircraft.Engine.WING_LOCATIONS, + val=np.zeros(int(total_num_wing_engines / 2)), + ) + else: + add_aviary_input(self, Aircraft.Engine.WING_LOCATIONS, val=[[0.0]]) add_aviary_input(self, Aircraft.Wing.THICKNESS_TO_CHORD, val=0.0) add_aviary_input(self, Aircraft.Wing.THICKNESS_TO_CHORD_REF, val=0.0) - add_aviary_output(self, Aircraft.Wing.BENDING_FACTOR, val=0.0) + add_aviary_output(self, Aircraft.Wing.BENDING_MATERIAL_FACTOR, val=0.0) add_aviary_output(self, Aircraft.Wing.ENG_POD_INERTIA_FACTOR, val=0.0) @@ -70,12 +85,10 @@ def setup_partials(self): self.declare_partials("*", "*", method='cs') def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - input_station_dist = aviary_options.get_val(Aircraft.Wing.INPUT_STATION_DIST) + input_station_dist = self.options[Aircraft.Wing.INPUT_STATION_DIST] inp_stations = np.array(input_station_dist) - num_integration_stations = \ - aviary_options.get_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS) - num_wing_engines = aviary_options.get_val(Aircraft.Engine.NUM_WING_ENGINES) + num_integration_stations = self.options[Aircraft.Wing.NUM_INTEGRATION_STATIONS] + num_wing_engines = self.options[Aircraft.Engine.NUM_WING_ENGINES] num_engine_type = len(num_wing_engines) # TODO: Support all options for this parameter. @@ -85,8 +98,7 @@ def compute(self, inputs, outputs): # 3.0 : rectangular distribution # 1.0-2.0 : blend of triangular and elliptical # 2.0-3.0 : blend of elliptical and rectangular - load_distribution_factor = \ - aviary_options.get_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL) + load_distribution_factor = self.options[Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL] load_path_sweep = inputs[Aircraft.Wing.LOAD_PATH_SWEEP_DIST] thickness_to_chord = inputs[Aircraft.Wing.THICKNESS_TO_CHORD_DIST] @@ -121,53 +133,77 @@ def compute(self, inputs, outputs): per_section = int(stations_per_section[i]) integration_stations = np.append( integration_stations, - np.linspace(inp_stations[i], val, per_section, endpoint=endpoint)) - sweep_int_stations = np.append(sweep_int_stations, - load_path_sweep[i] * np.ones(per_section)) + np.linspace(inp_stations[i], val, per_section, endpoint=endpoint), + ) + sweep_int_stations = np.append( + sweep_int_stations, load_path_sweep[i] * np.ones(per_section) + ) dy = np.diff(integration_stations) - avg_sweep = np.sum((dy[1:] + 2.0 * integration_stations[1:-1]) * dy[1:] * - sweep_int_stations[1:-1]) + avg_sweep = np.sum( + (dy[1:] + 2.0 * integration_stations[1:-1]) + * dy[1:] + * sweep_int_stations[1:-1] + ) # TODO: add all load_distribution_factor options if load_distribution_factor == 1: load_intensity = 1.0 - integration_stations elif load_distribution_factor == 2: - load_intensity = np.sqrt(1.0 - integration_stations ** 2) + load_intensity = np.sqrt(1.0 - integration_stations**2) elif load_distribution_factor == 3: load_intensity = np.ones(num_integration_stations + 1) else: raise om.AnalysisError( - f'{load_distribution_factor} is not a valid value for {Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL}, it must be "1", "2", or "3".') + f'{load_distribution_factor} is not a valid value for ' + f'{Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL}, it must be "1", "2", or "3".' + ) - chord_interp = InterpND(method='slinear', points=(inp_stations), - x_interp=integration_stations) + chord_interp = InterpND( + method='slinear', points=(inp_stations), x_interp=integration_stations + ) chord_int_stations = chord_interp.evaluate_spline( - chord, compute_derivative=False) + chord, compute_derivative=False + ) if arref > 0.0: # Scale chord_int_stations *= arref / ar - del_load = dy * ( - chord_int_stations[:-1] * (2*load_intensity[:-1] + load_intensity[1:]) + - chord_int_stations[1:] * (2*load_intensity[1:] + load_intensity[:-1])) / 6 + del_load = ( + dy + * ( + chord_int_stations[:-1] * (2 * load_intensity[:-1] + load_intensity[1:]) + + chord_int_stations[1:] + * (2 * load_intensity[1:] + load_intensity[:-1]) + ) + / 6 + ) el = np.sum(del_load) - del_moment = dy**2 * ( - chord_int_stations[:-1] * (load_intensity[:-1]+load_intensity[1:]) + - chord_int_stations[1:] * (3*load_intensity[1:]+load_intensity[:-1])) / 12 + del_moment = ( + dy**2 + * ( + chord_int_stations[:-1] * (load_intensity[:-1] + load_intensity[1:]) + + chord_int_stations[1:] + * (3 * load_intensity[1:] + load_intensity[:-1]) + ) + / 12 + ) load_path_length = np.flip( - np.append(np.zeros(1, chord.dtype), np.cumsum(np.flip(del_load)[:-1]))) - csw = 1. / np.cos(sweep_int_stations[:-1] * np.pi/180.) + np.append(np.zeros(1, chord.dtype), np.cumsum(np.flip(del_load)[:-1])) + ) + csw = 1.0 / np.cos(sweep_int_stations[:-1] * np.pi / 180.0) emi = (del_moment + dy * load_path_length) * csw # em = np.sum(emi) - tc_interp = InterpND(method='slinear', points=(inp_stations), - x_interp=integration_stations) + tc_interp = InterpND( + method='slinear', points=(inp_stations), x_interp=integration_stations + ) tc_int_stations = tc_interp.evaluate_spline( - thickness_to_chord, compute_derivative=False) + thickness_to_chord, compute_derivative=False + ) if tcref > 0.0: tc_int_stations *= tc / tcref @@ -181,15 +217,22 @@ def compute(self, inputs, outputs): btb = 4 * pm / el - sa = np.sin(avg_sweep * np.pi / 180.) + sa = np.sin(avg_sweep * np.pi / 180.0) if ar <= 5.0: caya = 0.0 else: caya = ar - 5.0 - bt = btb / (ar**(0.25*fstrt) * (1.0 + (0.5*faert - 0.16*fstrt) - * sa**2 + 0.03*caya * (1.0-0.5*faert)*sa)) - outputs[Aircraft.Wing.BENDING_FACTOR] = bt + bt = btb / ( + ar ** (0.25 * fstrt) + * ( + 1.0 + + (0.5 * faert - 0.16 * fstrt) * sa**2 + + 0.03 * caya * (1.0 - 0.5 * faert) * sa + ) + ) + + outputs[Aircraft.Wing.BENDING_MATERIAL_FACTOR] = bt inertia_factor = np.zeros(num_engine_type, dtype=chord.dtype) eel = np.zeros(len(dy) + 1, dtype=chord.dtype) @@ -199,25 +242,29 @@ def compute(self, inputs, outputs): # i is the counter for which engine model we are checking for i in range(num_engine_type): # idx2 is the last index for the range of engines of this type - idx2 = idx + int(num_wing_engines[i]/2) + idx2 = idx + int(num_wing_engines[i] / 2) + if num_wing_engines[i] > 0: + # engine locations must be in order from wing root to tip + eng_loc = np.sort(engine_locations[idx:idx2]) - eng_loc = engine_locations[idx:idx2][0] + else: + continue - if eng_loc <= integration_stations[0]: + if eng_loc[0] <= integration_stations[0]: inertia_factor[i] = 1.0 - elif eng_loc >= integration_stations[-1]: + elif eng_loc[0] >= integration_stations[-1]: inertia_factor[i] = 0.84 else: eel[:] = 0.0 - loc = np.where(integration_stations < eng_loc)[0] + # Find all points on integration station before first engine + loc = np.where(integration_stations < eng_loc[0])[0] eel[loc] = 1.0 delme = dy * eel[1:] - delme[loc[-1]] = engine_locations[idx:idx2][0] - \ - integration_stations[loc[-1]] + delme[loc[-1]] = eng_loc[0] - integration_stations[loc[-1]] eem = delme * csw eem = np.cumsum(eem[::-1])[::-1] diff --git a/aviary/subsystems/mass/flops_based/wing_group.py b/aviary/subsystems/mass/flops_based/wing_group.py index 9be1571f3..2cd4fad1d 100644 --- a/aviary/subsystems/mass/flops_based/wing_group.py +++ b/aviary/subsystems/mass/flops_based/wing_group.py @@ -6,7 +6,7 @@ WingBendingMass, WingMiscMass, WingShearControlMass, WingTotalMass) from aviary.subsystems.mass.flops_based.wing_detailed import DetailedWingBendingFact from aviary.subsystems.mass.flops_based.wing_simple import SimpleWingBendingFact -from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft @@ -16,39 +16,42 @@ class WingMassGroup(om.Group): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Wing.INPUT_STATION_DIST) def setup(self): - aviary_options: AviaryValues = self.options['aviary_options'] self.add_subsystem('engine_pod_mass', - EnginePodMass(aviary_options=aviary_options), + EnginePodMass(), promotes_inputs=['*'], promotes_outputs=['*']) - if Aircraft.Wing.INPUT_STATION_DIST in aviary_options: - self.add_subsystem('wing_bending_factor', - DetailedWingBendingFact(aviary_options=aviary_options), - promotes_inputs=['*'], promotes_outputs=['*']) + if self.options[Aircraft.Wing.INPUT_STATION_DIST] is not None: + self.add_subsystem( + 'wing_BENDING_MATERIAL_FACTOR', + DetailedWingBendingFact(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) else: - self.add_subsystem('wing_bending_factor', - SimpleWingBendingFact(aviary_options=aviary_options), - promotes_inputs=['*'], promotes_outputs=['*']) + self.add_subsystem( + 'wing_BENDING_MATERIAL_FACTOR', + SimpleWingBendingFact(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) self.add_subsystem('wing_misc', - WingMiscMass(aviary_options=aviary_options), + WingMiscMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem('wing_shear_control', - WingShearControlMass(aviary_options=aviary_options), + WingShearControlMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem('wing_bending', - WingBendingMass(aviary_options=aviary_options), + WingBendingMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem('wing_total', - WingTotalMass(aviary_options=aviary_options), + WingTotalMass(), promotes_inputs=['*'], promotes_outputs=['*']) diff --git a/aviary/subsystems/mass/flops_based/wing_simple.py b/aviary/subsystems/mass/flops_based/wing_simple.py index 180c8f3de..04808ebdb 100644 --- a/aviary/subsystems/mass/flops_based/wing_simple.py +++ b/aviary/subsystems/mass/flops_based/wing_simple.py @@ -1,8 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -13,9 +12,7 @@ class SimpleWingBendingFact(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) def setup(self): add_aviary_input(self, Aircraft.Wing.AREA, val=0.0) @@ -34,24 +31,27 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.SWEEP, val=0.0) - add_aviary_output(self, Aircraft.Wing.BENDING_FACTOR, val=0.0) + add_aviary_output(self, Aircraft.Wing.BENDING_MATERIAL_FACTOR, val=0.0) add_aviary_output(self, Aircraft.Wing.ENG_POD_INERTIA_FACTOR, val=0.0) def setup_partials(self): - self.declare_partials(of=Aircraft.Wing.BENDING_FACTOR, - wrt=[Aircraft.Wing.STRUT_BRACING_FACTOR, - Aircraft.Wing.SPAN, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.AREA, - Aircraft.Wing.THICKNESS_TO_CHORD, - Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP]) + self.declare_partials( + of=Aircraft.Wing.BENDING_MATERIAL_FACTOR, + wrt=[ + Aircraft.Wing.STRUT_BRACING_FACTOR, + Aircraft.Wing.SPAN, + Aircraft.Wing.TAPER_RATIO, + Aircraft.Wing.AREA, + Aircraft.Wing.THICKNESS_TO_CHORD, + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, + Aircraft.Wing.ASPECT_RATIO, + Aircraft.Wing.SWEEP, + ], + ) def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - num_wing_eng = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) + num_wing_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES] fstrt = inputs[Aircraft.Wing.STRUT_BRACING_FACTOR] span = inputs[Aircraft.Wing.SPAN] tr = inputs[Aircraft.Wing.TAPER_RATIO] @@ -77,14 +77,13 @@ def compute(self, inputs, outputs): ems = 1.0 - 0.25 * fstrt - outputs[Aircraft.Wing.BENDING_FACTOR] = \ - 0.215 * (0.37 + 0.7 * tr) * (span**2 / area)**ems / (cayl * tca) + outputs[Aircraft.Wing.BENDING_MATERIAL_FACTOR] = ( + 0.215 * (0.37 + 0.7 * tr) * (span**2 / area) ** ems / (cayl * tca) + ) outputs[Aircraft.Wing.ENG_POD_INERTIA_FACTOR] = 1.0 - 0.03 * num_wing_eng def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_wing_eng = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) fstrt = inputs[Aircraft.Wing.STRUT_BRACING_FACTOR] span = inputs[Aircraft.Wing.SPAN] tr = inputs[Aircraft.Wing.TAPER_RATIO] @@ -134,26 +133,37 @@ def compute_partials(self, inputs, J): dbend_tr = 0.215 * 0.7 * term2 * term3 dbend_cayl = -0.215 * term1 * term2 * tca * term3**2 - J[Aircraft.Wing.BENDING_FACTOR, Aircraft.Wing.STRUT_BRACING_FACTOR] = \ + J[Aircraft.Wing.BENDING_MATERIAL_FACTOR, Aircraft.Wing.STRUT_BRACING_FACTOR] = ( dbend_exp + dbend_cayl * dcayl_fstrt + ) - J[Aircraft.Wing.BENDING_FACTOR, Aircraft.Wing.SPAN] = \ - 2.0 * 0.215 * term1 * ems * term2a**(ems - 1) * term3 * span / area + J[Aircraft.Wing.BENDING_MATERIAL_FACTOR, Aircraft.Wing.SPAN] = ( + 2.0 * 0.215 * term1 * ems * term2a ** (ems - 1) * term3 * span / area + ) - J[Aircraft.Wing.BENDING_FACTOR, Aircraft.Wing.TAPER_RATIO] = \ + J[Aircraft.Wing.BENDING_MATERIAL_FACTOR, Aircraft.Wing.TAPER_RATIO] = ( dbend_tr + dbend_cayl * (dcayl_slam * dslam * dtlam_tr) + ) - J[Aircraft.Wing.BENDING_FACTOR, Aircraft.Wing.AREA] = \ - -0.215 * term1 * ems * term2a**(ems - 1) * term3 * term2a / area + J[Aircraft.Wing.BENDING_MATERIAL_FACTOR, Aircraft.Wing.AREA] = ( + -0.215 * term1 * ems * term2a ** (ems - 1) * term3 * term2a / area + ) - J[Aircraft.Wing.BENDING_FACTOR, Aircraft.Wing.THICKNESS_TO_CHORD] = \ + J[Aircraft.Wing.BENDING_MATERIAL_FACTOR, Aircraft.Wing.THICKNESS_TO_CHORD] = ( -0.215 * term1 * term2 * cayl * term3**2 + ) - J[Aircraft.Wing.BENDING_FACTOR, Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR] = \ + J[ + Aircraft.Wing.BENDING_MATERIAL_FACTOR, + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, + ] = ( dbend_cayl * dcayl_faert + ) - J[Aircraft.Wing.BENDING_FACTOR, Aircraft.Wing.ASPECT_RATIO] = \ + J[Aircraft.Wing.BENDING_MATERIAL_FACTOR, Aircraft.Wing.ASPECT_RATIO] = ( dbend_cayl * (dcayl_ar + dcayl_slam * dslam * dtlam_ar) + ) - J[Aircraft.Wing.BENDING_FACTOR, Aircraft.Wing.SWEEP] = \ - dbend_cayl * (dcayl_slam * dslam * dtlam_sweep) + J[Aircraft.Wing.BENDING_MATERIAL_FACTOR, Aircraft.Wing.SWEEP] = dbend_cayl * ( + dcayl_slam * dslam * dtlam_sweep + ) diff --git a/aviary/subsystems/mass/gasp_based/design_load.py b/aviary/subsystems/mass/gasp_based/design_load.py index d88a41ea2..3312b5642 100644 --- a/aviary/subsystems/mass/gasp_based/design_load.py +++ b/aviary/subsystems/mass/gasp_based/design_load.py @@ -2,8 +2,7 @@ import openmdao.api as om from aviary.constants import RHO_SEA_LEVEL_ENGLISH -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -27,17 +26,16 @@ class LoadSpeeds(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Design.PART25_STRUCTURAL_CATEGORY) + add_aviary_option(self, Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES) + add_aviary_option(self, Aircraft.Wing.LOADING_ABOVE_20) def setup(self): add_aviary_input(self, Aircraft.Design.MAX_STRUCTURAL_SPEED, val=200, units="mi/h") - if self.options["aviary_options"].get_val(Aircraft.Design.PART25_STRUCTURAL_CATEGORY, units='unitless') < 3: + if self.options[Aircraft.Design.PART25_STRUCTURAL_CATEGORY] < 3: add_aviary_input(self, Aircraft.Wing.LOADING, val=128) @@ -68,12 +66,9 @@ def compute(self, inputs, outputs): max_struct_speed_mph = inputs[Aircraft.Design.MAX_STRUCTURAL_SPEED] - CATD = self.options["aviary_options"].get_val( - Aircraft.Design.PART25_STRUCTURAL_CATEGORY, units='unitless') - smooth = self.options["aviary_options"].get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') - WGS_greater_than_20_flag = self.options["aviary_options"].get_val( - Aircraft.Wing.LOADING_ABOVE_20, units='unitless') + CATD = self.options[Aircraft.Design.PART25_STRUCTURAL_CATEGORY] + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] + WGS_greater_than_20_flag = self.options[Aircraft.Wing.LOADING_ABOVE_20] max_struct_speed_kts = max_struct_speed_mph / 1.15 @@ -156,12 +151,9 @@ def compute_partials(self, inputs, partials): max_struct_speed_mph = inputs[Aircraft.Design.MAX_STRUCTURAL_SPEED] - CATD = self.options["aviary_options"].get_val( - Aircraft.Design.PART25_STRUCTURAL_CATEGORY, units='unitless') - smooth = self.options["aviary_options"].get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') - WGS_greater_than_20_flag = self.options["aviary_options"].get_val( - Aircraft.Wing.LOADING_ABOVE_20, units='unitless') + CATD = self.options[Aircraft.Design.PART25_STRUCTURAL_CATEGORY] + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] + WGS_greater_than_20_flag = self.options[Aircraft.Wing.LOADING_ABOVE_20] max_struct_speed_kts = max_struct_speed_mph / 1.15 dmax_struct_speed_kts_dmax_struct_speed_mph = 1 / 1.15 @@ -382,10 +374,9 @@ class LoadParameters(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Design.PART25_STRUCTURAL_CATEGORY) + add_aviary_option(self, Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES) + add_aviary_option(self, Mission.Design.CRUISE_ALTITUDE, units='ft') def setup(self): @@ -425,12 +416,9 @@ def compute(self, inputs, outputs): vel_c = inputs["vel_c"] max_airspeed = inputs["max_airspeed"] - cruise_alt = self.options["aviary_options"].get_val( - Mission.Design.CRUISE_ALTITUDE, units='ft') - CATD = self.options["aviary_options"].get_val( - Aircraft.Design.PART25_STRUCTURAL_CATEGORY, units='unitless') - smooth = self.options["aviary_options"].get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') + cruise_alt, _ = self.options[Mission.Design.CRUISE_ALTITUDE] + CATD = self.options[Aircraft.Design.PART25_STRUCTURAL_CATEGORY] + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] if cruise_alt <= 22500.0: max_mach = max_airspeed / 486.33 @@ -496,12 +484,9 @@ def compute_partials(self, inputs, partials): vel_c = inputs["vel_c"] max_airspeed = inputs["max_airspeed"] - cruise_alt = self.options["aviary_options"].get_val( - Mission.Design.CRUISE_ALTITUDE, units='ft') - CATD = self.options["aviary_options"].get_val( - Aircraft.Design.PART25_STRUCTURAL_CATEGORY, units='unitless') - smooth = self.options["aviary_options"].get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') + cruise_alt, _ = self.options[Mission.Design.CRUISE_ALTITUDE] + CATD = self.options[Aircraft.Design.PART25_STRUCTURAL_CATEGORY] + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] if cruise_alt <= 22500.0: max_mach = max_airspeed / 486.33 @@ -692,10 +677,8 @@ class LoadFactors(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES) + add_aviary_option(self, Aircraft.Design.ULF_CALCULATED_FROM_MANEUVER) def setup(self): @@ -738,10 +721,8 @@ def compute(self, inputs, outputs): avg_chord = inputs[Aircraft.Wing.AVERAGE_CHORD] Cl_alpha = inputs[Aircraft.Design.LIFT_CURVE_SLOPE] - ULF_from_maneuver = self.options["aviary_options"].get_val( - Aircraft.Design.ULF_CALCULATED_FROM_MANEUVER, units='unitless') - smooth = self.options["aviary_options"].get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') + ULF_from_maneuver = self.options[Aircraft.Design.ULF_CALCULATED_FROM_MANEUVER] + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] mass_ratio = ( 2.0 * wing_loading / @@ -800,10 +781,8 @@ def compute_partials(self, inputs, partials): avg_chord = inputs[Aircraft.Wing.AVERAGE_CHORD] Cl_alpha = inputs[Aircraft.Design.LIFT_CURVE_SLOPE] - ULF_from_maneuver = self.options["aviary_options"].get_val( - Aircraft.Design.ULF_CALCULATED_FROM_MANEUVER, units='unitless') - smooth = self.options["aviary_options"].get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') + ULF_from_maneuver = self.options[Aircraft.Design.ULF_CALCULATED_FROM_MANEUVER] + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] mass_ratio = ( 2.0 * wing_loading / @@ -1248,22 +1227,11 @@ class DesignLoadGroup(om.Group): Design load group for GASP-based mass. """ - def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): - aviary_options = self.options['aviary_options'] - self.add_subsystem( "speeds", - LoadSpeeds( - aviary_options=aviary_options, - ), + LoadSpeeds(), promotes_inputs=['aircraft:*'], promotes_outputs=[ "max_airspeed", @@ -1275,10 +1243,11 @@ def setup(self): self.add_subsystem( "params", - LoadParameters( - aviary_options=aviary_options, - ), - promotes_inputs=["max_airspeed", "vel_c"], + LoadParameters(), + promotes_inputs=[ + "max_airspeed", + "vel_c", + ], promotes_outputs=["density_ratio", "V9", "max_mach"], ) @@ -1291,9 +1260,7 @@ def setup(self): self.add_subsystem( "factors", - LoadFactors( - aviary_options=aviary_options, - ), + LoadFactors(), promotes_inputs=[ "max_maneuver_factor", "min_dive_vel", diff --git a/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py b/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py index 90e7014aa..443e523ab 100644 --- a/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py +++ b/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py @@ -2,9 +2,8 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import GASPEngineType -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -22,15 +21,15 @@ class EquipAndUsefulLoadMass(om.ExplicitComponent): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) + add_aviary_option(self, Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Engine.TYPE) + add_aviary_option(self, Aircraft.LandingGear.FIXED_GEAR) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input( self, Aircraft.AirConditioning.MASS_COEFFICIENT, val=1, units="unitless") @@ -80,20 +79,13 @@ def setup(self): def compute(self, inputs, outputs): - options: AviaryValues = self.options["aviary_options"] - PAX = options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') - smooth = options.get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') + PAX = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] gross_wt_initial = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM - num_engines = self.options['aviary_options'].get_val( - Aircraft.Propulsion.TOTAL_NUM_ENGINES, units='unitless') + num_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] fus_len = inputs[Aircraft.Fuselage.LENGTH] wingspan = inputs[Aircraft.Wing.SPAN] - if options.get_val(Aircraft.LandingGear.FIXED_GEAR, units='unitless'): - gear_type = 1 - else: - gear_type = 0 landing_gear_wt = inputs[Aircraft.LandingGear.TOTAL_MASS] * \ GRAV_ENGLISH_LBM @@ -107,7 +99,7 @@ def compute(self, inputs, outputs): fuel_vol_frac = inputs[Aircraft.Fuel.WING_FUEL_FRACTION] subsystems_wt = inputs[Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS] - engine_type = options.get_val(Aircraft.Engine.TYPE, units='unitless')[0] + engine_type = self.options[Aircraft.Engine.TYPE][0] APU_wt = 0.0 if PAX > 35.0: @@ -133,11 +125,10 @@ def compute(self, inputs, outputs): * fus_len**0.05 * wingspan**0.696 ) - gear_val = 1 - gear_type hydraulic_wt = ( inputs[Aircraft.Hydraulics.FLIGHT_CONTROL_MASS_COEFFICIENT] * control_wt + inputs[Aircraft.Hydraulics.GEAR_MASS_COEFFICIENT] * - landing_gear_wt * gear_val + landing_gear_wt * (not self.options[Aircraft.LandingGear.FIXED_GEAR]) ) electrical_wt = 16.0 * PAX + 170.0 @@ -391,19 +382,14 @@ def compute(self, inputs, outputs): GRAV_ENGLISH_LBM def compute_partials(self, inputs, partials): - options = self.options['aviary_options'] - PAX = options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') - smooth = options.get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') + PAX = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] + gross_wt_initial = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM - num_engines = self.options['aviary_options'].get_val( - Aircraft.Propulsion.TOTAL_NUM_ENGINES, units='unitless') + num_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] fus_len = inputs[Aircraft.Fuselage.LENGTH] wingspan = inputs[Aircraft.Wing.SPAN] - if options.get_val(Aircraft.LandingGear.FIXED_GEAR, units='unitless'): - gear_type = 1 - else: - gear_type = 0 + landing_gear_wt = inputs[Aircraft.LandingGear.TOTAL_MASS] * \ GRAV_ENGLISH_LBM control_wt = inputs[Aircraft.Controls.TOTAL_MASS] * GRAV_ENGLISH_LBM @@ -414,7 +400,7 @@ def compute_partials(self, inputs, partials): cabin_width = inputs[Aircraft.Fuselage.AVG_DIAMETER] fuel_vol_frac = inputs[Aircraft.Fuel.WING_FUEL_FRACTION] - engine_type = options.get_val(Aircraft.Engine.TYPE, units='unitless')[0] + engine_type = self.options[Aircraft.Engine.TYPE][0] dAPU_wt_dmass_coeff_0 = 0.0 if ~( @@ -465,7 +451,7 @@ def compute_partials(self, inputs, partials): * wingspan ** (0.696 - 1) ) - gear_val = 1 - gear_type + gear_val = not self.options[Aircraft.LandingGear.FIXED_GEAR] dhydraulic_wt_dmass_coeff_2 = control_wt dhydraulic_wt_dcontrol_wt = inputs[Aircraft.Hydraulics.FLIGHT_CONTROL_MASS_COEFFICIENT] diff --git a/aviary/subsystems/mass/gasp_based/fixed.py b/aviary/subsystems/mass/gasp_based/fixed.py index 3f083f3b3..84fd865a0 100644 --- a/aviary/subsystems/mass/gasp_based/fixed.py +++ b/aviary/subsystems/mass/gasp_based/fixed.py @@ -3,9 +3,8 @@ from openmdao.components.ks_comp import KSfunction from aviary.constants import GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import FlapType -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission @@ -30,14 +29,13 @@ class MassParameters(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Engine.NUM_FUSELAGE_ENGINES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) + add_aviary_option(self, Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Wing.SWEEP, val=0.436, units='rad') add_aviary_input(self, Aircraft.Wing.TAPER_RATIO, val=0.33) @@ -100,14 +98,12 @@ def setup(self): "c_gear_loc", Aircraft.LandingGear.MAIN_GEAR_LOCATION) def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] sweep_c4 = inputs[Aircraft.Wing.SWEEP] taper_ratio = inputs[Aircraft.Wing.TAPER_RATIO] AR = inputs[Aircraft.Wing.ASPECT_RATIO] wingspan = inputs[Aircraft.Wing.SPAN] - num_engines = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_ENGINES, units='unitless') + num_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] max_mach = inputs["max_mach"] strut_x = inputs[Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS] gear_location = inputs[Aircraft.LandingGear.MAIN_GEAR_LOCATION] @@ -122,15 +118,12 @@ def compute(self, inputs, outputs): c_material = 1.0 + 2.5 / (struct_span**0.5) c_strut_braced = 1.0 - strut_x**2 - not_fuselage_mounted = self.options["aviary_options"].get_val( - Aircraft.Engine.NUM_FUSELAGE_ENGINES) == 0 + not_fuselage_mounted = self.options[Aircraft.Engine.NUM_FUSELAGE_ENGINES] == 0 # note: c_gear_loc doesn't actually depend on any of the inputs... perhaps use a # set_input_defaults call to declare this at a higher level c_gear_loc = 1.0 - if aviary_options.get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless' - ): + if self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES]: # smooth transition for c_gear_loc from 0.95 to 1 when gear_location varies # between 0 and 1% of span c_gear_loc = .95 * sigX((0.005 - gear_location)*100) + \ @@ -156,14 +149,12 @@ def compute(self, inputs, outputs): outputs["half_sweep"] = half_sweep def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] sweep_c4 = inputs[Aircraft.Wing.SWEEP] taper_ratio = inputs[Aircraft.Wing.TAPER_RATIO] AR = inputs[Aircraft.Wing.ASPECT_RATIO] wingspan = inputs[Aircraft.Wing.SPAN] - num_engines = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_ENGINES, units='unitless') + num_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] max_mach = inputs["max_mach"] strut_x = inputs[Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS] gear_location = inputs[Aircraft.LandingGear.MAIN_GEAR_LOCATION] @@ -177,8 +168,7 @@ def compute_partials(self, inputs, J): struct_span = wingspan / cos_half_sweep c_material = 1.0 + 2.5 / (struct_span**0.5) - not_fuselage_mounted = self.options["aviary_options"].get_val( - Aircraft.Engine.NUM_FUSELAGE_ENGINES) == 0 + not_fuselage_mounted = self.options[Aircraft.Engine.NUM_FUSELAGE_ENGINES] == 0 dTanHS_dSC4 = (1 / np.cos(sweep_c4) ** 2) dTanHS_TR = ( @@ -248,9 +238,7 @@ def compute_partials(self, inputs, J): J["c_strut_braced", Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS] = \ -2 * strut_x - if aviary_options.get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless' - ): + if self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES]: J["c_gear_loc", Aircraft.LandingGear.MAIN_GEAR_LOCATION] = ( .95 * (-100) * dSigXdX((0.005 - gear_location)*100) + 1 * (100) * dSigXdX(100*(gear_location - 0.005))) @@ -262,10 +250,9 @@ class PayloadMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.CrewPayload.NUM_PASSENGERS) + add_aviary_option(self, Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, + units='lbm') def setup(self): add_aviary_input(self, Aircraft.CrewPayload.CARGO_MASS, val=10040) @@ -289,11 +276,8 @@ def setup(self): val=1.0) def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options['aviary_options'] - pax_mass = aviary_options.get_val( - Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, units='lbm') - PAX = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS, units='unitless') + pax_mass, _ = self.options[Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS] + PAX = self.options[Aircraft.CrewPayload.NUM_PASSENGERS] cargo_mass = inputs[Aircraft.CrewPayload.CARGO_MASS] outputs[Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS] = \ @@ -308,10 +292,7 @@ class ElectricAugmentationMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) def setup(self): self.add_input( @@ -435,8 +416,7 @@ def compute(self, inputs, outputs): motor_spec_wt = inputs["motor_spec_mass"] / GRAV_ENGLISH_LBM inverter_spec_wt = inputs["inverter_spec_mass"] / GRAV_ENGLISH_LBM TMS_spec_wt = inputs["TMS_spec_mass"] * GRAV_ENGLISH_LBM - num_engines = self.options['aviary_options'].get_val( - Aircraft.Propulsion.TOTAL_NUM_ENGINES, units='unitless') + num_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] motor_current = 1000.0 * motor_power / motor_voltage num_wires = motor_current / max_amp_per_wire @@ -477,8 +457,7 @@ def compute_partials(self, inputs, J): motor_spec_wt = inputs["motor_spec_mass"] / GRAV_ENGLISH_LBM inverter_spec_wt = inputs["inverter_spec_mass"] / GRAV_ENGLISH_LBM TMS_spec_wt = inputs["TMS_spec_mass"] * GRAV_ENGLISH_LBM - num_engines = self.options['aviary_options'].get_val( - Aircraft.Propulsion.TOTAL_NUM_ENGINES, units='unitless') + num_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] motor_current = 1000.0 * motor_power / motor_voltage num_wires = motor_current / max_amp_per_wire @@ -592,20 +571,18 @@ def compute_partials(self, inputs, J): class EngineMass(om.ExplicitComponent): """ - Computation of total engine mass, nacelle mass, pylon mass, total engine POD mass, + Computation of total engine mass, nacelle mass, pylon mass, total engine POD mass, additional engine mass """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Electrical.HAS_HYBRID_SYSTEM) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) def setup(self): - aviary_options: AviaryValues = self.options['aviary_options'] - num_engine_type = len(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) - total_num_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) + total_num_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] add_aviary_input(self, Aircraft.Engine.MASS_SPECIFIC, val=np.full(num_engine_type, 0.21366)) @@ -630,8 +607,7 @@ def setup(self): add_aviary_input(self, Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0.15) - has_hybrid_system = aviary_options.get_val( - Aircraft.Electrical.HAS_HYBRID_SYSTEM, units='unitless') + has_hybrid_system = self.options[Aircraft.Electrical.HAS_HYBRID_SYSTEM] if has_hybrid_system: self.add_input( @@ -683,8 +659,7 @@ def setup(self): self.declare_partials("wing_mounted_mass", "prop_mass") # derivatives w.r.t vectorized engine inputs have known sparsity pattern - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) shape = np.arange(num_engine_type) self.declare_partials( @@ -765,12 +740,10 @@ def setup(self): ) def compute(self, inputs, outputs): - aviary_options = self.options['aviary_options'] - num_engine_type = len(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] + num_engine_type = len(num_engines) eng_spec_wt = inputs[Aircraft.Engine.MASS_SPECIFIC] * GRAV_ENGLISH_LBM Fn_SLS = inputs[Aircraft.Engine.SCALED_SLS_THRUST] - num_engines = aviary_options.get_val( - Aircraft.Engine.NUM_ENGINES, units='unitless') spec_nacelle_wt = inputs[Aircraft.Nacelle.MASS_SPECIFIC] * GRAV_ENGLISH_LBM nacelle_area = inputs[Aircraft.Nacelle.SURFACE_AREA] @@ -800,15 +773,13 @@ def compute(self, inputs, outputs): outputs["eng_comb_mass"] = (sum( CK5 * dry_wt_eng * num_engines) + CK7 * eng_instl_wt_all) / GRAV_ENGLISH_LBM - if aviary_options.get_val( - Aircraft.Electrical.HAS_HYBRID_SYSTEM, units='unitless' - ): + if self.options[Aircraft.Electrical.HAS_HYBRID_SYSTEM]: aug_wt = inputs["aug_mass"] * GRAV_ENGLISH_LBM outputs["eng_comb_mass"] = (sum(CK5 * dry_wt_eng * num_engines) + CK7 * eng_instl_wt_all + aug_wt) / GRAV_ENGLISH_LBM # prop_wt = np.zeros(num_engine_type) - # prop_idx = np.where(aviary_options.get_val(Aircraft.Engine.HAS_PROPELLERS)) + # prop_idx = np.where(self.options[Aircraft.Engine.HAS_PROPELLERS)) # prop_wt[prop_idx] = inputs["prop_mass"] * GRAV_ENGLISH_LBM prop_wt = inputs["prop_mass"] * GRAV_ENGLISH_LBM outputs["prop_mass_all"] = sum(num_engines * prop_wt) / GRAV_ENGLISH_LBM @@ -826,15 +797,11 @@ def compute(self, inputs, outputs): ) + main_gear_wt * loc_main_gear / (loc_main_gear + 0.001)) / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options['aviary_options'] - num_engine_type = len(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) eng_spec_wt = inputs[Aircraft.Engine.MASS_SPECIFIC] * GRAV_ENGLISH_LBM Fn_SLS = inputs[Aircraft.Engine.SCALED_SLS_THRUST] - num_engines = self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES, units='unitless') - total_num_engines = self.options['aviary_options'].get_val( - Aircraft.Propulsion.TOTAL_NUM_ENGINES, units='unitless') + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] spec_nacelle_wt = inputs[Aircraft.Nacelle.MASS_SPECIFIC] * GRAV_ENGLISH_LBM nacelle_area = inputs[Aircraft.Nacelle.SURFACE_AREA] @@ -916,7 +883,7 @@ def compute_partials(self, inputs, J): pod_wt = (nacelle_wt + pylon_wt) eng_instl_wt = c_instl * dry_wt_eng - # prop_idx = np.where(aviary_options.get_val(Aircraft.Engine.HAS_PROPELLERS)) + # prop_idx = np.where(self.options[Aircraft.Engine.HAS_PROPELLERS)) prop_wt = inputs["prop_mass"] * GRAV_ENGLISH_LBM # prop_wt_all = sum(num_engines * prop_wt) / GRAV_ENGLISH_LBM @@ -971,7 +938,7 @@ def compute_partials(self, inputs, J): J["wing_mounted_mass", "prop_mass"] = span_frac_factor_sum * num_engines - if self.options["aviary_options"].get_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, units='unitless'): + if self.options[Aircraft.Electrical.HAS_HYBRID_SYSTEM]: J["eng_comb_mass", "aug_mass"] = 1 @@ -980,12 +947,6 @@ class TailMass(om.ExplicitComponent): Computation of horizontal tail mass and vertical tail mass. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): add_aviary_input(self, Aircraft.VerticalTail.TAPER_RATIO, val=0.801) add_aviary_input(self, Aircraft.VerticalTail.ASPECT_RATIO, val=1.67) @@ -1608,10 +1569,8 @@ class HighLiftMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.FLAP_TYPE) + add_aviary_option(self, Aircraft.Wing.NUM_FLAP_SEGMENTS) def setup(self): add_aviary_input(self, Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, val=2.66) @@ -1668,11 +1627,10 @@ def setup(self): Mission.Landing.LIFT_COEFFICIENT_MAX]) def compute(self, inputs, outputs): - aviary_options: AviaryValues = self.options["aviary_options"] - flap_type = aviary_options.get_val(Aircraft.Wing.FLAP_TYPE, units='unitless') + flap_type = self.options[Aircraft.Wing.FLAP_TYPE] c_mass_trend_high_lift = inputs[Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT] wing_area = inputs[Aircraft.Wing.AREA] - num_flaps = aviary_options.get_val(Aircraft.Wing.NUM_FLAP_SEGMENTS) + num_flaps = self.options[Aircraft.Wing.NUM_FLAP_SEGMENTS] slat_chord_ratio = inputs[Aircraft.Wing.SLAT_CHORD_RATIO] flap_chord_ratio = inputs[Aircraft.Wing.FLAP_CHORD_RATIO] taper_ratio = inputs[Aircraft.Wing.TAPER_RATIO] @@ -1733,11 +1691,10 @@ def compute(self, inputs, outputs): WLED / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - aviary_options: AviaryValues = self.options["aviary_options"] - flap_type = aviary_options.get_val(Aircraft.Wing.FLAP_TYPE, units='unitless') + flap_type = self.options[Aircraft.Wing.FLAP_TYPE] c_mass_trend_high_lift = inputs[Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT] wing_area = inputs[Aircraft.Wing.AREA] - num_flaps = aviary_options.get_val(Aircraft.Wing.NUM_FLAP_SEGMENTS) + num_flaps = self.options[Aircraft.Wing.NUM_FLAP_SEGMENTS] slat_chord_ratio = inputs[Aircraft.Wing.SLAT_CHORD_RATIO] flap_chord_ratio = inputs[Aircraft.Wing.FLAP_CHORD_RATIO] taper_ratio = inputs[Aircraft.Wing.TAPER_RATIO] @@ -2083,12 +2040,6 @@ class ControlMass(om.ExplicitComponent): and mass of surface controls. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): add_aviary_input( self, Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, val=0.95) @@ -2314,14 +2265,10 @@ class GearMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Aircraft.Wing.MOUNTING_TYPE, val=0) add_aviary_input(self, Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04) @@ -2463,22 +2410,13 @@ class FixedMassGroup(om.Group): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Electrical.HAS_HYBRID_SYSTEM) def setup(self): - aviary_options: AviaryValues = self.options['aviary_options'] - - n_eng = aviary_options.get_val( - Aircraft.Propulsion.TOTAL_NUM_ENGINES, units='unitless') self.add_subsystem( "params", - MassParameters( - aviary_options=aviary_options, - ), + MassParameters(), promotes_inputs=["max_mach", ] + ["aircraft:*"], promotes_outputs=["c_strut_braced", "c_gear_loc", "half_sweep", ] + ["aircraft:*"], @@ -2486,54 +2424,51 @@ def setup(self): self.add_subsystem( "payload", - PayloadMass(aviary_options=aviary_options), + PayloadMass(), promotes_inputs=["aircraft:*"], promotes_outputs=["payload_mass_des", "payload_mass_max", ] + ["aircraft:*"], ) self.add_subsystem( "tail", - TailMass(aviary_options=aviary_options), + TailMass(), promotes_inputs=["min_dive_vel", ] + ["aircraft:*", "mission:*"], promotes_outputs=["aircraft:*"], ) self.add_subsystem( "HL", - HighLiftMass(aviary_options=aviary_options), + HighLiftMass(), promotes_inputs=["density"] + ["aircraft:*", "mission:*"], promotes_outputs=["aircraft:*"], ) self.add_subsystem( "controls", - ControlMass(aviary_options=aviary_options), + ControlMass(), promotes_inputs=["min_dive_vel", ] + ["aircraft:*", "mission:*"], promotes_outputs=["aircraft:*"], ) self.add_subsystem( "gear", - GearMass(aviary_options=aviary_options), + GearMass(), promotes_inputs=["mission:*", "aircraft:*"], promotes_outputs=[Aircraft.LandingGear.MAIN_GEAR_MASS, ] + ["aircraft:*"], ) - has_hybrid_system = aviary_options.get_val( - Aircraft.Electrical.HAS_HYBRID_SYSTEM, units='unitless') + has_hybrid_system = self.options[Aircraft.Electrical.HAS_HYBRID_SYSTEM] if has_hybrid_system: self.add_subsystem( "augmentation", - ElectricAugmentationMass( - aviary_options=aviary_options, - ), + ElectricAugmentationMass(), promotes_inputs=["aircraft:*"], promotes_outputs=["aug_mass", ], ) self.add_subsystem( "engine", - EngineMass(aviary_options=aviary_options), + EngineMass(), promotes_inputs=["aircraft:*"] + [Aircraft.LandingGear.MAIN_GEAR_MASS, ], promotes_outputs=["wing_mounted_mass", "eng_comb_mass"] + ["aircraft:*"], ) diff --git a/aviary/subsystems/mass/gasp_based/fuel.py b/aviary/subsystems/mass/gasp_based/fuel.py index b9b973fc9..8a202aece 100644 --- a/aviary/subsystems/mass/gasp_based/fuel.py +++ b/aviary/subsystems/mass/gasp_based/fuel.py @@ -3,9 +3,8 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import Verbosity -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission, Settings check = 1 @@ -33,10 +32,8 @@ class BodyTankCalculations(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES) + add_aviary_option(self, Settings.VERBOSITY) def setup(self): @@ -135,14 +132,13 @@ def compute(self, inputs, outputs): fuel_wt_des = inputs[Mission.Design.FUEL_MASS] * GRAV_ENGLISH_LBM OEW = inputs[Aircraft.Design.OPERATING_MASS] * GRAV_ENGLISH_LBM - smooth = self.options["aviary_options"].get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] extra_fuel_volume = sigX(design_fuel_vol - max_wingfuel_vol) * ( design_fuel_vol - geometric_fuel_vol ) - verbosity = self.options['aviary_options'].get_val(Settings.VERBOSITY) + verbosity = self.options[Settings.VERBOSITY] if verbosity >= Verbosity.BRIEF: if (req_fuel_wt > max_wingfuel_wt) and (design_fuel_vol > max_wingfuel_vol): print("Warning: req_fuel_mass > max_wingfuel_mass, adding a body tank") @@ -187,8 +183,7 @@ def compute_partials(self, inputs, J): fuel_wt_des = inputs[Mission.Design.FUEL_MASS] * GRAV_ENGLISH_LBM OEW = inputs[Aircraft.Design.OPERATING_MASS] * GRAV_ENGLISH_LBM - smooth = self.options["aviary_options"].get_val( - Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, units='unitless') + smooth = self.options[Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES] extra_fuel_volume = sigX(design_fuel_vol - max_wingfuel_vol) * ( design_fuel_vol - geometric_fuel_vol @@ -361,12 +356,6 @@ class FuelAndOEMOutputs(om.ExplicitComponent): wing fuel weight). """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): add_aviary_input(self, Aircraft.Fuel.DENSITY, val=6.687, units="lbm/ft**3") @@ -732,12 +721,6 @@ class FuelSysAndFullFuselageMass(om.ExplicitComponent): Computation of fuselage mass and fuel system mass """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): add_aviary_input(self, Mission.Design.GROSS_MASS, val=175400) @@ -866,14 +849,10 @@ class FuselageAndStructMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) self.add_input( "fus_mass_full", @@ -1208,12 +1187,6 @@ class FuelMass(om.ExplicitComponent): and minimum value of fuel mass. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): add_aviary_input(self, Aircraft.Design.STRUCTURE_MASS, val=50461.0) @@ -1514,16 +1487,8 @@ class FuelMassGroup(om.Group): FuselageAndStructMass, FuelMass, FuelAndOEMOutputs, and BodyTankCalculations. """ - def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): - aviary_options = self.options['aviary_options'] - # variables that are calculated at a higher level higher_level_inputs1 = ["wing_mounted_mass"] higher_level_inputs2 = [ @@ -1556,7 +1521,7 @@ def setup(self): self.add_subsystem( "sys_and_full_fus", - FuelSysAndFullFuselageMass(aviary_options=aviary_options), + FuelSysAndFullFuselageMass(), promotes_inputs=connected_inputs1 + higher_level_inputs1 + ["aircraft:*", "mission:*"], @@ -1565,14 +1530,14 @@ def setup(self): self.add_subsystem( "fus_and_struct", - FuselageAndStructMass(aviary_options=aviary_options), + FuselageAndStructMass(), promotes_inputs=connected_inputs2 + higher_level_inputs2 + ["aircraft:*"], promotes_outputs=["aircraft:*"], ) self.add_subsystem( "fuel", - FuelMass(aviary_options=aviary_options), + FuelMass(), promotes_inputs=higher_level_inputs3 + ["aircraft:*", "mission:*"], promotes_outputs=connected_outputs3 + ["aircraft:*", "mission:*"], @@ -1580,14 +1545,14 @@ def setup(self): self.add_subsystem( "fuel_and_oem", - FuelAndOEMOutputs(aviary_options=aviary_options), + FuelAndOEMOutputs(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=connected_outputs4 + ["aircraft:*"], ) self.add_subsystem( "body_tank", - BodyTankCalculations(aviary_options=aviary_options), + BodyTankCalculations(), promotes_inputs=connected_inputs5 + ["aircraft:*", "mission:*"], promotes_outputs=connected_outputs5 + ["aircraft:*"], diff --git a/aviary/subsystems/mass/gasp_based/mass_premission.py b/aviary/subsystems/mass/gasp_based/mass_premission.py index 187df60a2..df167c6a9 100644 --- a/aviary/subsystems/mass/gasp_based/mass_premission.py +++ b/aviary/subsystems/mass/gasp_based/mass_premission.py @@ -6,7 +6,6 @@ from aviary.subsystems.mass.gasp_based.fixed import FixedMassGroup from aviary.subsystems.mass.gasp_based.fuel import FuelMassGroup from aviary.subsystems.mass.gasp_based.wing import WingMassGroup -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Aircraft @@ -15,17 +14,8 @@ class MassPremission(om.Group): Pre-mission mass group for GASP-based mass. """ - def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) - def setup(self): - aviary_options = self.options['aviary_options'] - # output values from design_load that are connected to fixed_mass via promotion fixed_mass_design_load_values = [ "max_mach", "min_dive_vel"] @@ -66,43 +56,35 @@ def setup(self): self.add_subsystem( "design_load", - DesignLoadGroup( - aviary_options=aviary_options, - ), + DesignLoadGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=["*"], ) self.add_subsystem( "fixed_mass", - FixedMassGroup( - aviary_options=aviary_options, - ), + FixedMassGroup(), promotes_inputs=fixed_mass_inputs + ["aircraft:*", "mission:*"], promotes_outputs=fixed_mass_outputs + ["aircraft:*"], ) self.add_subsystem( "equip_and_useful_mass", - EquipAndUsefulLoadMass( - aviary_options=aviary_options, - ), + EquipAndUsefulLoadMass(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=["aircraft:*"], ) self.add_subsystem( "wing_mass", - WingMassGroup( - aviary_options=aviary_options, - ), + WingMassGroup(), promotes_inputs=wing_mass_inputs + ["aircraft:*", "mission:*"], promotes_outputs=["aircraft:*"], ) self.add_subsystem( "fuel_mass", - FuelMassGroup(aviary_options=aviary_options), + FuelMassGroup(), promotes_inputs=fuel_mass_inputs + ["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", "mission:*" diff --git a/aviary/subsystems/mass/gasp_based/test/test_design_load.py b/aviary/subsystems/mass/gasp_based/test/test_design_load.py index 5a9674f94..5df362720 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_design_load.py +++ b/aviary/subsystems/mass/gasp_based/test/test_design_load.py @@ -8,6 +8,7 @@ LoadParameters, LiftCurveSlopeAtCruise, LoadSpeeds) +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission @@ -20,7 +21,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds(aviary_options=get_option_defaults()), + LoadSpeeds(), promotes=["*"], ) @@ -54,7 +55,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds(aviary_options=options), + LoadSpeeds(), promotes=["*"], ) @@ -65,6 +66,8 @@ def setUp(self): Aircraft.Wing.LOADING, val=128, units="lbf/ft**2" ) # not actual bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -98,7 +101,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds(aviary_options=options), + LoadSpeeds(), promotes=["*"], ) @@ -109,6 +112,8 @@ def setUp(self): Aircraft.Wing.LOADING, val=128, units="lbf/ft**2" ) # not actual bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -141,7 +146,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds(aviary_options=options), + LoadSpeeds(), promotes=["*"], ) @@ -152,6 +157,8 @@ def setUp(self): Aircraft.Wing.LOADING, val=128, units="lbf/ft**2" ) # not actual bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -185,7 +192,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds(aviary_options=options), + LoadSpeeds(), promotes=["*"], ) @@ -193,6 +200,8 @@ def setUp(self): Aircraft.Design.MAX_STRUCTURAL_SPEED, val=402.5, units="mi/h" ) # not actual bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -223,9 +232,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds( - aviary_options=options - ), + LoadSpeeds(), promotes=["*"], ) @@ -233,6 +240,8 @@ def setUp(self): Aircraft.Design.MAX_STRUCTURAL_SPEED, val=402.5, units="mi/h" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -261,9 +270,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds( - aviary_options=options - ), + LoadSpeeds(), promotes=["*"], ) @@ -274,6 +281,8 @@ def setUp(self): Aircraft.Wing.LOADING, val=128, units="lbf/ft**2" ) # not actual bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -309,9 +318,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds( - aviary_options=options, - ), + LoadSpeeds(), promotes=["*"], ) @@ -322,6 +329,8 @@ def setUp(self): Aircraft.Wing.LOADING, val=128, units="lbf/ft**2" ) # not actual bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -356,9 +365,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds( - aviary_options=options, - ), + LoadSpeeds(), promotes=["*"], ) @@ -369,6 +376,8 @@ def setUp(self): Aircraft.Wing.LOADING, val=128, units="lbf/ft**2" ) # not actual bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -404,9 +413,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "speeds", - LoadSpeeds( - aviary_options=options, - ), + LoadSpeeds(), promotes=["*"], ) @@ -414,6 +421,8 @@ def setUp(self): Aircraft.Design.MAX_STRUCTURAL_SPEED, val=402.5, units="mi/h" ) # not actual bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -441,7 +450,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "params", LoadParameters(aviary_options=options), promotes=["*"] + "params", LoadParameters(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -451,6 +460,8 @@ def setUp(self): "max_airspeed", val=350, units="kn" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -476,7 +487,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "params", LoadParameters(aviary_options=options), promotes=["*"] + "params", LoadParameters(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -486,6 +497,8 @@ def setUp(self): "max_airspeed", val=350, units="kn" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -512,7 +525,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "params", LoadParameters(aviary_options=options), promotes=["*"] + "params", LoadParameters(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -522,6 +535,8 @@ def setUp(self): "max_airspeed", val=350, units="kn" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -543,14 +558,14 @@ class LoadParametersTestCase4smooth(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') options.set_val(Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, val=True, units='unitless') + options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') self.prob = om.Problem() self.prob.model.add_subsystem( "params", - LoadParameters(aviary_options=options,), + LoadParameters(), promotes=["*"], ) @@ -561,6 +576,8 @@ def setUp(self): "max_airspeed", val=350, units="kn" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -582,14 +599,14 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Design.PART25_STRUCTURAL_CATEGORY, val=2, units='unitless') - options.set_val(Mission.Design.CRUISE_ALTITUDE, val=30000, units='ft') options.set_val(Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, val=True, units='unitless') + options.set_val(Mission.Design.CRUISE_ALTITUDE, val=30000, units='ft') self.prob = om.Problem() self.prob.model.add_subsystem( "params", - LoadParameters(aviary_options=options,), + LoadParameters(), promotes=["*"], ) @@ -600,6 +617,8 @@ def setUp(self): "max_airspeed", val=350, units="kn" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -622,14 +641,14 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Design.PART25_STRUCTURAL_CATEGORY, val=4, units='unitless') - options.set_val(Mission.Design.CRUISE_ALTITUDE, val=22000, units='ft') options.set_val(Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, val=True, units='unitless') + options.set_val(Mission.Design.CRUISE_ALTITUDE, val=22000, units='ft') self.prob = om.Problem() self.prob.model.add_subsystem( "params", - LoadParameters(aviary_options=options,), + LoadParameters(), promotes=["*"], ) @@ -640,6 +659,8 @@ def setUp(self): "max_airspeed", val=350, units="kn" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -689,7 +710,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "factors", LoadFactors(aviary_options=get_option_defaults()), promotes=["*"] + "factors", LoadFactors(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -735,7 +756,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "factors", LoadFactors(aviary_options=options), promotes=["*"] + "factors", LoadFactors(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -756,6 +777,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Design.LIFT_CURVE_SLOPE, val=7.1765, units="1/rad") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -781,7 +804,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "factors", - LoadFactors(aviary_options=options), + LoadFactors(), promotes=["*"], ) @@ -805,6 +828,8 @@ def setUp(self): Aircraft.Design.LIFT_CURVE_SLOPE, val=7.1765, units="1/rad" ) # bug fixed value and original value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -829,7 +854,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "factors", - LoadFactors(aviary_options=options,), + LoadFactors(), promotes=["*"], ) @@ -851,6 +876,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Design.LIFT_CURVE_SLOPE, val=7.1765, units="1/rad") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -876,9 +903,7 @@ def setUp(self): self.prob.model.add_subsystem( "Dload", - DesignLoadGroup( - aviary_options=options, - ), + DesignLoadGroup(), promotes=["*"], ) @@ -893,6 +918,8 @@ def setUp(self): Aircraft.Wing.AVERAGE_CHORD, val=12.71, units="ft" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -913,17 +940,15 @@ class DesignLoadGroupTestCase2smooth(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') options.set_val(Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, val=True, units='unitless') + options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') self.prob = om.Problem() self.prob.model.add_subsystem( "Dload", - DesignLoadGroup( - aviary_options=options, - ), + DesignLoadGroup(), promotes=["*"], ) @@ -938,6 +963,8 @@ def setUp(self): Aircraft.Wing.AVERAGE_CHORD, val=12.71, units="ft" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): diff --git a/aviary/subsystems/mass/gasp_based/test/test_equipment_and_useful_load.py b/aviary/subsystems/mass/gasp_based/test/test_equipment_and_useful_load.py index 97549f437..242ad7427 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_equipment_and_useful_load.py +++ b/aviary/subsystems/mass/gasp_based/test/test_equipment_and_useful_load.py @@ -7,6 +7,7 @@ from aviary.subsystems.mass.gasp_based.equipment_and_useful_load import \ EquipAndUsefulLoadMass from aviary.variable_info.enums import GASPEngineType +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission @@ -17,14 +18,15 @@ class FixedEquipMassTestCase1(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.LandingGear.FIXED_GEAR, val=False, units='unitless') self.prob = om.Problem() self.prob.model.add_subsystem( "equip", - EquipAndUsefulLoadMass(aviary_options=options), + EquipAndUsefulLoadMass(), promotes=["*"], ) @@ -86,6 +88,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, val=0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -106,14 +110,15 @@ class FixedEquipMassTestCase2(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=5, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=5, units='unitless') options.set_val(Aircraft.LandingGear.FIXED_GEAR, val=False, units='unitless') self.prob = om.Problem() self.prob.model.add_subsystem( "equip", - EquipAndUsefulLoadMass(aviary_options=options), + EquipAndUsefulLoadMass(), promotes=["*"], ) @@ -175,6 +180,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, val=0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -204,7 +211,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "equip", - EquipAndUsefulLoadMass(aviary_options=options), + EquipAndUsefulLoadMass(), promotes=["*"], ) @@ -266,6 +273,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, val=0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -289,7 +298,8 @@ class FixedEquipMassTestCase4smooth(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.LandingGear.FIXED_GEAR, val=False, units='unitless') options.set_val(Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, @@ -298,9 +308,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "equip", - EquipAndUsefulLoadMass( - aviary_options=options, - ), + EquipAndUsefulLoadMass(), promotes=["*"], ) @@ -362,6 +370,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, val=0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -383,7 +393,8 @@ class FixedEquipMassTestCase5smooth(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=5, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=5, units='unitless') options.set_val(Aircraft.LandingGear.FIXED_GEAR, val=False, units='unitless') options.set_val(Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, @@ -392,9 +403,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "equip", - EquipAndUsefulLoadMass( - aviary_options=options, - ), + EquipAndUsefulLoadMass(), promotes=["*"], ) @@ -456,6 +465,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, val=0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -477,7 +488,8 @@ class FixedEquipMassTestCase6smooth(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=5, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=5, units='unitless') options.set_val(Aircraft.Engine.TYPE, val=[GASPEngineType.RECIP_CARB], units='unitless') options.set_val(Aircraft.LandingGear.FIXED_GEAR, @@ -488,9 +500,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "equip", - EquipAndUsefulLoadMass( - aviary_options=options - ), + EquipAndUsefulLoadMass(), promotes=["*"], ) @@ -552,6 +562,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, val=0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -575,14 +587,15 @@ class EquipAndUsefulMassGroupTestCase1(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.LandingGear.FIXED_GEAR, val=False, units='unitless') self.prob = om.Problem() self.prob.model.add_subsystem( "group", - EquipAndUsefulLoadMass(aviary_options=options), + EquipAndUsefulLoadMass(), promotes=["*"], ) @@ -646,6 +659,8 @@ def setUp(self): Aircraft.Fuel.WING_FUEL_FRACTION, val=0.6, units="unitless" ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -677,14 +692,15 @@ def tearDown(self): def test_case1(self): options = get_option_defaults() - options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.LandingGear.FIXED_GEAR, val=False, units='unitless') prob = om.Problem() prob.model.add_subsystem( "equip", - EquipAndUsefulLoadMass(aviary_options=options), + EquipAndUsefulLoadMass(), promotes=["*"], ) @@ -737,6 +753,9 @@ def test_case1(self): Aircraft.Engine.SCALED_SLS_THRUST, val=[29500.0], units="lbf") prob.model.set_input_defaults( Aircraft.Fuel.WING_FUEL_FRACTION, val=0.6, units="unitless") + + setup_model_options(prob, options) + prob.setup(check=False, force_alloc_complex=True) partial_data = prob.check_partials(out_stream=None, method="cs") diff --git a/aviary/subsystems/mass/gasp_based/test/test_fixed.py b/aviary/subsystems/mass/gasp_based/test/test_fixed.py index 522d7d469..8a95ece97 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_fixed.py +++ b/aviary/subsystems/mass/gasp_based/test/test_fixed.py @@ -16,6 +16,7 @@ MassParameters, PayloadMass, TailMass) from aviary.utils.aviary_values import AviaryValues, get_keys +from aviary.variable_info.functions import setup_model_options, extract_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission @@ -33,9 +34,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "parameters", - MassParameters( - aviary_options=options - ), + MassParameters(), promotes=["*"], ) @@ -55,6 +54,8 @@ def setUp(self): "max_mach", val=0.9, units="unitless" ) # bug fixed value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -86,9 +87,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "parameters", - MassParameters( - aviary_options=options, - ), + MassParameters(), promotes=["*"], ) @@ -109,6 +108,8 @@ def setUp(self): Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0 ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -141,9 +142,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "parameters", - MassParameters( - aviary_options=options, - ), + MassParameters(), promotes=["*"], ) @@ -164,6 +163,8 @@ def setUp(self): Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0 ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -197,9 +198,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "parameters", - MassParameters( - aviary_options=options, - ), + MassParameters(), promotes=["*"], ) @@ -220,6 +219,8 @@ def setUp(self): Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0 ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -253,9 +254,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "parameters", - MassParameters( - aviary_options=options, - ), + MassParameters(), promotes=["*"], ) @@ -276,6 +275,8 @@ def setUp(self): Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0 ) + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -309,12 +310,13 @@ def setUp(self): val=200, units="lbm") # bug fixed value and original value self.prob = om.Problem() - self.prob.model.add_subsystem("payload", PayloadMass( - aviary_options=options), promotes=["*"]) + self.prob.model.add_subsystem("payload", PayloadMass(), promotes=["*"]) self.prob.model.set_input_defaults( Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" ) # bug fixed value and original value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -340,8 +342,12 @@ class ElectricAugmentationTestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() + + options = { + Aircraft.Propulsion.TOTAL_NUM_ENGINES: 2, + } self.prob.model.add_subsystem( - "aug", ElectricAugmentationMass(aviary_options=get_option_defaults()), promotes=["*"] + "aug", ElectricAugmentationMass(**options), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -392,6 +398,7 @@ def setUp(self): self.prob.model.set_input_defaults( "TMS_spec_mass", val=0.125, units="lbm/kW" ) # electrified diff configuration value v3.6 + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -417,7 +424,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "engine", - EngineMass(aviary_options=options), + EngineMass(), promotes=["*"], ) @@ -455,6 +462,8 @@ def setUp(self): Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0.15, units="unitless" ) # bug fixed value and original value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -491,7 +500,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "engine", - EngineMass(aviary_options=options), + EngineMass(), promotes=["*"], ) @@ -535,6 +544,8 @@ def setUp(self): Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0.15, units="unitless" ) # bug fixed value and original value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -579,7 +590,7 @@ def test_case_1(self): self.prob = om.Problem() self.prob.model.add_subsystem( "engine", - EngineMass(aviary_options=options), + EngineMass(), promotes=["*"], ) @@ -606,6 +617,8 @@ def test_case_1(self): self.prob.model.set_input_defaults( Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0.15, units="unitless") + self.prob.model_options['*'] = extract_options(options) + self.prob.setup(check=False, force_alloc_complex=True) self.prob.run_model() @@ -636,7 +649,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "tail", TailMass(aviary_options=get_option_defaults()), promotes=["*"] + "tail", TailMass(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -735,7 +748,7 @@ def setUp(self): aviary_options.set_val(Aircraft.Wing.NUM_FLAP_SEGMENTS, val=2) self.prob.model.add_subsystem( - "HL", HighLiftMass(aviary_options=aviary_options), promotes=["*"] + "HL", HighLiftMass(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -778,6 +791,8 @@ def setUp(self): Mission.Landing.LIFT_COEFFICIENT_MAX, val=2.3648, units="unitless" ) + setup_model_options(self.prob, aviary_options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -798,8 +813,8 @@ class ControlMassTestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem("payload", ControlMass( - aviary_options=get_option_defaults()), promotes=["*"]) + self.prob.model.add_subsystem("payload", ControlMass(), + promotes=["*"]) self.prob.model.set_input_defaults( Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, val=0.95, units="unitless" @@ -854,7 +869,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "payload", GearMass(aviary_options=get_option_defaults()), promotes=["*"] + "payload", GearMass(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -899,7 +914,7 @@ def setUp(self): options = get_option_defaults() self.prob = om.Problem() self.prob.model.add_subsystem( - "payload", GearMass(aviary_options=options), promotes=["*"] + "payload", GearMass(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -914,6 +929,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Wing.MOUNTING_TYPE, val=0.1, units="unitless") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -941,7 +958,7 @@ def test_case1(self): self.prob = om.Problem() self.prob.model.add_subsystem( "gear_mass", - GearMass(aviary_options=options), + GearMass(), promotes=["*"], ) @@ -952,6 +969,8 @@ def test_case1(self): Aircraft.Nacelle.AVG_DIAMETER, val=[7.5, 8.22], units='ft' ) + self.prob.model_options['*'] = extract_options(options) + self.prob.setup(check=False, force_alloc_complex=True) self.prob.run_model() @@ -979,9 +998,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - FixedMassGroup( - aviary_options=options, - ), + FixedMassGroup(), promotes=["*"], ) @@ -1144,6 +1161,8 @@ def setUp(self): Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0.15, units="unitless" ) # bug fixed value and original value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -1234,9 +1253,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - FixedMassGroup( - aviary_options=options, - ), + FixedMassGroup(), promotes=["*"], ) @@ -1450,6 +1467,8 @@ def setUp(self): "engine.prop_mass", val=0, units="lbm" ) # bug fixed value and original value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -1536,9 +1555,12 @@ def _run_case(self, data): prob = om.Problem() prob.model.add_subsystem( 'fixed_mass', - FixedMassGroup(aviary_options=data), + FixedMassGroup(), promotes=['*'], ) + + setup_model_options(prob, data) + prob.setup(force_alloc_complex=True) for key in get_keys(data): @@ -1682,7 +1704,7 @@ def test_case1(self): if __name__ == "__main__": - unittest.main() + # unittest.main() # test = GearTestCaseMultiengine() - # test = EngineTestCaseMultiEngine() - # test.test_case_1() + test = EngineTestCaseMultiEngine() + test.test_case_1() diff --git a/aviary/subsystems/mass/gasp_based/test/test_fuel.py b/aviary/subsystems/mass/gasp_based/test/test_fuel.py index 6953f8a20..c0592d62b 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_fuel.py +++ b/aviary/subsystems/mass/gasp_based/test/test_fuel.py @@ -19,7 +19,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "wing_calcs", BodyTankCalculations(aviary_options=get_option_defaults(), ), promotes=["*"] + "wing_calcs", BodyTankCalculations(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -76,7 +76,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "wing_calcs", BodyTankCalculations(aviary_options=get_option_defaults(), ), promotes=["*"] + "wing_calcs", BodyTankCalculations(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -134,7 +134,7 @@ def tearDown(self): def test_case1(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "wing_calcs", BodyTankCalculations(aviary_options=get_option_defaults(), ), promotes=["*"] + "wing_calcs", BodyTankCalculations(), promotes=["*"] ) self.prob.model.set_input_defaults( Aircraft.Fuel.WING_VOLUME_DESIGN, val=989.2, units="ft**3") @@ -165,8 +165,9 @@ class FuelAndOEMTestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem("wing_calcs", FuelAndOEMOutputs( - aviary_options=get_option_defaults(), ), promotes=["*"]) + self.prob.model.add_subsystem("wing_calcs", + FuelAndOEMOutputs(), + promotes=["*"]) self.prob.model.set_input_defaults( Aircraft.Fuel.DENSITY, val=6.687, units="lbm/galUS") @@ -229,8 +230,10 @@ def tearDown(self): def test_case1(self): prob = om.Problem() - prob.model.add_subsystem("wing_calcs", FuelAndOEMOutputs( - aviary_options=get_option_defaults(), ), promotes=["*"] + prob.model.add_subsystem( + "wing_calcs", + FuelAndOEMOutputs(), + promotes=["*"] ) prob.model.set_input_defaults( Aircraft.Fuel.DENSITY, val=6.687, units="lbm/galUS") @@ -267,7 +270,9 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "sys_and_fus", FuelSysAndFullFuselageMass(aviary_options=get_option_defaults(), ), promotes=["*"] + "sys_and_fus", + FuelSysAndFullFuselageMass(), + promotes=["*"] ) self.prob.model.set_input_defaults( @@ -320,7 +325,9 @@ def tearDown(self): def test_case1(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "sys_and_fus", FuelSysAndFullFuselageMass(aviary_options=get_option_defaults(), ), promotes=["*"] + "sys_and_fus", + FuelSysAndFullFuselageMass(), + promotes=["*"] ) self.prob.model.set_input_defaults( Mission.Design.GROSS_MASS, val=175400, units="lbm") @@ -351,7 +358,9 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "fus_and_struct", FuselageAndStructMass(aviary_options=get_option_defaults(), ), promotes=["*"] + "fus_and_struct", + FuselageAndStructMass(), + promotes=["*"] ) self.prob.model.set_input_defaults("fus_mass_full", val=102270, units="lbm") @@ -426,7 +435,9 @@ def tearDown(self): def test_case1(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "fus_and_struct", FuselageAndStructMass(aviary_options=get_option_defaults(), ), promotes=["*"] + "fus_and_struct", + FuselageAndStructMass(), + promotes=["*"] ) self.prob.model.set_input_defaults("fus_mass_full", val=102270, units="lbm") @@ -478,8 +489,8 @@ class FuelMassTestCase(unittest.TestCase): # this is the large single aisle 1 V def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem("fuel", FuelMass( - aviary_options=get_option_defaults(), ), promotes=["*"]) + self.prob.model.add_subsystem("fuel", FuelMass(), + promotes=["*"]) self.prob.model.set_input_defaults( Aircraft.Design.STRUCTURE_MASS, val=50461.0, units="lbm") @@ -540,8 +551,7 @@ def tearDown(self): def test_case1(self): prob = om.Problem() - prob.model.add_subsystem("fuel", FuelMass( - aviary_options=get_option_defaults(), ), promotes=["*"]) + prob.model.add_subsystem("fuel", FuelMass(), promotes=["*"]) prob.model.set_input_defaults( Aircraft.Design.STRUCTURE_MASS, val=50461.0, units="lbm") prob.model.set_input_defaults( @@ -578,8 +588,7 @@ class FuelMassGroupTestCase1(unittest.TestCase): def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem("group", FuelMassGroup( - aviary_options=get_option_defaults(), ), promotes=["*"]) + self.prob.model.add_subsystem("group", FuelMassGroup(), promotes=["*"]) # top level self.prob.model.set_input_defaults( @@ -718,8 +727,7 @@ class FuelMassGroupTestCase2( def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem("group", FuelMassGroup( - aviary_options=get_option_defaults(), ), promotes=["*"]) + self.prob.model.add_subsystem("group", FuelMassGroup(), promotes=["*"]) # top level self.prob.model.set_input_defaults( @@ -858,8 +866,7 @@ class FuelMassGroupTestCase3( def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem("group", FuelMassGroup( - aviary_options=get_option_defaults(), ), promotes=["*"]) + self.prob.model.add_subsystem("group", FuelMassGroup(), promotes=["*"]) # top level self.prob.model.set_input_defaults( diff --git a/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py b/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py index 4101e5325..94a671914 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py @@ -7,6 +7,7 @@ from aviary.subsystems.geometry.gasp_based.size_group import SizeGroup from aviary.subsystems.mass.gasp_based.mass_premission import MassPremission from aviary.utils.aviary_values import get_items +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults, is_option from aviary.models.large_single_aisle_1.V3_bug_fixed_IO import ( V3_bug_fixed_non_metadata, V3_bug_fixed_options) @@ -25,9 +26,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "gasp_based_geom", - SizeGroup( - aviary_options=V3_bug_fixed_options, - ), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", @@ -35,9 +34,7 @@ def setUp(self): ) self.prob.model.add_subsystem( "total_mass", - MassPremission( - aviary_options=V3_bug_fixed_options, - ), + MassPremission(), promotes=['*'], ) @@ -56,6 +53,8 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Fuselage.WETTED_AREA_SCALER, val=0.86215, units="unitless") + setup_model_options(self.prob, V3_bug_fixed_options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -174,6 +173,8 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') options.set_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') @@ -194,9 +195,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", @@ -204,9 +203,7 @@ def setUp(self): ) self.prob.model.add_subsystem( "GASP_mass", - MassPremission( - aviary_options=options, - ), + MassPremission(), promotes=["*"], ) @@ -446,6 +443,8 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=0.0, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -563,6 +562,8 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') options.set_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') @@ -583,9 +584,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", @@ -593,9 +592,7 @@ def setUp(self): ) self.prob.model.add_subsystem( "GASP_mass", - MassPremission( - aviary_options=options, - ), + MassPremission(), promotes=["*"], ) @@ -836,6 +833,8 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=0.0, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -943,6 +942,8 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') options.set_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') @@ -963,9 +964,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", @@ -973,9 +972,7 @@ def setUp(self): ) self.prob.model.add_subsystem( "GASP_mass", - MassPremission( - aviary_options=options, - ), + MassPremission(), promotes=["*"], ) @@ -1217,6 +1214,8 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=0.0, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -1324,6 +1323,8 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') options.set_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') @@ -1344,9 +1345,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", @@ -1354,9 +1353,7 @@ def setUp(self): ) self.prob.model.add_subsystem( "GASP_mass", - MassPremission( - aviary_options=options, - ), + MassPremission(), promotes=["*"], ) @@ -1598,6 +1595,8 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=0.0, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -1704,6 +1703,8 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') options.set_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') @@ -1724,9 +1725,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", @@ -1734,9 +1733,7 @@ def setUp(self): ) self.prob.model.add_subsystem( "GASP_mass", - MassPremission( - aviary_options=options, - ), + MassPremission(), promotes=["*"], ) @@ -1978,6 +1975,8 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=0.0, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -2086,6 +2085,8 @@ def setUp(self): options.set_val(Aircraft.Wing.HAS_FOLD, val=True, units='unitless') options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=154, units='unitless') options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=154, units='unitless') options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37100, units='ft') options.set_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, @@ -2105,9 +2106,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", @@ -2115,9 +2114,7 @@ def setUp(self): ) self.prob.model.add_subsystem( "GASP_mass", - MassPremission( - aviary_options=options, - ), + MassPremission(), promotes=["*"], ) @@ -2363,6 +2360,8 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=0.0, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -2474,6 +2473,8 @@ def setUp(self): options.set_val(Aircraft.Wing.HAS_STRUT, val=True, units='unitless') options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=154, units='unitless') options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=154, units='unitless') options.set_val(Mission.Design.CRUISE_ALTITUDE, val=43000, units='ft') options.set_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') @@ -2496,9 +2497,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", @@ -2506,9 +2505,7 @@ def setUp(self): ) self.prob.model.add_subsystem( "GASP_mass", - MassPremission( - aviary_options=options, - ), + MassPremission(), promotes=["*"], ) @@ -2762,6 +2759,8 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=0.0, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -2868,6 +2867,8 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.Wing.HAS_FOLD, val=True, units='unitless') options.set_val(Aircraft.Wing.HAS_STRUT, val=True, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=154, units='unitless') options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=154, units='unitless') options.set_val(Mission.Design.CRUISE_ALTITUDE, val=43000, units='ft') options.set_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') @@ -2890,9 +2891,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "size", - SizeGroup( - aviary_options=options, - ), + SizeGroup(), promotes_inputs=["aircraft:*", "mission:*"], promotes_outputs=[ "aircraft:*", @@ -2900,9 +2899,7 @@ def setUp(self): ) self.prob.model.add_subsystem( "GASP_mass", - MassPremission( - aviary_options=options, - ), + MassPremission(), promotes=["*"], ) @@ -3201,6 +3198,8 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=0.0, units="ft") + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): diff --git a/aviary/subsystems/mass/gasp_based/test/test_wing.py b/aviary/subsystems/mass/gasp_based/test/test_wing.py index 43f481488..3c9fbbcd7 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_wing.py +++ b/aviary/subsystems/mass/gasp_based/test/test_wing.py @@ -6,6 +6,7 @@ from aviary.subsystems.mass.gasp_based.wing import (WingMassGroup, WingMassSolve, WingMassTotal) +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission @@ -16,8 +17,8 @@ class WingMassSolveTestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem("wingfuel", WingMassSolve( - aviary_options=get_option_defaults()), promotes=["*"]) + self.prob.model.add_subsystem("wingfuel", WingMassSolve(), + promotes=["*"]) self.prob.model.set_input_defaults( Mission.Design.GROSS_MASS, val=175400, units="lbm" @@ -86,8 +87,8 @@ def tearDown(self): def test_case1(self): prob = om.Problem() - prob.model.add_subsystem("wingfuel", WingMassSolve( - aviary_options=get_option_defaults()), promotes=["*"]) + prob.model.add_subsystem("wingfuel", WingMassSolve(), + promotes=["*"]) prob.model.set_input_defaults( Mission.Design.GROSS_MASS, val=175400, units="lbm") prob.model.set_input_defaults( @@ -138,7 +139,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "total", - WingMassTotal(aviary_options=get_option_defaults()), + WingMassTotal(), promotes=["*"], ) @@ -171,7 +172,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "total", - WingMassTotal(aviary_options=options), + WingMassTotal(), promotes=["*"], ) @@ -187,6 +188,8 @@ def setUp(self): Aircraft.Wing.FOLD_MASS_COEFFICIENT, val=0.2, units="unitless" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -215,7 +218,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "total", - WingMassTotal(aviary_options=options), + WingMassTotal(), promotes=["*"], ) @@ -225,6 +228,8 @@ def setUp(self): Aircraft.Strut.MASS_COEFFICIENT, val=0.5, units="unitless" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -253,7 +258,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "total", WingMassTotal(aviary_options=options), promotes=["*"] + "total", WingMassTotal(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -271,6 +276,8 @@ def setUp(self): Aircraft.Strut.MASS_COEFFICIENT, val=0.5, units="unitless" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -304,7 +311,7 @@ def test_case1(self): prob = om.Problem() prob.model.add_subsystem( "total", - WingMassTotal(aviary_options=get_option_defaults()), + WingMassTotal(), promotes=["*"], ) prob.model.set_input_defaults( @@ -335,7 +342,7 @@ def test_case1(self): self.prob = om.Problem() self.prob.model.add_subsystem( "total", - WingMassTotal(aviary_options=options), + WingMassTotal(), promotes=["*"], ) self.prob.model.set_input_defaults( @@ -346,6 +353,9 @@ def test_case1(self): Aircraft.Wing.FOLDING_AREA, val=50, units="ft**2") self.prob.model.set_input_defaults( Aircraft.Wing.FOLD_MASS_COEFFICIENT, val=0.2, units="unitless") + + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) partial_data = self.prob.check_partials(out_stream=None, method="cs") @@ -372,13 +382,16 @@ def test_case1(self): prob = om.Problem() prob.model.add_subsystem( "total", - WingMassTotal(aviary_options=options), + WingMassTotal(), promotes=["*"], ) prob.model.set_input_defaults( "isolated_wing_mass", val=15830.0, units="lbm") prob.model.set_input_defaults( Aircraft.Strut.MASS_COEFFICIENT, val=0.5, units="unitless") + + setup_model_options(prob, options) + prob.setup(check=False, force_alloc_complex=True) partial_data = prob.check_partials(out_stream=None, method="cs") @@ -405,7 +418,7 @@ def test_case1(self): options.set_val(Aircraft.Wing.HAS_STRUT, val=True, units='unitless') prob = om.Problem() prob.model.add_subsystem( - "total", WingMassTotal(aviary_options=options), promotes=["*"]) + "total", WingMassTotal(), promotes=["*"]) prob.model.set_input_defaults( "isolated_wing_mass", val=15830.0, units="lbm") prob.model.set_input_defaults( @@ -416,6 +429,9 @@ def test_case1(self): Aircraft.Wing.FOLD_MASS_COEFFICIENT, val=0.2, units="unitless") prob.model.set_input_defaults( Aircraft.Strut.MASS_COEFFICIENT, val=0.5, units="unitless") + + setup_model_options(prob, options) + prob.setup(check=False, force_alloc_complex=True) partial_data = prob.check_partials(out_stream=None, method="cs") @@ -430,7 +446,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - WingMassGroup(aviary_options=get_option_defaults()), + WingMassGroup(), promotes=["*"], ) @@ -485,7 +501,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - WingMassGroup(aviary_options=options), + WingMassGroup(), promotes=["*"], ) @@ -526,6 +542,8 @@ def setUp(self): Aircraft.Wing.FOLD_MASS_COEFFICIENT, val=0.2, units="unitless" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -551,7 +569,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "group", - WingMassGroup(aviary_options=options), + WingMassGroup(), promotes=["*"], ) @@ -586,6 +604,8 @@ def setUp(self): Aircraft.Strut.MASS_COEFFICIENT, val=0.5, units="unitless" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): @@ -611,7 +631,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "group", WingMassGroup(aviary_options=options), promotes=["*"] + "group", WingMassGroup(), promotes=["*"] ) self.prob.model.set_input_defaults( @@ -654,6 +674,8 @@ def setUp(self): Aircraft.Strut.MASS_COEFFICIENT, val=0.5, units="unitless" ) # not actual GASP value + setup_model_options(self.prob, options) + self.prob.setup(check=False, force_alloc_complex=True) def test_case1(self): diff --git a/aviary/subsystems/mass/gasp_based/wing.py b/aviary/subsystems/mass/gasp_based/wing.py index 0c9954abb..6eb3eada8 100644 --- a/aviary/subsystems/mass/gasp_based/wing.py +++ b/aviary/subsystems/mass/gasp_based/wing.py @@ -2,26 +2,21 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission class WingMassSolve(om.ImplicitComponent): """ - Computation of isolated wing mass, namely wing mass including high lift devices + Computation of isolated wing mass, namely wing mass including high lift devices (but excluding struts and fold effects) using a nonlinear solver. """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) add_aviary_input(self, Mission.Design.GROSS_MASS, val=175400) add_aviary_input(self, Aircraft.Wing.HIGH_LIFT_MASS, val=3645) @@ -298,11 +293,8 @@ class WingMassTotal(om.ExplicitComponent): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.HAS_FOLD) + add_aviary_option(self, Aircraft.Wing.HAS_STRUT) def setup(self): @@ -313,11 +305,10 @@ def setup(self): desc="WW: wing mass including high lift devices (but excluding struts and fold effects)", ) - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): + if self.options[Aircraft.Wing.HAS_STRUT]: add_aviary_input(self, Aircraft.Strut.MASS_COEFFICIENT, val=0.000000000001) - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless') == True: - + if self.options[Aircraft.Wing.HAS_FOLD]: add_aviary_input(self, Aircraft.Wing.AREA, val=100) add_aviary_input(self, Aircraft.Wing.FOLDING_AREA, val=50) add_aviary_input(self, Aircraft.Wing.FOLD_MASS_COEFFICIENT, val=0.2) @@ -327,10 +318,10 @@ def setup(self): add_aviary_output(self, Aircraft.Wing.FOLD_MASS, val=0) self.declare_partials(Aircraft.Wing.MASS, "*") - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): + if self.options[Aircraft.Wing.HAS_STRUT]: self.declare_partials(Aircraft.Strut.MASS, [ Aircraft.Strut.MASS_COEFFICIENT, "isolated_wing_mass"]) - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless'): + if self.options[Aircraft.Wing.HAS_FOLD]: self.declare_partials(Aircraft.Wing.FOLD_MASS, [ Aircraft.Wing.AREA, Aircraft.Wing.FOLDING_AREA, Aircraft.Wing.FOLD_MASS_COEFFICIENT, "isolated_wing_mass"]) @@ -338,7 +329,7 @@ def compute(self, inputs, outputs): isolated_wing_wt = inputs["isolated_wing_mass"] * GRAV_ENGLISH_LBM - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): + if self.options[Aircraft.Wing.HAS_STRUT]: c_strut_mass = inputs[Aircraft.Strut.MASS_COEFFICIENT] strut_wt = c_strut_mass * isolated_wing_wt @@ -347,7 +338,7 @@ def compute(self, inputs, outputs): else: outputs[Aircraft.Strut.MASS] = strut_wt = 0 - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless'): + if self.options[Aircraft.Wing.HAS_FOLD]: wing_area = inputs[Aircraft.Wing.AREA] folding_area = inputs[Aircraft.Wing.FOLDING_AREA] c_wing_fold = inputs[Aircraft.Wing.FOLD_MASS_COEFFICIENT] @@ -367,7 +358,7 @@ def compute_partials(self, inputs, J): isolated_wing_wt = inputs["isolated_wing_mass"] * GRAV_ENGLISH_LBM - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): + if self.options[Aircraft.Wing.HAS_STRUT]: c_strut_mass = inputs[Aircraft.Strut.MASS_COEFFICIENT] J[Aircraft.Wing.MASS, Aircraft.Strut.MASS_COEFFICIENT] = \ @@ -376,7 +367,7 @@ def compute_partials(self, inputs, J): J[Aircraft.Wing.MASS, "isolated_wing_mass"] = 1 + c_strut_mass J[Aircraft.Strut.MASS, "isolated_wing_mass"] = c_strut_mass - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless'): + if self.options[Aircraft.Wing.HAS_FOLD]: wing_area = inputs[Aircraft.Wing.AREA] folding_area = inputs[Aircraft.Wing.FOLDING_AREA] c_wing_fold = inputs[Aircraft.Wing.FOLD_MASS_COEFFICIENT] @@ -400,17 +391,16 @@ def compute_partials(self, inputs, J): J[Aircraft.Wing.FOLD_MASS, "isolated_wing_mass"] = c_wing_fold * \ folding_area / wing_area - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless') and \ - self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): + if self.options[Aircraft.Wing.HAS_FOLD] and \ + self.options[Aircraft.Wing.HAS_STRUT]: J[Aircraft.Wing.MASS, "isolated_wing_mass"] = ( 1 + c_wing_fold * folding_area / wing_area + c_strut_mass ) if ( - self.options["aviary_options"].get_val( - Aircraft.Wing.HAS_STRUT, units='unitless') == False - and self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless') == False + self.options[Aircraft.Wing.HAS_STRUT] == False + and self.options[Aircraft.Wing.HAS_FOLD] == False ): J[Aircraft.Wing.MASS, "isolated_wing_mass"] = 1 @@ -421,24 +411,19 @@ class WingMassGroup(om.Group): """ def initialize(self): - - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) + add_aviary_option(self, Aircraft.Wing.HAS_FOLD) + add_aviary_option(self, Aircraft.Wing.HAS_STRUT) def setup(self): - aviary_options = self.options['aviary_options'] - # variables that are calculated at a higher level higher_level_inputs_isolated = [ "c_strut_braced", "c_gear_loc", "half_sweep", ] - if self.options["aviary_options"].get_val(Aircraft.Wing.HAS_FOLD, units='unitless') or \ - self.options["aviary_options"].get_val(Aircraft.Wing.HAS_STRUT, units='unitless'): + if self.options[Aircraft.Wing.HAS_FOLD] or \ + self.options[Aircraft.Wing.HAS_STRUT]: higher_level_inputs_total = [ "aircraft:*" @@ -456,16 +441,14 @@ def setup(self): isolated_mass = self.add_subsystem( "isolated_mass", - WingMassSolve(aviary_options=aviary_options), + WingMassSolve(), promotes_inputs=higher_level_inputs_isolated + ["aircraft:*", "mission:*"], promotes_outputs=connected_outputs_isolated, ) total_mass = self.add_subsystem( "total_mass", - WingMassTotal( - aviary_options=aviary_options, - ), + WingMassTotal(), promotes_inputs=connected_inputs_total + higher_level_inputs_total, promotes_outputs=["aircraft:*"], ) diff --git a/aviary/subsystems/mass/mass_builder.py b/aviary/subsystems/mass/mass_builder.py index 07ee3a0df..772a9b838 100644 --- a/aviary/subsystems/mass/mass_builder.py +++ b/aviary/subsystems/mass/mass_builder.py @@ -59,10 +59,10 @@ def build_pre_mission(self, aviary_inputs): code_origin = self.code_origin if code_origin is GASP: - mass_premission = MassPremissionGASP(aviary_options=aviary_inputs,) + mass_premission = MassPremissionGASP() elif code_origin is FLOPS: - mass_premission = MassPremissionFLOPS(aviary_options=aviary_inputs) + mass_premission = MassPremissionFLOPS() return mass_premission diff --git a/aviary/subsystems/mass/test/test_flops_mass_builder.py b/aviary/subsystems/mass/test/test_flops_mass_builder.py index 2e9b0ee98..98b152507 100644 --- a/aviary/subsystems/mass/test/test_flops_mass_builder.py +++ b/aviary/subsystems/mass/test/test_flops_mass_builder.py @@ -26,9 +26,12 @@ def setUp(self): 'test_core_mass', meta_data=BaseMetaData, code_origin=FLOPS) self.aviary_values = av.AviaryValues() self.aviary_values.set_val(Aircraft.Design.USE_ALT_MASS, False, units='unitless') - self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') self.aviary_values.set_val( - Aircraft.Engine.NUM_WING_ENGINES, [2], units='unitless') + Aircraft.Engine.NUM_ENGINES, np.array([1]), units='unitless' + ) + self.aviary_values.set_val( + Aircraft.Engine.NUM_WING_ENGINES, np.array([2]), units='unitless' + ) class TestFLOPSMassBuilderAltMass(av.TestSubsystemBuilderBase): @@ -43,9 +46,12 @@ def setUp(self): 'test_core_mass', meta_data=BaseMetaData, code_origin=FLOPS) self.aviary_values = av.AviaryValues() self.aviary_values.set_val(Aircraft.Design.USE_ALT_MASS, True, units='unitless') - self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') self.aviary_values.set_val( - Aircraft.Engine.NUM_WING_ENGINES, [2], units='unitless') + Aircraft.Engine.NUM_ENGINES, np.array([1]), units='unitless' + ) + self.aviary_values.set_val( + Aircraft.Engine.NUM_WING_ENGINES, np.array([2]), units='unitless' + ) if __name__ == '__main__': diff --git a/aviary/subsystems/propulsion/engine_deck.py b/aviary/subsystems/propulsion/engine_deck.py index 6ec669cb1..fa4fd1014 100644 --- a/aviary/subsystems/propulsion/engine_deck.py +++ b/aviary/subsystems/propulsion/engine_deck.py @@ -100,7 +100,6 @@ # EngineDecks internally require these options to have values. Input checks will set # these options to default values in self.options if they are not provided -# TODO should this instead be a set to prevent duplicates? required_options = ( Aircraft.Engine.SCALE_PERFORMANCE, Aircraft.Engine.IGNORE_NEGATIVE_THRUST, @@ -109,7 +108,7 @@ # TODO fuel flow scaler is required for the EngineScaling component but does not need # to be defined on a per-engine basis, so it could exist only in the problem- # level aviary_options without issue. Is this a propulsion_preprocessor task? - Mission.Summary.FUEL_FLOW_SCALER + Mission.Summary.FUEL_FLOW_SCALER, ) # options that are only required based on the value of another option @@ -146,9 +145,14 @@ class EngineDeck(EngineModel): update """ - def __init__(self, name='engine_deck', options: AviaryValues = None, - data: NamedValues = None, - required_variables: set = default_required_variables): + def __init__( + self, + name='engine_deck', + options: AviaryValues = None, + data: NamedValues = None, + required_variables: set = default_required_variables, + meta_data: dict = _MetaData, + ): if data is not None: self.read_from_file = False else: @@ -156,7 +160,7 @@ def __init__(self, name='engine_deck', options: AviaryValues = None, # TODO update default name to be based on filename # also calls _preprocess_inputs() as part of EngineModel __init__ - super().__init__(name, options) + super().__init__(name, options, meta_data=meta_data) # copy of raw data read from data_file or memory, never modified or used outside # EngineDeck @@ -180,12 +184,20 @@ def __init__(self, name='engine_deck', options: AviaryValues = None, # Create dict for variables present in engine data with associated units self.engine_variables = {} - # TODO make this an option - disabling global throttle ranges is better to - # prevent unintended extrapolation, but breaks missions using GASP-based - # engines that have uneven throttle ranges (need t4 constraint on mission - # to truly fix) - self.global_throttle = True - self.global_hybrid_throttle = True + if Aircraft.Engine.GLOBAL_THROTTLE in options: + self.global_throttle = self.options.get_val(Aircraft.Engine.GLOBAL_THROTTLE) + else: + default = meta_data[Aircraft.Engine.GLOBAL_THROTTLE]['default_value'] + self.options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, default) + self.global_throttle = default + if Aircraft.Engine.GLOBAL_HYBRID_THROTTLE in options: + self.global_hybrid_throttle = self.options.get_val( + Aircraft.Engine.GLOBAL_HYBRID_THROTTLE + ) + else: + default = meta_data[Aircraft.Engine.GLOBAL_HYBRID_THROTTLE]['default_value'] + self.options.set_val(Aircraft.Engine.GLOBAL_HYBRID_THROTTLE, default) + self.global_hybrid_throttle = default # ensure required variables are a set self.required_variables = {*required_variables} @@ -216,8 +228,8 @@ def _preprocess_inputs(self): for key in additional_options + required_options: if key not in options: - val = _MetaData[key]['default_value'] - units = _MetaData[key]['units'] + val = self.meta_data[key]['default_value'] + units = self.meta_data[key]['units'] if self.get_val(Settings.VERBOSITY) >= Verbosity.BRIEF: warnings.warn( @@ -232,8 +244,8 @@ def _preprocess_inputs(self): if self.get_val(key): for item in dependent_options[key]: if item not in options: - val = _MetaData[item]['default_value'] - units = _MetaData[item]['units'] + val = self.meta_data[item]['default_value'] + units = self.meta_data[item]['units'] self.set_val(item, val, units) # LOGIC CHECKS @@ -772,7 +784,7 @@ def build_pre_mission(self, aviary_inputs) -> om.ExplicitComponent: scaling factors. """ - return SizeEngine(aviary_options=self.options) + return SizeEngine() def _build_engine_interpolator(self, num_nodes, aviary_inputs): """ @@ -881,14 +893,18 @@ def build_mission(self, num_nodes, aviary_inputs) -> om.Group: alt_table, packed_data[ALTITUDE][M, A, 0]) # add inputs and outputs to interpolator - interp_throttles.add_input(Dynamic.Mission.MACH, - mach_table, - units='unitless', - desc='Current flight Mach number') - interp_throttles.add_input(Dynamic.Mission.ALTITUDE, - alt_table, - units=units[ALTITUDE], - desc='Current flight altitude') + interp_throttles.add_input( + Dynamic.Atmosphere.MACH, + mach_table, + units='unitless', + desc='Current flight Mach number', + ) + interp_throttles.add_input( + Dynamic.Mission.ALTITUDE, + alt_table, + units=units[ALTITUDE], + desc='Current flight altitude', + ) if not self.global_throttle: interp_throttles.add_output('throttle_max', self.throttle_max, @@ -907,14 +923,18 @@ def build_mission(self, num_nodes, aviary_inputs) -> om.Group: max_thrust_engine = om.MetaModelSemiStructuredComp( method=interp_method, extrapolate=False, vec_size=num_nodes) - max_thrust_engine.add_input(Dynamic.Mission.MACH, - self.data[MACH], - units='unitless', - desc='Current flight Mach number') - max_thrust_engine.add_input(Dynamic.Mission.ALTITUDE, - self.data[ALTITUDE], - units=units[ALTITUDE], - desc='Current flight altitude') + max_thrust_engine.add_input( + Dynamic.Atmosphere.MACH, + self.data[MACH], + units='unitless', + desc='Current flight Mach number', + ) + max_thrust_engine.add_input( + Dynamic.Mission.ALTITUDE, + self.data[ALTITUDE], + units=units[ALTITUDE], + desc='Current flight altitude', + ) # replace throttle coming from mission with max value based on flight condition max_thrust_engine.add_input('throttle_max', self.data[THROTTLE], @@ -946,7 +966,7 @@ def build_mission(self, num_nodes, aviary_inputs) -> om.Group: # add created subsystems to engine_group outputs = [] if getattr(self, 'use_t4', False): - outputs.append(Dynamic.Mission.TEMPERATURE_T4) + outputs.append(Dynamic.Vehicle.Propulsion.TEMPERATURE_T4) engine_group.add_subsystem('interpolation', engine, @@ -960,11 +980,11 @@ def build_mission(self, num_nodes, aviary_inputs) -> om.Group: uncorrect_shp = True engine_group.add_subsystem( 'uncorrect_shaft_power', - subsys=UncorrectData(num_nodes=num_nodes, aviary_options=self.options), + subsys=UncorrectData(num_nodes=num_nodes), promotes_inputs=[ - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.STATIC_PRESSURE, - Dynamic.Mission.MACH, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, + Dynamic.Atmosphere.MACH, ], ) @@ -994,12 +1014,12 @@ def build_mission(self, num_nodes, aviary_inputs) -> om.Group: engine_group.add_subsystem( 'uncorrect_max_shaft_power', subsys=UncorrectData( - num_nodes=num_nodes, aviary_options=self.options + num_nodes=num_nodes, ), promotes_inputs=[ - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.STATIC_PRESSURE, - Dynamic.Mission.MACH, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, + Dynamic.Atmosphere.MACH, ], ) @@ -1015,10 +1035,9 @@ def build_mission(self, num_nodes, aviary_inputs) -> om.Group: 'engine_scaling', subsys=EngineScaling( num_nodes=num_nodes, - aviary_options=self.options, engine_variables=engine_outputs, ), - promotes_inputs=[Aircraft.Engine.SCALE_FACTOR, Dynamic.Mission.MACH], + promotes_inputs=[Aircraft.Engine.SCALE_FACTOR, Dynamic.Atmosphere.MACH], promotes_outputs=['*'], ) @@ -1058,7 +1077,13 @@ def build_mission(self, num_nodes, aviary_inputs) -> om.Group: return engine_group def get_parameters(self): - params = {Aircraft.Engine.SCALE_FACTOR: {'static_target': True}} + params = { + Aircraft.Engine.SCALE_FACTOR: { + 'val': 1.0, + 'units': 'unitless', + 'static_target': True, + } + } return params def report(self, problem, reports_file, **kwargs): diff --git a/aviary/subsystems/propulsion/engine_model.py b/aviary/subsystems/propulsion/engine_model.py index c2200da2f..51caaf07f 100644 --- a/aviary/subsystems/propulsion/engine_model.py +++ b/aviary/subsystems/propulsion/engine_model.py @@ -39,9 +39,8 @@ class EngineModel(SubsystemBuilderBase): default_name = 'engine_model' - def __init__( - self, name: str = None, options: AviaryValues = None, meta_data: dict = None, - ): + def __init__(self, name: str = None, options: AviaryValues = None, + meta_data: dict = None, **kwargs): super().__init__(name, meta_data=meta_data) if options is not None: self.options = options.deepcopy() @@ -146,27 +145,28 @@ def _preprocess_inputs(self): # if val is multidimensional, raise error if isinstance(val[0], (list, np.ndarray, tuple)): - raise UserWarning(f'Multidimensional {type(val)} was given ' - f'for variable {key} in EngineModel ' - f'<{self.name}>, but ' - f"{type(self.meta_data[key]['default_value'])} " - 'was expected.') + raise UserWarning( + f'Multidimensional {type(val)} was given for variable ' + f'{key} in EngineModel <{self.name}>, but ' + f"{type(self.meta_data[key]['default_value'])} " + 'was expected.' + ) # use first item in val and warn user if verbosity >= 1: if len(val) > 1: warnings.warn( f'The value of {key} passed to EngineModel ' - f'<{self.name}> is {type(val)}. Only the first entry in ' - 'this iterable will be used.') + f'<{self.name}> is {type(val)}. Only the first ' + 'entry in this iterable will be used.') # if val is supposed to be an iterable... else: # but val is multidimensional, use first item and warn user if isinstance(val[0], (list, np.ndarray, tuple)): warnings.warn( - f'The value of {key} passed to EngineModel <{self.name}> ' - f'is multidimensional {type(val)}. Only the first entry ' - 'in this iterable will be used.') + f'The value of {key} passed to EngineModel ' + f'<{self.name}> is multidimensional {type(val)}. Only ' + 'the first entry in this iterable will be used.') # and val is 1-D, then it is ok! else: continue diff --git a/aviary/subsystems/propulsion/engine_scaling.py b/aviary/subsystems/propulsion/engine_scaling.py index 2366aff8a..d6ba7df44 100644 --- a/aviary/subsystems/propulsion/engine_scaling.py +++ b/aviary/subsystems/propulsion/engine_scaling.py @@ -1,9 +1,8 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.subsystems.propulsion.utils import EngineModelVariables, max_variables -from aviary.variable_info.functions import add_aviary_input +from aviary.variable_info.functions import add_aviary_input, add_aviary_option from aviary.variable_info.variables import Aircraft, Dynamic, Mission @@ -39,25 +38,32 @@ class EngineScaling(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - self.options.declare( 'engine_variables', types=dict, desc='dict of variables to be scaled for this engine with units', ) + add_aviary_option(self, Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, units='lbm/h') + add_aviary_option(self, Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM) + add_aviary_option(self, Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM) + add_aviary_option(self, Aircraft.Engine.SCALE_PERFORMANCE) + add_aviary_option(self, Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER) + add_aviary_option(self, Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER) + add_aviary_option(self, Mission.Summary.FUEL_FLOW_SCALER) + def setup(self): nn = self.options['num_nodes'] - options: AviaryValues = self.options['aviary_options'] engine_variables = self.options['engine_variables'] add_aviary_input(self, Aircraft.Engine.SCALE_FACTOR, val=1.0) - self.add_input(Dynamic.Mission.MACH, val=np.zeros(nn), - desc='current Mach number', units='unitless') + self.add_input( + Dynamic.Atmosphere.MACH, + val=np.zeros(nn), + desc='current Mach number', + units='unitless', + ) # loop through all variables, special handling for fuel flow to output negative version # add outputs for 'max' counterpart of variables that have them @@ -71,7 +77,7 @@ def setup(self): if variable is FUEL_FLOW: self.add_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, val=np.zeros(nn), units=engine_variables[variable], ) @@ -96,24 +102,21 @@ def setup(self): ) def compute(self, inputs, outputs): - nn = self.options['num_nodes'] - options: AviaryValues = self.options['aviary_options'] - engine_variables = self.options['engine_variables'] - scale_performance = options.get_val(Aircraft.Engine.SCALE_PERFORMANCE) - - subsonic_fuel_factor = options.get_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER) - supersonic_fuel_factor = options.get_val( - Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER) - constant_fuel_term = options.get_val( - Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM) - linear_fuel_term = options.get_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM) - constant_fuel_flow = options.get_val( - Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, units='lbm/h') - mission_fuel_scaler = options.get_val(Mission.Summary.FUEL_FLOW_SCALER) + options = self.options + nn = options['num_nodes'] + engine_variables = options['engine_variables'] + scale_performance = options[Aircraft.Engine.SCALE_PERFORMANCE] + + subsonic_fuel_factor = options[Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER] + supersonic_fuel_factor = options[Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER] + constant_fuel_term = options[Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM] + linear_fuel_term = options[Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM] + constant_fuel_flow, _ = options[Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION] + mission_fuel_scaler = options[Mission.Summary.FUEL_FLOW_SCALER] # thrust-based engine scaling factor engine_scale_factor = inputs[Aircraft.Engine.SCALE_FACTOR] - mach_number = inputs[Dynamic.Mission.MACH] + mach_number = inputs[Dynamic.Atmosphere.MACH] scale_factor = 1 fuel_flow_scale_factor = np.ones(nn, dtype=engine_scale_factor.dtype) @@ -144,7 +147,7 @@ def compute(self, inputs, outputs): for variable in engine_variables: if variable not in skip_variables: if variable is FUEL_FLOW: - outputs[Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE] = -( + outputs[Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE] = -( inputs['fuel_flow_rate_unscaled'] * fuel_flow_scale_factor + constant_fuel_flow ) @@ -170,13 +173,13 @@ def setup_partials(self): if variable not in skip_variables: if variable is FUEL_FLOW: self.declare_partials( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, Aircraft.Engine.SCALE_FACTOR, rows=r, cols=c, ) self.declare_partials( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, 'fuel_flow_rate_unscaled', rows=r, cols=r, @@ -210,20 +213,18 @@ def setup_partials(self): ) def compute_partials(self, inputs, J): - nn = self.options['num_nodes'] - options: AviaryValues = self.options['aviary_options'] - engine_variables = self.options['engine_variables'] - scale_performance = options.get_val(Aircraft.Engine.SCALE_PERFORMANCE) - - subsonic_fuel_factor = options.get_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER) - supersonic_fuel_factor = options.get_val( - Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER) - constant_fuel_term = options.get_val( - Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, units='unitless') - linear_fuel_term = options.get_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM) - mission_fuel_scaler = options.get_val(Mission.Summary.FUEL_FLOW_SCALER) - - mach_number = inputs[Dynamic.Mission.MACH] + options = self.options + nn = options['num_nodes'] + engine_variables = options['engine_variables'] + scale_performance = options[Aircraft.Engine.SCALE_PERFORMANCE] + + subsonic_fuel_factor = options[Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER] + supersonic_fuel_factor = options[Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER] + constant_fuel_term = options[Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM] + linear_fuel_term = options[Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM] + mission_fuel_scaler = options[Mission.Summary.FUEL_FLOW_SCALER] + + mach_number = inputs[Dynamic.Atmosphere.MACH] engine_scale_factor = inputs[Aircraft.Engine.SCALE_FACTOR] # determine which mach-based fuel flow scaler is applied at each node @@ -270,11 +271,11 @@ def compute_partials(self, inputs, J): if variable not in skip_variables: if variable is FUEL_FLOW: J[ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, 'fuel_flow_rate_unscaled', ] = fuel_flow_deriv J[ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, Aircraft.Engine.SCALE_FACTOR, ] = fuel_flow_scale_deriv else: diff --git a/aviary/subsystems/propulsion/engine_sizing.py b/aviary/subsystems/propulsion/engine_sizing.py index 379c5272b..a2dd7aab4 100644 --- a/aviary/subsystems/propulsion/engine_sizing.py +++ b/aviary/subsystems/propulsion/engine_sizing.py @@ -1,8 +1,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft @@ -16,14 +15,13 @@ class SizeEngine(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.REFERENCE_SLS_THRUST, units='lbf') + add_aviary_option(self, Aircraft.Engine.SCALE_PERFORMANCE) def setup(self): - add_aviary_input(self, Aircraft.Engine.SCALED_SLS_THRUST, val=0.0) + add_aviary_input(self, Aircraft.Engine.SCALE_FACTOR, val=1.0) - add_aviary_output(self, Aircraft.Engine.SCALE_FACTOR, val=0.0) + add_aviary_output(self, Aircraft.Engine.SCALED_SLS_THRUST, val=0.0) # variables that also may require scaling # TODO - inlet_weight @@ -34,36 +32,32 @@ def setup(self): # TODO - nacelle_wetted_area: if length, diam get scaled - this should be covered by geom def compute(self, inputs, outputs): - options: AviaryValues = self.options['aviary_options'] - scale_engine = options.get_val(Aircraft.Engine.SCALE_PERFORMANCE) + scale_engine = self.options[Aircraft.Engine.SCALE_PERFORMANCE] + reference_sls_thrust, _ = self.options[Aircraft.Engine.REFERENCE_SLS_THRUST] - reference_sls_thrust = options.get_val(Aircraft.Engine.REFERENCE_SLS_THRUST, - units='lbf') - - scaled_sls_thrust = inputs[Aircraft.Engine.SCALED_SLS_THRUST] + engine_scale_factor = inputs[Aircraft.Engine.SCALE_FACTOR] # Engine is only scaled if required # engine scale factor is ratio of scaled thrust target and reference thrust - engine_scale_factor = 1 if scale_engine: - engine_scale_factor = scaled_sls_thrust / reference_sls_thrust + scaled_sls_thrust = engine_scale_factor * reference_sls_thrust + else: + scaled_sls_thrust = reference_sls_thrust - outputs[Aircraft.Engine.SCALE_FACTOR] = engine_scale_factor + outputs[Aircraft.Engine.SCALED_SLS_THRUST] = scaled_sls_thrust def setup_partials(self): - self.declare_partials(Aircraft.Engine.SCALE_FACTOR, - Aircraft.Engine.SCALED_SLS_THRUST) - - def compute_partials(self, inputs, J): - options: AviaryValues = self.options['aviary_options'] - scale_engine = options.get_val(Aircraft.Engine.SCALE_PERFORMANCE) - reference_sls_thrust = options.get_val( - Aircraft.Engine.REFERENCE_SLS_THRUST, units='lbf') + scale_engine = self.options[Aircraft.Engine.SCALE_PERFORMANCE] - deriv_scale_factor = 0 if scale_engine: - deriv_scale_factor = 1.0 / reference_sls_thrust + self.declare_partials( + Aircraft.Engine.SCALED_SLS_THRUST, Aircraft.Engine.SCALE_FACTOR + ) + + def compute_partials(self, inputs, J): + reference_sls_thrust, _ = self.options[Aircraft.Engine.REFERENCE_SLS_THRUST] - J[Aircraft.Engine.SCALE_FACTOR, - Aircraft.Engine.SCALED_SLS_THRUST] = deriv_scale_factor + J[Aircraft.Engine.SCALED_SLS_THRUST, Aircraft.Engine.SCALE_FACTOR] = ( + reference_sls_thrust + ) diff --git a/aviary/subsystems/propulsion/gearbox/gearbox_builder.py b/aviary/subsystems/propulsion/gearbox/gearbox_builder.py index f62e88b24..84d0b2dc7 100644 --- a/aviary/subsystems/propulsion/gearbox/gearbox_builder.py +++ b/aviary/subsystems/propulsion/gearbox/gearbox_builder.py @@ -6,15 +6,15 @@ class GearboxBuilder(SubsystemBuilderBase): """ - Define the builder for a single gearbox subsystem that provides methods - to define the gearbox subsystem's states, design variables, fixed values, - initial guesses, and mass names. It also provides methods to build OpenMDAO - systems for the pre-mission and mission computations of the subsystem, + Define the builder for a single gearbox subsystem that provides methods + to define the gearbox subsystem's states, design variables, fixed values, + initial guesses, and mass names. It also provides methods to build OpenMDAO + systems for the pre-mission and mission computations of the subsystem, to get the constraints for the subsystem, and to preprocess the inputs for - the subsystem. + the subsystem. - This is meant to be computations for a single gearbox, so there is no notion - of "num_gearboxs" in this code. + This is meant to be computations for a single gearbox, so there is no notion + of "num_gearboxes" in this code. This is a reduction gearbox, so gear ratio is input_RPM/output_RPM. """ @@ -26,32 +26,31 @@ def __init__(self, name='gearbox', include_constraints=True): def build_pre_mission(self, aviary_inputs): """Builds an OpenMDAO system for the pre-mission computations of the subsystem.""" - return GearboxPreMission(aviary_inputs=aviary_inputs, simple_mass=True) + return GearboxPreMission(simple_mass=True) def build_mission(self, num_nodes, aviary_inputs): """Builds an OpenMDAO system for the mission computations of the subsystem.""" - return GearboxMission(num_nodes=num_nodes, aviary_inputs=aviary_inputs) + return GearboxMission(num_nodes=num_nodes) def get_design_vars(self): """ Design vars are only tested to see if they exist in pre_mission - Returns a dictionary of design variables for the gearbox subsystem, where the keys are the - names of the design variables, and the values are dictionaries that contain the units for - the design variable, the lower and upper bounds for the design variable, and any + Returns a dictionary of design variables for the gearbox subsystem, where the keys are the + names of the design variables, and the values are dictionaries that contain the units for + the design variable, the lower and upper bounds for the design variable, and any additional keyword arguments required by OpenMDAO for the design variable. """ DVs = { Aircraft.Engine.Gearbox.GEAR_RATIO: { - 'opt': True, 'units': 'unitless', 'lower': 1.0, 'upper': 20.0, - 'val': 10 # initial value + # 'val': 10 # initial value }, # This var appears in both mission and pre-mission Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN: { - 'val': 10000, + # 'val': 10000, 'units': 'kW', 'lower': 1.0, 'upper': None, @@ -62,11 +61,11 @@ def get_design_vars(self): def get_parameters(self, aviary_inputs=None, phase_info=None): """ Parameters are only tested to see if they exist in mission. - A value the doesn't change throught the mission mission - Returns a dictionary of fixed values for the gearbox subsystem, where the keys are the names - of the fixed values, and the values are dictionaries that contain the fixed value for the - variable, the units for the variable, and any additional keyword arguments required by - OpenMDAO for the variable. + The value doesn't change throughout the mission. + Returns a dictionary of fixed values for the gearbox subsystem, where the keys + are the names of the fixed values, and the values are dictionaries that contain + the fixed value for the variable, the units for the variable, and any additional + keyword arguments required by OpenMDAO for the variable. Returns ------- @@ -75,9 +74,21 @@ def get_parameters(self, aviary_inputs=None, phase_info=None): """ parameters = { Aircraft.Engine.Gearbox.EFFICIENCY: { - 'val': 0.98, + 'val': 1.0, 'units': 'unitless', + 'static_target': True, }, + Aircraft.Engine.Gearbox.GEAR_RATIO: { + 'val': 1.0, + 'units': 'unitless', + 'static_target': True, + }, + Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN: { + 'val': 1.0, + 'units': 'kW', + 'lower': 1.0, + 'upper': None, + } } return parameters @@ -87,17 +98,17 @@ def get_mass_names(self): def get_outputs(self): return [ - Dynamic.Mission.RPM_GEARBOX, - Dynamic.Mission.SHAFT_POWER_GEARBOX, - Dynamic.Mission.SHAFT_POWER_MAX_GEARBOX, - Dynamic.Mission.TORQUE_GEARBOX, - Mission.Constraints.SHAFT_POWER_RESIDUAL, + Dynamic.Vehicle.Propulsion.SHAFT_POWER + '_out', + Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX + '_out', + Dynamic.Vehicle.Propulsion.RPM + '_out', + Dynamic.Vehicle.Propulsion.TORQUE + '_out', + Mission.Constraints.GEARBOX_SHAFT_POWER_RESIDUAL, ] def get_constraints(self): if self.include_constraints: constraints = { - Mission.Constraints.SHAFT_POWER_RESIDUAL: { + Mission.Constraints.GEARBOX_SHAFT_POWER_RESIDUAL: { 'lower': 0.0, 'type': 'path', 'units': 'kW', diff --git a/aviary/subsystems/propulsion/gearbox/model/gearbox_mission.py b/aviary/subsystems/propulsion/gearbox/model/gearbox_mission.py index 87243747e..9f366dce2 100644 --- a/aviary/subsystems/propulsion/gearbox/model/gearbox_mission.py +++ b/aviary/subsystems/propulsion/gearbox/model/gearbox_mission.py @@ -1,85 +1,120 @@ import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic, Aircraft, Mission class GearboxMission(om.Group): - """Calculates the mission performance (ODE) of a single gearbox.""" + """ + Calculates the mission performance of a single gearbox. + """ def initialize(self): self.options.declare("num_nodes", types=int) - self.options.declare( - 'aviary_inputs', types=AviaryValues, - desc='collection of Aircraft/Mission specific options', - default=None, - ) self.name = 'gearbox_mission' def setup(self): n = self.options["num_nodes"] - self.add_subsystem('RPM_comp', - om.ExecComp('RPM_out = RPM_in / gear_ratio', - RPM_out={'val': np.ones(n), 'units': 'rpm'}, - gear_ratio={'val': 1.0, 'units': 'unitless'}, - RPM_in={'val': np.ones(n), 'units': 'rpm'}, - has_diag_partials=True), - promotes_inputs=[('RPM_in', Aircraft.Engine.RPM_DESIGN), - ('gear_ratio', Aircraft.Engine.Gearbox.GEAR_RATIO)], - promotes_outputs=[('RPM_out', Dynamic.Mission.RPM_GEARBOX)]) + self.add_subsystem( + 'rpm_comp', + om.ExecComp( + 'rpm_out = rpm_in / gear_ratio', + rpm_out={'val': np.ones(n), 'units': 'rpm'}, + gear_ratio={'val': 1.0, 'units': 'unitless'}, + rpm_in={'val': np.ones(n), 'units': 'rpm'}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('rpm_in', Dynamic.Vehicle.Propulsion.RPM + '_in'), + ('gear_ratio', Aircraft.Engine.Gearbox.GEAR_RATIO), + ], + promotes_outputs=[('rpm_out', Dynamic.Vehicle.Propulsion.RPM + '_out')], + ) - self.add_subsystem('shaft_power_comp', - om.ExecComp('shaft_power_out = shaft_power_in * eff', - shaft_power_in={'val': np.ones(n), 'units': 'kW'}, - shaft_power_out={ - 'val': np.ones(n), 'units': 'kW'}, - eff={'val': 0.98, 'units': 'unitless'}, - has_diag_partials=True), - promotes_inputs=[('shaft_power_in', Dynamic.Mission.SHAFT_POWER), - ('eff', Aircraft.Engine.Gearbox.EFFICIENCY)], - promotes_outputs=[('shaft_power_out', Dynamic.Mission.SHAFT_POWER_GEARBOX)]) + self.add_subsystem( + 'shaft_power_comp', + om.ExecComp( + 'shaft_power_out = shaft_power_in * efficiency', + shaft_power_in={'val': np.ones(n), 'units': 'kW'}, + shaft_power_out={'val': np.ones(n), 'units': 'kW'}, + efficiency={'val': 1.0, 'units': 'unitless'}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('shaft_power_in', Dynamic.Vehicle.Propulsion.SHAFT_POWER + '_in'), + ('efficiency', Aircraft.Engine.Gearbox.EFFICIENCY), + ], + promotes_outputs=[ + ('shaft_power_out', Dynamic.Vehicle.Propulsion.SHAFT_POWER + '_out') + ], + ) + + self.add_subsystem( + 'torque_comp', + om.ExecComp( + 'torque_out = shaft_power_out / rpm_out', + shaft_power_out={'val': np.ones(n), 'units': 'kW'}, + torque_out={'val': np.ones(n), 'units': 'kN*m'}, + rpm_out={'val': np.ones(n), 'units': 'rad/s'}, + has_diag_partials=True, + ), + promotes_outputs=[ + ('torque_out', Dynamic.Vehicle.Propulsion.TORQUE + '_out')], + ) + self.connect( + f'{Dynamic.Vehicle.Propulsion.SHAFT_POWER}_out', + f'torque_comp.shaft_power_out', + ) - self.add_subsystem('torque_comp', - om.ExecComp('torque_out = shaft_power_out / RPM_out', - shaft_power_out={ - 'val': np.ones(n), 'units': 'kW'}, - torque_out={'val': np.ones(n), 'units': 'kN*m'}, - RPM_out={'val': np.ones(n), 'units': 'rad/s'}, - has_diag_partials=True), - promotes_inputs=[('shaft_power_out', Dynamic.Mission.SHAFT_POWER_GEARBOX), - ('RPM_out', Dynamic.Mission.RPM_GEARBOX)], - promotes_outputs=[('torque_out', Dynamic.Mission.TORQUE_GEARBOX)]) + self.connect( + f'{Dynamic.Vehicle.Propulsion.RPM}_out', + f'torque_comp.rpm_out', + ) # Determine the maximum power available at this flight condition # this is used for excess power constraints - self.add_subsystem('shaft_power_max_comp', - om.ExecComp('shaft_power_out = shaft_power_in * eff', - shaft_power_in={'val': np.ones(n), 'units': 'kW'}, - shaft_power_out={ - 'val': np.ones(n), 'units': 'kW'}, - eff={'val': 0.98, 'units': 'unitless'}, - has_diag_partials=True), - promotes_inputs=[('shaft_power_in', Dynamic.Mission.SHAFT_POWER_MAX), - ('eff', Aircraft.Engine.Gearbox.EFFICIENCY)], - promotes_outputs=[('shaft_power_out', Dynamic.Mission.SHAFT_POWER_MAX_GEARBOX)]) + self.add_subsystem( + 'shaft_power_max_comp', + om.ExecComp( + 'shaft_power_out = shaft_power_in * efficiency', + shaft_power_in={'val': np.ones(n), 'units': 'kW'}, + shaft_power_out={'val': np.ones(n), 'units': 'kW'}, + efficiency={'val': 1.0, 'units': 'unitless'}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('shaft_power_in', Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX + '_in'), + ('efficiency', Aircraft.Engine.Gearbox.EFFICIENCY), + ], + promotes_outputs=[ + ('shaft_power_out', Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX + '_out') + ], + ) # We must ensure the design shaft power that was provided to pre-mission is - # larger than the maximum shaft power that could be drawn by the mission. - # Note this is a larger value than the actual maximum shaft power drawn during the mission - # because the aircraft might need to climb to avoid obstacles at anytime during the mission - self.add_subsystem('shaft_power_residual', - om.ExecComp('shaft_power_resid = shaft_power_design - shaft_power_max', - shaft_power_max={ - 'val': np.ones(n), 'units': 'kW'}, - shaft_power_design={'val': 1.0, 'units': 'kW'}, - shaft_power_resid={ - 'val': np.ones(n), 'units': 'kW'}, - has_diag_partials=True), - promotes_inputs=[('shaft_power_max', Dynamic.Mission.SHAFT_POWER_MAX), - ('shaft_power_design', Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN)], - promotes_outputs=[('shaft_power_resid', Mission.Constraints.SHAFT_POWER_RESIDUAL)]) - - # TODO max thrust from the props will depend on this max shaft power from the gearbox and the new gearbox RPM value + # larger than the maximum shaft power that could be drawn by the mission. + # Note this is a larger value than the actual maximum shaft power drawn during + # the mission because the aircraft might need to climb to avoid obstacles at + # anytime during the mission + self.add_subsystem( + 'shaft_power_residual', + om.ExecComp( + 'shaft_power_residual = shaft_power_design - shaft_power_max', + shaft_power_max={'val': np.ones(n), 'units': 'kW'}, + shaft_power_design={'val': 1.0, 'units': 'kW'}, + shaft_power_residual={'val': np.ones(n), 'units': 'kW'}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('shaft_power_max', Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX + '_in'), + ('shaft_power_design', Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN), + ], + promotes_outputs=[ + ( + 'shaft_power_residual', + Mission.Constraints.GEARBOX_SHAFT_POWER_RESIDUAL, + ) + ], + ) diff --git a/aviary/subsystems/propulsion/gearbox/model/gearbox_premission.py b/aviary/subsystems/propulsion/gearbox/model/gearbox_premission.py index 226fca7cc..bce6f81fc 100644 --- a/aviary/subsystems/propulsion/gearbox/model/gearbox_premission.py +++ b/aviary/subsystems/propulsion/gearbox/model/gearbox_premission.py @@ -2,70 +2,97 @@ import numpy as np from aviary.variable_info.variables import Aircraft, Dynamic -from aviary.utils.aviary_values import AviaryValues class GearboxPreMission(om.Group): """ Calculate gearbox mass for a single gearbox. - Gearbox design assumes collective control which means that RPM coming into the + Gearbox design assumes collective control which means that RPM coming into the gearbox is fixed and RPM going out of the gearbox is fixed over the whole mission. """ def initialize(self, ): self.options.declare("simple_mass", types=bool, default=True) - self.options.declare( - "aviary_inputs", types=AviaryValues, - desc="collection of Aircraft/Mission specific options", - default=None, - ) self.name = 'gearbox_premission' def setup(self): - self.add_subsystem('gearbox_PRM', - om.ExecComp('RPM_out = RPM_in / gear_ratio', - RPM_out={'val': 0.0, 'units': 'rpm'}, - gear_ratio={'val': 1.0, 'units': 'unitless'}, - RPM_in={'val': 0.0, 'units': 'rpm'}, - has_diag_partials=True), - promotes_inputs=[('RPM_in', Aircraft.Engine.RPM_DESIGN), - ('gear_ratio', Aircraft.Engine.Gearbox.GEAR_RATIO)], - promotes_outputs=['RPM_out']) + self.add_subsystem( + 'gearbox_RPM', + om.ExecComp( + 'RPM_out = RPM_in / gear_ratio', + RPM_out={'val': 0.0, 'units': 'rpm'}, + gear_ratio={'val': 1.0, 'units': 'unitless'}, + RPM_in={'val': 0.0, 'units': 'rpm'}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('RPM_in', Aircraft.Engine.RPM_DESIGN), + ('gear_ratio', Aircraft.Engine.Gearbox.GEAR_RATIO), + ], + # promotes_outputs=['RPM_out'], + ) # max torque is calculated based on input shaft power and output RPM - self.add_subsystem('torque_comp', - om.ExecComp('torque_max = shaft_power / RPM_out', - shaft_power={'val': 1.0, 'units': 'kW'}, - torque_max={'val': 1.0, 'units': 'kN*m'}, - RPM_out={'val': 1.0, 'units': 'rad/s'}, - has_diag_partials=True), - promotes_inputs=[('shaft_power', Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN), - 'RPM_out'], - promotes_outputs=['torque_max']) + self.add_subsystem( + 'torque_comp', + om.ExecComp( + 'torque_max = shaft_power / RPM_out', + shaft_power={'val': 1.0, 'units': 'kW'}, + torque_max={'val': 1.0, 'units': 'kN*m'}, + RPM_out={'val': 1.0, 'units': 'rad/s'}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('shaft_power', Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN) + ], + # 'RPM_out'], + # promotes_outputs=['torque_max'], + ) - # Simple gearbox mass will always produce positive values for mass based on a fixed specific torque - self.add_subsystem('mass_comp', - om.ExecComp('gearbox_mass = torque_max / specific_torque', - gearbox_mass={'val': 0.0, 'units': 'kg'}, - torque_max={'val': 0.0, 'units': 'N*m'}, - specific_torque={'val': 0.0, 'units': 'N*m/kg'}, - has_diag_partials=True), - promotes_inputs=['torque_max', - ('specific_torque', Aircraft.Engine.Gearbox.SPECIFIC_TORQUE)], - promotes_outputs=[('gearbox_mass', Aircraft.Engine.Gearbox.MASS)]) + if self.options["simple_mass"]: + # Simple gearbox mass will always produce positive values for mass based + # on a fixed specific torque + self.add_subsystem( + 'mass_comp', + om.ExecComp( + 'gearbox_mass = torque_max / specific_torque', + gearbox_mass={'val': 0.0, 'units': 'kg'}, + torque_max={'val': 0.0, 'units': 'N*m'}, + specific_torque={'val': 0.0, 'units': 'N*m/kg'}, + has_diag_partials=True, + ), + promotes_inputs=[ + # 'torque_max', + ('specific_torque', Aircraft.Engine.Gearbox.SPECIFIC_TORQUE), + ], + promotes_outputs=[('gearbox_mass', Aircraft.Engine.Gearbox.MASS)], + ) - if self.options["simple_mass"] is False: + else: # This gearbox mass calc can work for large systems but can produce negative weights for some inputs # Gearbox mass from "An N+3 Technolgoy Level Reference Propulsion System" by Scott Jones, William Haller, and Michael Tong # NASA TM 2017-219501 - self.add_subsystem('gearbox_mass', - om.ExecComp('gearbox_mass = (shaftpower / RPM_out)**(0.75) * (RPM_in / RPM_out)**(0.15)', - gearbox_mass={'val': 0.0, 'units': 'lb'}, - shaftpower={'val': 0.0, 'units': 'hp'}, - RPM_out={'val': 0.0, 'units': 'rpm'}, - RPM_in={'val': 0.0, 'units': 'rpm'}, - has_diag_partials=True), - promotes_inputs=[('shaftpower', Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN), - 'RPM_out', ('RPM_in', Aircraft.Engine.RPM_DESIGN)], - promotes_outputs=[('gearbox_mass', Aircraft.Engine.Gearbox.MASS)]) + self.add_subsystem( + 'gearbox_mass', + om.ExecComp( + 'gearbox_mass = (shaftpower / RPM_out)**(0.75) * (RPM_in / RPM_out)**(0.15)', + gearbox_mass={'val': 0.0, 'units': 'lb'}, + shaftpower={'val': 0.0, 'units': 'hp'}, + RPM_out={'val': 0.0, 'units': 'rpm'}, + RPM_in={'val': 0.0, 'units': 'rpm'}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('shaftpower', Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN), + # 'RPM_out', + ('RPM_in', Aircraft.Engine.RPM_DESIGN), + ], + promotes_outputs=[('gearbox_mass', Aircraft.Engine.Gearbox.MASS)], + ) + + self.connect('gearbox_RPM.RPM_out', 'torque_comp.RPM_out') + if self.options["simple_mass"]: + self.connect('torque_comp.torque_max', 'mass_comp.torque_max') + else: + self.connect('gearbox_RPM.RPM_out', 'gearbox_mass.RPM_out') diff --git a/aviary/subsystems/propulsion/gearbox/test/test_gearbox.py b/aviary/subsystems/propulsion/gearbox/test/test_gearbox.py index ebeb6c5a2..4806844a9 100644 --- a/aviary/subsystems/propulsion/gearbox/test/test_gearbox.py +++ b/aviary/subsystems/propulsion/gearbox/test/test_gearbox.py @@ -33,7 +33,7 @@ def test_gearbox_premission(self): prob.run_model() mass = prob.get_val(av.Aircraft.Engine.Gearbox.MASS, 'lb') - torque_max = prob.get_val('torque_max', 'lbf*ft') + torque_max = prob.get_val('gearbox_premission.torque_comp.torque_max', 'lbf*ft') torque_max_expected = 4005.84967696 mass_expected = 116.25002688 @@ -53,31 +53,38 @@ def test_gearbox_mission(self): prob.setup(force_alloc_complex=True) - prob.set_val(av.Aircraft.Engine.RPM_DESIGN, [5000, 6195, 6195], units='rpm') - prob.set_val(av.Dynamic.Mission.SHAFT_POWER, [100, 200, 375], units='hp') - prob.set_val(av.Dynamic.Mission.SHAFT_POWER_MAX, [375, 300, 375], units='hp') + prob.set_val(av.Dynamic.Vehicle.Propulsion.RPM + '_in', + [5000, 6195, 6195], units='rpm') + prob.set_val(av.Dynamic.Vehicle.Propulsion.SHAFT_POWER + '_in', + [100, 200, 375], units='hp') + prob.set_val(av.Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX + '_in', + [375, 300, 375], units='hp') prob.set_val(av.Aircraft.Engine.Gearbox.GEAR_RATIO, 12.6, units=None) prob.set_val(av.Aircraft.Engine.Gearbox.EFFICIENCY, 0.98, units=None) prob.run_model() - SHAFT_POWER_GEARBOX = prob.get_val(av.Dynamic.Mission.SHAFT_POWER_GEARBOX, 'hp') - RPM_GEARBOX = prob.get_val(av.Dynamic.Mission.RPM_GEARBOX, 'rpm') - TORQUE_GEARBOX = prob.get_val(av.Dynamic.Mission.TORQUE_GEARBOX, 'ft*lbf') - SHAFT_POWER_MAX_GEARBOX = prob.get_val( - av.Dynamic.Mission.SHAFT_POWER_MAX_GEARBOX, 'hp') - - SHAFT_POWER_GEARBOX_expected = [98., 196., 367.5] - RPM_GEARBOX_expected = [396.82539683, 491.66666667, 491.66666667] - TORQUE_GEARBOX_expected = [1297.0620786, 2093.72409783, 3925.73268342] - SHAFT_POWER_MAX_GEARBOX_expected = [367.5, 294., 367.5] - - assert_near_equal(SHAFT_POWER_GEARBOX, - SHAFT_POWER_GEARBOX_expected, tolerance=1e-6) - assert_near_equal(RPM_GEARBOX, RPM_GEARBOX_expected, tolerance=1e-6) - assert_near_equal(TORQUE_GEARBOX, TORQUE_GEARBOX_expected, tolerance=1e-6) - assert_near_equal(SHAFT_POWER_MAX_GEARBOX, - SHAFT_POWER_MAX_GEARBOX_expected, tolerance=1e-6) + shaft_power = prob.get_val( + av.Dynamic.Vehicle.Propulsion.SHAFT_POWER + '_out', 'hp' + ) + rpm = prob.get_val(av.Dynamic.Vehicle.Propulsion.RPM + '_out', 'rpm') + torque = prob.get_val( + av.Dynamic.Vehicle.Propulsion.TORQUE + '_out', 'ft*lbf') + shaft_power_max = prob.get_val( + av.Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX + '_out', 'hp' + ) + + shaft_power_expected = [98., 196., 367.5] + rpm_expected = [396.82539683, 491.66666667, 491.66666667] + torque_expected = [1297.0620786, 2093.72409783, 3925.73268342] + shaft_power_max_expected = [367.5, 294., 367.5] + + assert_near_equal(shaft_power, + shaft_power_expected, tolerance=1e-6) + assert_near_equal(rpm, rpm_expected, tolerance=1e-6) + assert_near_equal(torque, torque_expected, tolerance=1e-6) + assert_near_equal(shaft_power_max, + shaft_power_max_expected, tolerance=1e-6) partial_data = prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-9, rtol=1e-9) diff --git a/aviary/subsystems/propulsion/motor/model/motor_map.py b/aviary/subsystems/propulsion/motor/model/motor_map.py index 894c154f8..8e3be4114 100644 --- a/aviary/subsystems/propulsion/motor/model/motor_map.py +++ b/aviary/subsystems/propulsion/motor/model/motor_map.py @@ -4,7 +4,9 @@ from aviary.variable_info.variables import Dynamic, Aircraft - +# block auto-formatting of tables +# autopep8: off +# fmt: off motor_map = np.array([ # speed---- .0 .083333 .16667 .25 .33333.41667 .5, .58333 .66667 .75, .83333, .91667 1. [.871, .872, .862, .853, .845, .838, .832, .825, .819, .813, .807, .802, .796], # 0 @@ -25,31 +27,33 @@ [.807, .808, .884, .912, .927, .936, .942, .947, .950, .952, .954, .955, .956], # 0.936 [.795, .796, .877, .907, .923, .933, .939, .944, .948, .950, .952, .953, .954] # 1.000 ]).T +# autopep8: on +# fmt: on class MotorMap(om.Group): - ''' This function takes in 0-1 values for electric motor throttle, scales those values into 0 to max_torque on the motor map this also allows us to solve for motor efficiency then we scale the torque up based on the actual scale factor of the motor. This avoids the need to rescale the map values, and still allows for the motor scale to be optimized. - Scaling only effects Torque. RPM is not scaled and is assumed to be maxed at 6,000 rpm. + Scaling only effects torque (and therefore shaft power production, and electric power consumption). + RPM is not scaled and is assumed to be maxed at 6,000 rpm. The original maps were put together for a 746kw (1,000 hp) electric motor published in the TTBW paper: https://ntrs.nasa.gov/api/citations/20230016987/downloads/TTBW_SciTech_2024_Final_12_5_2023.pdf The map is shown in Figure 4. Inputs ---------- - Dynamic.Mission.THROTTLE : float (unitless) (0 to 1) + Dynamic.Vehicle.Propulsion.THROTTLE : float (unitless) (0 to 1) The throttle command which will be translated into torque output from the engine - Aircraft.Engine.SCALE_FACTOR : float (unitless) (positive) + Aircraft.Engine.SCALE_FACTOR : float (unitless) (positive) Aircraft.Motor.RPM : float (rpm) (0 to 6000) Outputs ---------- - Dynamic.Mission.TORQUE : float (positive) + Dynamic.Vehicle.Propulsion.TORQUE : float (positive) Dynamic.Mission.Motor.EFFICIENCY : float (positive) ''' @@ -61,25 +65,37 @@ def setup(self): n = self.options["num_nodes"] # Training data + # autopep8: off + # fmt: off rpm_vals = np.array([0, .083333, .16667, .25, .33333, .41667, .5, - .58333, .66667, .75, .83333, .91667, 1.])*6000 + .58333, .66667, .75, .83333, .91667, 1.]) * 6000 torque_vals = np.array([0.0, 0.040, 0.104, 0.168, 0.232, 0.296, 0.360, 0.424, 0.488, 0.552, 0.616, 0.680, 0.744, 0.808, - 0.872, 0.936, 1.000])*1800 - + 0.872, 0.936, 1.000]) * 1800 + # autopep8: on + # fmt: on # Create a structured metamodel to compute motor efficiency from rpm - motor = om.MetaModelStructuredComp(method="slinear", - vec_size=n, - extrapolate=True) - motor.add_input(Dynamic.Mission.RPM, val=np.ones(n), - training_data=rpm_vals, - units="rpm") - motor.add_input("torque_unscaled", val=np.ones(n), # unscaled torque - training_data=torque_vals, - units="N*m") - motor.add_output("motor_efficiency", val=np.ones(n), - training_data=motor_map, - units='unitless') + motor = om.MetaModelStructuredComp( + method="slinear", vec_size=n, extrapolate=True + ) + motor.add_input( + Dynamic.Vehicle.Propulsion.RPM, + val=np.ones(n), + training_data=rpm_vals, + units="rpm", + ) + motor.add_input( + "torque_unscaled", + val=np.ones(n), # unscaled torque + training_data=torque_vals, + units="N*m", + ) + motor.add_output( + "motor_efficiency", + val=np.ones(n), + training_data=motor_map, + units='unitless', + ) self.add_subsystem( 'throttle_to_torque', @@ -90,15 +106,18 @@ def setup(self): throttle={'val': np.ones(n), 'units': 'unitless'}, has_diag_partials=True, ), - promotes=["torque_unscaled", ("throttle", Dynamic.Mission.THROTTLE)], + promotes=[("throttle", Dynamic.Vehicle.Propulsion.THROTTLE)], ) - self.add_subsystem(name="motor_efficiency", - subsys=motor, - promotes_inputs=[Dynamic.Mission.RPM, "torque_unscaled"], - promotes_outputs=["motor_efficiency"]) + self.add_subsystem( + name="motor_efficiency", + subsys=motor, + promotes_inputs=[Dynamic.Vehicle.Propulsion.RPM], + promotes_outputs=["motor_efficiency"], + ) - # now that we know the efficiency, scale up the torque correctly for the engine size selected + # Now that we know the efficiency, scale up the torque correctly for the engine + # size selected # Note: This allows the optimizer to optimize the motor size if desired self.add_subsystem( 'scale_motor_torque', @@ -110,8 +129,12 @@ def setup(self): has_diag_partials=True, ), promotes=[ - ("torque", Dynamic.Mission.TORQUE), - "torque_unscaled", + ("torque", Dynamic.Vehicle.Propulsion.TORQUE), ("scale_factor", Aircraft.Engine.SCALE_FACTOR), ], ) + + self.connect( + 'throttle_to_torque.torque_unscaled', + ['motor_efficiency.torque_unscaled', 'scale_motor_torque.torque_unscaled'], + ) diff --git a/aviary/subsystems/propulsion/motor/model/motor_mission.py b/aviary/subsystems/propulsion/motor/model/motor_mission.py index 843603727..19df04708 100644 --- a/aviary/subsystems/propulsion/motor/model/motor_mission.py +++ b/aviary/subsystems/propulsion/motor/model/motor_mission.py @@ -8,7 +8,6 @@ class MotorMission(om.Group): - ''' Calculates the mission performance (ODE) of a single electric motor. ''' @@ -16,7 +15,8 @@ class MotorMission(om.Group): def initialize(self): self.options.declare("num_nodes", types=int) self.options.declare( - 'aviary_inputs', types=AviaryValues, + 'aviary_inputs', + types=AviaryValues, desc='collection of Aircraft/Mission specific options', default=None, ) @@ -36,12 +36,12 @@ def setup(self): 'motor_map', MotorMap(num_nodes=nn), promotes_inputs=[ - Dynamic.Mission.THROTTLE, + Dynamic.Vehicle.Propulsion.THROTTLE, Aircraft.Engine.SCALE_FACTOR, - Dynamic.Mission.RPM, + Dynamic.Vehicle.Propulsion.RPM, ], promotes_outputs=[ - Dynamic.Mission.TORQUE, + Dynamic.Vehicle.Propulsion.TORQUE, 'motor_efficiency', ], ) @@ -55,13 +55,13 @@ def setup(self): RPM={'val': np.ones(nn), 'units': 'rad/s'}, has_diag_partials=True, ), # fixed RPM system - promotes_inputs=[('RPM', Dynamic.Mission.RPM)], - promotes_outputs=[('shaft_power', Dynamic.Mission.SHAFT_POWER)], + promotes_inputs=[('RPM', Dynamic.Vehicle.Propulsion.RPM)], + promotes_outputs=[('shaft_power', Dynamic.Vehicle.Propulsion.SHAFT_POWER)], ) # Can't promote torque as an input, as it will create a feedback loop with # propulsion mux component. Connect it here instead - motor_group.connect(Dynamic.Mission.TORQUE, 'power_comp.torque') + motor_group.connect(Dynamic.Vehicle.Propulsion.TORQUE, 'power_comp.torque') motor_group.add_subsystem( 'energy_comp', @@ -73,16 +73,20 @@ def setup(self): has_diag_partials=True, ), promotes_inputs=[('efficiency', 'motor_efficiency')], - promotes_outputs=[('power_elec', Dynamic.Mission.ELECTRIC_POWER_IN)], + promotes_outputs=[ + ('power_elec', Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN) + ], ) # Can't promote shaft power as an input, as it will create a feedback loop with # propulsion mux component. Connect it here instead - motor_group.connect(Dynamic.Mission.SHAFT_POWER, 'energy_comp.shaft_power') + motor_group.connect( + Dynamic.Vehicle.Propulsion.SHAFT_POWER, 'energy_comp.shaft_power' + ) - self.add_subsystem('motor_group', motor_group, - promotes_inputs=['*'], - promotes_outputs=['*']) + self.add_subsystem( + 'motor_group', motor_group, promotes_inputs=['*'], promotes_outputs=['*'] + ) # Determine the maximum power available at this flight condition # this is used for excess power constraints @@ -93,12 +97,15 @@ def setup(self): 'motor_map_max', MotorMap(num_nodes=nn), promotes_inputs=[ - (Dynamic.Mission.THROTTLE, 'max_throttle'), + (Dynamic.Vehicle.Propulsion.THROTTLE, 'max_throttle'), Aircraft.Engine.SCALE_FACTOR, - Dynamic.Mission.RPM, + Dynamic.Vehicle.Propulsion.RPM, ], promotes_outputs=[ - (Dynamic.Mission.TORQUE, Dynamic.Mission.TORQUE_MAX), + ( + Dynamic.Vehicle.Propulsion.TORQUE, + Dynamic.Vehicle.Propulsion.TORQUE_MAX, + ), 'motor_efficiency', ], ) @@ -113,10 +120,12 @@ def setup(self): has_diag_partials=True, ), promotes_inputs=[ - ('max_torque', Dynamic.Mission.TORQUE_MAX), - ('RPM', Dynamic.Mission.RPM), + ('max_torque', Dynamic.Vehicle.Propulsion.TORQUE_MAX), + ('RPM', Dynamic.Vehicle.Propulsion.RPM), + ], + promotes_outputs=[ + ('max_power', Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX) ], - promotes_outputs=[('max_power', Dynamic.Mission.SHAFT_POWER_MAX)], ) self.add_subsystem( @@ -124,9 +133,11 @@ def setup(self): motor_group_max, promotes_inputs=['*', 'max_throttle'], promotes_outputs=[ - Dynamic.Mission.SHAFT_POWER_MAX, - Dynamic.Mission.TORQUE_MAX, + Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX, + Dynamic.Vehicle.Propulsion.TORQUE_MAX, ], ) - self.set_input_defaults(Dynamic.Mission.RPM, val=np.ones(nn), units='rpm') + self.set_input_defaults( + Dynamic.Vehicle.Propulsion.RPM, val=np.ones(nn), units='rpm' + ) diff --git a/aviary/subsystems/propulsion/motor/model/motor_premission.py b/aviary/subsystems/propulsion/motor/model/motor_premission.py index c6964d41d..a5e872074 100644 --- a/aviary/subsystems/propulsion/motor/model/motor_premission.py +++ b/aviary/subsystems/propulsion/motor/model/motor_premission.py @@ -13,7 +13,8 @@ class MotorPreMission(om.Group): def initialize(self): self.options.declare( - "aviary_inputs", types=AviaryValues, + "aviary_inputs", + types=AviaryValues, desc="collection of Aircraft/Mission specific options", default=None, ) @@ -31,7 +32,7 @@ def setup(self): Aircraft.Engine.RPM_DESIGN, units='rpm' ) - self.set_input_defaults(Dynamic.Mission.THROTTLE, 1.0, units=None) + self.set_input_defaults(Dynamic.Vehicle.Propulsion.THROTTLE, 1.0, units=None) self.set_input_defaults('design_rpm', design_rpm, units='rpm') self.add_subsystem( @@ -39,11 +40,11 @@ def setup(self): MotorMap(num_nodes=1), promotes_inputs=[ Aircraft.Engine.SCALE_FACTOR, - Dynamic.Mission.THROTTLE, - (Dynamic.Mission.RPM, 'design_rpm'), + Dynamic.Vehicle.Propulsion.THROTTLE, + (Dynamic.Vehicle.Propulsion.RPM, 'design_rpm'), ], promotes_outputs=[ - (Dynamic.Mission.TORQUE, Aircraft.Engine.Motor.TORQUE_MAX) + (Dynamic.Vehicle.Propulsion.TORQUE, Aircraft.Engine.Motor.TORQUE_MAX) ], ) diff --git a/aviary/subsystems/propulsion/motor/motor_builder.py b/aviary/subsystems/propulsion/motor/motor_builder.py index 3f199bcb7..963ac693f 100644 --- a/aviary/subsystems/propulsion/motor/motor_builder.py +++ b/aviary/subsystems/propulsion/motor/motor_builder.py @@ -6,11 +6,16 @@ class MotorBuilder(SubsystemBuilderBase): ''' - Define the builder for a single motor subsystem that provides methods to define the motor subsystem's states, design variables, fixed values, initial guesses, and mass names. + Define the builder for a single motor subsystem that provides methods to define the + motor subsystem's states, design variables, fixed values, initial guesses, and mass + names. - It also provides methods to build OpenMDAO systems for the pre-mission and mission computations of the subsystem, to get the constraints for the subsystem, and to preprocess the inputs for the subsystem. + It also provides methods to build OpenMDAO systems for the pre-mission and mission + computations of the subsystem, to get the constraints for the subsystem, and to + preprocess the inputs for the subsystem. - This is meant to be computations for a single motor, so there is no notion of "num_motors" in this code. + This is meant to be computations for a single motor, so there is no notion of + "num_motors" in this code. Attributes ---------- @@ -22,7 +27,10 @@ class MotorBuilder(SubsystemBuilderBase): __init__(self, name='motor'): Initializes the MotorBuilder object with a given name. get_states(self) -> dict: - Returns a dictionary of the subsystem's states, where the keys are the names of the state variables, and the values are dictionaries that contain the units for the state variable and any additional keyword arguments required by OpenMDAO for the state variable. + Returns a dictionary of the subsystem's states, where the keys are the names of + the state variables, and the values are dictionaries that contain the units for + the state variable and any additional keyword arguments required by OpenMDAO for + the state variable. get_linked_variables(self) -> list: Links voltage input from the battery subsystem build_pre_mission(self) -> openmdao.core.System: @@ -30,25 +38,38 @@ class MotorBuilder(SubsystemBuilderBase): build_mission(self, num_nodes, aviary_inputs) -> openmdao.core.System: Builds an OpenMDAO system for the mission computations of the subsystem. get_constraints(self) -> dict: - Returns a dictionary of constraints for the motor subsystem, where the keys are the names of the variables to be constrained, and the values are dictionaries that contain the lower and upper bounds for the constraint and any additional keyword arguments accepted by Dymos for the constraint. + Returns a dictionary of constraints for the motor subsystem, where the keys are + the names of the variables to be constrained, and the values are dictionaries + that contain the lower and upper bounds for the constraint and any additional + keyword arguments accepted by Dymos for the constraint. get_design_vars(self) -> dict: - Returns a dictionary of design variables for the motor subsystem, where the keys are the names of the design variables, and the values are dictionaries that contain the units for the design variable, the lower and upper bounds for the design variable, and any additional keyword arguments required by OpenMDAO for the design variable. + Returns a dictionary of design variables for the motor subsystem, where the keys + are the names of the design variables, and the values are dictionaries that + contain the units for the design variable, the lower and upper bounds for the + design variable, and any additional keyword arguments required by OpenMDAO for + the design variable. get_parameters(self) -> dict: - Returns a dictionary of fixed values for the motor subsystem, where the keys are the names of the fixed values, and the values are dictionaries that contain the fixed value for the variable, the units for the variable, and any additional keyword arguments required by OpenMDAO for the variable. + Returns a dictionary of fixed values for the motor subsystem, where the keys are + the names of the fixed values, and the values are dictionaries that contain the + fixed value for the variable, the units for the variable, and any additional + keyword arguments required by OpenMDAO for the variable. get_initial_guesses(self) -> dict: - Returns a dictionary of initial guesses for the motor subsystem, where the keys are the names of the initial guesses, and the values are dictionaries that contain the initial guess value, the type of variable (state or control), and any additional keyword arguments required by OpenMDAO for the variable. + Returns a dictionary of initial guesses for the motor subsystem, where the keys + are the names of the initial guesses, and the values are dictionaries that + contain the initial guess value, the type of variable (state or control), and any + additional keyword arguments required by OpenMDAO for the variable. get_mass_names(self) -> list: Returns a list of names for the motor subsystem mass. preprocess_inputs(self, aviary_inputs) -> aviary_inputs: No preprocessing needed for the motor subsystem. ''' - def __init__(self, name='motor', include_constraints=True): - self.include_constraints = include_constraints + def __init__(self, name='motor'): # , include_constraints=True): + # self.include_constraints = include_constraints super().__init__(name) def build_pre_mission(self, aviary_inputs): - return MotorPreMission(aviary_inputs=aviary_inputs, simple_mass=True) + return MotorPreMission(aviary_inputs=aviary_inputs) # , simple_mass=True) def build_mission(self, num_nodes, aviary_inputs): return MotorMission(num_nodes=num_nodes, aviary_inputs=aviary_inputs) @@ -56,11 +77,7 @@ def build_mission(self, num_nodes, aviary_inputs): # def get_constraints(self): # if self.include_constraints: # constraints = { - # Dynamic.Mission.Motor.TORQUE_CON: { - # 'upper': 0.0, - # 'type': 'path' - # } - # TBD Gearbox torque constraint + # Dynamic.Mission.Motor.TORQUE_CON: {'upper': 0.0, 'type': 'path'} # } # else: # constraints = {} @@ -72,17 +89,22 @@ def get_design_vars(self): Aircraft.Engine.SCALE_FACTOR: { 'units': 'unitless', 'lower': 0.001, - 'upper': None + 'upper': None, }, - Aircraft.Engine.Gearbox.GEAR_RATIO: { - 'units': None, - 'lower': 1.0, - 'upper': 1.0, - } } return DVs + def get_parameters(self): + params = { + Aircraft.Engine.SCALE_FACTOR: { + 'val': 1.0, + 'units': 'unitless', + 'static_target': True, + } + } + return params + # def get_initial_guesses(self): # initial_guess_dict = { # Aircraft.Motor.RPM: { @@ -117,8 +139,8 @@ def get_outputs(self): ''' return [ - Dynamic.Mission.TORQUE, - Dynamic.Mission.SHAFT_POWER, - Dynamic.Mission.SHAFT_POWER_MAX, - Dynamic.Mission.ELECTRIC_POWER_IN, + Dynamic.Vehicle.Propulsion.TORQUE, + Dynamic.Vehicle.Propulsion.SHAFT_POWER, + Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX, + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, ] diff --git a/aviary/subsystems/propulsion/motor/test/test_motor_map.py b/aviary/subsystems/propulsion/motor/test/test_motor_map.py index 20256022f..4be1d9429 100644 --- a/aviary/subsystems/propulsion/motor/test/test_motor_map.py +++ b/aviary/subsystems/propulsion/motor/test/test_motor_map.py @@ -21,14 +21,13 @@ def test_motor_map(self): prob.setup(force_alloc_complex=True) - prob.set_val(Dynamic.Mission.THROTTLE, np.linspace(0, 1, nn)) - prob.set_val(Dynamic.Mission.RPM, np.linspace(0, 6000, nn)) - prob.set_val('torque_unscaled', np.linspace(0, 1800, nn), 'N*m') + prob.set_val(Dynamic.Vehicle.Propulsion.THROTTLE, np.linspace(0, 1, nn)) + prob.set_val(Dynamic.Vehicle.Propulsion.RPM, np.linspace(0, 6000, nn)) prob.set_val(Aircraft.Engine.SCALE_FACTOR, 1.12) prob.run_model() - torque = prob.get_val(Dynamic.Mission.TORQUE) + torque = prob.get_val(Dynamic.Vehicle.Propulsion.TORQUE) efficiency = prob.get_val('motor_efficiency') torque_expected = np.array([0.0, 900.0, 1800.0]) * 1.12 diff --git a/aviary/subsystems/propulsion/motor/test/test_motor_mission.py b/aviary/subsystems/propulsion/motor/test/test_motor_mission.py index 0b1b27871..646b861bf 100644 --- a/aviary/subsystems/propulsion/motor/test/test_motor_mission.py +++ b/aviary/subsystems/propulsion/motor/test/test_motor_mission.py @@ -23,19 +23,19 @@ def test_motor_map(self): prob.setup(force_alloc_complex=True) - prob.set_val(Dynamic.Mission.THROTTLE, np.linspace(0, 1, nn)) - prob.set_val(Dynamic.Mission.RPM, np.linspace(0, 6000, nn)) + prob.set_val(Dynamic.Vehicle.Propulsion.THROTTLE, np.linspace(0, 1, nn)) + prob.set_val(Dynamic.Vehicle.Propulsion.RPM, np.linspace(0, 6000, nn)) # prob.set_val('torque_unscaled', np.linspace(0, 1800, nn), 'N*m') prob.set_val(Aircraft.Engine.SCALE_FACTOR, 1.12) prob.run_model() - torque = prob.get_val(Dynamic.Mission.TORQUE, 'N*m') - max_torque = prob.get_val(Dynamic.Mission.TORQUE_MAX, 'N*m') + torque = prob.get_val(Dynamic.Vehicle.Propulsion.TORQUE, 'N*m') + max_torque = prob.get_val(Dynamic.Vehicle.Propulsion.TORQUE_MAX, 'N*m') efficiency = prob.get_val('motor_efficiency') - shp = prob.get_val(Dynamic.Mission.SHAFT_POWER) - max_shp = prob.get_val(Dynamic.Mission.SHAFT_POWER_MAX) - power = prob.get_val(Dynamic.Mission.ELECTRIC_POWER_IN, 'kW') + shp = prob.get_val(Dynamic.Vehicle.Propulsion.SHAFT_POWER) + max_shp = prob.get_val(Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX) + power = prob.get_val(Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, 'kW') torque_expected = np.array([0.0, 900.0, 1800.0]) * 1.12 max_torque_expected = [2016, 2016, 2016] diff --git a/aviary/subsystems/propulsion/motor/test/test_motor_premission.py b/aviary/subsystems/propulsion/motor/test/test_motor_premission.py index b9ec5a567..6864f25ef 100644 --- a/aviary/subsystems/propulsion/motor/test/test_motor_premission.py +++ b/aviary/subsystems/propulsion/motor/test/test_motor_premission.py @@ -24,7 +24,6 @@ def test_motor_map(self): prob.setup(force_alloc_complex=True) - # prob.set_val('torque_unscaled', np.linspace(0, 1800, nn), 'N*m') prob.set_val(Aircraft.Engine.SCALE_FACTOR, 1.12) prob.run_model() diff --git a/aviary/subsystems/propulsion/propeller/hamilton_standard.py b/aviary/subsystems/propulsion/propeller/hamilton_standard.py index 952f37430..0b502c9b9 100644 --- a/aviary/subsystems/propulsion/propeller/hamilton_standard.py +++ b/aviary/subsystems/propulsion/propeller/hamilton_standard.py @@ -1,11 +1,13 @@ +import math import warnings + import numpy as np import openmdao.api as om -from aviary.utils.aviary_values import AviaryValues + +from aviary.constants import RHO_SEA_LEVEL_ENGLISH from aviary.variable_info.enums import Verbosity from aviary.variable_info.variables import Aircraft, Dynamic, Settings -from aviary.constants import RHO_SEA_LEVEL_ENGLISH, TSLS_DEGR -from aviary.utils.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option def _unint(xa, ya, x): @@ -67,18 +69,25 @@ def _unint(xa, ya, x): d2 = x - xa[jx1+1] d3 = x - xa[jx1+2] d4 = x - xa[jx1+3] - c1 = ra/p1*d2/p4*d3 - c2 = -ra/p1*d1/p2*d3 + rb/p2*d3/p5*d4 - c3 = ra/p2*d1/p4*d2 - rb/p2*d2/p3*d4 - c4 = rb/p5*d2/p3*d3 + c1 = ra / p1 * d2 / p4 * d3 + c2 = -ra / p1 * d1 / p2 * d3 + rb / p2 * d3 / p5 * d4 + c3 = ra / p2 * d1 / p4 * d2 - rb / p2 * d2 / p3 * d4 + c4 = rb / p5 * d2 / p3 * d3 y = ya[jx1]*c1 + ya[jx1+1]*c2 + ya[jx1+2]*c3 + ya[jx1+3]*c4 + # we don't want y to be an array + try: + y = y[0] + # floats/ints will give TypeError, numpy versions give IndexError + except (TypeError, IndexError): + pass + return y, Lmt def _biquad(T, i, xi, yi): """ - This routine interpolates over a 4 point interval using a + This routine interpolates over a 4 point interval using a variation of 2nd degree interpolation to produce a continuity of slope between adjacent intervals. @@ -239,6 +248,9 @@ def _biquad(T, i, xi, yi): return z, lmt +# block auto-formatting of tables +# autopep8: off +# fmt: off CP_Angle_table = np.array([ [ # 2 blades [0.0158, 0.0165, .0188, .0230, .0369, @@ -457,6 +469,8 @@ def _biquad(T, i, xi, yi): .525, .540, .565, .615, .670, .710, .745, .790, .825, .860, .880, .895, # X = 0.20 .225, .260, .320, .375, .430, .495, .550, .610, .660, .710, .740, .775, # X = 0.30 ]) +# autopep8: on +# fmt: on class PreHamiltonStandard(om.ExplicitComponent): @@ -470,140 +484,167 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - add_aviary_input(self, Aircraft.Engine.PROPELLER_DIAMETER, val=0.0, units='ft') + add_aviary_input(self, Aircraft.Engine.Propeller.DIAMETER, val=0.0, units='ft') add_aviary_input( - self, Dynamic.Mission.PROPELLER_TIP_SPEED, val=np.zeros(nn), units='ft/s' + self, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + val=np.zeros(nn), + units='ft/s', ) add_aviary_input( - self, Dynamic.Mission.SHAFT_POWER, val=np.zeros(nn), units='hp' + self, Dynamic.Vehicle.Propulsion.SHAFT_POWER, val=np.zeros(nn), units='hp' ) add_aviary_input( - self, Dynamic.Mission.DENSITY, val=np.zeros(nn), units='slug/ft**3' + self, Dynamic.Atmosphere.DENSITY, val=np.zeros(nn), units='slug/ft**3' ) - add_aviary_input(self, Dynamic.Mission.VELOCITY, val=np.zeros(nn), units='knot') + add_aviary_input(self, Dynamic.Mission.VELOCITY, val=np.zeros(nn), units='ft/s') add_aviary_input( - self, Dynamic.Mission.SPEED_OF_SOUND, val=np.zeros(nn), units='knot' + self, Dynamic.Atmosphere.SPEED_OF_SOUND, val=np.zeros(nn), units='ft/s' ) self.add_output('power_coefficient', val=np.zeros(nn), units='unitless') self.add_output('advance_ratio', val=np.zeros(nn), units='unitless') self.add_output('tip_mach', val=np.zeros(nn), units='unitless') - self.add_output('density_ratio', val=np.zeros(nn), units='unitless') + # TODO this conflicts with 2DOF phases that also output density ratio + # Right now repeating calculation in post-HS component where it is also used + # self.add_output('density_ratio', val=np.zeros(nn), units='unitless') def setup_partials(self): arange = np.arange(self.options['num_nodes']) - self.declare_partials( - 'density_ratio', Dynamic.Mission.DENSITY, rows=arange, cols=arange) + # self.declare_partials( + # 'density_ratio', Dynamic.Atmosphere.DENSITY, rows=arange, cols=arange) self.declare_partials( 'tip_mach', [ - Dynamic.Mission.PROPELLER_TIP_SPEED, - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + Dynamic.Atmosphere.SPEED_OF_SOUND, ], rows=arange, cols=arange, ) - self.declare_partials('advance_ratio', [ - Dynamic.Mission.VELOCITY, - Dynamic.Mission.PROPELLER_TIP_SPEED, - ], rows=arange, cols=arange) - self.declare_partials('power_coefficient', [ - Dynamic.Mission.SHAFT_POWER, - Dynamic.Mission.DENSITY, - Dynamic.Mission.PROPELLER_TIP_SPEED, - ], rows=arange, cols=arange) - self.declare_partials('power_coefficient', Aircraft.Engine.PROPELLER_DIAMETER) + self.declare_partials( + 'advance_ratio', + [ + Dynamic.Mission.VELOCITY, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + ], + rows=arange, + cols=arange, + ) + self.declare_partials( + 'power_coefficient', + [ + Dynamic.Vehicle.Propulsion.SHAFT_POWER, + Dynamic.Atmosphere.DENSITY, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + ], + rows=arange, + cols=arange, + ) + self.declare_partials('power_coefficient', Aircraft.Engine.Propeller.DIAMETER) def compute(self, inputs, outputs): - diam_prop = inputs[Aircraft.Engine.PROPELLER_DIAMETER] - shp = inputs[Dynamic.Mission.SHAFT_POWER] - vktas = inputs[Dynamic.Mission.VELOCITY] - tipspd = inputs[Dynamic.Mission.PROPELLER_TIP_SPEED] - sos = inputs[Dynamic.Mission.SPEED_OF_SOUND] + diam_prop = inputs[Aircraft.Engine.Propeller.DIAMETER] + shp = inputs[Dynamic.Vehicle.Propulsion.SHAFT_POWER] + vtas = inputs[Dynamic.Mission.VELOCITY] + tipspd = inputs[Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED] + sos = inputs[Dynamic.Atmosphere.SPEED_OF_SOUND] # arbitrarily small number to keep advance ratio nonzero, which allows for static thrust prediction - # NOTE need for a separate static thrust calc method? - vktas[np.where(vktas <= 1e-6)] = 1e-6 - density_ratio = inputs[Dynamic.Mission.DENSITY] / RHO_SEA_LEVEL_ENGLISH + vtas[np.where(vtas <= 1e-6)] = 1e-6 + density_ratio = inputs[Dynamic.Atmosphere.DENSITY] / RHO_SEA_LEVEL_ENGLISH if diam_prop <= 0.0: raise om.AnalysisError( - "Aircraft.Engine.PROPELLER_DIAMETER must be positive.") + "Aircraft.Engine.Propeller.DIAMETER must be positive.") if any(tipspd) <= 0.0: raise om.AnalysisError( - "Dynamic.Mission.PROPELLER_TIP_SPEED must be positive.") + "Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED must be positive." + ) if any(sos) <= 0.0: raise om.AnalysisError( - "Dynamic.Mission.SPEED_OF_SOUND must be positive.") + "Dynamic.Atmosphere.SPEED_OF_SOUND must be positive." + ) if any(density_ratio) <= 0.0: - raise om.AnalysisError("Dynamic.Mission.DENSITY must be positive.") + raise om.AnalysisError("Dynamic.Atmosphere.DENSITY must be positive.") if any(shp) < 0.0: - raise om.AnalysisError("Dynamic.Mission.SHAFT_POWER must be non-negative.") + raise om.AnalysisError( + "Dynamic.Vehicle.Propulsion.SHAFT_POWER must be non-negative." + ) - outputs['density_ratio'] = density_ratio - # 1118.21948771 is speed of sound at sea level + # outputs['density_ratio'] = density_ratio # TODO tip mach was already calculated, revisit this outputs['tip_mach'] = tipspd / sos - outputs['advance_ratio'] = 5.309 * vktas / tipspd - outputs['power_coefficient'] = shp * 10.E10 / (2 * 6966.) / density_ratio \ + outputs['advance_ratio'] = math.pi * vtas / tipspd + # TODO back out what is going on with unit conversion factor 10e10/(2*6966) + + outputs['power_coefficient'] = ( + shp + * 10.0e10 + / (2 * 6966.0) + / density_ratio / (tipspd**3 * diam_prop**2) + ) def compute_partials(self, inputs, partials): - vktas = inputs[Dynamic.Mission.VELOCITY] - tipspd = inputs[Dynamic.Mission.PROPELLER_TIP_SPEED] - rho = inputs[Dynamic.Mission.DENSITY] - diam_prop = inputs[Aircraft.Engine.PROPELLER_DIAMETER] - shp = inputs[Dynamic.Mission.SHAFT_POWER] - sos = inputs[Dynamic.Mission.SPEED_OF_SOUND] + vtas = inputs[Dynamic.Mission.VELOCITY] + tipspd = inputs[Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED] + rho = inputs[Dynamic.Atmosphere.DENSITY] + diam_prop = inputs[Aircraft.Engine.Propeller.DIAMETER] + shp = inputs[Dynamic.Vehicle.Propulsion.SHAFT_POWER] + sos = inputs[Dynamic.Atmosphere.SPEED_OF_SOUND] unit_conversion_const = 10.E10 / (2 * 6966.) - partials["density_ratio", Dynamic.Mission.DENSITY] = 1 / RHO_SEA_LEVEL_ENGLISH - partials["tip_mach", Dynamic.Mission.PROPELLER_TIP_SPEED] = 1 / sos - partials["tip_mach", Dynamic.Mission.SPEED_OF_SOUND] = -tipspd / sos**2 - partials["advance_ratio", Dynamic.Mission.VELOCITY] = 5.309 / tipspd - partials["advance_ratio", Dynamic.Mission.PROPELLER_TIP_SPEED] = - \ - 5.309 * vktas / (tipspd * tipspd) - partials["power_coefficient", Dynamic.Mission.SHAFT_POWER] = unit_conversion_const * \ + # partials["density_ratio", Dynamic.Atmosphere.DENSITY] = 1 / RHO_SEA_LEVEL_ENGLISH + partials["tip_mach", Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED] = 1 / sos + partials["tip_mach", Dynamic.Atmosphere.SPEED_OF_SOUND] = -tipspd / sos**2 + partials["advance_ratio", Dynamic.Mission.VELOCITY] = math.pi / tipspd + partials["advance_ratio", Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED] = ( + -math.pi * vtas / (tipspd * tipspd) + ) + partials["power_coefficient", Dynamic.Vehicle.Propulsion.SHAFT_POWER] = unit_conversion_const * \ RHO_SEA_LEVEL_ENGLISH / (rho * tipspd**3*diam_prop**2) - partials["power_coefficient", Dynamic.Mission.DENSITY] = -unit_conversion_const * shp * \ + partials["power_coefficient", Dynamic.Atmosphere.DENSITY] = -unit_conversion_const * shp * \ RHO_SEA_LEVEL_ENGLISH / (rho * rho * tipspd**3*diam_prop**2) - partials["power_coefficient", Dynamic.Mission.PROPELLER_TIP_SPEED] = -3 * \ + partials["power_coefficient", Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED] = -3 * \ unit_conversion_const * shp * RHO_SEA_LEVEL_ENGLISH / \ (rho * tipspd**4*diam_prop**2) - partials["power_coefficient", Aircraft.Engine.PROPELLER_DIAMETER] = -2 * \ + partials["power_coefficient", Aircraft.Engine.Propeller.DIAMETER] = -2 * \ unit_conversion_const * shp * RHO_SEA_LEVEL_ENGLISH / \ (rho * tipspd**3*diam_prop**3) class HamiltonStandard(om.ExplicitComponent): """ - This is Hamilton Standard component rewritten from Fortran code. - The original documentation is available at + This is Hamilton Standard component rewritten from Fortran code. + The original documentation is available at https://ntrs.nasa.gov/api/citations/19720010354/downloads/19720010354.pdf It computes the thrust coefficient of a propeller blade. """ def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') self.options.declare('num_nodes', default=1, types=int) + add_aviary_option(self, Aircraft.Engine.Propeller.NUM_BLADES) + add_aviary_option(self, Settings.VERBOSITY) + def setup(self): nn = self.options['num_nodes'] self.add_input('power_coefficient', val=np.zeros(nn), units='unitless') self.add_input('advance_ratio', val=np.zeros(nn), units='unitless') - add_aviary_input(self, Dynamic.Mission.MACH, val=np.zeros(nn), units='unitless') + add_aviary_input( + self, Dynamic.Atmosphere.MACH, val=np.zeros(nn), units='unitless' + ) self.add_input('tip_mach', val=np.zeros(nn), units='unitless') add_aviary_input( - self, Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, val=0.0, units='unitless' + self, Aircraft.Engine.Propeller.ACTIVITY_FACTOR, val=0.0, units='unitless' ) # Actitivty Factor per Blade add_aviary_input( self, - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, val=0.0, units='unitless', ) # blade integrated lift coeff @@ -615,9 +656,21 @@ def setup(self): self.declare_partials('*', '*', method='fd', form='forward') def compute(self, inputs, outputs): - verbosity = self.options['aviary_options'].get_val(Settings.VERBOSITY) - num_blades = self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_PROPELLER_BLADES) + verbosity = self.options[Settings.VERBOSITY] + num_blades = self.options[Aircraft.Engine.Propeller.NUM_BLADES] + + act_factor = inputs[Aircraft.Engine.Propeller.ACTIVITY_FACTOR][0] + cli = inputs[Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT][0] + + # TODO verify this works with multiple engine models (i.e. prop mission is + # properly slicing these inputs) + # ensure num_blades is an int, so it can be used as array index later + try: + len(num_blades) + except TypeError: + num_blades = int(num_blades) + else: + num_blades = int(num_blades[0]) for i_node in range(self.options['num_nodes']): ichck = 0 @@ -635,7 +688,7 @@ def compute(self, inputs, outputs): TXCLI = np.zeros(6) CTTT = np.zeros(4) XXXFT = np.zeros(4) - act_factor = inputs[Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR][0] + for k in range(2): AF_adj_CP[k], run_flag = _unint(Act_Factor_arr, AFCPC[k], act_factor) AF_adj_CT[k], run_flag = _unint(Act_Factor_arr, AFCTC[k], act_factor) @@ -667,7 +720,7 @@ def compute(self, inputs, outputs): # flag that given lift coeff (cli) does not fall on a node point of CL_arr CL_tab_idx_flg = 0 # NCL_flg ifnd = 0 - cli = inputs[Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT][0] + power_coefficient = inputs['power_coefficient'][i_node] for ii in range(6): cl_idx = ii @@ -693,7 +746,7 @@ def compute(self, inputs, outputs): lmod = (num_blades % 2) + 1 if (lmod == 1): nbb = 1 - idx_blade = int(num_blades/2.0) + idx_blade = int(num_blades / 2) # even number of blades idx_blade = 1 if 2 blades; # idx_blade = 2 if 4 blades; # idx_blade = 3 if 6 blades; @@ -723,10 +776,15 @@ def compute(self, inputs, outputs): CP_CLi_table[CL_tab_idx][:cli_len], XPCLI[CL_tab_idx], CPE1X) if (run_flag == 1): ichck = ichck + 1 - if verbosity >= Verbosity.DEBUG or ichck <= 1: + if verbosity == Verbosity.DEBUG or ichck <= Verbosity.BRIEF: if (run_flag == 1): warnings.warn( - f"Mach,VTMACH,J,power_coefficient,CP_Eff =: {inputs[Dynamic.Mission.MACH][i_node]},{inputs['tip_mach'][i_node]},{inputs['advance_ratio'][i_node]},{power_coefficient},{CP_Eff}") + f"Mach = {inputs[Dynamic.Atmosphere.MACH][i_node]}\n" + f"VTMACH = {inputs['tip_mach'][i_node]}\n" + f"J = {inputs['advance_ratio'][i_node]}\n" + f"power_coefficient = {power_coefficient}\n" + f"CP_Eff = {CP_Eff}" + ) if (kl == 4 and CPE1 < 0.010): print( f"Extrapolated data is being used for CLI=.6--CPE1,PXCLI,L= , {CPE1},{PXCLI[kl]},{idx_blade} Suggest inputting CLI=.5") @@ -740,7 +798,7 @@ def compute(self, inputs, outputs): CL_tab_idx = CL_tab_idx+1 if (CL_tab_idx_flg != 1): PCLI, run_flag = _unint( - CL_arr[CL_tab_idx_begin:CL_tab_idx_begin+4], PXCLI[CL_tab_idx_begin:CL_tab_idx_begin+4], inputs[Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT][0]) + CL_arr[CL_tab_idx_begin:CL_tab_idx_begin+4], PXCLI[CL_tab_idx_begin:CL_tab_idx_begin+4], inputs[Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT][0]) else: PCLI = PXCLI[CL_tab_idx_begin] # PCLI = CLI adjustment to power_coefficient @@ -748,7 +806,10 @@ def compute(self, inputs, outputs): ang_len = ang_arr_len[kdx] BLL[kdx], run_flag = _unint( # blade angle at baseline point for kdx - CP_Angle_table[idx_blade][kdx][:ang_len], Blade_angle_table[kdx], CP_Eff) + CP_Angle_table[idx_blade][kdx][:ang_len], + Blade_angle_table[kdx], + CP_Eff, + ) try: CTT[kdx], run_flag = _unint( # thrust coeff at baseline point for kdx @@ -758,9 +819,9 @@ def compute(self, inputs, outputs): "interp failed for CTT (thrust coefficient) in hamilton_standard.py") if run_flag > 1: NERPT = 2 - if verbosity >= Verbosity.DEBUG: - print( - f"ERROR IN PROP. PERF.-- NERPT={NERPT}, run_flag={run_flag}") + print( + f"ERROR IN PROP. PERF.-- NERPT={NERPT}, run_flag={run_flag}" + ) BLLL[ibb], run_flag = _unint( advance_ratio_array[J_begin:J_begin+4], BLL[J_begin:J_begin+4], inputs['advance_ratio'][i_node]) @@ -794,13 +855,14 @@ def compute(self, inputs, outputs): NERPT = 5 if (run_flag == 1): # off lower bound only. - if verbosity >= Verbosity.DEBUG: - print( - f"ERROR IN PROP. PERF.-- NERPT={NERPT}, run_flag={run_flag}, il = {il}, kl = {kl}") + print( + f"ERROR IN PROP. PERF.-- NERPT={NERPT}, " + f"run_flag={run_flag}, il={il}, kl = {kl}" + ) if (inputs['advance_ratio'][i_node] != 0.0): ZMCRT, run_flag = _unint( advance_ratio_array2, mach_corr_table[CL_tab_idx], inputs['advance_ratio'][i_node]) - DMN = inputs[Dynamic.Mission.MACH][i_node] - ZMCRT + DMN = inputs[Dynamic.Atmosphere.MACH][i_node] - ZMCRT else: ZMCRT = mach_tip_corr_arr[CL_tab_idx] DMN = inputs['tip_mach'][i_node] - ZMCRT @@ -810,7 +872,7 @@ def compute(self, inputs, outputs): XFFT[kl], run_flag = _biquad(comp_mach_CT_arr, 1, DMN, CTE2) CL_tab_idx = CL_tab_idx + 1 if (CL_tab_idx_flg != 1): - cli = inputs[Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT][0] + cli = inputs[Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT][0] TCLII, run_flag = _unint( CL_arr[CL_tab_idx_begin:CL_tab_idx_begin+4], TXCLI[CL_tab_idx_begin:CL_tab_idx_begin+4], cli) xft, run_flag = _unint( @@ -850,7 +912,7 @@ def compute(self, inputs, outputs): xft, run_flag = _unint(num_blades_arr, XXXFT, num_blades) # NOTE this could be handled via the metamodel comps (extrapolate flag) - if verbosity >= Verbosity.DEBUG and ichck > 0: + if ichck > 0: print(f" table look-up error = {ichck} (if you go outside the tables.)") outputs['thrust_coefficient'][i_node] = ct @@ -868,21 +930,26 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - add_aviary_input(self, Aircraft.Engine.PROPELLER_DIAMETER, val=0.0, units='ft') + add_aviary_input(self, Aircraft.Engine.Propeller.DIAMETER, val=0.0, units='ft') self.add_input('install_loss_factor', val=np.zeros(nn), units='unitless') self.add_input('thrust_coefficient', val=np.zeros(nn), units='unitless') self.add_input('comp_tip_loss_factor', val=np.zeros(nn), units='unitless') add_aviary_input( - self, Dynamic.Mission.PROPELLER_TIP_SPEED, val=np.zeros(nn), units='ft/s' + self, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + val=np.zeros(nn), + units='ft/s', ) - self.add_input('density_ratio', val=np.zeros(nn), units='unitless') + self.add_input(Dynamic.Atmosphere.DENSITY, val=np.zeros(nn), units='slug/ft**3') self.add_input('advance_ratio', val=np.zeros(nn), units='unitless') self.add_input('power_coefficient', val=np.zeros(nn), units='unitless') self.add_output('thrust_coefficient_comp_loss', val=np.zeros(nn), units='unitless') - add_aviary_output(self, Dynamic.Mission.THRUST, val=np.zeros(nn), units='lbf') + add_aviary_output( + self, Dynamic.Vehicle.Propulsion.THRUST, val=np.zeros(nn), units='lbf' + ) # keep them for reporting but don't seem to be required self.add_output('propeller_efficiency', val=np.zeros(nn), units='unitless') self.add_output('install_efficiency', val=np.zeros(nn), units='unitless') @@ -894,16 +961,24 @@ def setup_partials(self): 'thrust_coefficient', 'comp_tip_loss_factor', ], rows=arange, cols=arange) - self.declare_partials(Dynamic.Mission.THRUST, [ - 'thrust_coefficient', - 'comp_tip_loss_factor', - Dynamic.Mission.PROPELLER_TIP_SPEED, - 'density_ratio', - 'install_loss_factor', - ], rows=arange, cols=arange) - self.declare_partials(Dynamic.Mission.THRUST, [ - Aircraft.Engine.PROPELLER_DIAMETER, - ]) + self.declare_partials( + Dynamic.Vehicle.Propulsion.THRUST, + [ + 'thrust_coefficient', + 'comp_tip_loss_factor', + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + Dynamic.Atmosphere.DENSITY, + 'install_loss_factor', + ], + rows=arange, + cols=arange, + ) + self.declare_partials( + Dynamic.Vehicle.Propulsion.THRUST, + [ + Aircraft.Engine.Propeller.DIAMETER, + ] + ) self.declare_partials('propeller_efficiency', [ 'advance_ratio', 'power_coefficient', @@ -921,11 +996,19 @@ def setup_partials(self): def compute(self, inputs, outputs): ctx = inputs['thrust_coefficient']*inputs['comp_tip_loss_factor'] outputs['thrust_coefficient_comp_loss'] = ctx - diam_prop = inputs[Aircraft.Engine.PROPELLER_DIAMETER] - tipspd = inputs[Dynamic.Mission.PROPELLER_TIP_SPEED] + diam_prop = inputs[Aircraft.Engine.Propeller.DIAMETER] + tipspd = inputs[Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED] install_loss_factor = inputs['install_loss_factor'] - outputs[Dynamic.Mission.THRUST] = ctx*tipspd**2*diam_prop**2 * \ - inputs['density_ratio']/(1.515E06)*364.76*(1. - install_loss_factor) + density_ratio = inputs[Dynamic.Atmosphere.DENSITY] / RHO_SEA_LEVEL_ENGLISH + outputs[Dynamic.Vehicle.Propulsion.THRUST] = ( + ctx + * tipspd**2 + * diam_prop**2 + * density_ratio + / (1.515e06) + * 364.76 + * (1.0 - install_loss_factor) + ) # avoid divide by zero when shaft power is zero calc_idx = np.where(inputs['power_coefficient'] > 1e-6) # index where CP > 1e-5 @@ -940,26 +1023,59 @@ def compute_partials(self, inputs, partials): nn = self.options['num_nodes'] XFT = inputs['comp_tip_loss_factor'] ctx = inputs['thrust_coefficient']*XFT - diam_prop = inputs[Aircraft.Engine.PROPELLER_DIAMETER] + diam_prop = inputs[Aircraft.Engine.Propeller.DIAMETER] install_loss_factor = inputs['install_loss_factor'] - tipspd = inputs[Dynamic.Mission.PROPELLER_TIP_SPEED] + tipspd = inputs[Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED] + density_ratio = inputs[Dynamic.Atmosphere.DENSITY] / RHO_SEA_LEVEL_ENGLISH unit_conversion_factor = 364.76 / 1.515E06 partials["thrust_coefficient_comp_loss", 'thrust_coefficient'] = XFT partials["thrust_coefficient_comp_loss", 'comp_tip_loss_factor'] = inputs['thrust_coefficient'] - partials[Dynamic.Mission.THRUST, 'thrust_coefficient'] = XFT*tipspd**2*diam_prop**2 * \ - inputs['density_ratio']*unit_conversion_factor*(1. - install_loss_factor) - partials[Dynamic.Mission.THRUST, 'comp_tip_loss_factor'] = inputs['thrust_coefficient']*tipspd**2*diam_prop**2 * \ - inputs['density_ratio']*unit_conversion_factor*(1. - install_loss_factor) - partials[Dynamic.Mission.THRUST, Dynamic.Mission.PROPELLER_TIP_SPEED] = 2*ctx*tipspd*diam_prop**2 * \ - inputs['density_ratio']*unit_conversion_factor*(1. - install_loss_factor) - partials[Dynamic.Mission.THRUST, Aircraft.Engine.PROPELLER_DIAMETER] = 2*ctx*tipspd**2*diam_prop * \ - inputs['density_ratio']*unit_conversion_factor*(1. - install_loss_factor) - partials[Dynamic.Mission.THRUST, 'density_ratio'] = ctx*tipspd**2 * \ - diam_prop**2*unit_conversion_factor*(1. - install_loss_factor) - partials[Dynamic.Mission.THRUST, 'install_loss_factor'] = -ctx*tipspd**2*diam_prop**2 * \ - inputs['density_ratio']*unit_conversion_factor + partials[Dynamic.Vehicle.Propulsion.THRUST, 'thrust_coefficient'] = ( + XFT + * tipspd**2 + * diam_prop**2 + * density_ratio + * unit_conversion_factor + * (1.0 - install_loss_factor) + ) + partials[Dynamic.Vehicle.Propulsion.THRUST, 'comp_tip_loss_factor'] = ( + inputs['thrust_coefficient'] + * tipspd**2 + * diam_prop**2 + * density_ratio + * unit_conversion_factor + * (1.0 - install_loss_factor) + ) + partials[Dynamic.Vehicle.Propulsion.THRUST, Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED] = ( + 2 + * ctx + * tipspd + * diam_prop**2 + * density_ratio + * unit_conversion_factor + * (1.0 - install_loss_factor) + ) + partials[Dynamic.Vehicle.Propulsion.THRUST, Aircraft.Engine.Propeller.DIAMETER] = ( + 2 + * ctx + * tipspd**2 + * diam_prop + * density_ratio + * unit_conversion_factor + * (1.0 - install_loss_factor) + ) + partials[Dynamic.Vehicle.Propulsion.THRUST, Dynamic.Atmosphere.DENSITY] = ( + ctx + * tipspd**2 + * diam_prop**2 + * unit_conversion_factor + * (1.0 - install_loss_factor) / RHO_SEA_LEVEL_ENGLISH + ) + partials[Dynamic.Vehicle.Propulsion.THRUST, 'install_loss_factor'] = ( + -ctx * tipspd**2 * diam_prop**2 * density_ratio * unit_conversion_factor + ) calc_idx = np.where(inputs['power_coefficient'] > 1e-6) pow_coeff = inputs['power_coefficient'] diff --git a/aviary/subsystems/propulsion/propeller/propeller_builder.py b/aviary/subsystems/propulsion/propeller/propeller_builder.py new file mode 100644 index 000000000..ddcb60e83 --- /dev/null +++ b/aviary/subsystems/propulsion/propeller/propeller_builder.py @@ -0,0 +1,124 @@ +from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase +from aviary.subsystems.propulsion.propeller.propeller_performance import ( + PropellerPerformance, +) +from aviary.variable_info.variables import Aircraft, Dynamic, Mission + + +class PropellerBuilder(SubsystemBuilderBase): + """ + Define the builder for a propeller model using the Hamilton Standard methodology that + provides methods to define the propeller subsystem's states, design variables, + fixed values, initial guesses, and mass names. It also provides methods to build + OpenMDAO systems for the pre-mission and mission computations of the subsystem, + to get the constraints for the subsystem, and to preprocess the inputs for + the subsystem. + """ + + def __init__(self, name='HS_propeller'): + """Initializes the PropellerBuilder object with a given name.""" + super().__init__(name) + + def build_pre_mission(self, aviary_inputs): + """Builds an OpenMDAO system for the pre-mission computations of the subsystem.""" + return + + def build_mission(self, num_nodes, aviary_inputs): + """Builds an OpenMDAO system for the mission computations of the subsystem.""" + return PropellerPerformance(num_nodes=num_nodes, aviary_options=aviary_inputs) + + def get_design_vars(self): + """ + Design vars are only tested to see if they exist in pre_mission + Returns a dictionary of design variables for the gearbox subsystem, where the keys are the + names of the design variables, and the values are dictionaries that contain the units for + the design variable, the lower and upper bounds for the design variable, and any + additional keyword arguments required by OpenMDAO for the design variable. + + Returns + ------- + parameters : dict + A dict of names for the propeller subsystem. + """ + + # TODO bounds are rough placeholders + DVs = { + Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR: { + 'units': 'unitless', + 'lower': 100, + 'upper': 200, + # 'val': 100, # initial value + }, + Aircraft.Engine.PROPELLER_DIAMETER: { + 'units': 'ft', + 'lower': 0.0, + 'upper': None, + # 'val': 8, # initial value + }, + Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT: { + 'units': 'unitless', + 'lower': 0.0, + 'upper': 0.5, + # 'val': 0.5, + }, + } + return DVs + + def get_parameters(self, aviary_inputs=None, phase_info=None): + """ + Parameters are only tested to see if they exist in mission. + The value doesn't change throughout the mission. + Returns a dictionary of fixed values for the propeller subsystem, where the keys + are the names of the fixed values, and the values are dictionaries that contain + the fixed value for the variable, the units for the variable, and any additional + keyword arguments required by OpenMDAO for the variable. + + Returns + ------- + parameters : dict + A dict of names for the propeller subsystem. + """ + parameters = { + Aircraft.Engine.PROPELLER_TIP_MACH_MAX: { + 'val': 1.0, + 'units': 'unitless', + }, + Aircraft.Engine.PROPELLER_TIP_SPEED_MAX: { + 'val': 0.0, + 'units': 'unitless', + }, + Aircraft.Engine.PROPELLER_TIP_SPEED_MAX: { + 'val': 0.0, + 'units': 'ft/s', + }, + Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT: { + 'val': 0.0, + 'units': 'unitless', + }, + Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR: { + 'val': 0.0, + 'units': 'unitless', + }, + Aircraft.Engine.PROPELLER_DIAMETER: { + 'val': 0.0, + 'units': 'ft', + }, + Aircraft.Nacelle.AVG_DIAMETER: { + 'val': 0.0, + 'units': 'ft', + }, + } + + return parameters + + def get_mass_names(self): + return [Aircraft.Engine.Gearbox.MASS] + + def get_outputs(self): + return [ + Dynamic.Mission.SHAFT_POWER + '_out', + Dynamic.Mission.SHAFT_POWER_MAX + '_out', + Dynamic.Mission.RPM + '_out', + Dynamic.Mission.TORQUE + '_out', + Mission.Constraints.GEARBOX_SHAFT_POWER_RESIDUAL, + ] diff --git a/aviary/subsystems/propulsion/propeller/propeller_map.py b/aviary/subsystems/propulsion/propeller/propeller_map.py index 29cdd7a8b..204bc9de0 100644 --- a/aviary/subsystems/propulsion/propeller/propeller_map.py +++ b/aviary/subsystems/propulsion/propeller/propeller_map.py @@ -50,7 +50,7 @@ def __init__(self, name='propeller', options: AviaryValues = None, # Create dict for variables present in propeller data with associated units self.propeller_variables = {} - data_file = options.get_val(Aircraft.Engine.PROPELLER_DATA_FILE) + data_file = options.get_val(Aircraft.Engine.Propeller.DATA_FILE) self._read_data(data_file) def _read_data(self, data_file): @@ -122,7 +122,7 @@ def build_propeller_interpolator(self, num_nodes, options=None): method=interp_method, extrapolate=True, vec_size=num_nodes) # add inputs and outputs to interpolator - # depending on p, selected_mach can be Mach number (Dynamic.Mission.MACH) or helical Mach number + # depending on p, selected_mach can be Mach number (Dynamic.Atmosphere.MACH) or helical Mach number propeller.add_input('selected_mach', self.data[MACH], units='unitless', diff --git a/aviary/subsystems/propulsion/propeller/propeller_performance.py b/aviary/subsystems/propulsion/propeller/propeller_performance.py index 161fa7868..15917c46f 100644 --- a/aviary/subsystems/propulsion/propeller/propeller_performance.py +++ b/aviary/subsystems/propulsion/propeller/propeller_performance.py @@ -5,11 +5,16 @@ from openmdao.components.ks_comp import KSfunction -from aviary.subsystems.propulsion.propeller.hamilton_standard import HamiltonStandard, PostHamiltonStandard, PreHamiltonStandard +from aviary.subsystems.propulsion.propeller.hamilton_standard import ( + HamiltonStandard, + PostHamiltonStandard, + PreHamiltonStandard, +) from aviary.subsystems.propulsion.propeller.propeller_map import PropellerMap from aviary.utils.aviary_values import AviaryValues -from aviary.utils.functions import add_aviary_input, add_aviary_output + from aviary.variable_info.enums import OutMachType +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Dynamic @@ -47,60 +52,53 @@ def d_smooth_min(x, b, alpha=100.0): return d_sum_log_exp -class TipSpeedLimit(om.ExplicitComponent): +class TipSpeed(om.ExplicitComponent): """ - Computation of propeller tip speed. + Compute current propeller speed and allowable max tip speed + Maximum allowable tip speed is lower of helical tip Mach limited speed and + tip rotational speed limit """ def initialize(self): self.options.declare( - 'num_nodes', types=int, default=1, - desc='Number of nodes to be evaluated in the RHS') + 'num_nodes', + types=int, + default=1, + desc='Number of nodes to be evaluated in the RHS', + ) def setup(self): num_nodes = self.options['num_nodes'] add_aviary_input( - self, - Dynamic.Mission.VELOCITY, - val=np.zeros(num_nodes), - units='ft/s' + self, Dynamic.Mission.VELOCITY, val=np.zeros(num_nodes), units='ft/s' ) add_aviary_input( self, - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.SPEED_OF_SOUND, val=np.zeros(num_nodes), - units='ft/s' + units='ft/s', ) add_aviary_input( - self, - Aircraft.Engine.PROPELLER_TIP_MACH_MAX, - val=1.0, - units='unitless' + self, Dynamic.Vehicle.Propulsion.RPM, val=np.zeros(num_nodes), units='rpm' ) add_aviary_input( - self, - Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, - val=0.0, - units='ft/s' + self, Aircraft.Engine.Propeller.TIP_MACH_MAX, val=1.0, units='unitless' ) + add_aviary_input( - self, - Aircraft.Engine.PROPELLER_DIAMETER, - val=0.0, - units='ft' + self, Aircraft.Engine.Propeller.TIP_SPEED_MAX, val=0.0, units='ft/s' ) + add_aviary_input(self, Aircraft.Engine.Propeller.DIAMETER, val=0.0, units='ft') add_aviary_output( self, - Dynamic.Mission.PROPELLER_TIP_SPEED, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, val=np.zeros(num_nodes), - units='ft/s' + units='ft/s', ) self.add_output( - 'rpm', - val=np.zeros(num_nodes), - units='rpm' + 'propeller_tip_speed_limit', val=np.zeros(num_nodes), units='ft/s' ) def setup_partials(self): @@ -110,37 +108,35 @@ def setup_partials(self): r = np.arange(num_nodes) self.declare_partials( - Dynamic.Mission.PROPELLER_TIP_SPEED, + 'propeller_tip_speed_limit', [ Dynamic.Mission.VELOCITY, - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.SPEED_OF_SOUND, ], - rows=r, cols=r, + rows=r, + cols=r, ) - self.declare_partials( - Dynamic.Mission.PROPELLER_TIP_SPEED, + 'propeller_tip_speed_limit', [ - Aircraft.Engine.PROPELLER_TIP_MACH_MAX, - Aircraft.Engine.PROPELLER_TIP_SPEED_MAX + Aircraft.Engine.Propeller.TIP_MACH_MAX, + Aircraft.Engine.Propeller.TIP_SPEED_MAX, ], ) self.declare_partials( - 'rpm', + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, [ - Dynamic.Mission.VELOCITY, - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Vehicle.Propulsion.RPM, ], - rows=r, cols=r, + rows=r, + cols=r, ) self.declare_partials( - 'rpm', + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, [ - Aircraft.Engine.PROPELLER_TIP_MACH_MAX, - Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, - Aircraft.Engine.PROPELLER_DIAMETER + Aircraft.Engine.Propeller.DIAMETER, ], ) @@ -148,36 +144,38 @@ def compute(self, inputs, outputs): num_nodes = self.options['num_nodes'] velocity = inputs[Dynamic.Mission.VELOCITY] - sos = inputs[Dynamic.Mission.SPEED_OF_SOUND] - tip_mach_max = inputs[Aircraft.Engine.PROPELLER_TIP_MACH_MAX] - tip_speed_max = inputs[Aircraft.Engine.PROPELLER_TIP_SPEED_MAX] - diam = inputs[Aircraft.Engine.PROPELLER_DIAMETER] + sos = inputs[Dynamic.Atmosphere.SPEED_OF_SOUND] + tip_mach_max = inputs[Aircraft.Engine.Propeller.TIP_MACH_MAX] + tip_speed_max = inputs[Aircraft.Engine.Propeller.TIP_SPEED_MAX] + rpm = inputs[Dynamic.Vehicle.Propulsion.RPM] + diam = inputs[Aircraft.Engine.Propeller.DIAMETER] - tip_speed_mach_limit = ((sos * tip_mach_max)**2 - velocity**2)**0.5 + tip_speed_mach_limit = ((sos * tip_mach_max) ** 2 - velocity**2) ** 0.5 # use KSfunction for smooth derivitive across minimum tip_speed_max_nn = np.tile(tip_speed_max, num_nodes) - prop_tip_speed = -KSfunction.compute( + propeller_tip_speed_limit = -KSfunction.compute( -np.stack((tip_speed_max_nn, tip_speed_mach_limit), axis=1) ).flatten() - rpm = prop_tip_speed / (diam * math.pi / 60) + propeller_tip_speed = rpm * diam * math.pi / 60 - outputs[Dynamic.Mission.PROPELLER_TIP_SPEED] = prop_tip_speed - outputs['rpm'] = rpm + outputs[Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED] = propeller_tip_speed + outputs['propeller_tip_speed_limit'] = propeller_tip_speed_limit def compute_partials(self, inputs, J): num_nodes = self.options['num_nodes'] velocity = inputs[Dynamic.Mission.VELOCITY] - sos = inputs[Dynamic.Mission.SPEED_OF_SOUND] - tip_mach_max = inputs[Aircraft.Engine.PROPELLER_TIP_MACH_MAX] - tip_speed_max = inputs[Aircraft.Engine.PROPELLER_TIP_SPEED_MAX] - diam = inputs[Aircraft.Engine.PROPELLER_DIAMETER] + sos = inputs[Dynamic.Atmosphere.SPEED_OF_SOUND] + rpm = inputs[Dynamic.Vehicle.Propulsion.RPM] + tip_mach_max = inputs[Aircraft.Engine.Propeller.TIP_MACH_MAX] + tip_speed_max = inputs[Aircraft.Engine.Propeller.TIP_SPEED_MAX] + diam = inputs[Aircraft.Engine.Propeller.DIAMETER] tip_speed_max_nn = np.tile(tip_speed_max, num_nodes) - tip_speed_mach_limit = ((sos * tip_mach_max)**2 - velocity**2)**0.5 + tip_speed_mach_limit = ((sos * tip_mach_max) ** 2 - velocity**2) ** 0.5 val = -np.stack((tip_speed_max_nn, tip_speed_mach_limit), axis=1) - prop_tip_speed = -KSfunction.compute(val).flatten() + # prop_tip_speed = -KSfunction.compute(val).flatten() dKS, _ = KSfunction.derivatives(val) @@ -190,32 +188,25 @@ def compute_partials(self, inputs, J): dspeed_dmm = dKS[:, 1] * dtpml_m dspeed_dsm = dKS[:, 0] - J[Dynamic.Mission.PROPELLER_TIP_SPEED, - Dynamic.Mission.VELOCITY] = dspeed_dv - J[Dynamic.Mission.PROPELLER_TIP_SPEED, - Dynamic.Mission.SPEED_OF_SOUND] = dspeed_ds - J[Dynamic.Mission.PROPELLER_TIP_SPEED, - Aircraft.Engine.PROPELLER_TIP_MACH_MAX] = dspeed_dmm - J[Dynamic.Mission.PROPELLER_TIP_SPEED, - Aircraft.Engine.PROPELLER_TIP_SPEED_MAX] = dspeed_dsm - - rpm_fact = (diam * math.pi / 60) + J['propeller_tip_speed_limit', Dynamic.Mission.VELOCITY] = dspeed_dv + J['propeller_tip_speed_limit', Dynamic.Atmosphere.SPEED_OF_SOUND] = dspeed_ds + J['propeller_tip_speed_limit', Aircraft.Engine.Propeller.TIP_MACH_MAX] = ( + dspeed_dmm + ) + J['propeller_tip_speed_limit', Aircraft.Engine.Propeller.TIP_SPEED_MAX] = ( + dspeed_dsm + ) - J['rpm', - Dynamic.Mission.VELOCITY] = dspeed_dv / rpm_fact - J['rpm', - Dynamic.Mission.SPEED_OF_SOUND] = dspeed_ds / rpm_fact - J['rpm', - Aircraft.Engine.PROPELLER_TIP_MACH_MAX] = dspeed_dmm / rpm_fact - J['rpm', - Aircraft.Engine.PROPELLER_TIP_SPEED_MAX] = dspeed_dsm / rpm_fact + J[Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + Dynamic.Vehicle.Propulsion.RPM] = (diam * math.pi / 60) - J['rpm', Aircraft.Engine.PROPELLER_DIAMETER] = - \ - 60 * prop_tip_speed / (math.pi * diam**2) + J[Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + Aircraft.Engine.Propeller.DIAMETER] = (rpm * math.pi / 60) class OutMachs(om.ExplicitComponent): - """This utility sets up relations among helical Mach, free stream Mach and propeller tip Mach. + """ + This utility sets up relations among helical Mach, free stream Mach and propeller tip Mach. helical_mach = sqrt(mach^2 + tip_mach^2). It computes the value of one from the inputs of the other two. """ @@ -253,8 +244,9 @@ def setup(self): units="unitless", desc="helical Mach number", ) - self.declare_partials("helical_mach", [ - "tip_mach", "mach"], rows=arange, cols=arange) + self.declare_partials( + "helical_mach", ["tip_mach", "mach"], rows=arange, cols=arange + ) elif out_type is OutMachType.MACH: self.add_input( "tip_mach", @@ -274,8 +266,9 @@ def setup(self): units="unitless", desc="Mach number", ) - self.declare_partials("mach", [ - "tip_mach", "helical_mach"], rows=arange, cols=arange) + self.declare_partials( + "mach", ["tip_mach", "helical_mach"], rows=arange, cols=arange + ) elif out_type is OutMachType.TIP_MACH: self.add_input( "mach", @@ -295,8 +288,9 @@ def setup(self): units="unitless", desc="tip Mach number of a blade", ) - self.declare_partials("tip_mach", [ - "mach", "helical_mach"], rows=arange, cols=arange) + self.declare_partials( + "tip_mach", ["mach", "helical_mach"], rows=arange, cols=arange + ) def compute(self, inputs, outputs): out_type = self.options["output_mach_type"] @@ -320,23 +314,30 @@ def compute_partials(self, inputs, J): if out_type is OutMachType.HELICAL_MACH: mach = inputs["mach"] tip_mach = inputs["tip_mach"] - J["helical_mach", "mach"] = mach/np.sqrt(mach * mach + tip_mach * tip_mach) - J["helical_mach", "tip_mach"] = tip_mach / \ - np.sqrt(mach * mach + tip_mach * tip_mach) + J["helical_mach", "mach"] = mach / np.sqrt( + mach * mach + tip_mach * tip_mach + ) + J["helical_mach", "tip_mach"] = tip_mach / np.sqrt( + mach * mach + tip_mach * tip_mach + ) elif out_type is OutMachType.MACH: tip_mach = inputs["tip_mach"] helical_mach = inputs["helical_mach"] - J["mach", "helical_mach"] = helical_mach / \ - np.sqrt(helical_mach * helical_mach - tip_mach * tip_mach) - J["mach", "tip_mach"] = -tip_mach / \ - np.sqrt(helical_mach * helical_mach - tip_mach * tip_mach) + J["mach", "helical_mach"] = helical_mach / np.sqrt( + helical_mach * helical_mach - tip_mach * tip_mach + ) + J["mach", "tip_mach"] = -tip_mach / np.sqrt( + helical_mach * helical_mach - tip_mach * tip_mach + ) elif out_type is OutMachType.TIP_MACH: mach = inputs["mach"] helical_mach = inputs["helical_mach"] - J["tip_mach", "helical_mach"] = helical_mach / \ - np.sqrt(helical_mach * helical_mach - mach * mach) - J["tip_mach", "mach"] = -mach / \ - np.sqrt(helical_mach * helical_mach - mach * mach) + J["tip_mach", "helical_mach"] = helical_mach / np.sqrt( + helical_mach * helical_mach - mach * mach + ) + J["tip_mach", "mach"] = -mach / np.sqrt( + helical_mach * helical_mach - mach * mach + ) class AreaSquareRatio(om.ExplicitComponent): @@ -415,13 +416,13 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] range = np.arange(nn) - self.add_input("vktas", val=np.zeros(nn), units='knot') + self.add_input("vtas", val=np.zeros(nn), units='ft/s') self.add_input("tipspd", val=np.zeros(nn), units='ft/s') self.add_input("sqa_array", val=np.zeros(nn), units='unitless') self.add_output("equiv_adv_ratio", val=np.zeros(nn), units='unitless') self.declare_partials("equiv_adv_ratio", - ["vktas", "tipspd"], + ["vtas", "tipspd"], rows=range, cols=range) self.declare_partials("equiv_adv_ratio", @@ -430,10 +431,10 @@ def setup(self): def compute(self, inputs, outputs): nn = self.options['num_nodes'] - vktas = inputs["vktas"] + vtas = inputs["vtas"] tipspd = inputs["tipspd"] sqa_array = inputs["sqa_array"] - equiv_adv_ratio = (1.0 - 0.254 * sqa_array) * 5.309 * vktas / tipspd + equiv_adv_ratio = (1.0 - 0.254 * sqa_array) * math.pi * vtas / tipspd smooth = self.options["smooth_zje"] if smooth: @@ -445,65 +446,198 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, partials): nn = self.options['num_nodes'] - vktas = inputs["vktas"] + vtas = inputs["vtas"] tipspd = inputs["tipspd"] sqa_array = inputs["sqa_array"] - jze = (1.0 - 0.254 * sqa_array) * 5.309 * vktas / tipspd + jze = (1.0 - 0.254 * sqa_array) * math.pi * vtas / tipspd - djze_dsqa = -0.254 * 5.309 * vktas / tipspd - djze_dvktas = (1.0 - 0.254 * sqa_array) * 5.309 / tipspd - djze_dtipspd = -(1.0 - 0.254 * sqa_array) * 5.309 * vktas / tipspd**2 + djze_dsqa = -0.254 * math.pi * vtas / tipspd + djze_dvtas = (1.0 - 0.254 * sqa_array) * math.pi / tipspd + djze_dtipspd = -(1.0 - 0.254 * sqa_array) * math.pi * vtas / tipspd**2 smooth = self.options["smooth_zje"] if smooth: alpha = self.options["alpha"] - djze_dsqa = d_smooth_min(jze, np.ones(nn) * 5.0, alpha) * djze_dsqa - djze_dvktas = d_smooth_min(jze, np.ones(nn) * 5.0, alpha) * djze_dvktas - djze_dtipspd = d_smooth_min(jze, np.ones(nn) * 5.0, alpha) * djze_dtipspd + djze_dsqa = d_smooth_min(jze, np.ones(nn) * 5.0, alpha) * djze_dsqa + djze_dvtas = d_smooth_min(jze, np.ones(nn) * 5.0, alpha) * djze_dvtas + djze_dtipspd = d_smooth_min(jze, np.ones(nn) * 5.0, alpha) * djze_dtipspd else: djze_dsqa = np.piecewise(jze, [jze < 5, jze >= 5], [1, 0]) * djze_dsqa - djze_dvktas = np.piecewise(jze, [jze < 5, jze >= 5], [1, 0]) * djze_dvktas + djze_dvtas = np.piecewise(jze, [jze < 5, jze >= 5], [1, 0]) * djze_dvtas djze_dtipspd = np.piecewise(jze, [jze < 5, jze >= 5], [1, 0]) * djze_dtipspd partials["equiv_adv_ratio", "sqa_array"] = djze_dsqa - partials["equiv_adv_ratio", "vktas"] = djze_dvktas + partials["equiv_adv_ratio", "vtas"] = djze_dvtas partials["equiv_adv_ratio", "tipspd"] = djze_dtipspd -class InstallLoss(om.Group): +class AreaSquareRatio(om.ExplicitComponent): """ - Compute installation loss + Compute the area ratio nacelle and propeller with a maximum 0.5. + """ + + def initialize(self): + self.options.declare("num_nodes", types=int) + self.options.declare('smooth_sqa', default=True, types=bool) + self.options.declare('alpha', default=100.0, types=float) + + def setup(self): + nn = self.options["num_nodes"] + arange = np.arange(self.options["num_nodes"]) + self.add_input("DiamNac", val=0.0, units='ft') + self.add_input("DiamProp", val=0.0, units='ft') + + self.add_output('sqa_array', val=np.zeros(nn), units='unitless') + + self.declare_partials("sqa_array", + [ + "DiamNac", + "DiamProp", + ], + rows=arange, cols=np.zeros(nn)) + + def compute(self, inputs, outputs): + nn = self.options["num_nodes"] + diamNac = inputs["DiamNac"] + diamProp = inputs["DiamProp"] + sqa = diamNac**2 / diamProp**2 + + smooth = self.options["smooth_sqa"] + if smooth: + alpha = self.options['alpha'] + sqa = smooth_min(sqa, 0.50, alpha) + else: + sqa = np.minimum(sqa, 0.50) + outputs["sqa_array"] = np.ones(nn) * sqa + + def compute_partials(self, inputs, partials): + diamNac = inputs["DiamNac"] + diamProp = inputs["DiamProp"] + sqa = diamNac**2 / diamProp**2 + + dSQA_dNacDiam = 2 * diamNac / diamProp**2 + dSQA_dPropDiam = -2 * diamNac**2 / diamProp**3 + + smooth = self.options["smooth_sqa"] + if smooth: + alpha = self.options['alpha'] + dSQA_dNacDiam = d_smooth_min(sqa, 0.50, alpha) * dSQA_dNacDiam + dSQA_dPropDiam = d_smooth_min(sqa, 0.50, alpha) * dSQA_dPropDiam + else: + dSQA_dNacDiam = np.piecewise( + sqa, [sqa < 0.5, sqa >= 0.5], [1, 0]) * dSQA_dNacDiam + dSQA_dPropDiam = np.piecewise( + sqa, [sqa < 0.5, sqa >= 0.5], [1, 0]) * dSQA_dPropDiam + partials['sqa_array', "DiamNac"] = dSQA_dNacDiam + partials['sqa_array', "DiamProp"] = dSQA_dPropDiam + + +class AdvanceRatio(om.ExplicitComponent): + """ + Compute the advance ratio jze with a maximum 5.0. """ def initialize(self): self.options.declare( 'num_nodes', types=int, default=1, desc='Number of nodes to be evaluated in the RHS') + self.options.declare('smooth_zje', default=True, types=bool) + self.options.declare('alpha', default=100.0, types=float) + + def setup(self): + nn = self.options['num_nodes'] + range = np.arange(nn) + self.add_input("vtas", val=np.zeros(nn), units='ft/s') + self.add_input("tipspd", val=np.zeros(nn), units='ft/s') + self.add_input("sqa_array", val=np.zeros(nn), units='unitless') + self.add_output("equiv_adv_ratio", val=np.zeros(nn), units='unitless') + + self.declare_partials("equiv_adv_ratio", + ["vtas", "tipspd"], + rows=range, cols=range) + + self.declare_partials("equiv_adv_ratio", + ["sqa_array"], + rows=range, cols=range) + + def compute(self, inputs, outputs): + nn = self.options['num_nodes'] + vtas = inputs["vtas"] + tipspd = inputs["tipspd"] + sqa_array = inputs["sqa_array"] + equiv_adv_ratio = (1.0 - 0.254 * sqa_array) * math.pi * vtas / tipspd + + smooth = self.options["smooth_zje"] + if smooth: + alpha = self.options['alpha'] + jze = smooth_min(equiv_adv_ratio, np.ones(nn) * 5.0, alpha) + else: + jze = np.minimum(equiv_adv_ratio, np.ones(nn) * 5.0) + outputs["equiv_adv_ratio"] = jze + + def compute_partials(self, inputs, partials): + nn = self.options['num_nodes'] + vtas = inputs["vtas"] + tipspd = inputs["tipspd"] + sqa_array = inputs["sqa_array"] + jze = (1.0 - 0.254 * sqa_array) * math.pi * vtas / tipspd + + djze_dsqa = -0.254 * math.pi * vtas / tipspd + djze_dvtas = (1.0 - 0.254 * sqa_array) * math.pi / tipspd + djze_dtipspd = -(1.0 - 0.254 * sqa_array) * math.pi * vtas / tipspd**2 + + smooth = self.options["smooth_zje"] + if smooth: + alpha = self.options["alpha"] + djze_dsqa = d_smooth_min(jze, np.ones(nn) * 5.0, alpha) * djze_dsqa + djze_dvtas = d_smooth_min(jze, np.ones(nn) * 5.0, alpha) * djze_dvtas + djze_dtipspd = d_smooth_min(jze, np.ones(nn) * 5.0, alpha) * djze_dtipspd + else: + djze_dsqa = np.piecewise(jze, [jze < 5, jze >= 5], [1, 0]) * djze_dsqa + djze_dvtas = np.piecewise(jze, [jze < 5, jze >= 5], [1, 0]) * djze_dvtas + djze_dtipspd = np.piecewise(jze, [jze < 5, jze >= 5], [1, 0]) * djze_dtipspd + partials["equiv_adv_ratio", "sqa_array"] = djze_dsqa + partials["equiv_adv_ratio", "vtas"] = djze_dvtas + partials["equiv_adv_ratio", "tipspd"] = djze_dtipspd + + +class InstallLoss(om.Group): + """ + Compute installation loss + """ + + def initialize(self): self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + 'num_nodes', + types=int, + default=1, + desc='Number of nodes to be evaluated in the RHS', + ) def setup(self): nn = self.options['num_nodes'] self.add_subsystem( name='sqa_comp', subsys=AreaSquareRatio(num_nodes=nn, smooth_sqa=True), - promotes_inputs=[("DiamNac", Aircraft.Nacelle.AVG_DIAMETER), - ("DiamProp", Aircraft.Engine.PROPELLER_DIAMETER)], + promotes_inputs=[ + ("DiamNac", Aircraft.Nacelle.AVG_DIAMETER), + ("DiamProp", Aircraft.Engine.Propeller.DIAMETER), + ], promotes_outputs=["sqa_array"], ) self.add_subsystem( name='zje_comp', subsys=AdvanceRatio(num_nodes=nn, smooth_zje=True), - promotes_inputs=["sqa_array", ("vktas", Dynamic.Mission.VELOCITY), - ("tipspd", Dynamic.Mission.PROPELLER_TIP_SPEED)], + promotes_inputs=["sqa_array", ("vtas", Dynamic.Mission.VELOCITY), + ("tipspd", Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED)], promotes_outputs=["equiv_adv_ratio"], ) self.blockage_factor_interp = self.add_subsystem( "blockage_factor_interp", - om.MetaModelStructuredComp(method="2D-slinear", - extrapolate=True, vec_size=nn), + om.MetaModelStructuredComp( + method="2D-slinear", extrapolate=True, vec_size=nn + ), promotes_inputs=["sqa_array", "equiv_adv_ratio"], promotes_outputs=[ "blockage_factor", @@ -521,7 +655,7 @@ def setup(self): self.blockage_factor_interp.add_input( "equiv_adv_ratio", 0.0, - training_data=[0., 0.5, 1.0, 2.0, 3.0, 4.0, 5.0], + training_data=[0.0, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0], units="unitless", desc="square of DiamNac vs DiamProp", ) @@ -532,16 +666,18 @@ def setup(self): units="unitless", desc="blockage factor", training_data=np.array( - [[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], - [0.992, 0.991, 0.988, 0.983, 0.976, 0.970, 0.963], - [0.986, 0.982, 0.977, 0.965, 0.953, 0.940, 0.927], - [0.979, 0.974, 0.967, 0.948, 0.929, 0.908, 0.887], - [0.972, 0.965, 0.955, 0.932, 0.905, 0.872, 0.835], - [0.964, 0.954, 0.943, 0.912, 0.876, 0.834, 0.786], - [0.955, 0.943, 0.928, 0.892, 0.848, 0.801, 0.751], - [0.948, 0.935, 0.917, 0.872, 0.820, 0.763, 0.706], - [0.940, 0.924, 0.902, 0.848, 0.790, 0.726, 0.662], - [0.904, 0.875, 0.835, 0.740, 0.655, 0.560, 0.464]] + [ + [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], + [0.992, 0.991, 0.988, 0.983, 0.976, 0.970, 0.963], + [0.986, 0.982, 0.977, 0.965, 0.953, 0.940, 0.927], + [0.979, 0.974, 0.967, 0.948, 0.929, 0.908, 0.887], + [0.972, 0.965, 0.955, 0.932, 0.905, 0.872, 0.835], + [0.964, 0.954, 0.943, 0.912, 0.876, 0.834, 0.786], + [0.955, 0.943, 0.928, 0.892, 0.848, 0.801, 0.751], + [0.948, 0.935, 0.917, 0.872, 0.820, 0.763, 0.706], + [0.940, 0.924, 0.902, 0.848, 0.790, 0.726, 0.662], + [0.904, 0.875, 0.835, 0.740, 0.655, 0.560, 0.464], + ] ), ) @@ -562,64 +698,55 @@ class PropellerPerformance(om.Group): """ Computation of propeller thrust coefficient based on the Hamilton Standard model or a user provided propeller map. Note that a propeller map allows either the helical Mach number or - free stream Mach number as input. This infomation will be detected automatically when the + free stream Mach number as input. This infomation will be detected automatically when the propeller map is loaded into memory. The installation loss factor is either a user input or computed internally. """ def initialize(self): self.options.declare( - 'num_nodes', types=int, default=1, - desc='Number of nodes to be evaluated in the RHS') + 'num_nodes', + types=int, + default=1, + desc='Number of nodes to be evaluated in the RHS', + ) + self.options.declare( - 'input_rpm', types=bool, default=False, - desc='If True, the input is RPM, otherwise RPM is set by propeller limits') + 'aviary_options', + types=AviaryValues, + desc='collection of Aircraft/Mission specific options', + ) - self.options.declare('aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS) + add_aviary_option(self, Aircraft.Engine.Propeller.DATA_FILE) def setup(self): options = self.options nn = options['num_nodes'] aviary_options = options['aviary_options'] - # TODO options are lists here when using full Aviary problem - need further investigation - compute_installation_loss = aviary_options.get_val( - Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS - ) + # TODO options are lists here when using full Aviary problem - need + # further investigation + compute_installation_loss = options[ + Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS + ] + if isinstance(compute_installation_loss, (list, np.ndarray)): compute_installation_loss = compute_installation_loss[0] - use_propeller_map = aviary_options.get_val(Aircraft.Engine.USE_PROPELLER_MAP) - if isinstance(use_propeller_map, (list, np.ndarray)): - use_propeller_map = use_propeller_map[0] + try: + prop_file_path = aviary_options.get_val(Aircraft.Engine.Propeller.DATA_FILE) + except KeyError: + prop_file_path = None + if isinstance(prop_file_path, (list, np.ndarray)): + prop_file_path = prop_file_path[0] - if self.options['input_rpm']: - # compute the propeller tip speed based on the input RPM and diameter of the propeller - # NOTE allows for violation of tip speed limits - self.add_subsystem( - 'compute_tip_speed', - om.ExecComp( - 'prop_tip_speed = diameter * rpm * pi / 60.', - prop_tip_speed={'units': "ft/s", 'shape': nn}, - diameter={'val': 0., 'units': "ft"}, - rpm={'units': "rpm", 'shape': nn}, - has_diag_partials=True, - ), - promotes_inputs=[ - 'rpm', # TODO this should be in dynamic - ('diameter', Aircraft.Engine.PROPELLER_DIAMETER), - ], - promotes_outputs=[ - ('prop_tip_speed', Dynamic.Mission.PROPELLER_TIP_SPEED)], - ) - - else: - self.add_subsystem( - 'tip_speed_limit', - subsys=TipSpeedLimit(num_nodes=nn), - promotes=['*'] - ) + # compute the propeller tip speed based on the input RPM and diameter of the propeller + # NOTE allows for violation of tip speed limits + # TODO provide warning to user when max tip speeds are violated + self.add_subsystem( + 'compute_tip_speed', subsys=TipSpeed(num_nodes=nn), promotes=['*'] + ) if compute_installation_loss: self.add_subsystem( @@ -627,46 +754,46 @@ def setup(self): subsys=InstallLoss(num_nodes=nn), promotes_inputs=[ Aircraft.Nacelle.AVG_DIAMETER, - Aircraft.Engine.PROPELLER_DIAMETER, + Aircraft.Engine.Propeller.DIAMETER, Dynamic.Mission.VELOCITY, - Dynamic.Mission.PROPELLER_TIP_SPEED, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, ], promotes_outputs=['install_loss_factor'], ) else: self.set_input_defaults( - 'install_loss_factor', val=np.ones(nn), units="unitless") + 'install_loss_factor', val=np.ones(nn), units="unitless" + ) self.add_subsystem( name='pre_hamilton_standard', subsys=PreHamiltonStandard(num_nodes=nn), promotes_inputs=[ - Dynamic.Mission.DENSITY, - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, Dynamic.Mission.VELOCITY, - Dynamic.Mission.PROPELLER_TIP_SPEED, - Aircraft.Engine.PROPELLER_DIAMETER, - Dynamic.Mission.SHAFT_POWER, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + Aircraft.Engine.Propeller.DIAMETER, + Dynamic.Vehicle.Propulsion.SHAFT_POWER, ], promotes_outputs=[ "power_coefficient", "advance_ratio", "tip_mach", - "density_ratio", + # "density_ratio", ], ) - if use_propeller_map: + if prop_file_path is not None: prop_model = PropellerMap('prop', aviary_options) - prop_file_path = aviary_options.get_val( - Aircraft.Engine.PROPELLER_DATA_FILE) mach_type = prop_model.read_and_set_mach_type(prop_file_path) if mach_type == OutMachType.HELICAL_MACH: self.add_subsystem( name='selectedMach', subsys=OutMachs( - num_nodes=nn, output_mach_type=OutMachType.HELICAL_MACH), - promotes_inputs=[("mach", Dynamic.Mission.MACH), "tip_mach"], + num_nodes=nn, output_mach_type=OutMachType.HELICAL_MACH + ), + promotes_inputs=[("mach", Dynamic.Atmosphere.MACH), "tip_mach"], promotes_outputs=[("helical_mach", "selected_mach")], ) else: @@ -678,7 +805,9 @@ def setup(self): selected_mach={'units': 'unitless', 'shape': nn}, has_diag_partials=True, ), - promotes_inputs=[("mach", Dynamic.Mission.MACH),], + promotes_inputs=[ + ("mach", Dynamic.Atmosphere.MACH), + ], promotes_outputs=["selected_mach"], ) propeller = prop_model.build_propeller_interpolator(nn, aviary_options) @@ -692,27 +821,30 @@ def setup(self): ], promotes_outputs=[ "thrust_coefficient", - ]) + ], + ) # propeller map has taken compresibility into account. - self.set_input_defaults('comp_tip_loss_factor', - np.linspace(1.0, 1.0, nn), units='unitless') + self.set_input_defaults( + 'comp_tip_loss_factor', np.linspace(1.0, 1.0, nn), units='unitless' + ) else: self.add_subsystem( name='hamilton_standard', - subsys=HamiltonStandard(num_nodes=nn, aviary_options=aviary_options), + subsys=HamiltonStandard(num_nodes=nn), promotes_inputs=[ - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, "power_coefficient", "advance_ratio", "tip_mach", - Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, + Aircraft.Engine.Propeller.ACTIVITY_FACTOR, + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, ], promotes_outputs=[ "thrust_coefficient", "comp_tip_loss_factor", - ]) + ], + ) self.add_subsystem( name='post_hamilton_standard', @@ -720,16 +852,17 @@ def setup(self): promotes_inputs=[ "thrust_coefficient", "comp_tip_loss_factor", - Dynamic.Mission.PROPELLER_TIP_SPEED, - Aircraft.Engine.PROPELLER_DIAMETER, - "density_ratio", + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + Aircraft.Engine.Propeller.DIAMETER, + Dynamic.Atmosphere.DENSITY, 'install_loss_factor', "advance_ratio", "power_coefficient", ], promotes_outputs=[ "thrust_coefficient_comp_loss", - Dynamic.Mission.THRUST, + Dynamic.Vehicle.Propulsion.THRUST, "propeller_efficiency", "install_efficiency", - ]) + ], + ) diff --git a/aviary/subsystems/propulsion/propulsion_builder.py b/aviary/subsystems/propulsion/propulsion_builder.py index 3ba9ea872..47109287e 100644 --- a/aviary/subsystems/propulsion/propulsion_builder.py +++ b/aviary/subsystems/propulsion/propulsion_builder.py @@ -10,6 +10,8 @@ import numpy as np +from openmdao.utils.units import convert_units as _convert_units + from aviary.interface.utils.markdown_utils import write_markdown_variable_table from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase @@ -113,7 +115,8 @@ def build_pre_mission(self, aviary_inputs): engine_models=self.engine_models) def build_mission(self, num_nodes, aviary_inputs, **kwargs): - return PropulsionMission(num_nodes=num_nodes, aviary_options=aviary_inputs, + return PropulsionMission(num_nodes=num_nodes, + aviary_options=aviary_inputs, engine_models=self.engine_models) # NOTE untested! @@ -151,11 +154,23 @@ def get_parameters(self, aviary_inputs=None, phase_info=None): # collect all the parameters for engines for engine in self.engine_models: engine_params = engine.get_parameters() + # for param in engine_params: + # # For any parameters that need to be vectorized for multiple engines, + # # apply correct shape + # if param in params: + # try: + # shape_old = params[param]['shape'][0] + # except KeyError: + # # If shape is not defined yet, this is the first time there is + # # a duplicate + # shape_old = 1 + # engine_params[param]['shape'] = (shape_old + 1,) + params.update(engine_params) # for any parameters that need to be vectorized for multiple engines, apply # correct shape - engine_vars = _get_engine_variables() + engine_vars = [var for var in _get_engine_variables()] for var in params: if var in engine_vars: # TODO shape for variables that are supposed to be vectors, like wing diff --git a/aviary/subsystems/propulsion/propulsion_mission.py b/aviary/subsystems/propulsion/propulsion_mission.py index 6237f7dcf..3c79eee15 100644 --- a/aviary/subsystems/propulsion/propulsion_mission.py +++ b/aviary/subsystems/propulsion/propulsion_mission.py @@ -4,6 +4,7 @@ import openmdao.api as om from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft, Dynamic, Settings @@ -34,21 +35,50 @@ def setup(self): num_engine_type = len(engine_models) if num_engine_type > 1: + # We need a component to add parameters to problem. Dymos can't find it when + # it is already sliced across several components. + # TODO is this problem fixable from dymos end (introspection includes parameters)? + + # create set of params + # TODO get_parameters() should have access to aviary options + phase info + param_dict = {} + # save parameters for use in configure() + parameters = self.parameters = set() + for engine in engine_models: + eng_params = engine.get_parameters() + param_dict.update(eng_params) + + parameters.update(param_dict.keys()) + + # if params exist, create execcomp, fill with placeholder equations + if len(parameters) != 0: + comp = om.ExecComp(has_diag_partials=True) + + for i, param in enumerate(parameters): + # try to find units information + try: + units = param_dict[param]['units'] + except KeyError: + units = 'unitless' + + attrs = { + f'x_{i}': { + 'val': np.ones(num_engine_type), + 'units': units, + }, + f'y_{i}': { + 'val': np.ones(num_engine_type), + 'units': units, + }, + } + comp.add_expr( + f'y_{i}=x_{i}', + **attrs, + ) - # We need a single component with scale_factor. Dymos can't find it when it is - # already sliced across several component. - # TODO this only works for engine decks. Need to fix problem in generic way - comp = om.ExecComp( - "y=x", - y={'val': np.ones(num_engine_type), 'units': 'unitless'}, - x={'val': np.ones(num_engine_type), 'units': 'unitless'}, - has_diag_partials=True, - ) self.add_subsystem( - "scale_passthrough", + "parameter_passthrough", comp, - promotes_inputs=[('x', Aircraft.Engine.SCALE_FACTOR)], - promotes_outputs=[('y', 'passthrough_scale_factor')], ) for i, engine in enumerate(engine_models): @@ -61,22 +91,25 @@ def setup(self): # split vectorized throttles and connect to the correct engine model self.promotes( engine.name, - inputs=[Dynamic.Mission.THROTTLE], + inputs=[Dynamic.Vehicle.Propulsion.THROTTLE], src_indices=om.slicer[:, i], ) - self.promotes( - engine.name, - inputs=[(Aircraft.Engine.SCALE_FACTOR, 'passthrough_scale_factor')], - src_indices=om.slicer[i], - ) + # loop through params and slice as needed + params = engine.get_parameters() + for param in params: + self.promotes( + engine.name, + inputs=[(param, param + '_passthrough')], + src_indices=om.slicer[i], + ) # TODO if only some engine use hybrid throttle, source vector will have an # index for that engine that is unused, will this confuse optimizer? if engine.use_hybrid_throttle: self.promotes( engine.name, - inputs=[Dynamic.Mission.HYBRID_THROTTLE], + inputs=[Dynamic.Vehicle.Propulsion.HYBRID_THROTTLE], src_indices=om.slicer[:, i], ) else: @@ -89,41 +122,67 @@ def setup(self): promotes_inputs=['*'], ) - self.promotes(engine.name, inputs=[Dynamic.Mission.THROTTLE]) + self.promotes(engine.name, inputs=[Dynamic.Vehicle.Propulsion.THROTTLE]) if engine.use_hybrid_throttle: - self.promotes(engine.name, inputs=[Dynamic.Mission.HYBRID_THROTTLE]) + self.promotes( + engine.name, inputs=[Dynamic.Vehicle.Propulsion.HYBRID_THROTTLE] + ) # TODO might be able to avoid hardcoding using propulsion Enums # mux component to vectorize individual engine outputs into 2d arrays perf_mux = om.MuxComp(vec_size=num_engine_type) # add each engine data variable to mux component perf_mux.add_var( - Dynamic.Mission.THRUST, val=0, shape=(nn,), axis=1, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST, val=0, shape=(nn,), axis=1, units='lbf' ) perf_mux.add_var( - Dynamic.Mission.THRUST_MAX, val=0, shape=(nn,), axis=1, units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_MAX, + val=0, + shape=(nn,), + axis=1, + units='lbf', ) perf_mux.add_var( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, val=0, shape=(nn,), axis=1, units='lbm/h', ) perf_mux.add_var( - Dynamic.Mission.ELECTRIC_POWER_IN, val=0, shape=(nn,), axis=1, units='kW' + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, + val=0, + shape=(nn,), + axis=1, + units='kW', ) perf_mux.add_var( - Dynamic.Mission.NOX_RATE, val=0, shape=(nn,), axis=1, units='lb/h' + Dynamic.Vehicle.Propulsion.NOX_RATE, + val=0, + shape=(nn,), + axis=1, + units='lb/h', ) perf_mux.add_var( - Dynamic.Mission.TEMPERATURE_T4, val=0, shape=(nn,), axis=1, units='degR' + Dynamic.Vehicle.Propulsion.TEMPERATURE_T4, + val=0, + shape=(nn,), + axis=1, + units='degR', ) perf_mux.add_var( - Dynamic.Mission.SHAFT_POWER, val=0, shape=(nn,), axis=1, units='hp' + Dynamic.Vehicle.Propulsion.SHAFT_POWER, + val=0, + shape=(nn,), + axis=1, + units='hp', ) perf_mux.add_var( - Dynamic.Mission.SHAFT_POWER_MAX, val=0, shape=(nn,), axis=1, units='hp' + Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX, + val=0, + shape=(nn,), + axis=1, + units='hp', ) # perf_mux.add_var( # 'exit_area_unscaled', @@ -137,7 +196,7 @@ def setup(self): self.add_subsystem( 'propulsion_sum', - subsys=PropulsionSum(num_nodes=nn, aviary_options=options), + subsys=PropulsionSum(num_nodes=nn), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -149,19 +208,19 @@ def configure(self): # TODO this list shouldn't be hardcoded so it can be extended by users supported_outputs = [ - Dynamic.Mission.ELECTRIC_POWER_IN, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, - Dynamic.Mission.NOX_RATE, - Dynamic.Mission.SHAFT_POWER, - Dynamic.Mission.SHAFT_POWER_MAX, - Dynamic.Mission.TEMPERATURE_T4, - Dynamic.Mission.THRUST, - Dynamic.Mission.THRUST_MAX, + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.NOX_RATE, + Dynamic.Vehicle.Propulsion.SHAFT_POWER, + Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX, + Dynamic.Vehicle.Propulsion.TEMPERATURE_T4, + Dynamic.Vehicle.Propulsion.THRUST, + Dynamic.Vehicle.Propulsion.THRUST_MAX, ] engine_models = self.options['engine_models'] engine_names = [engine.name for engine in engine_models] - # num_engine_type = len(engine_models) + num_engine_type = len(engine_models) # determine if openMDAO messages and warnings should be suppressed verbosity = self.options['aviary_options'].get_val(Settings.VERBOSITY) @@ -218,6 +277,38 @@ def configure(self): ) # TODO handle setting of other variables from engine outputs (e.g. Aircraft.Engine.****) + if num_engine_type > 1: + # commented out block of code is for experimenting with automatically finding + # inputs that need a passthrough, rather than relying on get_parameters() + # being properly set up + + # custom promote parameters with aliasing to connect to passthrough component + # for engine in engine_models: + # get inputs to engine model + # engine_comp = self._get_subsystem(engine.name) + # input_dict = engine_comp.list_inputs( + # return_format='dict', units=True, out_stream=None, all_procs=True + # ) + # # TODO this catches not fully promoted variables are caught - is this + # # wanted? + # input_list = list( + # set( + # input_dict[key]['prom_name'] + # for key in input_dict + # if '.' not in input_dict[key]['prom_name'] + # ) + # ) + # promotions = [] + for i, param in enumerate(self.parameters): + self.promotes( + 'parameter_passthrough', + inputs=[(f'x_{i}', param)], + outputs=[(f'y_{i}', param + '_passthrough')], + ) + # if param in input_dict: + # promotions.append((param, param + '_passthrough')) + # self.promotes(engine.name, inputs=promotions) + class PropulsionSum(om.ExplicitComponent): ''' @@ -226,56 +317,66 @@ class PropulsionSum(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int, lower=0) - - self.options.declare( - 'aviary_options', - types=AviaryValues, - desc='collection of Aircraft/Mission specific options', - ) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): nn = self.options['num_nodes'] num_engine_type = len( - self.options['aviary_options'].get_val(Aircraft.Engine.NUM_ENGINES) + self.options[Aircraft.Engine.NUM_ENGINES] ) self.add_input( - Dynamic.Mission.THRUST, val=np.zeros((nn, num_engine_type)), units='lbf' + Dynamic.Vehicle.Propulsion.THRUST, + val=np.zeros((nn, num_engine_type)), + units='lbf', ) self.add_input( - Dynamic.Mission.THRUST_MAX, val=np.zeros((nn, num_engine_type)), units='lbf' + Dynamic.Vehicle.Propulsion.THRUST_MAX, + val=np.zeros((nn, num_engine_type)), + units='lbf', ) self.add_input( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, val=np.zeros((nn, num_engine_type)), units='lbm/h', ) self.add_input( - Dynamic.Mission.ELECTRIC_POWER_IN, + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, val=np.zeros((nn, num_engine_type)), units='kW', ) self.add_input( - Dynamic.Mission.NOX_RATE, val=np.zeros((nn, num_engine_type)), units='lbm/h' + Dynamic.Vehicle.Propulsion.NOX_RATE, + val=np.zeros((nn, num_engine_type)), + units='lbm/h', ) - self.add_output(Dynamic.Mission.THRUST_TOTAL, val=np.zeros(nn), units='lbf') - self.add_output(Dynamic.Mission.THRUST_MAX_TOTAL, val=np.zeros(nn), units='lbf') self.add_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, val=np.zeros(nn), units='lbf' + ) + self.add_output( + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, + val=np.zeros(nn), + units='lbf', + ) + self.add_output( + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, val=np.zeros(nn), units='lbm/h', ) self.add_output( - Dynamic.Mission.ELECTRIC_POWER_IN_TOTAL, val=np.zeros(nn), units='kW' + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN_TOTAL, + val=np.zeros(nn), + units='kW', + ) + self.add_output( + Dynamic.Vehicle.Propulsion.NOX_RATE_TOTAL, val=np.zeros(nn), units='lbm/h' ) - self.add_output(Dynamic.Mission.NOX_RATE_TOTAL, val=np.zeros(nn), units='lbm/h') def setup_partials(self): nn = self.options['num_nodes'] - num_engines = self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES - ) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] + num_engine_type = len(num_engines) deriv = np.tile(num_engines, nn) @@ -283,56 +384,58 @@ def setup_partials(self): c = np.arange(nn * num_engine_type, dtype=int) self.declare_partials( - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.THRUST, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST, val=deriv, rows=r, cols=c, ) self.declare_partials( - Dynamic.Mission.THRUST_MAX_TOTAL, - Dynamic.Mission.THRUST_MAX, + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_MAX, val=deriv, rows=r, cols=c, ) self.declare_partials( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, val=deriv, rows=r, cols=c, ) self.declare_partials( - Dynamic.Mission.ELECTRIC_POWER_IN_TOTAL, - Dynamic.Mission.ELECTRIC_POWER_IN, + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN_TOTAL, + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, val=deriv, rows=r, cols=c, ) self.declare_partials( - Dynamic.Mission.NOX_RATE_TOTAL, - Dynamic.Mission.NOX_RATE, + Dynamic.Vehicle.Propulsion.NOX_RATE_TOTAL, + Dynamic.Vehicle.Propulsion.NOX_RATE, val=deriv, rows=r, cols=c, ) def compute(self, inputs, outputs): - num_engines = self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES - ) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] - thrust = inputs[Dynamic.Mission.THRUST] - thrust_max = inputs[Dynamic.Mission.THRUST_MAX] - fuel_flow = inputs[Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE] - electric = inputs[Dynamic.Mission.ELECTRIC_POWER_IN] - nox = inputs[Dynamic.Mission.NOX_RATE] + thrust = inputs[Dynamic.Vehicle.Propulsion.THRUST] + thrust_max = inputs[Dynamic.Vehicle.Propulsion.THRUST_MAX] + fuel_flow = inputs[Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE] + electric = inputs[Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN] + nox = inputs[Dynamic.Vehicle.Propulsion.NOX_RATE] - outputs[Dynamic.Mission.THRUST_TOTAL] = np.dot(thrust, num_engines) - outputs[Dynamic.Mission.THRUST_MAX_TOTAL] = np.dot(thrust_max, num_engines) - outputs[Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL] = np.dot( + outputs[Dynamic.Vehicle.Propulsion.THRUST_TOTAL] = np.dot(thrust, num_engines) + outputs[Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL] = np.dot( + thrust_max, num_engines + ) + outputs[Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL] = np.dot( fuel_flow, num_engines ) - outputs[Dynamic.Mission.ELECTRIC_POWER_IN_TOTAL] = np.dot(electric, num_engines) - outputs[Dynamic.Mission.NOX_RATE_TOTAL] = np.dot(nox, num_engines) + outputs[Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN_TOTAL] = np.dot( + electric, num_engines + ) + outputs[Dynamic.Vehicle.Propulsion.NOX_RATE_TOTAL] = np.dot(nox, num_engines) diff --git a/aviary/subsystems/propulsion/propulsion_premission.py b/aviary/subsystems/propulsion/propulsion_premission.py index 7480211bf..ec613c728 100644 --- a/aviary/subsystems/propulsion/propulsion_premission.py +++ b/aviary/subsystems/propulsion/propulsion_premission.py @@ -4,7 +4,7 @@ import openmdao.api as om from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output, add_aviary_option from aviary.variable_info.variables import Aircraft, Settings from aviary.variable_info.enums import Verbosity @@ -17,12 +17,15 @@ class PropulsionPreMission(om.Group): def initialize(self): self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + 'aviary_options', + types=AviaryValues, + desc='collection of Aircraft/Mission specific options', + ) self.options.declare( - 'engine_models', types=list, - desc='list of EngineModels on aircraft' + 'engine_models', types=list, desc='list of EngineModels on aircraft' ) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Settings.VERBOSITY) def setup(self): options = self.options['aviary_options'] @@ -33,7 +36,7 @@ def setup(self): # value relevant to that variable - this group's configure step will handle # promoting/connecting just the relevant index in vectorized inputs/outputs for # each component here - # Promotions are handled in self.configure() + # Promotions are handled in configure() for engine in engine_models: subsys = engine.build_pre_mission(options) if subsys: @@ -41,26 +44,24 @@ def setup(self): proms = None else: proms = ['*'] - self.add_subsystem(engine.name, - subsys=subsys, - promotes_outputs=proms, - ) + self.add_subsystem( + engine.name, + subsys=subsys, + promotes_outputs=proms, + ) if num_engine_type > 1: # Add an empty mux comp, which will be customized to handle all required - # outputs in self.configure() + # outputs in configure() self.add_subsystem( - 'pre_mission_mux', - subsys=om.MuxComp(), - promotes_outputs=['*'] + 'pre_mission_mux', subsys=om.MuxComp(), promotes_outputs=['*'] ) self.add_subsystem( 'propulsion_sum', - subsys=PropulsionSum( - aviary_options=options), + subsys=PropulsionSum(), promotes_inputs=['*'], - promotes_outputs=['*'] + promotes_outputs=['*'], ) def configure(self): @@ -69,88 +70,109 @@ def configure(self): # so vectorized inputs/outputs are a problem. Slice all needed vector inputs and pass # pre_mission components only the value they need, then mux all the outputs back together - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + engine_models = self.options['engine_models'] + num_engine_type = len(engine_models) # determine if openMDAO messages and warnings should be suppressed - verbosity = self.options['aviary_options'].get_val(Settings.VERBOSITY) + verbosity = self.options[Settings.VERBOSITY] out_stream = None # DEBUG if verbosity > Verbosity.VERBOSE: out_stream = sys.stdout - comp_list = [ - self._get_subsystem(group) - for group in dir(self) - if self._get_subsystem(group) - and group not in ['pre_mission_mux', 'propulsion_sum'] - ] + # Patterns to identify which inputs/outputs are vectorized and need to be + # split then re-muxed + pattern = ['engine:', 'nacelle:'] # Dictionary of all unique inputs/outputs from all new components, keys are # units for each var unique_outputs = {} - unique_inputs = {} + # unique_inputs = {} - # dictionaries of inputs/outputs for each added component in prop pre-mission + # dictionaries of inputs/outputs for engine in prop pre-mission input_dict = {} output_dict = {} - for idx, comp in enumerate(comp_list): + for idx, engine_model in enumerate(engine_models): + engine = self._get_subsystem(engine_model.name) # Patterns to identify which inputs/outputs are vectorized and need to be # split then re-muxed pattern = ['engine:', 'nacelle:'] # pull out all inputs (in dict format) in component - comp_inputs = comp.list_inputs( - return_format='dict', units=True, out_stream=out_stream, all_procs=True + eng_inputs = engine.list_inputs( + return_format='dict', + units=True, + out_stream=out_stream, + all_procs=True, + ) + # switch dictionary keys to promoted name rather than full path + # only handle variables that were top-level promoted inside engine model + eng_inputs = dict( + [ + (eng_inputs[key]['prom_name'], eng_inputs[key]) + for key in eng_inputs + if '.' not in eng_inputs[key]['prom_name'] + ] ) # only keep inputs if they contain the pattern - input_dict[comp.name] = dict( - (key, comp_inputs[key]) - for key in comp_inputs + input_dict[engine.name] = dict( + (key, eng_inputs[key]) + for key in eng_inputs if any([x in key for x in pattern]) ) - # Track list of ALL inputs present in prop pre-mission in a "flat" dict. - # Repeating inputs will just override what's already in the dict - we don't - # care if units get overridden, if they differ openMDAO will convert - # (if they aren't compatible, then a component specified the wrong units and - # needs to be fixed there) - unique_inputs.update([(key, input_dict[comp.name][key]['units']) - for key in input_dict[comp.name]]) # do the same thing with outputs - comp_outputs = comp.list_outputs( + eng_outputs = engine.list_outputs( return_format='dict', units=True, out_stream=out_stream, all_procs=True ) - output_dict[comp.name] = dict( - (key, comp_outputs[key]) - for key in comp_outputs + eng_outputs = dict( + [ + (eng_outputs[key]['prom_name'], eng_outputs[key]) + for key in eng_outputs + if '.' not in eng_outputs[key]['prom_name'] + ] + ) + output_dict[engine.name] = dict( + (key, eng_outputs[key]) + for key in eng_outputs if any([x in key for x in pattern]) ) unique_outputs.update( [ - (key, output_dict[comp.name][key]['units']) - for key in output_dict[comp.name] + ( + key, + output_dict[engine.name][key]['units'], + ) + for key in output_dict[engine.name] ] ) - # slice incoming inputs for this component, so it only gets the correct index + # slice incoming inputs for this engine, so it only gets the correct index + if num_engine_type > 1: + src_indices = om.slicer[idx] + else: + src_indices = None + self.promotes( - comp.name, inputs=input_dict[comp.name].keys(), src_indices=om.slicer[idx]) + engine.name, + inputs=[*input_dict[engine.name]], + src_indices=src_indices, + ) - # promote all other inputs/outputs for this component normally (handle vectorized outputs later) + # promote all other inputs/outputs for this engine normally (handle vectorized outputs later) self.promotes( - comp.name, + engine.name, inputs=[ - comp_inputs[input]['prom_name'] - for input in comp_inputs - if input not in input_dict[comp.name] + input + for input in eng_inputs + if input not in input_dict[engine.name] ], outputs=[ - comp_outputs[output]['prom_name'] - for output in comp_outputs - if output not in output_dict[comp.name] + output + for output in eng_outputs + if output not in output_dict[engine.name] ], ) @@ -160,11 +182,11 @@ def configure(self): for output in unique_outputs: self.pre_mission_mux.add_var(output, units=unique_outputs[output]) # promote/alias outputs for each comp that has relevant outputs - for i, comp in enumerate(output_dict): - if output in output_dict[comp]: + for i, engine in enumerate(output_dict): + if output in output_dict[engine]: # if this component provides the output, connect it to the correct mux input self.connect( - comp + '.' + output, + engine + '.' + output, 'pre_mission_mux.' + output + '_' + str(i), ) else: @@ -183,30 +205,31 @@ class PropulsionSum(om.ExplicitComponent): ''' def initialize(self): - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val( - Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) - add_aviary_input(self, Aircraft.Engine.SCALED_SLS_THRUST, - val=np.zeros(num_engine_type)) + add_aviary_input( + self, Aircraft.Engine.SCALED_SLS_THRUST, val=np.zeros(num_engine_type) + ) - add_aviary_output( - self, Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, val=0.0) + add_aviary_output(self, Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, val=0.0) def setup_partials(self): - num_engines = self.options['aviary_options'].get_val(Aircraft.Engine.NUM_ENGINES) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] - self.declare_partials(Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, - Aircraft.Engine.SCALED_SLS_THRUST, val=num_engines) + self.declare_partials( + Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, + Aircraft.Engine.SCALED_SLS_THRUST, + val=num_engines, + ) def compute(self, inputs, outputs): - num_engines = self.options['aviary_options'].get_val(Aircraft.Engine.NUM_ENGINES) + num_engines = self.options[Aircraft.Engine.NUM_ENGINES] thrust = inputs[Aircraft.Engine.SCALED_SLS_THRUST] outputs[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST] = np.dot( - thrust, num_engines) + thrust, num_engines + ) diff --git a/aviary/subsystems/propulsion/test/test_custom_engine_model.py b/aviary/subsystems/propulsion/test/test_custom_engine_model.py index 9577ce5fe..b62bd6922 100644 --- a/aviary/subsystems/propulsion/test/test_custom_engine_model.py +++ b/aviary/subsystems/propulsion/test/test_custom_engine_model.py @@ -40,7 +40,7 @@ def setup(self): nn = self.options['num_nodes'] # add inputs and outputs to interpolator self.add_input( - Dynamic.Mission.MACH, + Dynamic.Atmosphere.MACH, shape=nn, units='unitless', desc='Current flight Mach number', @@ -52,7 +52,7 @@ def setup(self): desc='Current flight altitude', ) self.add_input( - Dynamic.Mission.THROTTLE, + Dynamic.Vehicle.Propulsion.THROTTLE, shape=nn, units='unitless', desc='Current engine throttle', @@ -66,37 +66,37 @@ def setup(self): self.add_input('y', units='m**2', desc='Dummy variable for bus testing') self.add_output( - Dynamic.Mission.THRUST, + Dynamic.Vehicle.Propulsion.THRUST, shape=nn, units='lbf', desc='Current net thrust produced (scaled)', ) self.add_output( - Dynamic.Mission.THRUST_MAX, + Dynamic.Vehicle.Propulsion.THRUST_MAX, shape=nn, units='lbf', desc='Current net thrust produced (scaled)', ) self.add_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, shape=nn, units='lbm/s', desc='Current fuel flow rate (scaled)', ) self.add_output( - Dynamic.Mission.ELECTRIC_POWER_IN, + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, shape=nn, units='W', desc='Current electric energy rate (scaled)', ) self.add_output( - Dynamic.Mission.NOX_RATE, + Dynamic.Vehicle.Propulsion.NOX_RATE, shape=nn, units='lbm/s', desc='Current NOx emission rate (scaled)', ) self.add_output( - Dynamic.Mission.TEMPERATURE_T4, + Dynamic.Vehicle.Propulsion.TEMPERATURE_T4, shape=nn, units='degR', desc='Current turbine exit temperature', @@ -106,14 +106,15 @@ def setup(self): def compute(self, inputs, outputs): combined_throttle = ( - inputs[Dynamic.Mission.THROTTLE] + inputs['different_throttle'] + inputs[Dynamic.Vehicle.Propulsion.THROTTLE] + inputs['different_throttle'] ) # calculate outputs - outputs[Dynamic.Mission.THRUST] = 10000.0 * combined_throttle - outputs[Dynamic.Mission.THRUST_MAX] = 10000.0 - outputs[Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE] = -10.0 * combined_throttle - outputs[Dynamic.Mission.TEMPERATURE_T4] = 2800.0 + outputs[Dynamic.Vehicle.Propulsion.THRUST] = 10000.0 * combined_throttle + outputs[Dynamic.Vehicle.Propulsion.THRUST_MAX] = 10000.0 + outputs[Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE] = - \ + 10.0 * combined_throttle + outputs[Dynamic.Vehicle.Propulsion.TEMPERATURE_T4] = 2800.0 class SimpleTestEngine(EngineModel): @@ -244,124 +245,6 @@ def test_custom_engine(self): assert_near_equal(float(prob.get_val('traj.cruise.rhs_all.y')), 4.0, tol) -@use_tempdirs -class TurbopropTest(unittest.TestCase): - """ - Test integrating turboprop component with full AviaryProblem - """ - - def test_turboprop(self): - phase_info = { - 'pre_mission': { - 'include_takeoff': False, - 'external_subsystems': [], - 'optimize_mass': True, - }, - 'cruise': { - "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, - "user_options": { - "optimize_mach": False, - "optimize_altitude": False, - "polynomial_control_order": 1, - "num_segments": 2, - "order": 3, - "solve_for_distance": False, - "initial_mach": (0.76, "unitless"), - "final_mach": (0.76, "unitless"), - "mach_bounds": ((0.7, 0.78), "unitless"), - "initial_altitude": (35000.0, "ft"), - "final_altitude": (35000.0, "ft"), - "altitude_bounds": ((23000.0, 38000.0), "ft"), - "throttle_enforcement": "boundary_constraint", - "fix_initial": False, - "constrain_final": False, - "fix_duration": False, - "initial_bounds": ((0.0, 0.0), "min"), - "duration_bounds": ((30.0, 60.0), "min"), - }, - "initial_guesses": {"time": ([0, 30], "min")}, - }, - 'post_mission': { - 'include_landing': False, - 'external_subsystems': [], - }, - } - - engine_filepath = get_path('models/engines/turboshaft_4465hp.deck') - options = get_option_defaults() - options.set_val(Aircraft.Engine.DATA_FILE, engine_filepath) - options.set_val(Aircraft.Engine.NUM_ENGINES, 2) - options.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10, units='ft') - - options.set_val( - Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, - val=True, - units='unitless', - ) - options.set_val(Aircraft.Engine.NUM_PROPELLER_BLADES, val=4, units='unitless') - - engine = TurbopropModel(options=options) - - prob = AviaryProblem(reports=True) - - # Load aircraft and options data from user - # Allow for user overrides here - prob.load_inputs( - "models/test_aircraft/aircraft_for_bench_FwFm.csv", - phase_info, - engine_builders=[engine], - ) - - # Preprocess inputs - prob.check_and_preprocess_inputs() - - prob.add_pre_mission_systems() - - prob.add_phases() - - prob.add_post_mission_systems() - - # Link phases and variables - prob.link_phases() - - prob.add_driver("SLSQP", max_iter=20) - - prob.add_design_variables() - - prob.add_objective('fuel_burned') - - prob.setup() - - prob.set_initial_guesses() - - prob.set_val( - f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_TIP_SPEED_MAX}', - 710.0, - units='ft/s', - ) - prob.set_val( - f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_DIAMETER}', 10, units='ft' - ) - prob.set_val( - f'traj.cruise.rhs_all.{Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR}', - 150.0, - units='unitless', - ) - prob.set_val( - ( - 'traj.cruise.rhs_all.' - f'{Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT}' - ), - 0.5, - units='unitless', - ) - - prob.set_solver_print(level=0) - - # and run mission - dm.run_problem(prob, run_driver=True, simulate=False, make_plots=True) - - if __name__ == '__main__': unittest.main() # test = TurbopropTest() diff --git a/aviary/subsystems/propulsion/test/test_data_interpolator.py b/aviary/subsystems/propulsion/test/test_data_interpolator.py index cdefe0590..2cef754ed 100644 --- a/aviary/subsystems/propulsion/test/test_data_interpolator.py +++ b/aviary/subsystems/propulsion/test/test_data_interpolator.py @@ -1,4 +1,3 @@ - import csv import unittest @@ -13,6 +12,7 @@ from aviary.validation_cases.validation_data.flops_data.FLOPS_Test_Data import \ FLOPS_Test_Data from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.variable_info.variables import Aircraft class DataInterpolationTest(unittest.TestCase): @@ -20,6 +20,7 @@ def test_data_interpolation(self): tol = 1e-6 aviary_values = FLOPS_Test_Data['LargeSingleAisle2FLOPS']['inputs'] + aviary_values.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) model = build_engine_deck(aviary_values)[0] @@ -30,12 +31,14 @@ def test_data_interpolation(self): fuel_flow_rate = model.data[keys.FUEL_FLOW] inputs = NamedValues() - inputs.set_val(Dynamic.Mission.MACH, mach_number) + inputs.set_val(Dynamic.Atmosphere.MACH, mach_number) inputs.set_val(Dynamic.Mission.ALTITUDE, altitude, units='ft') - inputs.set_val(Dynamic.Mission.THROTTLE, throttle) + inputs.set_val(Dynamic.Vehicle.Propulsion.THROTTLE, throttle) - outputs = {Dynamic.Mission.THRUST: 'lbf', - Dynamic.Mission.FUEL_FLOW_RATE: 'lbm/h'} + outputs = { + Dynamic.Vehicle.Propulsion.THRUST: 'lbf', + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE: 'lbm/h', + } test_mach_list = np.linspace(0, 0.85, 5) test_alt_list = np.linspace(0, 40_000, 5) @@ -47,21 +50,31 @@ def test_data_interpolation(self): num_nodes = len(test_mach.flatten()) engine_data = om.IndepVarComp() - engine_data.add_output(Dynamic.Mission.MACH + '_train', - val=np.array(mach_number), - units='unitless') - engine_data.add_output(Dynamic.Mission.ALTITUDE + '_train', - val=np.array(altitude), - units='ft') - engine_data.add_output(Dynamic.Mission.THROTTLE + '_train', - val=np.array(throttle), - units='unitless') - engine_data.add_output(Dynamic.Mission.THRUST + '_train', - val=np.array(thrust), - units='lbf') - engine_data.add_output(Dynamic.Mission.FUEL_FLOW_RATE + '_train', - val=np.array(fuel_flow_rate), - units='lbm/h') + engine_data.add_output( + Dynamic.Atmosphere.MACH + '_train', + val=np.array(mach_number), + units='unitless', + ) + engine_data.add_output( + Dynamic.Mission.ALTITUDE + '_train', + val=np.array(altitude), + units='ft', + ) + engine_data.add_output( + Dynamic.Vehicle.Propulsion.THROTTLE + '_train', + val=np.array(throttle), + units='unitless', + ) + engine_data.add_output( + Dynamic.Vehicle.Propulsion.THRUST + '_train', + val=np.array(thrust), + units='lbf', + ) + engine_data.add_output( + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE + '_train', + val=np.array(fuel_flow_rate), + units='lbm/h', + ) engine_interpolator = EngineDataInterpolator(num_nodes=num_nodes, interpolator_inputs=inputs, @@ -74,15 +87,20 @@ def test_data_interpolation(self): prob.setup() - prob.set_val(Dynamic.Mission.MACH, np.array(test_mach.flatten()), 'unitless') + prob.set_val(Dynamic.Atmosphere.MACH, np.array(test_mach.flatten()), 'unitless') prob.set_val(Dynamic.Mission.ALTITUDE, np.array(test_alt.flatten()), 'ft') - prob.set_val(Dynamic.Mission.THROTTLE, np.array( - test_throttle.flatten()), 'unitless') + prob.set_val( + Dynamic.Vehicle.Propulsion.THROTTLE, + np.array(test_throttle.flatten()), + 'unitless', + ) prob.run_model() - interp_thrust = prob.get_val(Dynamic.Mission.THRUST, 'lbf') - interp_fuel_flow = prob.get_val(Dynamic.Mission.FUEL_FLOW_RATE, 'lbm/h') + interp_thrust = prob.get_val(Dynamic.Vehicle.Propulsion.THRUST, 'lbf') + interp_fuel_flow = prob.get_val( + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE, 'lbm/h' + ) expected_thrust = [0.00000000e+00, 3.54196788e+02, 6.13575369e+03, 1.44653862e+04, 2.65599096e+04, -3.53133516e+02, 5.80901330e+01, 4.31423671e+03, diff --git a/aviary/subsystems/propulsion/test/test_engine_deck.py b/aviary/subsystems/propulsion/test/test_engine_deck.py index 93a8136a7..dc0ae0a2f 100644 --- a/aviary/subsystems/propulsion/test/test_engine_deck.py +++ b/aviary/subsystems/propulsion/test/test_engine_deck.py @@ -11,12 +11,16 @@ FLOPS_Test_Data from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.variable_info.variables import Aircraft + class EngineDeckTest(unittest.TestCase): def test_flight_idle(self): tol = 1e-6 aviary_values = FLOPS_Test_Data['LargeSingleAisle2FLOPS']['inputs'] + # Test data grabbed from LEAPS uses the global throttle approach + aviary_values.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) model = build_engine_deck(aviary_values)[0] diff --git a/aviary/subsystems/propulsion/test/test_engine_scaling.py b/aviary/subsystems/propulsion/test/test_engine_scaling.py index 75daf047b..132b6fdf0 100644 --- a/aviary/subsystems/propulsion/test/test_engine_scaling.py +++ b/aviary/subsystems/propulsion/test/test_engine_scaling.py @@ -9,6 +9,7 @@ from aviary.utils.aviary_values import AviaryValues from aviary.utils.preprocessors import preprocess_propulsion from aviary.utils.functions import get_path +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.subsystems.propulsion.utils import EngineModelVariables @@ -57,11 +58,15 @@ def test_case(self): self.prob.model.add_subsystem( 'engine', EngineScaling( - num_nodes=nn, aviary_options=options, engine_variables=engine_variables + num_nodes=nn, engine_variables=engine_variables ), promotes=['*'], ) + + setup_model_options(self.prob, options) + self.prob.setup(force_alloc_complex=True) + self.prob.set_val( 'thrust_net_unscaled', np.ones([nn, count]) * 1000, units='lbf' ) @@ -70,7 +75,7 @@ def test_case(self): ) self.prob.set_val('nox_rate_unscaled', np.ones([nn, count]) * 10, units='lbm/h') self.prob.set_val( - Dynamic.Mission.MACH, np.linspace(0, 0.75, nn), units='unitless' + Dynamic.Atmosphere.MACH, np.linspace(0, 0.75, nn), units='unitless' ) self.prob.set_val( Aircraft.Engine.SCALE_FACTOR, options.get_val(Aircraft.Engine.SCALE_FACTOR) @@ -78,9 +83,11 @@ def test_case(self): self.prob.run_model() - thrust = self.prob.get_val(Dynamic.Mission.THRUST) - fuel_flow = self.prob.get_val(Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE) - nox_rate = self.prob.get_val(Dynamic.Mission.NOX_RATE) + thrust = self.prob.get_val(Dynamic.Vehicle.Propulsion.THRUST) + fuel_flow = self.prob.get_val( + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE + ) + nox_rate = self.prob.get_val(Dynamic.Vehicle.Propulsion.NOX_RATE) # exit_area = self.prob.get_val(Dynamic.Mission.EXIT_AREA) thrust_expected = np.array([900.0, 900.0, 900.0, 900]) diff --git a/aviary/subsystems/propulsion/test/test_engine_sizing.py b/aviary/subsystems/propulsion/test/test_engine_sizing.py index b273050a9..096d0a90e 100644 --- a/aviary/subsystems/propulsion/test/test_engine_sizing.py +++ b/aviary/subsystems/propulsion/test/test_engine_sizing.py @@ -13,7 +13,7 @@ class EngineSizingTest1(unittest.TestCase): def setUp(self): - self.prob = om.Problem(model=om.Group()) + self.prob = om.Problem() def test_case_multiengine(self): filename = 'models/engines/turbofan_28k.deck' @@ -22,7 +22,6 @@ def test_case_multiengine(self): options = AviaryValues() options.set_val(Aircraft.Engine.DATA_FILE, filename) options.set_val(Aircraft.Engine.SCALE_PERFORMANCE, True) - options.set_val(Aircraft.Engine.SCALE_FACTOR, 1.0) options.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) options.set_val(Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False) options.set_val(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0) @@ -31,27 +30,30 @@ def test_case_multiengine(self): options.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) engine = EngineDeck(name='engine', options=options) - options.set_val(Aircraft.Engine.REFERENCE_SLS_THRUST, engine.get_val( - Aircraft.Engine.REFERENCE_SLS_THRUST, 'lbf'), 'lbf') # options.set_val(Aircraft.Engine.SCALE_PERFORMANCE, False) # engine2 = EngineDeck(name='engine2', options=options) # preprocess_propulsion(options, [engine, engine2]) - self.prob.model.add_subsystem('engine', SizeEngine( - aviary_options=options), promotes=['*']) + ref_thrust = engine.get_item(Aircraft.Engine.REFERENCE_SLS_THRUST) + options = { + Aircraft.Engine.SCALE_PERFORMANCE: True, + Aircraft.Engine.REFERENCE_SLS_THRUST: ref_thrust, + } + + self.prob.model.add_subsystem('engine', SizeEngine(**options), + promotes=['*']) + self.prob.setup(force_alloc_complex=True) - self.prob.set_val( - Aircraft.Engine.SCALED_SLS_THRUST, - np.array([15250]), - units='lbf') + + self.prob.set_val(Aircraft.Engine.SCALE_FACTOR, np.array([0.52716908])) self.prob.run_model() - scale_factor = self.prob.get_val(Aircraft.Engine.SCALE_FACTOR) + sls_thrust = self.prob.get_val(Aircraft.Engine.SCALED_SLS_THRUST, units='lbf') - expected_scale_factor = np.array([0.52716908]) + expected_sls_thrust = np.array([15250]) - assert_near_equal(scale_factor, expected_scale_factor, tolerance=1e-8) + assert_near_equal(sls_thrust, expected_sls_thrust, tolerance=1e-8) partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-10) diff --git a/aviary/subsystems/propulsion/test/test_hamilton_standard.py b/aviary/subsystems/propulsion/test/test_hamilton_standard.py index 5434eea63..c8ec6fbd0 100644 --- a/aviary/subsystems/propulsion/test/test_hamilton_standard.py +++ b/aviary/subsystems/propulsion/test/test_hamilton_standard.py @@ -1,5 +1,5 @@ import unittest - +import numpy as np import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal @@ -7,9 +7,10 @@ from aviary.subsystems.propulsion.propeller.hamilton_standard import ( HamiltonStandard, PreHamiltonStandard, PostHamiltonStandard, ) -from aviary.variable_info.variables import Aircraft, Dynamic +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Dynamic +from aviary.constants import RHO_SEA_LEVEL_ENGLISH class PreHamiltonStandardTest(unittest.TestCase): @@ -34,27 +35,40 @@ def setUp(self): def test_preHS(self): prob = self.prob - prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10, units="ft") - prob.set_val(Dynamic.Mission.PROPELLER_TIP_SPEED, - [700.0, 750.0, 800.0], units="ft/s") - prob.set_val(Dynamic.Mission.SHAFT_POWER, [1850.0, 1850.0, 900.0], units="hp") - prob.set_val(Dynamic.Mission.DENSITY, - [0.00237717, 0.00237717, 0.00106526], units="slug/ft**3") + prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 10, units="ft") + prob.set_val( + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + [700.0, 750.0, 800.0], + units="ft/s", + ) + prob.set_val( + Dynamic.Vehicle.Propulsion.SHAFT_POWER, [1850.0, 1850.0, 900.0], units="hp" + ) + prob.set_val( + Dynamic.Atmosphere.DENSITY, + [0.00237717, 0.00237717, 0.00106526], + units="slug/ft**3", + ) prob.set_val(Dynamic.Mission.VELOCITY, [100.0, 100, 100], units="ft/s") - prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, - [661.46474547, 661.46474547, 601.93668333], units="knot") + prob.set_val( + Dynamic.Atmosphere.SPEED_OF_SOUND, + [661.46474547, 661.46474547, 601.93668333], + units="knot", + ) prob.run_model() tol = 5e-4 assert_near_equal(prob.get_val("power_coefficient"), [0.3871, 0.3147, 0.2815], tolerance=tol) - assert_near_equal(prob.get_val("advance_ratio"), - [0.4494, 0.4194, 0.3932], tolerance=tol) - assert_near_equal(prob.get_val("tip_mach"), - [1.05826, 1.1338, 1.3290], tolerance=tol) - assert_near_equal(prob.get_val("density_ratio"), - [1.0001, 1.0001, 0.4482], tolerance=tol) + assert_near_equal( + prob.get_val("advance_ratio"), + [0.44879895, 0.41887902, 0.39269908], + tolerance=tol, + ) + assert_near_equal( + prob.get_val("tip_mach"), [0.6270004, 0.67178614, 0.78743671], tolerance=tol + ) partial_data = prob.check_partials( out_stream=None, @@ -76,7 +90,7 @@ class HamiltonStandardTest(unittest.TestCase): def setUp(self): options = get_option_defaults() - options.set_val(Aircraft.Engine.NUM_PROPELLER_BLADES, val=4, units='unitless') + options.set_val(Aircraft.Engine.Propeller.NUM_BLADES, val=4, units='unitless') prob = om.Problem() @@ -84,11 +98,13 @@ def setUp(self): prob.model.add_subsystem( 'hs', - HamiltonStandard(num_nodes=num_nodes, aviary_options=options), + HamiltonStandard(num_nodes=num_nodes), promotes_inputs=['*'], promotes_outputs=["*"], ) + setup_model_options(prob, options) + prob.setup() self.prob = prob @@ -96,10 +112,12 @@ def test_HS(self): prob = self.prob prob.set_val("power_coefficient", [0.2352, 0.2352, 0.2553], units="unitless") prob.set_val("advance_ratio", [0.0066, 0.8295, 1.9908], units="unitless") - prob.set_val(Dynamic.Mission.MACH, [0.001509, 0.1887, 0.4976], units="unitless") + prob.set_val( + Dynamic.Atmosphere.MACH, [0.001509, 0.1887, 0.4976], units="unitless" + ) prob.set_val("tip_mach", [1.2094, 1.2094, 1.3290], units="unitless") - prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 114.0, units="unitless") - prob.set_val(Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, + prob.set_val(Aircraft.Engine.Propeller.ACTIVITY_FACTOR, 114.0, units="unitless") + prob.set_val(Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless") prob.run_model() @@ -147,10 +165,14 @@ def test_postHS(self): prob = self.prob prob.set_val("power_coefficient", [0.3871, 0.3147, 0.2815], units="unitless") prob.set_val("advance_ratio", [0.4494, 0.4194, 0.3932], units="unitless") - prob.set_val(Dynamic.Mission.PROPELLER_TIP_SPEED, + prob.set_val(Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, [700.0, 750.0, 800.0], units="ft/s") - prob.set_val("density_ratio", [1.0001, 1.0001, 0.4482], units="unitless") - prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10.0, units="ft") + prob.set_val( + Dynamic.Atmosphere.DENSITY, + np.array([1.0001, 1.0001, 0.4482]) * RHO_SEA_LEVEL_ENGLISH, + units="slug/ft**3", + ) + prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 10.0, units="ft") prob.set_val("thrust_coefficient", [0.2765, 0.2052, 0.1158], units="unitless") prob.set_val("install_loss_factor", [0.0133, 0.0200, 0.0325], units="unitless") prob.set_val("comp_tip_loss_factor", [1.0, 1.0, 0.9819], units="unitless") @@ -160,8 +182,11 @@ def test_postHS(self): tol = 5e-4 assert_near_equal(prob.get_val("thrust_coefficient_comp_loss"), [0.2765, 0.2052, 0.1137], tolerance=tol) - assert_near_equal(prob.get_val(Dynamic.Mission.THRUST), - [3218.9508, 2723.7294, 759.7543], tolerance=tol) + assert_near_equal( + prob.get_val(Dynamic.Vehicle.Propulsion.THRUST), + [3218.9508, 2723.7294, 759.7543], + tolerance=tol, + ) assert_near_equal(prob.get_val("propeller_efficiency"), [0.321, 0.2735, 0.1588], tolerance=tol) assert_near_equal(prob.get_val("install_efficiency"), @@ -182,3 +207,6 @@ def test_postHS(self): if __name__ == "__main__": unittest.main() + # test = HamiltonStandardTest() + # test.setUp() + # test.test_HS() diff --git a/aviary/subsystems/propulsion/test/test_propeller_map.py b/aviary/subsystems/propulsion/test/test_propeller_map.py index f3b2ce3a4..197410766 100644 --- a/aviary/subsystems/propulsion/test/test_propeller_map.py +++ b/aviary/subsystems/propulsion/test/test_propeller_map.py @@ -23,11 +23,11 @@ def test_general_aviation(self): aviary_options = get_option_defaults() prop_file_path = 'models/propellers/general_aviation.prop' aviary_options.set_val( - Aircraft.Engine.PROPELLER_DATA_FILE, val=prop_file_path, units='unitless') + Aircraft.Engine.Propeller.DATA_FILE, val=prop_file_path, units='unitless' + ) aviary_options.set_val( - Aircraft.Engine.INTERPOLATION_METHOD, val='slinear', units='unitless') - aviary_options.set_val( - Aircraft.Engine.USE_PROPELLER_MAP, val=True, units='unitless') + Aircraft.Engine.INTERPOLATION_METHOD, val='slinear', units='unitless' + ) prop_model = PropellerMap('prop', aviary_options) prop_model.build_propeller_interpolator(3, aviary_options) @@ -48,11 +48,11 @@ def test_propfan(self): aviary_options = get_option_defaults() prop_file_path = 'models/propellers/PropFan.prop' aviary_options.set_val( - Aircraft.Engine.PROPELLER_DATA_FILE, val=prop_file_path, units='unitless') - aviary_options.set_val( - Aircraft.Engine.INTERPOLATION_METHOD, val='slinear', units='unitless') + Aircraft.Engine.Propeller.DATA_FILE, val=prop_file_path, units='unitless' + ) aviary_options.set_val( - Aircraft.Engine.USE_PROPELLER_MAP, val=True, units='unitless') + Aircraft.Engine.INTERPOLATION_METHOD, val='slinear', units='unitless' + ) prop_model = PropellerMap('prop', aviary_options) prop_model.build_propeller_interpolator(3, aviary_options) @@ -72,11 +72,11 @@ def test_mach_type(self): aviary_options = get_option_defaults() prop_file_path = 'models/propellers/general_aviation.prop' aviary_options.set_val( - Aircraft.Engine.PROPELLER_DATA_FILE, val=prop_file_path, units='unitless') - aviary_options.set_val( - Aircraft.Engine.INTERPOLATION_METHOD, val='slinear', units='unitless') + Aircraft.Engine.Propeller.DATA_FILE, val=prop_file_path, units='unitless' + ) aviary_options.set_val( - Aircraft.Engine.USE_PROPELLER_MAP, val=True, units='unitless') + Aircraft.Engine.INTERPOLATION_METHOD, val='slinear', units='unitless' + ) prop_model = PropellerMap('prop', aviary_options) out_mach_type = prop_model.read_and_set_mach_type(prop_file_path) self.assertEqual(out_mach_type, OutMachType.HELICAL_MACH) diff --git a/aviary/subsystems/propulsion/test/test_propeller_performance.py b/aviary/subsystems/propulsion/test/test_propeller_performance.py index 572dde581..d16ab2c72 100644 --- a/aviary/subsystems/propulsion/test/test_propeller_performance.py +++ b/aviary/subsystems/propulsion/test/test_propeller_performance.py @@ -7,12 +7,12 @@ from aviary.subsystems.atmosphere.atmosphere import Atmosphere from aviary.subsystems.propulsion.propeller.propeller_performance import ( - OutMachs, PropellerPerformance, TipSpeedLimit, AreaSquareRatio, AdvanceRatio + OutMachs, PropellerPerformance, TipSpeed, AreaSquareRatio, AdvanceRatio ) from aviary.variable_info.enums import OutMachType -from aviary.variable_info.variables import Aircraft, Dynamic, Settings +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Aircraft, Dynamic +from aviary.variable_info.variables import Aircraft, Dynamic, Settings # Setting up truth values from GASP (The first 12 are actual truth values, the rest are intelligent guesses) # test values now are slightly different due to setup - max tip speed was limited to test @@ -43,7 +43,7 @@ ) XFT = np.array( [1.0, 1.0, 0.9976, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0, 1.0, 0.9976, 1.0, 1.0, 1.0,] + 1.0, 1.0, 1.0, 1.0, 1.0, 0.9976, 1.0, 1.0, 1.0,] ) # CTX = np.array([0.27651, 0.20518, 0.13062, 0.10236, 0.10236, 0.19331, # 0.10189, 0.10189, 0.18123, 0.08523, 0.06463, 0.02800]) @@ -173,13 +173,12 @@ class PropellerPerformanceTest(unittest.TestCase): def setUp(self): options = get_option_defaults() options.set_val( - Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, + Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, val=True, units='unitless', ) - options.set_val(Aircraft.Engine.NUM_PROPELLER_BLADES, val=4, units='unitless') + options.set_val(Aircraft.Engine.Propeller.NUM_BLADES, val=4, units='unitless') options.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, False) - options.set_val(Aircraft.Engine.USE_PROPELLER_MAP, False) options.set_val(Settings.VERBOSITY, 0) prob = om.Problem() @@ -194,33 +193,39 @@ def setUp(self): pp = prob.model.add_subsystem( 'pp', - PropellerPerformance(num_nodes=num_nodes, aviary_options=options), + PropellerPerformance(num_nodes=num_nodes, + aviary_options=options), promotes_inputs=['*'], promotes_outputs=["*"], ) - pp.set_input_defaults(Aircraft.Engine.PROPELLER_DIAMETER, 10, units="ft") + pp.set_input_defaults(Aircraft.Engine.Propeller.DIAMETER, 10, units="ft") pp.set_input_defaults( - Dynamic.Mission.PROPELLER_TIP_SPEED, 800 * np.ones(num_nodes), units="ft/s" + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, + 800 * np.ones(num_nodes), + units="ft/s", ) pp.set_input_defaults( Dynamic.Mission.VELOCITY, 100.0 * np.ones(num_nodes), units="knot" ) num_blades = 4 options.set_val( - Aircraft.Engine.NUM_PROPELLER_BLADES, val=num_blades, units='unitless' + Aircraft.Engine.Propeller.NUM_BLADES, val=num_blades, units='unitless' ) options.set_val( - Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, + Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, val=True, units='unitless', ) + + setup_model_options(prob, options) + prob.setup() - prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10.5, units="ft") - prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 114.0, units="unitless") + prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 10.5, units="ft") + prob.set_val(Aircraft.Engine.Propeller.ACTIVITY_FACTOR, 114.0, units="unitless") prob.set_val( - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" ) prob.set_val(Aircraft.Nacelle.AVG_DIAMETER, 2.8875, units='ft') @@ -232,7 +237,7 @@ def compare_results(self, case_idx_begin, case_idx_end): cthr = p.get_val('thrust_coefficient') ctlf = p.get_val('comp_tip_loss_factor') tccl = p.get_val('thrust_coefficient_comp_loss') - thrt = p.get_val(Dynamic.Mission.THRUST) + thrt = p.get_val(Dynamic.Vehicle.Propulsion.THRUST) peff = p.get_val('propeller_efficiency') lfac = p.get_val('install_loss_factor') ieff = p.get_val('install_efficiency') @@ -254,9 +259,16 @@ def test_case_0_1_2(self): prob = self.prob prob.set_val(Dynamic.Mission.ALTITUDE, [0.0, 0.0, 25000.0], units="ft") prob.set_val(Dynamic.Mission.VELOCITY, [0.10, 125.0, 300.0], units="knot") - prob.set_val(Dynamic.Mission.SHAFT_POWER, [1850.0, 1850.0, 900.0], units="hp") - prob.set_val(Aircraft.Engine.PROPELLER_TIP_MACH_MAX, 1.0, units="unitless") - prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 800.0, units="ft/s") + prob.set_val( + Dynamic.Vehicle.Propulsion.RPM, + [1455.13090827, 1455.13090827, 1455.13090827], + units='rpm', + ) + prob.set_val( + Dynamic.Vehicle.Propulsion.SHAFT_POWER, [1850.0, 1850.0, 900.0], units="hp" + ) + prob.set_val(Aircraft.Engine.Propeller.TIP_MACH_MAX, 1.0, units="unitless") + prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 800.0, units="ft/s") prob.run_model() self.compare_results(case_idx_begin=0, case_idx_end=2) @@ -280,23 +292,34 @@ def test_case_3_4_5(self): options = self.options options.set_val( - Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, + Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, val=False, units='unitless', ) + + setup_model_options(prob, options) + prob.setup() prob.set_val('install_loss_factor', [0.0, 0.05, 0.05], units="unitless") - prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 12.0, units="ft") - prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 150.0, units="unitless") + prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 12.0, units="ft") + prob.set_val(Aircraft.Engine.Propeller.ACTIVITY_FACTOR, 150.0, units="unitless") prob.set_val( - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" ) prob.set_val(Dynamic.Mission.ALTITUDE, [10000.0, 10000.0, 0.0], units="ft") prob.set_val(Dynamic.Mission.VELOCITY, [200.0, 200.0, 50.0], units="knot") - prob.set_val(Dynamic.Mission.SHAFT_POWER, [1000.0, 1000.0, 1250.0], units="hp") - prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 769.70, units="ft/s") + prob.set_val( + Dynamic.Vehicle.Propulsion.SHAFT_POWER, [1000.0, 1000.0, 1250.0], units="hp" + ) + prob.set_val( + Dynamic.Vehicle.Propulsion.RPM, + [1225.02, 1225.02, 1225.02], + units='rpm', + ) + prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 769.70, units="ft/s") prob.run_model() + self.compare_results(case_idx_begin=3, case_idx_end=5) partial_data = prob.check_partials( @@ -319,24 +342,34 @@ def test_case_6_7_8(self): num_blades = 3 options.set_val( - Aircraft.Engine.NUM_PROPELLER_BLADES, val=num_blades, units='unitless' + Aircraft.Engine.Propeller.NUM_BLADES, val=num_blades, units='unitless' ) options.set_val( - Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, + Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, val=False, units='unitless', ) + + setup_model_options(prob, options) + prob.setup() prob.set_val('install_loss_factor', [0.0, 0.05, 0.05], units="unitless") - prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 12.0, units="ft") - prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 150.0, units="unitless") + prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 12.0, units="ft") + prob.set_val(Aircraft.Engine.Propeller.ACTIVITY_FACTOR, 150.0, units="unitless") prob.set_val( - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" ) prob.set_val(Dynamic.Mission.ALTITUDE, [10000.0, 10000.0, 0.0], units="ft") prob.set_val(Dynamic.Mission.VELOCITY, [200.0, 200.0, 50.0], units="knot") - prob.set_val(Dynamic.Mission.SHAFT_POWER, [1000.0, 1000.0, 1250.0], units="hp") - prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 750.0, units="ft/s") + prob.set_val( + Dynamic.Vehicle.Propulsion.SHAFT_POWER, [1000.0, 1000.0, 1250.0], units="hp" + ) + prob.set_val( + Dynamic.Vehicle.Propulsion.RPM, + [1193.66207319, 1193.66207319, 1193.66207319], + units='rpm', + ) + prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 750.0, units="ft/s") prob.run_model() self.compare_results(case_idx_begin=6, case_idx_end=8) @@ -357,18 +390,26 @@ def test_case_6_7_8(self): def test_case_9_10_11(self): # Case 9, 10, 11, to test CLI > 0.5 prob = self.prob - prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 12.0, units="ft") + prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 12.0, units="ft") prob.set_val(Aircraft.Nacelle.AVG_DIAMETER, 2.4, units='ft') - prob.set_val(Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 150.0, units="unitless") + prob.set_val(Aircraft.Engine.Propeller.ACTIVITY_FACTOR, 150.0, units="unitless") prob.set_val( - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, 0.65, units="unitless", ) prob.set_val(Dynamic.Mission.ALTITUDE, [10000.0, 10000.0, 10000.0], units="ft") prob.set_val(Dynamic.Mission.VELOCITY, [200.0, 200.0, 200.0], units="knot") - prob.set_val(Dynamic.Mission.SHAFT_POWER, [900.0, 750.0, 500.0], units="hp") - prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 750.0, units="ft/s") + prob.set_val( + Dynamic.Vehicle.Propulsion.SHAFT_POWER, [900.0, 750.0, 500.0], units="hp" + ) + prob.set_val( + Dynamic.Vehicle.Propulsion.RPM, + [1193.66207319, 1193.66207319, 1193.66207319], + units='rpm', + ) + + prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 750.0, units="ft/s") prob.run_model() self.compare_results(case_idx_begin=9, case_idx_end=11) @@ -385,11 +426,11 @@ def test_case_9_10_11(self): excludes=["*atmosphere*"], ) # remove partial derivative of 'comp_tip_loss_factor' with respect to - # 'aircraft:engine:propeller_integrated_lift_coefficient' from assert_check_partials + # integrated lift coefficient from assert_check_partials partial_data_hs = partial_data['pp.hamilton_standard'] key_pair = ( 'comp_tip_loss_factor', - 'aircraft:engine:propeller_integrated_lift_coefficient', + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, ) del partial_data_hs[key_pair] assert_check_partials(partial_data, atol=1.5e-3, rtol=1e-4) @@ -399,9 +440,16 @@ def test_case_12_13_14(self): prob = self.prob prob.set_val(Dynamic.Mission.ALTITUDE, [0.0, 0.0, 25000.0], units="ft") prob.set_val(Dynamic.Mission.VELOCITY, [0.10, 125.0, 300.0], units="knot") - prob.set_val(Dynamic.Mission.SHAFT_POWER, [1850.0, 1850.0, 900.0], units="hp") - prob.set_val(Aircraft.Engine.PROPELLER_TIP_MACH_MAX, 0.8, units="unitless") - prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 800.0, units="ft/s") + prob.set_val( + Dynamic.Vehicle.Propulsion.SHAFT_POWER, [1850.0, 1850.0, 900.0], units="hp" + ) + prob.set_val( + Dynamic.Vehicle.Propulsion.RPM, + [1455.1309082687574, 1455.1309082687574, 1156.4081529986502], + units='rpm', + ) + prob.set_val(Aircraft.Engine.Propeller.TIP_MACH_MAX, 0.8, units="unitless") + prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 800.0, units="ft/s") prob.run_model() self.compare_results(case_idx_begin=12, case_idx_end=13) @@ -424,23 +472,33 @@ def test_case_15_16_17(self): prob = self.prob options = self.options - options.set_val(Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, - val=False, units='unitless') - options.set_val(Aircraft.Engine.USE_PROPELLER_MAP, - val=True, units='unitless') + options.set_val( + Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, + val=False, + units='unitless', + ) prop_file_path = 'models/propellers/PropFan.prop' - options.set_val(Aircraft.Engine.PROPELLER_DATA_FILE, + options.set_val(Aircraft.Engine.Propeller.DATA_FILE, val=prop_file_path, units='unitless') options.set_val(Aircraft.Engine.INTERPOLATION_METHOD, val='slinear', units='unitless') + setup_model_options(prob, options) + prob.setup(force_alloc_complex=True) prob.set_val('install_loss_factor', [0.0, 0.05, 0.05], units="unitless") - prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 12.0, units="ft") + prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 12.0, units="ft") prob.set_val(Dynamic.Mission.ALTITUDE, [10000.0, 10000.0, 0.0], units="ft") prob.set_val(Dynamic.Mission.VELOCITY, [200.0, 200.0, 50.0], units="knot") - prob.set_val(Dynamic.Mission.SHAFT_POWER, [1000.0, 1000.0, 1250.0], units="hp") - prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 769.70, units="ft/s") + prob.set_val( + Dynamic.Vehicle.Propulsion.SHAFT_POWER, [1000.0, 1000.0, 1250.0], units="hp" + ) + prob.set_val( + Dynamic.Vehicle.Propulsion.RPM, + [1225.0155969783186, 1225.0155969783186, 1225.0155969783186], + units='rpm', + ) + prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 769.70, units="ft/s") prob.run_model() self.compare_results(case_idx_begin=15, case_idx_end=17) @@ -477,13 +535,19 @@ def test_helical_mach(self): prob.set_val("tip_mach", val=[0.5, 0.7], units="unitless") prob.run_model() y = prob.get_val("helical_mach") - y_exact = np.sqrt([0.5*0.5 + 0.5*0.5, 0.7*0.7 + 0.7*0.7]) + y_exact = np.sqrt([0.5 * 0.5 + 0.5 * 0.5, 0.7 * 0.7 + 0.7 * 0.7]) assert_near_equal(y, y_exact, tolerance=tol) partial_data = prob.check_partials( - out_stream=None, compact_print=True, show_only_incorrect=True, form='central', method="fd", - minimum_step=1e-12, abs_err_tol=5.0E-4, rel_err_tol=5.0E-5) + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method="fd", + minimum_step=1e-12, + abs_err_tol=5.0E-4, + rel_err_tol=5.0E-5) assert_check_partials(partial_data, atol=1e-4, rtol=1e-4) def test_mach(self): @@ -500,13 +564,19 @@ def test_mach(self): prob.set_val("tip_mach", val=[0.5, 0.4], units="unitless") prob.run_model() y = prob.get_val("mach") - y_exact = np.sqrt([0.7*0.7 - 0.5*0.5, 0.8*0.8 - 0.4*0.4]) + y_exact = np.sqrt([0.7 * 0.7 - 0.5 * 0.5, 0.8 * 0.8 - 0.4 * 0.4]) assert_near_equal(y, y_exact, tolerance=tol) partial_data = prob.check_partials( - out_stream=None, compact_print=True, show_only_incorrect=True, form='central', method="fd", - minimum_step=1e-12, abs_err_tol=5.0E-4, rel_err_tol=5.0E-5) + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method="fd", + minimum_step=1e-12, + abs_err_tol=5.0E-4, + rel_err_tol=5.0E-5) assert_check_partials(partial_data, atol=1e-4, rtol=1e-4) def test_tip_mach(self): @@ -523,13 +593,19 @@ def test_tip_mach(self): prob.set_val("mach", val=[0.5, 0.4], units="unitless") prob.run_model() y = prob.get_val("tip_mach") - y_exact = np.sqrt([0.7*0.7 - 0.5*0.5, 0.8*0.8 - 0.4*0.4]) + y_exact = np.sqrt([0.7 * 0.7 - 0.5 * 0.5, 0.8 * 0.8 - 0.4 * 0.4]) assert_near_equal(y, y_exact, tolerance=tol) partial_data = prob.check_partials( - out_stream=None, compact_print=True, show_only_incorrect=True, form='central', method="fd", - minimum_step=1e-12, abs_err_tol=5.0E-4, rel_err_tol=5.0E-5) + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method="fd", + minimum_step=1e-12, + abs_err_tol=5.0E-4, + rel_err_tol=5.0E-5) assert_check_partials(partial_data, atol=1e-4, rtol=1e-4) @@ -544,24 +620,28 @@ def test_tipspeed(self): prob = om.Problem() prob.model.add_subsystem( "group", - TipSpeedLimit(num_nodes=3), + TipSpeed(num_nodes=3), promotes=["*"], ) prob.setup() - prob.set_val(Dynamic.Mission.VELOCITY, - val=[0.16878, 210.97623, 506.34296], units='ft/s') - prob.set_val(Dynamic.Mission.SPEED_OF_SOUND, - val=[1116.42671, 1116.42671, 1015.95467], units='ft/s') - prob.set_val(Aircraft.Engine.PROPELLER_TIP_MACH_MAX, val=[0.8], units='unitless') - prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, val=[800], units='ft/s') - prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, val=[10.5], units='ft') + prob.set_val( + Dynamic.Mission.VELOCITY, + val=[0.16878, 210.97623, 506.34296], + units='ft/s', + ) + prob.set_val( + Dynamic.Atmosphere.SPEED_OF_SOUND, + val=[1116.42671, 1116.42671, 1015.95467], + units='ft/s', + ) + prob.set_val(Aircraft.Engine.Propeller.TIP_MACH_MAX, val=[0.8], units='unitless') + prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, val=[800], units='ft/s') + prob.set_val(Aircraft.Engine.Propeller.DIAMETER, val=[10.5], units='ft') prob.run_model() - tip_speed = prob.get_val(Dynamic.Mission.PROPELLER_TIP_SPEED, units='ft/s') - rpm = prob.get_val('rpm', units='rpm') + tip_speed = prob.get_val('propeller_tip_speed_limit', units='ft/s') assert_near_equal(tip_speed, [800, 800, 635.7686], tolerance=tol) - assert_near_equal(rpm, [1455.1309, 1455.1309, 1156.4082], tolerance=tol) partial_data = prob.check_partials( out_stream=None, @@ -653,14 +733,14 @@ def test_zje_1(self): promotes=["*"], ) prob.setup(force_alloc_complex=True) - prob.set_val("vktas", val=[0.1, 125., 300., 1000.], units='knot') + prob.set_val("vtas", val=[0.1, 125., 300., 1000.], units='knot') prob.set_val("tipspd", val=[800., 800., 750., 500.], units='ft/s') prob.set_val("sqa_array", val=[0.0756, 0.0756, 0.0756, 1.0], units='unitless') prob.run_model() equiv_adv_ratio = prob.get_val("equiv_adv_ratio", units='unitless') assert_near_equal(equiv_adv_ratio, [ - 0.000650881807, 0.813602259, 2.08282178, 5], tolerance=1e-5) + 6.50074004e-04, 8.12592505e-01, 2.08023681e+00, 5.0], tolerance=1e-5) partial_data = prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) @@ -673,14 +753,17 @@ def test_zje_2(self): promotes=["*"], ) prob.setup(force_alloc_complex=True) - prob.set_val("vktas", val=[0.1, 125., 300., 1000.], units='knot') + prob.set_val("vtas", val=[0.1, 125., 300., 1000.], units='knot') prob.set_val("tipspd", val=[800., 800., 750., 500.], units='ft/s') prob.set_val("sqa_array", val=[0.0756, 0.0756, 0.0756, 1.0], units='unitless') prob.run_model() equiv_adv_ratio = prob.get_val("equiv_adv_ratio", units='unitless') - assert_near_equal(equiv_adv_ratio, [ - 0.000650881807, 0.813602259, 2.08282178, 5], tolerance=1e-5) + assert_near_equal( + equiv_adv_ratio, + [6.50074004e-04, 8.12592505e-01, 2.08023681e+00, 5.0], + tolerance=1e-5 + ) partial_data = prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) @@ -688,3 +771,6 @@ def test_zje_2(self): if __name__ == "__main__": unittest.main() + # test = PropellerPerformanceTest() + # test.setUp() + # test.test_case_3_4_5() diff --git a/aviary/subsystems/propulsion/test/test_propulsion_mission.py b/aviary/subsystems/propulsion/test/test_propulsion_mission.py index b334b10d3..ab9271849 100644 --- a/aviary/subsystems/propulsion/test/test_propulsion_mission.py +++ b/aviary/subsystems/propulsion/test/test_propulsion_mission.py @@ -13,6 +13,7 @@ from aviary.utils.preprocessors import preprocess_propulsion from aviary.utils.functions import get_path from aviary.validation_cases.validation_tests import get_flops_inputs +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings from aviary.subsystems.propulsion.utils import build_engine_deck @@ -33,6 +34,7 @@ def test_case_1(self): options = self.options options.set_val(Aircraft.Engine.DATA_FILE, filename) + options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) options.set_val(Aircraft.Engine.NUM_ENGINES, 2) options.set_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0) options.set_val(Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0) @@ -56,42 +58,78 @@ def test_case_1(self): self.prob.model = PropulsionMission( num_nodes=nn, aviary_options=options, engine_models=[engine]) - IVC = om.IndepVarComp(Dynamic.Mission.MACH, - np.linspace(0, 0.8, nn), - units='unitless') - IVC.add_output(Dynamic.Mission.ALTITUDE, - np.linspace(0, 40000, nn), - units='ft') - IVC.add_output(Dynamic.Mission.THROTTLE, - np.linspace(1, 0.7, nn), - units='unitless') + IVC = om.IndepVarComp( + Dynamic.Atmosphere.MACH, np.linspace(0, 0.8, nn), units='unitless' + ) + IVC.add_output(Dynamic.Mission.ALTITUDE, np.linspace(0, 40000, nn), units='ft') + IVC.add_output( + Dynamic.Vehicle.Propulsion.THROTTLE, + np.linspace(1, 0.7, nn), + units='unitless', + ) self.prob.model.add_subsystem('IVC', IVC, promotes=['*']) + setup_model_options(self.prob, options) + self.prob.setup(force_alloc_complex=True) self.prob.set_val(Aircraft.Engine.SCALE_FACTOR, options.get_val( Aircraft.Engine.SCALE_FACTOR), units='unitless') self.prob.run_model() - thrust = self.prob.get_val(Dynamic.Mission.THRUST_TOTAL, units='lbf') + thrust = self.prob.get_val(Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf') fuel_flow = self.prob.get_val( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h') - - expected_thrust = np.array([26559.90955398, 24186.4637312, 21938.65874407, - 19715.77939805, 17507.00655484, 15461.29892872, - 13781.56317005, 12281.64477782, 10975.64977233, - 9457.34056514, 7994.85977229, 7398.22905691, - 7147.50679938, 6430.71565916, 5774.57932944, - 5165.15558103, 4583.1380952, 3991.15088149, - 3338.98524687, 2733.56788119]) - - expected_fuel_flow = np.array([-14707.1792863, -14065.2831058, -13383.11681516, - -12535.21693425, -11524.37848035, -10514.44342419, - -9697.03653898, -8936.66146966, -8203.85487648, - -8447.54167564, -8705.14277314, -7470.29404109, - -5980.15247732, -5493.23821772, -5071.79842346, - -4660.12833977, -4260.89619679, -3822.61002621, - -3344.41332545, -2889.68646353]) + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h') + + expected_thrust = np.array( + [ + 26559.90955398, + 24186.4637312, + 21938.65874407, + 19715.77939805, + 17507.00655484, + 15461.29892872, + 13781.56317005, + 12281.64477782, + 10975.64977233, + 9457.34056514, + 7994.85977229, + 7398.22905691, + 7147.50679938, + 6430.71565916, + 5774.57932944, + 5165.15558103, + 4583.1380952, + 3991.15088149, + 3338.98524687, + 2733.56788119, + ] + ) + + expected_fuel_flow = np.array( + [ + -14707.1792863, + -14065.2831058, + -13383.11681516, + -12535.21693425, + -11524.37848035, + -10514.44342419, + -9697.03653898, + -8936.66146966, + -8203.85487648, + -8447.54167564, + -8705.14277314, + -7470.29404109, + -5980.15247732, + -5493.23821772, + -5071.79842346, + -4660.12833977, + -4260.89619679, + -3822.61002621, + -3344.41332545, + -2889.68646353, + ] + ) assert_near_equal(thrust, expected_thrust, tolerance=1e-10) assert_near_equal(fuel_flow, expected_fuel_flow, tolerance=1e-10) @@ -101,36 +139,45 @@ def test_case_1(self): def test_propulsion_sum(self): nn = 2 - options = self.options - options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([3, 2])) + options = { + Aircraft.Engine.NUM_ENGINES: np.array([3, 2]), + } self.prob.model = om.Group() self.prob.model.add_subsystem('propsum', PropulsionSum(num_nodes=nn, - aviary_options=options), + **options), promotes=['*']) self.prob.setup(force_alloc_complex=True) - self.prob.set_val(Dynamic.Mission.THRUST, np.array( - [[500.4, 423.001], [325, 6780]])) - self.prob.set_val(Dynamic.Mission.THRUST_MAX, - np.array([[602.11, 3554], [100, 9000]])) - self.prob.set_val(Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + self.prob.set_val( + Dynamic.Vehicle.Propulsion.THRUST, np.array([[500.4, 423.001], [325, 6780]]) + ) + self.prob.set_val( + Dynamic.Vehicle.Propulsion.THRUST_MAX, + np.array([[602.11, 3554], [100, 9000]]), + ) + self.prob.set_val(Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, np.array([[123, -221.44], [-765.2, -1]])) - self.prob.set_val(Dynamic.Mission.ELECTRIC_POWER_IN, + self.prob.set_val(Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, np.array([[3.01, -12], [484.2, 8123]])) - self.prob.set_val(Dynamic.Mission.NOX_RATE, - np.array([[322, 4610], [1.54, 2.844]])) + self.prob.set_val( + Dynamic.Vehicle.Propulsion.NOX_RATE, np.array([[322, 4610], [1.54, 2.844]]) + ) self.prob.run_model() - thrust = self.prob.get_val(Dynamic.Mission.THRUST_TOTAL, units='lbf') - thrust_max = self.prob.get_val(Dynamic.Mission.THRUST_MAX_TOTAL, units='lbf') + thrust = self.prob.get_val(Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf') + thrust_max = self.prob.get_val( + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, units='lbf' + ) fuel_flow = self.prob.get_val( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lb/h') + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lb/h' + ) electric_power_in = self.prob.get_val( - Dynamic.Mission.ELECTRIC_POWER_IN_TOTAL, units='kW') - nox = self.prob.get_val(Dynamic.Mission.NOX_RATE_TOTAL, units='lb/h') + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN_TOTAL, units='kW' + ) + nox = self.prob.get_val(Dynamic.Vehicle.Propulsion.NOX_RATE_TOTAL, units='lb/h') expected_thrust = np.array([2347.202, 14535]) expected_thrust_max = np.array([8914.33, 18300]) @@ -153,6 +200,7 @@ def test_case_multiengine(self): options = get_flops_inputs('LargeSingleAisle2FLOPS') options.set_val(Settings.VERBOSITY, 0) + options.set_val(Aircraft.Engine.GLOBAL_THROTTLE, True) engine = build_engine_deck(options)[0] engine2 = build_engine_deck(options)[0] @@ -160,47 +208,105 @@ def test_case_multiengine(self): engine_models = [engine, engine2] preprocess_propulsion(options, engine_models=engine_models) - self.prob.model = PropulsionMission( - num_nodes=20, aviary_options=options, engine_models=engine_models) + model = self.prob.model + prop = PropulsionMission( + num_nodes=20, + aviary_options=options, + engine_models=engine_models, + ) + model.add_subsystem('core_propulsion', prop, + promotes=['*']) - self.prob.model.add_subsystem(Dynamic.Mission.MACH, - om.IndepVarComp(Dynamic.Mission.MACH, - np.linspace(0, 0.85, nn), - units='unitless'), - promotes=['*']) + self.prob.model.add_subsystem( + Dynamic.Atmosphere.MACH, + om.IndepVarComp( + Dynamic.Atmosphere.MACH, np.linspace(0, 0.85, nn), units='unitless' + ), + promotes=['*'], + ) self.prob.model.add_subsystem( Dynamic.Mission.ALTITUDE, om.IndepVarComp( - Dynamic.Mission.ALTITUDE, - np.linspace(0, 40000, nn), - units='ft'), - promotes=['*']) + Dynamic.Mission.ALTITUDE, np.linspace(0, 40000, nn), units='ft' + ), + promotes=['*'], + ) throttle = np.linspace(1.0, 0.6, nn) self.prob.model.add_subsystem( - Dynamic.Mission.THROTTLE, om.IndepVarComp(Dynamic.Mission.THROTTLE, np.vstack((throttle, throttle)).transpose(), units='unitless'), promotes=['*']) + Dynamic.Vehicle.Propulsion.THROTTLE, + om.IndepVarComp( + Dynamic.Vehicle.Propulsion.THROTTLE, + np.vstack((throttle, throttle)).transpose(), + units='unitless', + ), + promotes=['*'], + ) + + setup_model_options(self.prob, options, engine_models=engine_models) self.prob.setup(force_alloc_complex=True) - self.prob.set_val(Aircraft.Engine.SCALE_FACTOR, [0.975], units='unitless') + self.prob.set_val(Aircraft.Engine.SCALE_FACTOR, [0.975, 0.975], units='unitless') self.prob.run_model() - thrust = self.prob.get_val(Dynamic.Mission.THRUST_TOTAL, units='lbf') + thrust = self.prob.get_val(Dynamic.Vehicle.Propulsion.THRUST_TOTAL, units='lbf') fuel_flow = self.prob.get_val( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h') - nox_rate = self.prob.get_val(Dynamic.Mission.NOX_RATE_TOTAL, units='lbm/h') - - expected_thrust = np.array([103583.64726051, 92899.15059987, 82826.62014006, 73006.74478288, - 63491.73778033, 55213.71927899, 48317.05801159, 42277.98362824, - 36870.43915515, 29716.58670587, 26271.29434561, 24680.25359966, - 22043.65303425, 19221.1253513, 16754.1861966, 14405.43665682, - 12272.31373152, 10141.72397926, 7869.3816548, 5792.62871788]) - - expected_fuel_flow = np.array([-38238.66614438, -36078.76817864, -33777.65206416, -31057.41872898, - -28036.92997813, -25279.48301301, -22902.98616678, -20749.08916211, - -19058.23299911, -19972.32193796, -17701.86829646, -14370.68121827, - -12584.1724091, -11320.06786905, -10192.11938107, -9100.08365082, - -8100.4835652, -7069.62950088, -5965.78834865, -4914.94081538]) + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h' + ) + nox_rate = self.prob.get_val( + Dynamic.Vehicle.Propulsion.NOX_RATE_TOTAL, units='lbm/h' + ) + + expected_thrust = np.array( + [ + 103583.64726051, + 92899.15059987, + 82826.62014006, + 73006.74478288, + 63491.73778033, + 55213.71927899, + 48317.05801159, + 42277.98362824, + 36870.43915515, + 29716.58670587, + 26271.29434561, + 24680.25359966, + 22043.65303425, + 19221.1253513, + 16754.1861966, + 14405.43665682, + 12272.31373152, + 10141.72397926, + 7869.3816548, + 5792.62871788, + ] + ) + + expected_fuel_flow = np.array( + [ + -38238.66614438, + -36078.76817864, + -33777.65206416, + -31057.41872898, + -28036.92997813, + -25279.48301301, + -22902.98616678, + -20749.08916211, + -19058.23299911, + -19972.32193796, + -17701.86829646, + -14370.68121827, + -12584.1724091, + -11320.06786905, + -10192.11938107, + -9100.08365082, + -8100.4835652, + -7069.62950088, + -5965.78834865, + -4914.94081538, + ] + ) expected_nox_rate = np.array( [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) diff --git a/aviary/subsystems/propulsion/test/test_propulsion_premission.py b/aviary/subsystems/propulsion/test/test_propulsion_premission.py index a56a17d3a..82c27d9e9 100644 --- a/aviary/subsystems/propulsion/test/test_propulsion_premission.py +++ b/aviary/subsystems/propulsion/test/test_propulsion_premission.py @@ -10,6 +10,7 @@ from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.validation_cases.validation_tests import get_flops_inputs from aviary.models.multi_engine_single_aisle.multi_engine_single_aisle_data import engine_1_inputs, engine_2_inputs +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Settings from aviary.utils.preprocessors import preprocess_options @@ -23,12 +24,17 @@ def test_case(self): options.set_val(Settings.VERBOSITY, 0) options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2])) - self.prob.model = PropulsionPreMission(aviary_options=options, - engine_models=build_engine_deck(options)) + self.prob.model = PropulsionPreMission( + aviary_options=options, engine_models=build_engine_deck(options) + ) + + self.prob.model.set_input_defaults(Aircraft.Engine.SCALE_FACTOR, np.ones(1)) + + setup_model_options(self.prob, options) self.prob.setup(force_alloc_complex=True) - self.prob.set_val(Aircraft.Engine.SCALED_SLS_THRUST, options.get_val( - Aircraft.Engine.SCALED_SLS_THRUST, units='lbf')) + # self.prob.set_val(Aircraft.Engine.SCALED_SLS_THRUST, options.get_val( + # Aircraft.Engine.SCALED_SLS_THRUST, units='lbf')) self.prob.run_model() @@ -48,11 +54,21 @@ def test_multi_engine(self): engine1 = build_engine_deck(engine_1_inputs)[0] engine2 = build_engine_deck(engine_2_inputs)[0] engine_models = [engine1, engine2] - preprocess_options(options, engine_models=engine_models) - self.prob.model = PropulsionPreMission(aviary_options=options, - engine_models=engine_models) + setup_model_options(self.prob, options, engine_models=engine_models) + + model = self.prob.model + prop = PropulsionPreMission(aviary_options=options, + engine_models=engine_models) + model.add_subsystem('core_propulsion', prop, + promotes=['*']) + + setup_model_options(self.prob, options, engine_models=engine_models) + + self.prob.model.set_input_defaults( + Aircraft.Engine.SCALE_FACTOR, np.ones(2) * 0.5 + ) self.prob.setup(force_alloc_complex=True) self.prob.set_val(Aircraft.Engine.SCALED_SLS_THRUST, options.get_val( @@ -70,12 +86,12 @@ def test_multi_engine(self): assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) def test_propulsion_sum(self): - options = AviaryValues() - options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([1, 2, 5])) - options.set_val(Settings.VERBOSITY, 0) + options = { + Aircraft.Engine.NUM_ENGINES: np.array([1, 2, 5]), + } self.prob.model = om.Group() self.prob.model.add_subsystem('propsum', - PropulsionSum(aviary_options=options), + PropulsionSum(**options), promotes=['*']) self.prob.setup(force_alloc_complex=True) diff --git a/aviary/subsystems/propulsion/test/test_throttle_allocation.py b/aviary/subsystems/propulsion/test/test_throttle_allocation.py index 969e28c60..6ec4aadbf 100644 --- a/aviary/subsystems/propulsion/test/test_throttle_allocation.py +++ b/aviary/subsystems/propulsion/test/test_throttle_allocation.py @@ -7,7 +7,6 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.subsystems.propulsion.throttle_allocation import ThrottleAllocator -from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import ThrottleAllocation from aviary.variable_info.variables import Aircraft @@ -15,17 +14,16 @@ class ThrottleAllocationTest(unittest.TestCase): def setUp(self): - aviary_inputs = AviaryValues() - aviary_inputs.set_val(Aircraft.Engine.NUM_ENGINES, np.array([1, 1, 1])) - - self.aviary_inputs = aviary_inputs + self.options = { + Aircraft.Engine.NUM_ENGINES: np.array([1, 1, 1]), + } def test_derivs_fixed_or_static(self): prob = om.Problem() model = prob.model model.add_subsystem('comp', ThrottleAllocator(num_nodes=4, - aviary_options=self.aviary_inputs, - throttle_allocation=ThrottleAllocation.FIXED), + throttle_allocation=ThrottleAllocation.FIXED, + **self.options), promotes=['*']) prob.setup(force_alloc_complex=True) @@ -41,8 +39,8 @@ def test_derivs_dynamic(self): prob = om.Problem() model = prob.model model.add_subsystem('comp', ThrottleAllocator(num_nodes=4, - aviary_options=self.aviary_inputs, - throttle_allocation=ThrottleAllocation.DYNAMIC), + throttle_allocation=ThrottleAllocation.DYNAMIC, + **self.options), promotes=['*']) prob.setup(force_alloc_complex=True) diff --git a/aviary/subsystems/propulsion/test/test_turboprop_model.py b/aviary/subsystems/propulsion/test/test_turboprop_model.py index eacd6595e..a461a363d 100644 --- a/aviary/subsystems/propulsion/test/test_turboprop_model.py +++ b/aviary/subsystems/propulsion/test/test_turboprop_model.py @@ -5,13 +5,16 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.atmosphere.atmosphere import Atmosphere from pathlib import Path +from openmdao.utils.testing_utils import use_tempdirs +from aviary.interface.methods_for_level2 import AviaryProblem from aviary.subsystems.propulsion.turboprop_model import TurbopropModel from aviary.subsystems.propulsion.propeller.propeller_performance import ( PropellerPerformance, ) from aviary.utils.preprocessors import preprocess_propulsion from aviary.utils.functions import get_path +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.variable_info.enums import SpeedType from aviary.variable_info.options import get_option_defaults @@ -19,7 +22,8 @@ from aviary.subsystems.propulsion.motor.motor_builder import MotorBuilder -class TurbopropTest(unittest.TestCase): +@use_tempdirs +class TurbopropMissionTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() @@ -50,13 +54,18 @@ def prepare_model( options.set_val(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08) options.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) options.set_val(Aircraft.Engine.INTERPOLATION_METHOD, 'slinear') + options.set_val( + Aircraft.Engine.FIXED_RPM, + 1455.13090827, + units='rpm', + ) options.set_val( - Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, + Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, val=True, units='unitless', ) - options.set_val(Aircraft.Engine.NUM_PROPELLER_BLADES, val=4, units='unitless') + options.set_val(Aircraft.Engine.Propeller.NUM_BLADES, val=4, units='unitless') num_nodes = len(test_points) @@ -66,9 +75,12 @@ def prepare_model( preprocess_propulsion(options, [engine]) machs, alts, throttles = zip(*test_points) - IVC = om.IndepVarComp(Dynamic.Mission.MACH, np.array(machs), units='unitless') + IVC = om.IndepVarComp( + Dynamic.Atmosphere.MACH, np.array(machs), units='unitless' + ) IVC.add_output(Dynamic.Mission.ALTITUDE, np.array(alts), units='ft') - IVC.add_output(Dynamic.Mission.THROTTLE, np.array(throttles), units='unitless') + IVC.add_output(Dynamic.Vehicle.Propulsion.THROTTLE, + np.array(throttles), units='unitless') self.prob.model.add_subsystem('IVC', IVC, promotes=['*']) # calculate atmospheric properties @@ -87,19 +99,22 @@ def prepare_model( promotes_outputs=['*'], ) + setup_model_options(self.prob, options) + self.prob.setup(force_alloc_complex=False) self.prob.set_val(Aircraft.Engine.SCALE_FACTOR, 1, units='unitless') def get_results(self, point_names=None, display_results=False): - shp = self.prob.get_val(Dynamic.Mission.SHAFT_POWER, units='hp') - total_thrust = self.prob.get_val(Dynamic.Mission.THRUST, units='lbf') + shp = self.prob.get_val(Dynamic.Vehicle.Propulsion.SHAFT_POWER, units='hp') + total_thrust = self.prob.get_val(Dynamic.Vehicle.Propulsion.THRUST, units='lbf') prop_thrust = self.prob.get_val('turboprop_model.propeller_thrust', units='lbf') tailpipe_thrust = self.prob.get_val( 'turboprop_model.turboshaft_thrust', units='lbf' ) - max_thrust = self.prob.get_val(Dynamic.Mission.THRUST_MAX, units='lbf') + max_thrust = self.prob.get_val( + Dynamic.Vehicle.Propulsion.THRUST_MAX, units='lbf') fuel_flow = self.prob.get_val( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, units='lbm/h' + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, units='lbm/h' ) results = [] @@ -124,61 +139,64 @@ def test_case_1(self): # shp, tailpipe thrust, prop_thrust, total_thrust, max_thrust, fuel flow truth_vals = [ ( - 223.99923788786057, + 111.99923788786062, 37.699999999999996, - 1195.4410168571105, - 1233.1410168571106, - 4983.816421227165, + 610.3580810058977, + 648.0580810058977, + 4184.157517016291, -195.79999999999995, ), ( - 2239.9923788786077, + 1119.992378878607, 136.29999999999967, - 4847.516421227166, - 4983.816421227165, - 4983.816421227165, + 4047.857517016292, + 4184.157517016291, + 4184.157517016291, -643.9999999999998, ), ( - 2466.55094358958, + 778.2106659424866, 21.30000000000001, - 1833.4755577366554, - 1854.7755577366554, - 1854.7755577366554, - -839.7000000000685, + 558.2951237599805, + 579.5951237599804, + 579.5951237599804, + -839.7000000000685 ), ] options = get_option_defaults() options.set_val( - Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, + Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, val=True, units='unitless', ) - options.set_val(Aircraft.Engine.NUM_PROPELLER_BLADES, val=4, units='unitless') + options.set_val(Aircraft.Engine.Propeller.NUM_BLADES, val=4, units='unitless') options.set_val('speed_type', SpeedType.MACH) prop_group = ExamplePropModel('custom_prop_model') self.prepare_model(test_points, filename, prop_group) - self.prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10.5, units="ft") + self.prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 10.5, units="ft") self.prob.set_val( - Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 114.0, units="unitless" + Aircraft.Engine.Propeller.ACTIVITY_FACTOR, 114.0, units="unitless" ) # self.prob.set_val(Dynamic.Mission.PERCENT_ROTOR_RPM_CORRECTED, # np.array([1, 1, 0.7]), units="unitless") self.prob.set_val( - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" ) - self.prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 800, units="ft/s") + self.prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 800, units="ft/s") self.prob.run_model() results = self.get_results() - assert_near_equal(results, truth_vals) + assert_near_equal(results[0], truth_vals[0], tolerance=1.5e-12) + assert_near_equal(results[1], truth_vals[1], tolerance=1.5e-12) + assert_near_equal(results[2], truth_vals[2], tolerance=1.5e-12) - # because Hamilton Standard model uses fd method, the following may not be accurate. + # because Hamilton Standard model uses fd method, the following may not be + # accurate. partial_data = self.prob.check_partials(out_stream=None, form="central") assert_check_partials(partial_data, atol=0.2, rtol=0.2) @@ -188,102 +206,110 @@ def test_case_2(self): test_points = [(0.001, 0, 0), (0, 0, 1), (0.6, 25000, 1)] truth_vals = [ ( - 223.99007751511726, - 37.507374999999996, - 1186.6952790705282, - 1224.202654070528, - 4984.168836459296, - -195.78762499999996, + 111.99470252, + 37.507375, + 610.74316702, + 648.25054202, + 4174.71017, + -195.787625, ), ( - 2239.9923788786077, + 1119.992378878607, 136.29999999999967, - 4847.516421227166, - 4983.816421227165, - 4983.816421227165, + 4047.857517016292, + 4184.157517016291, + 4184.157517016291, -643.9999999999998, ), ( - 2466.55094358958, + 778.2106659424866, 21.30000000000001, - 1833.4755577366554, - 1854.7755577366554, - 1854.7755577366554, - -839.7000000000685, + 558.2951237599805, + 579.5951237599804, + 579.5951237599804, + -839.7000000000685 ), ] self.prepare_model(test_points, filename) - self.prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10.5, units="ft") + self.prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 10.5, units="ft") self.prob.set_val( - Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 114.0, units="unitless" + Aircraft.Engine.Propeller.ACTIVITY_FACTOR, 114.0, units="unitless" ) # self.prob.set_val(Dynamic.Mission.PERCENT_ROTOR_RPM_CORRECTED, # np.array([1,1,0.7]), units="unitless") self.prob.set_val( - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" ) - self.prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 800, units="ft/s") + self.prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 800, units="ft/s") self.prob.run_model() results = self.get_results() - assert_near_equal(results, truth_vals) + assert_near_equal(results[0], truth_vals[0], tolerance=1.5e-12) + assert_near_equal(results[1], truth_vals[1], tolerance=1.5e-12) + assert_near_equal(results[2], truth_vals[2], tolerance=1.5e-12) partial_data = self.prob.check_partials(out_stream=None, form="central") assert_check_partials(partial_data, atol=0.15, rtol=0.15) def test_case_3(self): - # test case using GASP-derived engine deck w/o tailpipe thrust and default HS prop model. + # test case using GASP-derived engine deck w/o tailpipe thrust and default + # HS prop model. filename = get_path('models/engines/turboshaft_1120hp_no_tailpipe.deck') test_points = [(0, 0, 0), (0, 0, 1), (0.6, 25000, 1)] truth_vals = [ ( - 223.99923788786057, + 111.99923788786062, 0.0, - 1195.4410168571105, - 1195.4410168571105, - 4847.516421227166, + 610.3580810058977, + 610.3580810058977, + 4047.857517016292, -195.79999999999995, ), ( - 2239.9923788786077, + 1119.992378878607, 0.0, - 4847.516421227166, - 4847.516421227166, - 4847.516421227166, + 4047.857517016292, + 4047.857517016292, + 4047.857517016292, -643.9999999999998, ), ( - 2466.55094358958, + 778.2106659424866, 0.0, - 1833.4755577366554, - 1833.4755577366554, - 1833.4755577366554, - -839.7000000000685, - ), + 558.2951237599805, + 558.2951237599805, + 558.2951237599805, + -839.7000000000685 + ) ] self.prepare_model(test_points, filename) - self.prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10.5, units="ft") + self.prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 10.5, units="ft") self.prob.set_val( - Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 114.0, units="unitless" + Aircraft.Engine.Propeller.ACTIVITY_FACTOR, 114.0, units="unitless" ) self.prob.set_val( - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" ) - self.prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 800, units="ft/s") + self.prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 800, units="ft/s") self.prob.run_model() results = self.get_results() - assert_near_equal(results, truth_vals) + assert_near_equal(results[0], truth_vals[0], tolerance=1.5e-12) + assert_near_equal(results[1], truth_vals[1], tolerance=1.5e-12) + assert_near_equal(results[2], truth_vals[2], tolerance=1.5e-12) - partial_data = self.prob.check_partials(out_stream=None, form="central") - assert_check_partials(partial_data, atol=0.15, rtol=0.15) + # Note: There isn't much point in checking the partials of a component + # that computes them with FD. + partial_data = self.prob.check_partials(out_stream=None, form="forward", + step=1.01e-6) + assert_check_partials(partial_data, atol=1e10, rtol=1e-3) def test_electroprop(self): # test case using electric motor and default HS prop model. @@ -293,33 +319,34 @@ def test_electroprop(self): motor_model = MotorBuilder() self.prepare_model(test_points, motor_model, input_rpm=True) - self.prob.set_val(Dynamic.Mission.RPM, np.ones(num_nodes) * 2000.0, units='rpm') + self.prob.set_val(Dynamic.Vehicle.Propulsion.RPM, + np.ones(num_nodes) * 2000.0, units='rpm') - self.prob.set_val(Aircraft.Engine.PROPELLER_DIAMETER, 10.5, units="ft") + self.prob.set_val(Aircraft.Engine.Propeller.DIAMETER, 10.5, units="ft") self.prob.set_val( - Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, 114.0, units="unitless" + Aircraft.Engine.Propeller.ACTIVITY_FACTOR, 114.0, units="unitless" ) self.prob.set_val( - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, 0.5, units="unitless" ) - self.prob.set_val(Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, 800, units="ft/s") + self.prob.set_val(Aircraft.Engine.Propeller.TIP_SPEED_MAX, 800, units="ft/s") self.prob.run_model() - shp_expected = [0.0, 505.55333, 505.55333] + shp_expected = [0.0, 367.82313837, 367.82313837] prop_thrust_expected = total_thrust_expected = [ - 610.35808, - 2627.26329, - 312.27342, + 610.3580827654595, + 2083.253331913252, + 184.38117745374652 ] - electric_power_expected = [0.0, 408.4409047, 408.4409047] + electric_power_expected = [0.0, 303.31014553, 303.31014553] - shp = self.prob.get_val(Dynamic.Mission.SHAFT_POWER, units='hp') - total_thrust = self.prob.get_val(Dynamic.Mission.THRUST, units='lbf') + shp = self.prob.get_val(Dynamic.Vehicle.Propulsion.SHAFT_POWER, units='hp') + total_thrust = self.prob.get_val(Dynamic.Vehicle.Propulsion.THRUST, units='lbf') prop_thrust = self.prob.get_val('turboprop_model.propeller_thrust', units='lbf') electric_power = self.prob.get_val( - Dynamic.Mission.ELECTRIC_POWER_IN, units='kW' + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, units='kW' ) assert_near_equal(shp, shp_expected, tolerance=1e-8) @@ -327,10 +354,11 @@ def test_electroprop(self): assert_near_equal(prop_thrust, prop_thrust_expected, tolerance=1e-8) assert_near_equal(electric_power, electric_power_expected, tolerance=1e-8) - partial_data = self.prob.check_partials( - out_stream=None, method="fd", form="central" - ) - assert_check_partials(partial_data, atol=0.17, rtol=0.15) + # Note: There isn't much point in checking the partials of a component + # that computes them with FD. + partial_data = self.prob.check_partials(out_stream=None, form="forward", + step=1.01e-6) + assert_check_partials(partial_data, atol=1e10, rtol=1e-3) class ExamplePropModel(SubsystemBuilderBase): @@ -341,22 +369,25 @@ def build_mission(self, num_nodes, aviary_inputs, **kwargs): 'propeller_performance', PropellerPerformance(aviary_options=aviary_inputs, num_nodes=num_nodes), promotes_inputs=[ - Dynamic.Mission.MACH, - Dynamic.Mission.SPEED_OF_SOUND, - Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.MACH, + Aircraft.Engine.Propeller.TIP_SPEED_MAX, + Aircraft.Engine.Propeller.TIP_MACH_MAX, + Dynamic.Atmosphere.DENSITY, Dynamic.Mission.VELOCITY, - Aircraft.Engine.PROPELLER_DIAMETER, - Dynamic.Mission.SHAFT_POWER, - Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, + Aircraft.Engine.Propeller.DIAMETER, + Aircraft.Engine.Propeller.ACTIVITY_FACTOR, + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, + Aircraft.Nacelle.AVG_DIAMETER, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Vehicle.Propulsion.RPM, + Dynamic.Vehicle.Propulsion.SHAFT_POWER, ], promotes_outputs=['*'], ) - pp.set_input_defaults(Aircraft.Engine.PROPELLER_DIAMETER, 10, units="ft") + pp.set_input_defaults(Aircraft.Engine.Propeller.DIAMETER, 10, units="ft") pp.set_input_defaults( - Dynamic.Mission.PROPELLER_TIP_SPEED, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, 800.0 * np.ones(num_nodes), units="ft/s", ) diff --git a/aviary/subsystems/propulsion/throttle_allocation.py b/aviary/subsystems/propulsion/throttle_allocation.py index fd0543fe2..f898a8049 100644 --- a/aviary/subsystems/propulsion/throttle_allocation.py +++ b/aviary/subsystems/propulsion/throttle_allocation.py @@ -4,6 +4,7 @@ from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import ThrottleAllocation +from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft, Dynamic @@ -19,21 +20,17 @@ def initialize(self): types=int, lower=0 ) - self.options.declare( - 'aviary_options', - types=AviaryValues, - desc='collection of Aircraft/Mission specific options' - ) self.options.declare( 'throttle_allocation', default=ThrottleAllocation.FIXED, types=ThrottleAllocation, desc='Flag that determines how to handle throttles for multiple engines.' ) + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + def setup(self): - options: AviaryValues = self.options['aviary_options'] nn = self.options['num_nodes'] - num_engine_type = len(options.get_val(Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) alloc_mode = self.options['throttle_allocation'] self.add_input( @@ -56,10 +53,10 @@ def setup(self): ) self.add_output( - Dynamic.Mission.THROTTLE, + Dynamic.Vehicle.Propulsion.THROTTLE, np.ones((nn, num_engine_type)), units="unitless", - desc="Throttle setting for all engines." + desc="Throttle setting for all engines.", ) if alloc_mode == ThrottleAllocation.DYNAMIC: @@ -75,8 +72,12 @@ def setup(self): cols = np.repeat(np.arange(nn), num_engine_type) rows = np.arange(nn * num_engine_type) - self.declare_partials(of=[Dynamic.Mission.THROTTLE], wrt=["aggregate_throttle"], - rows=rows, cols=cols) + self.declare_partials( + of=[Dynamic.Vehicle.Propulsion.THROTTLE], + wrt=["aggregate_throttle"], + rows=rows, + cols=cols, + ) if alloc_mode == ThrottleAllocation.DYNAMIC: a = num_engine_type @@ -87,44 +88,51 @@ def setup(self): cols = np.tile(col, num_engine_type) all_rows = np.tile(rows, nn) + a * np.repeat(np.arange(nn), a * b) all_cols = np.tile(cols, nn) + b * np.repeat(np.arange(nn), a * b) - self.declare_partials(of=[Dynamic.Mission.THROTTLE], wrt=["throttle_allocations"], - rows=all_rows, cols=all_cols) + self.declare_partials( + of=[Dynamic.Vehicle.Propulsion.THROTTLE], + wrt=["throttle_allocations"], + rows=all_rows, + cols=all_cols, + ) rows = np.repeat(np.arange(nn), b) cols = np.arange(nn * b) self.declare_partials(of=["throttle_allocation_sum"], wrt=["throttle_allocations"], rows=rows, cols=cols, val=1.0) else: - self.declare_partials(of=[Dynamic.Mission.THROTTLE], - wrt=["throttle_allocations"]) + self.declare_partials( + of=[Dynamic.Vehicle.Propulsion.THROTTLE], wrt=["throttle_allocations"] + ) self.declare_partials(of=["throttle_allocation_sum"], wrt=["throttle_allocations"], val=1.0) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - nn = self.options['num_nodes'] alloc_mode = self.options['throttle_allocation'] agg_throttle = inputs["aggregate_throttle"] allocation = inputs["throttle_allocations"] if alloc_mode == ThrottleAllocation.DYNAMIC: - outputs[Dynamic.Mission.THROTTLE][:, :- - 1] = np.einsum("i,ij->ij", agg_throttle, allocation) + outputs[Dynamic.Vehicle.Propulsion.THROTTLE][:, :-1] = np.einsum( + "i,ij->ij", agg_throttle, allocation + ) sum_alloc = np.sum(allocation, axis=1) else: - outputs[Dynamic.Mission.THROTTLE][:, :- - 1] = np.einsum("i,j->ij", agg_throttle, allocation) + outputs[Dynamic.Vehicle.Propulsion.THROTTLE][:, :-1] = np.einsum( + "i,j->ij", agg_throttle, allocation + ) sum_alloc = np.sum(allocation) - outputs[Dynamic.Mission.THROTTLE][:, -1] = agg_throttle * (1.0 - sum_alloc) + outputs[Dynamic.Vehicle.Propulsion.THROTTLE][:, -1] = agg_throttle * ( + 1.0 - sum_alloc + ) outputs["throttle_allocation_sum"] = sum_alloc def compute_partials(self, inputs, partials, discrete_inputs=None): - options: AviaryValues = self.options['aviary_options'] nn = self.options['num_nodes'] alloc_mode = self.options['throttle_allocation'] - num_engine_type = len(options.get_val(Aircraft.Engine.NUM_ENGINES)) + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) agg_throttle = inputs["aggregate_throttle"] allocation = inputs["throttle_allocations"] @@ -132,7 +140,9 @@ def compute_partials(self, inputs, partials, discrete_inputs=None): if alloc_mode == ThrottleAllocation.DYNAMIC: sum_alloc = np.sum(allocation, axis=1) allocs = np.vstack((allocation.T, 1.0 - sum_alloc)) - partials[Dynamic.Mission.THROTTLE, "aggregate_throttle"] = allocs.T.ravel() + partials[Dynamic.Vehicle.Propulsion.THROTTLE, "aggregate_throttle"] = ( + allocs.T.ravel() + ) ne = num_engine_type - 1 mask1 = np.eye(ne) @@ -140,13 +150,16 @@ def compute_partials(self, inputs, partials, discrete_inputs=None): mask = np.vstack((mask1, mask2)).ravel() deriv = np.outer(agg_throttle, mask).reshape((nn * (ne + 1), ne)) - partials[Dynamic.Mission.THROTTLE, "throttle_allocations"] = deriv.ravel() + partials[Dynamic.Vehicle.Propulsion.THROTTLE, "throttle_allocations"] = ( + deriv.ravel() + ) else: sum_alloc = np.sum(allocation) allocs = np.hstack((allocation, 1.0 - sum_alloc)) - partials[Dynamic.Mission.THROTTLE, - "aggregate_throttle"] = np.tile(allocs, nn) + partials[Dynamic.Vehicle.Propulsion.THROTTLE, "aggregate_throttle"] = ( + np.tile(allocs, nn) + ) ne = num_engine_type - 1 mask1 = np.eye(ne) @@ -154,10 +167,12 @@ def compute_partials(self, inputs, partials, discrete_inputs=None): mask = np.vstack((mask1, mask2)).ravel() deriv = np.outer(agg_throttle, mask).reshape((nn * (ne + 1), ne)) - partials[Dynamic.Mission.THROTTLE, "throttle_allocations"] = deriv + partials[Dynamic.Vehicle.Propulsion.THROTTLE, "throttle_allocations"] = ( + deriv + ) # sum_alloc = np.sum(allocation) - # outputs[Dynamic.Mission.THROTTLE][:, -1] = agg_throttle * (1.0 - sum_alloc) + # outputs[Dynamic.Vehicle.Propulsion.THROTTLE][:, -1] = agg_throttle * (1.0 - sum_alloc) # outputs["throttle_allocation_sum"] = sum_alloc diff --git a/aviary/subsystems/propulsion/turboprop_model.py b/aviary/subsystems/propulsion/turboprop_model.py index 444d9db4a..fd0446bdf 100644 --- a/aviary/subsystems/propulsion/turboprop_model.py +++ b/aviary/subsystems/propulsion/turboprop_model.py @@ -1,13 +1,18 @@ +import warnings + import numpy as np import openmdao.api as om +from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase from aviary.subsystems.propulsion.engine_model import EngineModel from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.subsystems.propulsion.utils import EngineModelVariables from aviary.utils.named_values import NamedValues from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Aircraft, Dynamic -from aviary.subsystems.propulsion.propeller.propeller_performance import PropellerPerformance +from aviary.variable_info.variables import Aircraft, Dynamic, Settings +from aviary.variable_info.enums import Verbosity +from aviary.subsystems.propulsion.propeller.propeller_builder import PropellerBuilder +from aviary.subsystems.propulsion.gearbox.gearbox_builder import GearboxBuilder class TurbopropModel(EngineModel): @@ -25,11 +30,14 @@ class TurbopropModel(EngineModel): If using an engine deck, engine performance data (optional). If provided, used instead of tabular data file. shaft_power_model : SubsystemBuilderBase () - Subsystem builder for the shaft power generating component. If None, an + Subsystem builder for the shaft power generating component. If None, an EngineDeck built using provided options is used. propeller_model : SubsystemBuilderBase () - Subsystem builder for the propeller. If None, the Hamilton Standard methodology + Subsystem builder for the propeller. If None, the Hamilton Standard methodology is used to model the propeller. + gearbox_model : SubsystemBuilderBase () + Subsystem builder used for the gearbox. If None, the simple gearbox model is + used. Methods ------- @@ -41,14 +49,22 @@ class TurbopropModel(EngineModel): update """ - def __init__(self, name='turboprop_model', options: AviaryValues = None, - data: NamedValues = None, shaft_power_model=None, propeller_model=None): + def __init__( + self, + name='turboprop_model', + options: AviaryValues = None, + data: NamedValues = None, + shaft_power_model: SubsystemBuilderBase = None, + propeller_model: SubsystemBuilderBase = None, + gearbox_model: SubsystemBuilderBase = None, + ): # also calls _preprocess_inputs() as part of EngineModel __init__ super().__init__(name, options) self.shaft_power_model = shaft_power_model self.propeller_model = propeller_model + self.gearbox_model = gearbox_model # Initialize turboshaft engine deck. New required variable set w/o thrust if shaft_power_model is None: @@ -63,15 +79,31 @@ def __init__(self, name='turboprop_model', options: AviaryValues = None, }, ) - # BUG if using both custom subsystems that happen to share a kwarg but need different values, this breaks + # TODO No reason gearbox model needs to be required. All connections can + # be handled in configure - need to figure out when user wants gearbox without + # having to directly pass builder + if gearbox_model is None: + # TODO where can we bring in include_constraints? kwargs in init is an option, + # but that still requires the L2 interface + self.gearbox_model = GearboxBuilder( + name=name + '_gearbox', include_constraints=True + ) + + if propeller_model is None: + self.propeller_model = PropellerBuilder(name=name + '_propeller') + + # BUG if using both custom subsystems that happen to share a kwarg but + # need different values, this breaks def build_pre_mission(self, aviary_inputs, **kwargs) -> om.Group: shp_model = self.shaft_power_model propeller_model = self.propeller_model + gearbox_model = self.gearbox_model turboprop_group = om.Group() + # TODO engine scaling for turboshafts requires EngineSizing to be refactored to # accept target scaling variable as an option, skipping for now - if type(shp_model) is not EngineDeck: - shp_model_pre_mission = shp_model.build_pre_mission(aviary_inputs, **kwargs) + if not isinstance(shp_model, EngineDeck): + shp_model_pre_mission = shp_model.build_pre_mission(self.options, **kwargs) if shp_model_pre_mission is not None: turboprop_group.add_subsystem( shp_model_pre_mission.name, @@ -79,16 +111,25 @@ def build_pre_mission(self, aviary_inputs, **kwargs) -> om.Group: promotes=['*'] ) - if propeller_model is not None: - propeller_model_pre_mission = propeller_model.build_pre_mission( - aviary_inputs, **kwargs + gearbox_model_pre_mission = gearbox_model.build_pre_mission( + self.options, **kwargs + ) + if gearbox_model_pre_mission is not None: + turboprop_group.add_subsystem( + gearbox_model_pre_mission.name, + subsys=gearbox_model_pre_mission, + promotes=['*'], + ) + + propeller_model_pre_mission = propeller_model.build_pre_mission( + self.options, **kwargs + ) + if propeller_model_pre_mission is not None: + turboprop_group.add_subsystem( + propeller_model_pre_mission.name, + subsys=propeller_model_pre_mission, + promotes=['*'], ) - if propeller_model_pre_mission is not None: - turboprop_group.add_subsystem( - propeller_model_pre_mission.name, - subsys=propeller_model_pre_mission, - promotes=['*'] - ) return turboprop_group @@ -97,7 +138,8 @@ def build_mission(self, num_nodes, aviary_inputs, **kwargs): num_nodes=num_nodes, shaft_power_model=self.shaft_power_model, propeller_model=self.propeller_model, - aviary_inputs=aviary_inputs, + gearbox_model=self.gearbox_model, + aviary_inputs=self.options, kwargs=kwargs, ) @@ -105,36 +147,60 @@ def build_mission(self, num_nodes, aviary_inputs, **kwargs): def build_post_mission(self, aviary_inputs, **kwargs): shp_model = self.shaft_power_model + gearbox_model = self.gearbox_model propeller_model = self.propeller_model turboprop_group = om.Group() - if type(shp_model) is not EngineDeck: - shp_model_post_mission = shp_model.build_post_mission( - aviary_inputs, **kwargs + + shp_model_post_mission = shp_model.build_post_mission(aviary_inputs, **kwargs) + if shp_model_post_mission is not None: + turboprop_group.add_subsystem( + shp_model.name, + subsys=shp_model_post_mission, + aviary_options=aviary_inputs, ) - if shp_model_post_mission is not None: - turboprop_group.add_subsystem( - shp_model_post_mission.name, - subsys=shp_model_post_mission, - aviary_options=aviary_inputs, - ) - if self.propeller_model is not None: - propeller_model_post_mission = propeller_model.build_post_mission( - aviary_inputs, **kwargs + gearbox_model_post_mission = gearbox_model.build_post_mission( + aviary_inputs, **kwargs + ) + if gearbox_model_post_mission is not None: + turboprop_group.add_subsystem( + gearbox_model.name, + subsys=gearbox_model_post_mission, + aviary_options=aviary_inputs, ) - if propeller_model_post_mission is not None: - turboprop_group.add_subsystem( - propeller_model_post_mission.name, - subsys=propeller_model_post_mission, - aviary_options=aviary_inputs, - ) - # turboprop_group.set_input_default( - # Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, val=0.0, units='ft/s' - # ) + propeller_model_post_mission = propeller_model.build_post_mission( + aviary_inputs, **kwargs + ) + if propeller_model_post_mission is not None: + turboprop_group.add_subsystem( + propeller_model.name, + subsys=propeller_model_post_mission, + aviary_options=aviary_inputs, + ) return turboprop_group + def get_parameters(self): + params = super().get_parameters() # calls from EngineModel + if self.shaft_power_model is not None: + params.update(self.shaft_power_model.get_parameters()) + if self.gearbox_model is not None: + params.update(self.gearbox_model.get_parameters()) + if self.propeller_model is not None: + params.update(self.propeller_model.get_parameters()) + return params + + def get_design_vars(self): + desvars = super().get_design_vars() # calls from EngineModel + if self.shaft_power_model is not None: + desvars.update(self.shaft_power_model.get_design_vars()) + if self.gearbox_model is not None: + desvars.update(self.gearbox_model.get_design_vars()) + if self.propeller_model is not None: + desvars.update(self.propeller_model.get_design_vars()) + return desvars + class TurbopropMission(om.Group): def initialize(self): @@ -143,20 +209,30 @@ def initialize(self): ) self.options.declare('shaft_power_model', desc='shaft power generation model') self.options.declare('propeller_model', desc='propeller model') - self.options.declare('kwargs', desc='kwargs for turboprop mission models') + self.options.declare('gearbox_model', desc='gearbox model') + self.options.declare('kwargs', desc='kwargs for turboprop mission model') self.options.declare( - 'aviary_inputs', desc='aviary inputs for turboprop mission' + 'aviary_inputs', desc='aviary inputs for turboprop mission model' ) def setup(self): - num_nodes = self.options['num_nodes'] + # All promotions for configurable components in this group are handled during + # configure() + + # save num_nodes for use in configure() + self.num_nodes = num_nodes = self.options['num_nodes'] shp_model = self.options['shaft_power_model'] propeller_model = self.options['propeller_model'] + gearbox_model = self.options['gearbox_model'] kwargs = self.options['kwargs'] - aviary_inputs = self.options['aviary_inputs'] + # save aviary_inputs for use in configure() + self.aviary_inputs = aviary_inputs = self.options['aviary_inputs'] - max_thrust_group = om.Group() + # NOTE: this subsystem is a empty component that has fixed RPM added as an output + # in configure() if provided in aviary_inputs + self.add_subsystem('fixed_rpm_source', subsys=om.IndepVarComp()) + # Shaft Power Model try: shp_kwargs = kwargs[shp_model.name] except (AttributeError, KeyError): @@ -164,106 +240,103 @@ def setup(self): shp_model_mission = shp_model.build_mission( num_nodes, aviary_inputs, **shp_kwargs) if shp_model_mission is not None: - self.add_subsystem( - shp_model.name, - subsys=shp_model_mission, - promotes_inputs=['*'], - ) + self.add_subsystem(shp_model.name, subsys=shp_model_mission) - # Gearbox can go here + # Gearbox Model + try: + gearbox_kwargs = kwargs[gearbox_model.name] + except (AttributeError, KeyError): + gearbox_kwargs = {} + if gearbox_model is not None: + gearbox_model_mission = gearbox_model.build_mission( + num_nodes, aviary_inputs, **gearbox_kwargs + ) + if gearbox_model_mission is not None: + self.add_subsystem(gearbox_model.name, subsys=gearbox_model_mission) + # Propeller Model try: propeller_kwargs = kwargs[propeller_model.name] except (AttributeError, KeyError): propeller_kwargs = {} - if propeller_model is not None: - - propeller_model_mission = propeller_model.build_mission( - num_nodes, aviary_inputs, **propeller_kwargs - ) - if propeller_model_mission is not None: - self.add_subsystem( - propeller_model.name, - subsys=propeller_model_mission, - promotes_inputs=[ - '*', - (Dynamic.Mission.SHAFT_POWER, 'propeller_shaft_power'), - ], - promotes_outputs=[ - '*', - (Dynamic.Mission.THRUST, 'propeller_thrust'), - ], - ) - - self.connect(Dynamic.Mission.SHAFT_POWER, 'propeller_shaft_power') - propeller_model_mission_max = propeller_model.build_mission( - num_nodes, aviary_inputs, **propeller_kwargs - ) - max_thrust_group.add_subsystem( - propeller_model.name + '_max', - subsys=propeller_model_mission_max, - promotes_inputs=['*', - (Dynamic.Mission.SHAFT_POWER, 'propeller_shaft_power_max')], - promotes_outputs=[(Dynamic.Mission.THRUST, 'propeller_thrust_max')] - ) - - self.connect( - Dynamic.Mission.SHAFT_POWER_MAX, 'propeller_shaft_power_max' - ) + propeller_group = om.Group() + propeller_model_mission = propeller_model.build_mission( + num_nodes, aviary_inputs, **propeller_kwargs + ) - else: # use the Hamilton Standard model + if isinstance(propeller_model, PropellerBuilder): + # use the Hamilton Standard model # only promote top-level inputs to avoid conflicts with max group prop_inputs = [ - Dynamic.Mission.MACH, - Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.MACH, + Aircraft.Engine.Propeller.TIP_SPEED_MAX, + Aircraft.Engine.Propeller.TIP_MACH_MAX, + Dynamic.Atmosphere.DENSITY, Dynamic.Mission.VELOCITY, - Aircraft.Engine.PROPELLER_DIAMETER, - Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, + Aircraft.Engine.Propeller.DIAMETER, + Aircraft.Engine.Propeller.ACTIVITY_FACTOR, + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, Aircraft.Nacelle.AVG_DIAMETER, - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Atmosphere.SPEED_OF_SOUND, + Dynamic.Vehicle.Propulsion.RPM, ] try: propeller_kwargs = kwargs['hamilton_standard'] except KeyError: propeller_kwargs = {} - self.add_subsystem( - 'propeller_model', - PropellerPerformance( - aviary_options=aviary_inputs, - num_nodes=num_nodes, - **propeller_kwargs, - ), - promotes_inputs=[ - *prop_inputs, - (Dynamic.Mission.SHAFT_POWER, 'propeller_shaft_power'), - ], - promotes_outputs=[ - '*', - (Dynamic.Mission.THRUST, 'propeller_thrust'), - ], + propeller_group.add_subsystem( + 'propeller_model_base', + propeller_model_mission, + promotes=['*'], ) - self.connect(Dynamic.Mission.SHAFT_POWER, 'propeller_shaft_power') - - max_thrust_group.add_subsystem( + propeller_model_mission_max = propeller_model.build_mission( + num_nodes, aviary_inputs, **propeller_kwargs + ) + propeller_group.add_subsystem( 'propeller_model_max', - PropellerPerformance( - aviary_options=aviary_inputs, - num_nodes=num_nodes, - **propeller_kwargs, - ), + propeller_model_mission_max, promotes_inputs=[ *prop_inputs, - (Dynamic.Mission.SHAFT_POWER, 'propeller_shaft_power_max'), + (Dynamic.Vehicle.Propulsion.SHAFT_POWER, + Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX), ], - promotes_outputs=[(Dynamic.Mission.THRUST, 'propeller_thrust_max')], + promotes_outputs=[ + (Dynamic.Vehicle.Propulsion.THRUST, + Dynamic.Vehicle.Propulsion.THRUST_MAX)], ) - self.connect(Dynamic.Mission.SHAFT_POWER_MAX, 'propeller_shaft_power_max') + self.add_subsystem('propeller_model', propeller_group) + + else: + if propeller_model_mission is not None: + propeller_group.add_subsystem( + propeller_model.name + '_base', + subsys=propeller_model_mission, + promotes_inputs=['*'], + promotes_outputs=[Dynamic.Vehicle.Propulsion.THRUST], + ) + + propeller_model_mission_max = propeller_model.build_mission( + num_nodes, aviary_inputs, **propeller_kwargs + ) + propeller_group.add_subsystem( + propeller_model.name + '_max', + subsys=propeller_model_mission_max, + promotes_inputs=[ + '*', + (Dynamic.Vehicle.Propulsion.SHAFT_POWER, + Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX), + ], + promotes_outputs=[ + (Dynamic.Vehicle.Propulsion.THRUST, + Dynamic.Vehicle.Propulsion.THRUST_MAX) + ], + ) + + self.add_subsystem(propeller_model.name, propeller_group) thrust_adder = om.ExecComp( 'turboprop_thrust=turboshaft_thrust+propeller_thrust', @@ -285,40 +358,286 @@ def setup(self): 'thrust_adder', subsys=thrust_adder, promotes_inputs=['*'], - promotes_outputs=[('turboprop_thrust', Dynamic.Mission.THRUST)], + promotes_outputs=[('turboprop_thrust', Dynamic.Vehicle.Propulsion.THRUST)], ) - max_thrust_group.add_subsystem( + self.add_subsystem( 'max_thrust_adder', subsys=max_thrust_adder, promotes_inputs=['*'], - promotes_outputs=[('turboprop_thrust_max', Dynamic.Mission.THRUST_MAX)] - ) - - self.add_subsystem( - 'turboprop_max_group', - max_thrust_group, - promotes_inputs=['*'], - promotes_outputs=[Dynamic.Mission.THRUST_MAX], + promotes_outputs=[ + ('turboprop_thrust_max', + Dynamic.Vehicle.Propulsion.THRUST_MAX)], ) def configure(self): - # configure step to alias thrust output from shaft power model if present + """ + Correctly connect variables between shaft power model, gearbox, and propeller, + aliasing names if they are present in both sets of connections. + + If a gearbox is present, inputs to the gearbox are usually done via connection, + while outputs from the gearbox are promoted. This prevents intermediate values + from "leaking" out of the model and getting incorrectly connected to outside + components. It is assumed only the gearbox has variables like this. + + Set up fixed RPM value if requested by user, which overrides any RPM defined by + shaft power model + """ + has_gearbox = self.options['gearbox_model'] is not None + + # TODO this list shouldn't be hardcoded - it should mirror propulsion_mission list + # Don't promote inputs that are in this list - shaft power should be an output + # of this system, also having it as an input causes feedback loop problem at + # the propulsion level + skipped_inputs = [ + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Vehicle.Propulsion.NOX_RATE, + Dynamic.Vehicle.Propulsion.SHAFT_POWER, + Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX, + Dynamic.Vehicle.Propulsion.TEMPERATURE_T4, + Dynamic.Vehicle.Propulsion.THRUST, + Dynamic.Vehicle.Propulsion.THRUST_MAX, + ] + + # Build lists of inputs/outputs for each component as needed: + # "_input_list" or "_output_list" are all variables that still need to be + # connected or promoted. This list is pared down as each variable is handled. + # "_inputs" or "_outputs" is a list that tracks all the pomotions needed for a + # given component, which is done at the end as a bulk promote. + shp_model = self._get_subsystem(self.options['shaft_power_model'].name) - output_dict = shp_model.list_outputs( + shp_input_dict = shp_model.list_inputs( return_format='dict', units=True, out_stream=None, all_procs=True ) + shp_input_list = list( + set( + shp_input_dict[key]['prom_name'] + for key in shp_input_dict + if '.' not in shp_input_dict[key]['prom_name'] + ) + ) + shp_output_dict = shp_model.list_outputs( + return_format='dict', units=True, out_stream=None, all_procs=True + ) + shp_output_list = list( + set( + shp_output_dict[key]['prom_name'] + for key in shp_output_dict + if '.' not in shp_output_dict[key]['prom_name'] + ) + ) + # always promote all shaft power model inputs w/o aliasing + shp_inputs = ['*'] + shp_outputs = [] + + if has_gearbox: + gearbox_model = self._get_subsystem(self.options['gearbox_model'].name) + gearbox_input_dict = gearbox_model.list_inputs( + return_format='dict', units=True, out_stream=None, all_procs=True + ) + # Assumption is made that variables with '_out' should never be promoted or + # connected as top-level input to gearbox. This is necessary because + # Aviary gearbox uses things like shp_out internally, like when computing + # torque output, so "shp_out" is an input to that internal component + gearbox_input_list = list( + set( + gearbox_input_dict[key]['prom_name'] + for key in gearbox_input_dict + if '.' not in gearbox_input_dict[key]['prom_name'] + and '_out' not in gearbox_input_dict[key]['prom_name'] + ) + ) + gearbox_inputs = [] + gearbox_output_dict = gearbox_model.list_outputs( + return_format='dict', units=True, out_stream=None, all_procs=True + ) + gearbox_output_list = list( + set( + gearbox_output_dict[key]['prom_name'] + for key in gearbox_output_dict + if '.' not in gearbox_output_dict[key]['prom_name'] + ) + ) + gearbox_outputs = [] + + if isinstance(self.options['propeller_model'], PropellerBuilder): + propeller_model_name = 'propeller_model' + else: + propeller_model_name = self.options['propeller_model'].name + propeller_model = self._get_subsystem(propeller_model_name) + propeller_input_dict = propeller_model.list_inputs( + return_format='dict', units=True, out_stream=None, all_procs=True + ) + propeller_input_list = list( + set( + propeller_input_dict[key]['prom_name'] + for key in propeller_input_dict + if '.' not in propeller_input_dict[key]['prom_name'] + ) + ) + propeller_inputs = [] + # always promote all propeller model outputs w/o aliasing except thrust + propeller_outputs = [ + '*', + (Dynamic.Vehicle.Propulsion.THRUST, 'propeller_thrust'), + (Dynamic.Vehicle.Propulsion.THRUST_MAX, 'propeller_thrust_max'), + ] + + ######################### + # SHP MODEL CONNECTIONS # + ######################### + # Everything not explicitly handled here gets promoted later on + # Thrust outputs are directly promoted with alias (this is a special case) + if Dynamic.Vehicle.Propulsion.THRUST in shp_output_list: + shp_outputs.append((Dynamic.Vehicle.Propulsion.THRUST, 'turboshaft_thrust')) + shp_output_list.remove(Dynamic.Vehicle.Propulsion.THRUST) + + if Dynamic.Vehicle.Propulsion.THRUST_MAX in shp_output_list: + shp_outputs.append( + (Dynamic.Vehicle.Propulsion.THRUST_MAX, + 'turboshaft_thrust_max')) + shp_output_list.remove(Dynamic.Vehicle.Propulsion.THRUST_MAX) + + # Gearbox connections + if has_gearbox: + for var in shp_output_list.copy(): + # Check for case: var is output from shp_model, connects to gearbox, then + # gets updated by gearbox + # RPM has special handling, so skip it here + if var + '_in' in gearbox_input_list and var != Dynamic.Vehicle.Propulsion.RPM: + # if var is in gearbox input and output, connect on shp -> gearbox + # side + if ( + var in gearbox_output_list + or var + '_out' in gearbox_output_list + ): + shp_outputs.append((var, var + '_gearbox')) + shp_output_list.remove(var) + gearbox_inputs.append((var + '_in', var + '_gearbox')) + gearbox_input_list.remove(var + '_in') + # otherwise it gets promoted, which will get done later + + # If fixed RPM is requested by the user, use that value. Override RPM output + # from shaft power model if present, warning user + rpm_ivc = self._get_subsystem('fixed_rpm_source') + + if Aircraft.Engine.FIXED_RPM in self.aviary_inputs: + fixed_rpm = self.aviary_inputs.get_val( + Aircraft.Engine.FIXED_RPM, units='rpm' + ) - outputs = ['*'] - - if Dynamic.Mission.THRUST in [ - output_dict[key]['prom_name'] for key in output_dict - ]: - outputs.append((Dynamic.Mission.THRUST, 'turboshaft_thrust')) - - if Dynamic.Mission.THRUST_MAX in [ - output_dict[key]['prom_name'] for key in output_dict - ]: - outputs.append((Dynamic.Mission.THRUST_MAX, 'turboshaft_thrust_max')) + if Dynamic.Vehicle.Propulsion.RPM in shp_output_list: + if self.aviary_inputs.get_val(Settings.VERBOSITY) >= Verbosity.BRIEF: + warnings.warn( + 'Overriding RPM value outputted by EngineModel' + f'{shp_model.name} with fixed RPM of {fixed_rpm}' + ) + + shp_outputs.append( + (Dynamic.Vehicle.Propulsion.RPM, + 'AUTO_OVERRIDE:' + + Dynamic.Vehicle.Propulsion.RPM)) + shp_output_list.remove(Dynamic.Vehicle.Propulsion.RPM) + + fixed_rpm_nn = np.ones(self.num_nodes) * fixed_rpm + + rpm_ivc.add_output(Dynamic.Vehicle.Propulsion.RPM, fixed_rpm_nn, units='rpm') + if has_gearbox: + self.promotes( + 'fixed_rpm_source', [ + (Dynamic.Vehicle.Propulsion.RPM, 'fixed_rpm')]) + gearbox_inputs.append( + (Dynamic.Vehicle.Propulsion.RPM + '_in', 'fixed_rpm')) + gearbox_input_list.remove(Dynamic.Vehicle.Propulsion.RPM + '_in') + else: + self.promotes('fixed_rpm_source', ['*']) + # models such as motor take RPM as input + if Dynamic.Vehicle.Propulsion.RPM in shp_input_list: + shp_inputs.append((Dynamic.Vehicle.Propulsion.RPM, 'fixed_rpm')) + else: + rpm_ivc.add_output( + 'AUTO_OVERRIDE:' + + Dynamic.Vehicle.Propulsion.RPM, + 1.0, + units='rpm') + if has_gearbox: + if Dynamic.Vehicle.Propulsion.RPM in shp_output_list: + shp_outputs.append( + (Dynamic.Vehicle.Propulsion.RPM, + Dynamic.Vehicle.Propulsion.RPM + '_gearbox')) + shp_output_list.remove(Dynamic.Vehicle.Propulsion.RPM) + gearbox_inputs.append( + (Dynamic.Vehicle.Propulsion.RPM + '_in', + Dynamic.Vehicle.Propulsion.RPM + '_gearbox')) + gearbox_input_list.remove(Dynamic.Vehicle.Propulsion.RPM + '_in') + + # All other shp model outputs that don't interact with gearbox will be promoted + for var in shp_output_list: + shp_outputs.append(var) + + ############################# + # GEARBOX MODEL CONNECTIONS # + ############################# + if has_gearbox: + # Promote all inputs which don't come from shp model (those got connected), + # don't promote ones in skip list + for var in gearbox_input_list.copy(): + if var not in skipped_inputs: + gearbox_inputs.append(var) + # DO NOT promote inputs in skip list - always skip + gearbox_input_list.remove(var) + + # gearbox outputs can always get promoted + for var in propeller_input_list.copy(): + if var in gearbox_output_list and var in propeller_input_list: + gearbox_outputs.append((var, var)) + gearbox_output_list.remove(var) + # connect variables in skip list to propeller + if var in skipped_inputs: + self.connect( + var, + propeller_model.name + '.' + var, + ) + + # alias outputs with 'out' to match with propeller + if var + '_out' in gearbox_output_list and var in propeller_input_list: + gearbox_outputs.append((var + '_out', var)) + gearbox_output_list.remove(var + '_out') + # connect variables in skip list to propeller + if var in skipped_inputs: + self.connect( + var, + propeller_model.name + '.' + var, + ) + + # inputs/outputs that didn't need special handling will get promoted + for var in gearbox_input_list: + gearbox_inputs.append(var) + for var in gearbox_output_list: + gearbox_outputs.append(var) + + ############################### + # PROPELLER MODEL CONNECTIONS # + ############################### + # we will promote all inputs not in skip list + for var in propeller_input_list.copy(): + if var not in skipped_inputs: + propeller_inputs.append(var) + propeller_input_list.remove(var) + + ############## + # PROMOTIONS # + ############## + # bulk promote desired inputs and outputs for each subsystem we have been + # tracking + self.promotes(shp_model.name, inputs=shp_inputs, outputs=shp_outputs) + + if has_gearbox: + self.promotes( + gearbox_model.name, inputs=gearbox_inputs, outputs=gearbox_outputs + ) - self.promotes(shp_model.name, outputs=outputs) + self.promotes( + propeller_model_name, inputs=propeller_inputs, outputs=propeller_outputs + ) diff --git a/aviary/subsystems/propulsion/utils.py b/aviary/subsystems/propulsion/utils.py index 83c3e5f98..5ca421a40 100644 --- a/aviary/subsystems/propulsion/utils.py +++ b/aviary/subsystems/propulsion/utils.py @@ -17,6 +17,7 @@ from aviary.utils.named_values import NamedValues, get_keys, get_items from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.variable_info.variable_meta_data import _MetaData +from aviary.variable_info.enums import GASPEngineType class EngineModelVariables(Enum): @@ -24,21 +25,21 @@ class EngineModelVariables(Enum): Define constants that map to supported variable names in an engine model. """ - MACH = Dynamic.Mission.MACH + MACH = Dynamic.Atmosphere.MACH ALTITUDE = Dynamic.Mission.ALTITUDE - THROTTLE = Dynamic.Mission.THROTTLE - HYBRID_THROTTLE = Dynamic.Mission.HYBRID_THROTTLE - THRUST = Dynamic.Mission.THRUST + THROTTLE = Dynamic.Vehicle.Propulsion.THROTTLE + HYBRID_THROTTLE = Dynamic.Vehicle.Propulsion.HYBRID_THROTTLE + THRUST = Dynamic.Vehicle.Propulsion.THRUST TAILPIPE_THRUST = 'tailpipe_thrust' GROSS_THRUST = 'gross_thrust' - SHAFT_POWER = Dynamic.Mission.SHAFT_POWER + SHAFT_POWER = Dynamic.Vehicle.Propulsion.SHAFT_POWER SHAFT_POWER_CORRECTED = 'shaft_power_corrected' RAM_DRAG = 'ram_drag' - FUEL_FLOW = Dynamic.Mission.FUEL_FLOW_RATE - ELECTRIC_POWER_IN = Dynamic.Mission.ELECTRIC_POWER_IN - NOX_RATE = Dynamic.Mission.NOX_RATE - TEMPERATURE_T4 = Dynamic.Mission.TEMPERATURE_T4 - TORQUE = Dynamic.Mission.TORQUE + FUEL_FLOW = Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE + ELECTRIC_POWER_IN = Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN + NOX_RATE = Dynamic.Vehicle.Propulsion.NOX_RATE + TEMPERATURE_T4 = Dynamic.Vehicle.Propulsion.TEMPERATURE_T4 + TORQUE = Dynamic.Vehicle.Propulsion.TORQUE # EXIT_AREA = auto() @@ -63,8 +64,8 @@ class EngineModelVariables(Enum): # variables that have an accompanying max value max_variables = { - EngineModelVariables.THRUST: Dynamic.Mission.THRUST_MAX, - EngineModelVariables.SHAFT_POWER: Dynamic.Mission.SHAFT_POWER_MAX, + EngineModelVariables.THRUST: Dynamic.Vehicle.Propulsion.THRUST_MAX, + EngineModelVariables.SHAFT_POWER: Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX, } @@ -173,7 +174,7 @@ def build_engine_deck(aviary_options: AviaryValues, meta_data=_MetaData): if val_dim > expected_dim + 1: UserWarning( f'Provided vector for {var} has too many dimensions: ' - 'expecting a {expected_dim+1}D array ({expected_dim}D ' + f'expecting a {expected_dim+1}D array ({expected_dim}D ' 'per engine)' ) # if neither metadata nor aviary_val are numpy arrays, cannot check dimensions @@ -202,6 +203,7 @@ def build_engine_deck(aviary_options: AviaryValues, meta_data=_MetaData): except (KeyError, TypeError): continue + # name engine deck after filename # local import to avoid circular import from aviary.subsystems.propulsion.engine_deck import EngineDeck @@ -376,8 +378,8 @@ def setup(self): has_diag_partials=True, ), promotes_inputs=[ - ('P0', Dynamic.Mission.STATIC_PRESSURE), - ('mach', Dynamic.Mission.MACH), + ('P0', Dynamic.Atmosphere.STATIC_PRESSURE), + ('mach', Dynamic.Atmosphere.MACH), ], promotes_outputs=['delta_T'], ) @@ -396,8 +398,8 @@ def setup(self): has_diag_partials=True, ), promotes_inputs=[ - ('T0', Dynamic.Mission.TEMPERATURE), - ('mach', Dynamic.Mission.MACH), + ('T0', Dynamic.Atmosphere.TEMPERATURE), + ('mach', Dynamic.Atmosphere.MACH), ], promotes_outputs=['theta_T'], ) @@ -405,7 +407,7 @@ def setup(self): self.add_subsystem( 'uncorrection', om.ExecComp( - 'uncorrected_data = corrected_data * (delta_T + theta_T**.5)', + 'uncorrected_data = corrected_data * (delta_T * theta_T**.5)', uncorrected_data={'units': "hp", 'shape': num_nodes}, delta_T={'units': "unitless", 'shape': num_nodes}, theta_T={'units': "unitless", 'shape': num_nodes}, diff --git a/aviary/subsystems/subsystem_builder_base.py b/aviary/subsystems/subsystem_builder_base.py index 9eab4a7fa..9d4fa20fb 100644 --- a/aviary/subsystems/subsystem_builder_base.py +++ b/aviary/subsystems/subsystem_builder_base.py @@ -30,6 +30,14 @@ def __init__(self, name=None, meta_data=None): meta_data = _MetaData self.meta_data = meta_data + def needs_mission_solver(self, aviary_inputs): + """ + Return True if the mission subsystem needs to be in the solver loop in mission, otherwise + return False. Aviary will only place it in the solver loop when True. The default is + True. + """ + return True + def build_pre_mission(self, aviary_inputs, **kwargs): """ Build an OpenMDAO System for the pre-mission computations of the subsystem. diff --git a/aviary/subsystems/test/subsystem_tester.py b/aviary/subsystems/test/subsystem_tester.py index 771ceb003..636a7685f 100644 --- a/aviary/subsystems/test/subsystem_tester.py +++ b/aviary/subsystems/test/subsystem_tester.py @@ -7,6 +7,7 @@ from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.functions import setup_model_options def skipIfMissingDependencies(builder): @@ -249,6 +250,9 @@ def test_check_state_variables(self): group = om.Group() group.add_subsystem('mission', mission_sys, promotes=['*']) prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.setup() prob.final_setup() @@ -273,6 +277,9 @@ def test_check_pre_mission(self): group = om.Group() group.add_subsystem('pre_mission_sys', pre_mission_sys) prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.setup() prob.final_setup() @@ -305,6 +312,9 @@ def test_check_parameters(self): group = om.Group() group.add_subsystem('mission', mission_sys, promotes=['*']) prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.setup() prob.final_setup() @@ -330,6 +340,9 @@ def test_check_constraints(self): group = om.Group() group.add_subsystem('mission', mission_sys, promotes=['*']) prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.setup() prob.final_setup() @@ -359,6 +372,9 @@ def test_check_design_variables(self): group = om.Group() group.add_subsystem('pre_mission', pre_mission_sys, promotes=['*']) prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.setup() prob.final_setup() @@ -385,6 +401,9 @@ def test_check_initial_guesses(self): group = om.Group() group.add_subsystem('mission', mission_sys, promotes=['*']) prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.setup() prob.final_setup() diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index 7d8934b44..0650564f9 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -5,15 +5,17 @@ from openmdao.utils.assert_utils import assert_near_equal, assert_check_partials from aviary.subsystems.premission import CorePreMission +from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.aviary_values import AviaryValues from aviary.utils.functions import set_aviary_initial_values +from aviary.utils.preprocessors import preprocess_options +from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems from aviary.validation_cases.validation_tests import ( flops_validation_test, get_flops_inputs, get_flops_outputs, get_flops_case_names, print_case ) + +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Mission, Settings -from aviary.subsystems.propulsion.utils import build_engine_deck -from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems -from aviary.utils.preprocessors import preprocess_options class PreMissionGroupTest(unittest.TestCase): @@ -45,6 +47,8 @@ def test_case(self, case_name): promotes_outputs=['*'], ) + setup_model_options(prob, flops_inputs) + prob.setup(check=False, force_alloc_complex=True) prob.set_solver_print(2) @@ -104,6 +108,8 @@ def test_diff_configuration_mass(self): promotes_outputs=['*'], ) + setup_model_options(prob, flops_inputs) + prob.setup(check=False) set_aviary_initial_values(prob, flops_inputs) diff --git a/aviary/subsystems/test/test_premission.py b/aviary/subsystems/test/test_premission.py index 4ed926b35..cd5b678f5 100644 --- a/aviary/subsystems/test/test_premission.py +++ b/aviary/subsystems/test/test_premission.py @@ -16,7 +16,9 @@ from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData from aviary.models.large_single_aisle_1.V3_bug_fixed_IO import V3_bug_fixed_options, V3_bug_fixed_non_metadata from aviary.utils.functions import set_aviary_initial_values +from aviary.utils.preprocessors import preprocess_options from aviary.variable_info.enums import LegacyCode +from aviary.variable_info.functions import setup_model_options from aviary.subsystems.propulsion.utils import build_engine_deck @@ -104,6 +106,8 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=1.0, units='ft') + setup_model_options(self.prob, input_options) + self.prob.setup(check=False, force_alloc_complex=True) self.prob.set_solver_print(2) @@ -274,6 +278,7 @@ def test_manual_override(self): aviary_inputs.delete(Aircraft.Fuselage.WETTED_AREA) engine = build_engine_deck(aviary_inputs) + preprocess_options(aviary_inputs, engine_models=engine) prob = om.Problem() model = prob.model @@ -310,6 +315,8 @@ def test_manual_override(self): for (key, (val, units)) in get_items(V3_bug_fixed_non_metadata): prob.model.set_input_defaults(key, val=val, units=units) + setup_model_options(prob, aviary_inputs) + prob.setup() # Problem in setup is FLOPS prioritized, so shared inputs for FLOPS will be manually overriden. diff --git a/aviary/utils/aviary_values.py b/aviary/utils/aviary_values.py index 23736a4ca..e0d559592 100644 --- a/aviary/utils/aviary_values.py +++ b/aviary/utils/aviary_values.py @@ -58,16 +58,21 @@ def set_val(self, key, val, units='unitless', meta_data=_MetaData): # Special handling to access an Enum member from either the member name or its value. my_val = val if key in _MetaData.keys(): + expected_types = _MetaData[key]['types'] - if type(expected_types) is EnumMeta: - if self._is_iterable(val): - my_val = [self._convert_to_enum( - item, expected_types) for item in val] - else: - my_val = self._convert_to_enum(val, expected_types) - - # Special handling if the variable is supposed to be an array - if key in _MetaData.keys(): + if not isinstance(expected_types, tuple): + expected_types = (expected_types, ) + + for _type in expected_types: + if type(_type) is EnumMeta: + if self._is_iterable(val): + my_val = [self._convert_to_enum( + item, _type) for item in val] + else: + my_val = self._convert_to_enum(val, _type) + break + + # Special handling if the variable is supposed to be an array default_value = _MetaData[key]['default_value'] # if the item is supposed to be an iterable... if self._is_iterable(default_value): @@ -79,61 +84,64 @@ def set_val(self, key, val, units='unitless', meta_data=_MetaData): else: my_val = np.array([my_val], dtype=type(default_value[0])) - self._check_type(key, my_val, meta_data=meta_data) - self._check_units_compatability(key, my_val, units, meta_data=meta_data) + self._check_type(key, my_val, meta_data=meta_data) + self._check_units_compatability(key, my_val, units, meta_data=meta_data) super().set_val(key=key, val=my_val, units=units) def _check_type(self, key, val, meta_data=_MetaData): - if key in meta_data.keys(): - expected_types = meta_data[key]['types'] - if expected_types is not None: - if self._is_iterable(expected_types): - expected_types = tuple(expected_types) - # if val is not iterable, add it to a list (length 1), checks assume - # val is iterable - if not self._is_iterable(val): - val = [val] - # numpy arrays have special typings. Extract item of equivalent built-in python type - # numpy arrays do not allow mixed types, only have to check first entry - # empty arrays do not need this check - if isinstance(val, np.ndarray) and len(val) > 0: - # NoneType numpy arrays do not need to be "converted" to built-in python types - if val.dtype == type(None): - val = [val[0]] - else: - # item() gets us native Python equivalent object (i.e. int vs. numpy.int64) - # wrap first index in np array to ensures works on any dtype - val = [np.array(val[0]).item()] - for item in val: - has_bool = False # needs some fancy shenanigans because bools will register as ints - if (isinstance(expected_types, type)): - if expected_types is bool: - has_bool = True - elif bool in expected_types: - has_bool = True - if (not isinstance(item, expected_types)) or ( - (has_bool == False) and (isinstance(item, bool))): - raise TypeError( - f'{key} is of type(s) {meta_data[key]["types"]} but you ' - f'have provided a value of type {type(item)}.') - def _check_units_compatability(self, key, val, units, meta_data=_MetaData): - if key in meta_data.keys(): - expected_units = meta_data[key]['units'] - - try: - # NOTE the value here is unimportant, we only care if OpenMDAO will - # convert the units - _convert_units(10, expected_units, units) - except ValueError: - raise ValueError( - f'The units {units} which you have provided for {key} are invalid.') - except TypeError: + expected_types = meta_data[key]['types'] + if expected_types is None: + # MetaData item has no type requirement. + return + + if self._is_iterable(expected_types): + expected_types = tuple(expected_types) + + # if val is not iterable, add it to a list (length 1), checks assume + # val is iterable + if not self._is_iterable(val): + val = [val] + # numpy arrays have special typings. Extract item of equivalent built-in python type + # numpy arrays do not allow mixed types, only have to check first entry + # empty arrays do not need this check + if isinstance(val, np.ndarray) and len(val) > 0: + # NoneType numpy arrays do not need to be "converted" to built-in python types + if val.dtype == type(None): + val = [val[0]] + else: + # item() gets us native Python equivalent object (i.e. int vs. numpy.int64) + # wrap first index in np array to ensures works on any dtype + val = [np.array(val[0]).item()] + for item in val: + has_bool = False # needs some fancy shenanigans because bools will register as ints + if (isinstance(expected_types, type)): + if expected_types is bool: + has_bool = True + elif bool in expected_types: + has_bool = True + if (not isinstance(item, expected_types)) or ( + (has_bool == False) and (isinstance(item, bool))): raise TypeError( - f'The base units of {key} are {expected_units}, and you have tried to set {key} with units of {units}, which are not compatible.') - except BaseException: - raise KeyError('There is an unknown error with your units.') + f'{key} is of type(s) {meta_data[key]["types"]} but you ' + f'have provided a value of type {type(item)}.') + + def _check_units_compatability(self, key, val, units, meta_data=_MetaData): + expected_units = meta_data[key]['units'] + + try: + # NOTE the value here is unimportant, we only care if OpenMDAO will + # convert the units + _convert_units(10, expected_units, units) + except ValueError: + raise ValueError( + f'The units {units} which you have provided for {key} are invalid.') + except TypeError: + raise TypeError( + f'The base units of {key} are {expected_units}, and you have tried to set {key} with units of {units}, which are not compatible.') + except BaseException: + raise KeyError('There is an unknown error with your units.') def _is_iterable(self, val): return isinstance(val, _valid_iterables) diff --git a/aviary/utils/conflict_checks.py b/aviary/utils/conflict_checks.py index fd79461ed..0fafa70a2 100644 --- a/aviary/utils/conflict_checks.py +++ b/aviary/utils/conflict_checks.py @@ -3,13 +3,10 @@ from aviary.variable_info.variables import Aircraft -def check_fold_location_definition(inputs, options: AviaryValues): +def check_fold_location_definition(choose_fold_location, has_strut): """ If there is no strut, then CHOOSE_FOLD_LOCATION must be true. """ - choose_fold_location = options.get_val( - Aircraft.Wing.CHOOSE_FOLD_LOCATION, units='unitless') - has_strut = options.get_val(Aircraft.Wing.HAS_STRUT, units='unitless') if not choose_fold_location and not has_strut: raise RuntimeError( "The option CHOOSE_FOLD_LOCATION can only be False if the option HAS_STRUT is True.") diff --git a/aviary/utils/develop_metadata.py b/aviary/utils/develop_metadata.py index 4950a2d60..c7f2e0e45 100644 --- a/aviary/utils/develop_metadata.py +++ b/aviary/utils/develop_metadata.py @@ -6,6 +6,7 @@ def add_meta_data( default_value=0.0, option=False, types=None, + multivalue=False, historical_name=None, _check_unique=True): ''' @@ -36,7 +37,11 @@ def add_meta_data( indicates that this variable is an option, rather than a normal input types : type - gives the allowable type(s) of the variable + gives the allowable type(s) of the variable in the aviary API. + + multivalue : bool + when True, the variable can become a list of elements whose type is in types. + This is mainly used when there are multiple engine types. historical_name : dict or None dictionary of names that the variable held in prior codes @@ -67,7 +72,7 @@ def add_meta_data( of the provided key. This should only be set to false when update_meta_data is the calling function. Returns - ------- + ------- None No variables returned by this method. @@ -90,7 +95,8 @@ def add_meta_data( 'desc': desc, 'option': option, 'default_value': default_value, - 'types': types + 'types': types, + 'multivalue': multivalue, } @@ -102,6 +108,7 @@ def update_meta_data( default_value=0.0, option=False, types=None, + multivalue=False, historical_name=None): ''' Update existing meta data associated with variables in the Aviary data hierarchy. @@ -133,6 +140,10 @@ def update_meta_data( types : type gives the allowable type(s) of the variable + multivalue : bool + when True, the variable can become a list of elements whose type is in types. + This is mainly used when there are multiple engine types. + historical_name : dict or None dictionary of names that the variable held in prior codes @@ -158,7 +169,7 @@ def update_meta_data( represents the GWTOL variable of the ANALYS subroutine Returns - ------- + ------- None No variables returned by this method. @@ -173,4 +184,6 @@ def update_meta_data( f'You provided the variable {key} to a variable metadata dictionary via the update_meta_data function, but {key} does not exist in the dictionary. If you are sure you want to add this variable to the dictionary, call the add_meta_data function instead.') add_meta_data(key=key, meta_data=meta_data, units=units, desc=desc, - default_value=default_value, option=option, types=types, historical_name=historical_name, _check_unique=False) + default_value=default_value, option=option, types=types, + multivalue=multivalue, historical_name=historical_name, + _check_unique=False) diff --git a/aviary/docs/tests/utils.py b/aviary/utils/doctape.py similarity index 70% rename from aviary/docs/tests/utils.py rename to aviary/utils/doctape.py index 0a8646d86..149469570 100644 --- a/aviary/docs/tests/utils.py +++ b/aviary/utils/doctape.py @@ -3,8 +3,6 @@ import tempfile import os import numpy as np -from myst_nb import glue -from IPython.display import Markdown """ @@ -44,24 +42,80 @@ def gramatical_list(list_of_strings: list, cc='and', add_accents=False) -> str: ---------- list_of_strings : list A list of strings (or elements with a string representation) - cc : str - The coordinating conjunction to use with the list + cc : str, optional + The coordinating conjunction to use with the list (default is `and`) + add_accents : bool, optional + Whether or not to wrap each element with ` characters (default is False) Returns ------- str A string that combines the elements of the list into a string with proper punctuation """ - list_of_strings = ['`'+s+'`' if add_accents else s for s in list_of_strings] + list_of_strings = ['`'+str(s)+'`' if add_accents else str(s) + for s in list_of_strings] if len(list_of_strings) == 1: - return str(list_of_strings[0]) + return list_of_strings[0] elif len(list_of_strings) == 2: - return str(list_of_strings[0])+' '+cc+' '+str(list_of_strings[1]) + return list_of_strings[0]+' '+cc+' '+list_of_strings[1] else: - return ', '.join([str(s) for s in list_of_strings[:-1]]+[cc+' '+str(list_of_strings[-1])]) + return ', '.join(list_of_strings[:-1]+[cc+' '+list_of_strings[-1]]) -def check_value(val1, val2): +def get_previous_line(n=1) -> str: + """ + returns the previous n line(s) of code as a string + + Parameters + ---------- + n : int + The number of lines to return (default is 1) + + Returns + ------- + str + A string that contains the previous line of code or a + list that contains the previous n lines of code + """ + pframe = inspect.currentframe().f_back # get the previous frame that called this function + # get the lines of code as a list of strings + lines, first_line = inspect.getsourcelines(pframe) + # get the line number of the line that called this function + lineno = pframe.f_lineno - first_line if first_line else pframe.f_lineno - 1 + # get the previous lines + return lines[lineno-n:lineno] if n > 1 else lines[lineno-1].strip() + + +def get_variable_name(*variables) -> str: + """ + returns the name of the variable passed to the function as a string + + Parameters + ---------- + variables : any + The variable(s) of interest + + Returns + ------- + str + A string that contains the name of variable passed to this function + (or list of strings, if multiple arguments are passed) + """ + pframe = inspect.currentframe().f_back # get the previous frame that called this function + # get the lines of code as a list of strings + lines, first_line = inspect.getsourcelines(pframe) + # get the line number that called this function + lineno = pframe.f_lineno - first_line if first_line else pframe.f_lineno - 1 + # extract the argument and remove all whitespace + arg: str = ''.join(lines[lineno].split( + 'get_variable_name(')[1].split(')')[0].split()) + if ',' in arg: + return arg.split(',') + else: + return arg + + +def check_value(val1, val2, error_type=ValueError): """ Compares two values and raises a ValueError if they are not equal. @@ -75,18 +129,20 @@ def check_value(val1, val2): The first value to be compared. val2 : any The second value to be compared. + error_type : Exception, optional + The exception to raise (default is ValueError) Raises ------ ValueError If the values are not equal (or not the same object for non-primitive types). """ - if isinstance(val1, (str, int, float, list, tuple, dict, set, np.ndarray)): + if isinstance(val1, (str, int, float, list, tuple, dict, set, np.ndarray, type({}.keys()))): if val1 != val2: - raise ValueError(f"{val1} is not equal to {val2}") + raise error_type(f"{val1} is not equal to {val2}") else: if val1 is not val2: - raise ValueError(f"{val1} is not {val2}") + raise error_type(f"{val1} is not {val2}") def check_contains(expected_values, actual_values, error_string="{var} not in {actual_values}", error_type=RuntimeError): @@ -99,10 +155,10 @@ def check_contains(expected_values, actual_values, error_string="{var} not in {a expected_values : any iterable This can also be a single value, in which case it will be wrapped into a list actual_values : any iterable - error_string : str + error_string : str, optional The string to display as the error message, kwarg substitutions will be made using .format() for "var" and "actual_values" - error_type : Exception + error_type : Exception, optional The exception to raise (default is RuntimeError) Raises @@ -118,7 +174,7 @@ def check_contains(expected_values, actual_values, error_string="{var} not in {a raise error_type(error_string.format(var=var, actual_values=actual_values)) -def check_args(func, expected_args: tuple[list, dict, str], args_to_ignore: tuple[list, tuple] = ['self'], exact=True): +def check_args(func, expected_args: tuple[list, dict, str], args_to_ignore: tuple[list, tuple] = ['self'], exact=True, error_type=ValueError): """ Checks that the expected arguments are valid for a given function. @@ -138,6 +194,8 @@ def check_args(func, expected_args: tuple[list, dict, str], args_to_ignore: tupl Arguments to ignore during the check (default is ['self']). exact : bool, optional Whether to check for an exact match of arguments (default is True). + error_type : Exception, optional + The exception to raise (default is ValueError) Raises ------ @@ -158,13 +216,13 @@ def check_args(func, expected_args: tuple[list, dict, str], args_to_ignore: tupl else: for arg in expected_args: if arg not in available_args: - raise ValueError(f'{arg} is not a valid argument for {func.__name__}') + raise error_type(f'{arg} is not a valid argument for {func.__name__}') elif isinstance(expected_args, dict) and expected_args[arg] != available_args[arg]: - raise ValueError( + raise error_type( f"the default value of {arg} is {available_args[arg]}, not {expected_args[arg]}") -def run_command_no_file_error(command: str): +def run_command_no_file_error(command: str, verbose=False): """ Executes a CLI command and handles FileNotFoundError separately. @@ -177,6 +235,8 @@ def run_command_no_file_error(command: str): ---------- command : str The CLI command to be executed. + verbose : bool + Whether or not to include the error message if FileNotFoundError is raised Raises ------ @@ -184,18 +244,20 @@ def run_command_no_file_error(command: str): If the command returns a non-zero exit code (except for FileNotFoundError). """ with tempfile.TemporaryDirectory() as tempdir: - os.chdir(tempdir) - rc = subprocess.run(command.split(), capture_output=True, text=True) + rc = subprocess.run(command.split(), cwd=tempdir, capture_output=True, text=True) if rc.returncode: - err = rc.stderr.split('\n')[-2].split(':')[0] + err, info = rc.stderr.split('\n')[-2].split(':', 1) if err == 'FileNotFoundError': - print(err) + if verbose: + print(info) + print( + f"A file required by {command} couldn't be found, continuing anyway") else: print(rc.stderr) rc.check_returncode() -def get_attribute_name(object: object, attribute) -> str: +def get_attribute_name(object: object, attribute, error_type=AttributeError) -> str: """ Gets the name of an object's attribute based on it's value @@ -209,6 +271,8 @@ def get_attribute_name(object: object, attribute) -> str: The object whose attributes will be searched attribute : any The value of interest + error_type : Exception, optional + The exception to raise (default is AttributeError) Returns ------- @@ -224,11 +288,11 @@ def get_attribute_name(object: object, attribute) -> str: if val == attribute: return name - raise AttributeError( + raise error_type( f"`{object.__name__}` object has no attribute with a value of `{attribute}`") -def get_all_keys(dict_of_dicts: dict, track_layers=False, all_keys=None): +def get_all_keys(dict_of_dicts: dict, track_layers=False, all_keys=None) -> list: """ Recursively get all of the keys from a dict of dicts Note: this will not add duplicates of keys, but will @@ -237,7 +301,7 @@ def get_all_keys(dict_of_dicts: dict, track_layers=False, all_keys=None): Parameters ---------- dict_of_dicts : dict - The dictionary who's keys will are to be gathered + The dictionary who's keys will be gathered track_layers : Bool Whether or not to track where keys inside the dict of dicts came from. This will get every key, by ensuring that all keys @@ -296,6 +360,11 @@ def glue_variable(name: str, val=None, md_code=False, display=True): """ Glue a variable for later use in markdown cells of notebooks + Note: + glue_variable(get_variable_name(Aircraft.APU.MASS)) + can be used to glue the name of the variable (Aircraft.APU.MASS) + not the value of the variable ('aircraft:apu:mass') + Parameters ---------- name : str @@ -305,14 +374,19 @@ def glue_variable(name: str, val=None, md_code=False, display=True): md_code : Bool Whether to wrap the value in markdown code formatting (e.g. `code`) """ + # local import so myst isn't required unless glue is being used + from myst_nb import glue + from IPython.display import Markdown if val is None: val = name if md_code: val = Markdown('`'+val+'`') + else: + val = Markdown(val) glue(name, val, display) -def glue_keys(dict_of_dicts: dict, display=True): +def glue_keys(dict_of_dicts: dict, display=True) -> list: """ Recursively glue all of the keys from a dict of dicts diff --git a/aviary/utils/engine_deck_conversion.py b/aviary/utils/engine_deck_conversion.py index 16025095f..80d296103 100644 --- a/aviary/utils/engine_deck_conversion.py +++ b/aviary/utils/engine_deck_conversion.py @@ -214,34 +214,32 @@ def EngineDeckConverter(input_file, output_file, data_format: EngineDeckType): promotes=['*']) prob.model.add_subsystem( - Dynamic.Mission.MACH, - om.IndepVarComp( - Dynamic.Mission.MACH, - data[MACH], - units='unitless'), - promotes=['*']) + Dynamic.Atmosphere.MACH, + om.IndepVarComp(Dynamic.Atmosphere.MACH, data[MACH], units='unitless'), + promotes=['*'], + ) prob.model.add_subsystem( Dynamic.Mission.ALTITUDE, - om.IndepVarComp( - Dynamic.Mission.ALTITUDE, - data[ALTITUDE], - units='ft'), - promotes=['*']) + om.IndepVarComp(Dynamic.Mission.ALTITUDE, data[ALTITUDE], units='ft'), + promotes=['*'], + ) prob.model.add_subsystem( name='atmosphere', subsys=Atmosphere(num_nodes=len(data[MACH])), promotes_inputs=[Dynamic.Mission.ALTITUDE], - promotes_outputs=[Dynamic.Mission.TEMPERATURE], + promotes_outputs=[Dynamic.Atmosphere.TEMPERATURE], ) prob.model.add_subsystem( name='conversion', subsys=AtmosCalc(num_nodes=len(data[MACH])), - promotes_inputs=[Dynamic.Mission.MACH, - Dynamic.Mission.TEMPERATURE], - promotes_outputs=['t2'] + promotes_inputs=[ + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.TEMPERATURE, + ], + promotes_outputs=['t2'], ) prob.setup() @@ -254,28 +252,32 @@ def EngineDeckConverter(input_file, output_file, data_format: EngineDeckType): # By always keeping minimum T4 zero for normalization, throttle stays # consistent with fraction of T4max # TODO flight condition dependent throttle range? - # NOTE this often leaves max throttles less than 1 in the deck - this caues + # NOTE this often leaves max throttles less than 1 in the deck - this causes # problems when finding reference SLS thrust, as there is often no max - # power data at that point in the engine deck. It is reccomended GASP + # power data at that point in the engine deck. It is recommended GASP # engine decks override Aircraft.Engine.REFERENCE_THRUST in EngineDecks data[THROTTLE] = normalize(data[TEMPERATURE], minimum=0.0, maximum=t4max) - # remove all points above T4max - # TODO save these points as commented out? - valid_idx = np.where(data[THROTTLE] <= 1.0) - data[MACH] = data[MACH][valid_idx] - data[ALTITUDE] = data[ALTITUDE][valid_idx] - data[THROTTLE] = data[THROTTLE][valid_idx] - data[FUEL_FLOW] = data[FUEL_FLOW][valid_idx] + else: + # data[THROTTLE] = normalize( + # T4T2, minimum=scalars['t4flight_idle'], maximum=t4max + # ) + data[THROTTLE] = normalize(T4T2, minimum=0.0, maximum=t4max) + + # TODO save these points as commented out? + # remove points above T4max + valid_idx = np.where(data[THROTTLE] <= 1.0) + data[MACH] = data[MACH][valid_idx] + data[ALTITUDE] = data[ALTITUDE][valid_idx] + data[THROTTLE] = data[THROTTLE][valid_idx] + data[FUEL_FLOW] = data[FUEL_FLOW][valid_idx] + if compute_T4: data[TEMPERATURE] = data[TEMPERATURE][valid_idx] - if is_turbo_prop: - data[SHAFT_POWER_CORRECTED] = data[SHAFT_POWER_CORRECTED][valid_idx] - data[TAILPIPE_THRUST] = data[TAILPIPE_THRUST][valid_idx] - else: - data[THRUST] = data[THRUST][valid_idx] - + if is_turbo_prop: + data[SHAFT_POWER_CORRECTED] = data[SHAFT_POWER_CORRECTED][valid_idx] + data[TAILPIPE_THRUST] = data[TAILPIPE_THRUST][valid_idx] else: - data[THROTTLE] = T4T2 + data[THRUST] = data[THRUST][valid_idx] # data needs to be string so column length can be easily found later for var in data: @@ -540,39 +542,37 @@ def _generate_flight_idle(data, T4T2, ref_sls_airflow, ref_sfn_idle): prob = om.Problem() prob.model.add_subsystem( - Dynamic.Mission.MACH, - om.IndepVarComp( - Dynamic.Mission.MACH, - mach_list, - units='unitless'), - promotes=['*']) + Dynamic.Atmosphere.MACH, + om.IndepVarComp(Dynamic.Atmosphere.MACH, mach_list, units='unitless'), + promotes=['*'], + ) prob.model.add_subsystem( Dynamic.Mission.ALTITUDE, - om.IndepVarComp( - Dynamic.Mission.ALTITUDE, - alt_list, - units='ft'), - promotes=['*']) + om.IndepVarComp(Dynamic.Mission.ALTITUDE, alt_list, units='ft'), + promotes=['*'], + ) prob.model.add_subsystem( name='atmosphere', subsys=Atmosphere(num_nodes=nn), promotes_inputs=[Dynamic.Mission.ALTITUDE], - promotes_outputs=[Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE], + promotes_outputs=[ + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, + ], ) prob.model.add_subsystem( name='conversion', - subsys=AtmosCalc( - num_nodes=nn), + subsys=AtmosCalc(num_nodes=nn), promotes_inputs=[ - Dynamic.Mission.MACH, - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.STATIC_PRESSURE], - promotes_outputs=[ - 't2', - 'p2']) + Dynamic.Atmosphere.MACH, + Dynamic.Atmosphere.TEMPERATURE, + Dynamic.Atmosphere.STATIC_PRESSURE, + ], + promotes_outputs=['t2', 'p2'], + ) prob.model.add_subsystem( name='flight_idle', @@ -685,12 +685,16 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - self.add_input(Dynamic.Mission.MACH, val=np.zeros(nn), - desc='current Mach number', units='unitless') - self.add_input(Dynamic.Mission.TEMPERATURE, val=np.zeros(nn), + self.add_input( + Dynamic.Atmosphere.MACH, + val=np.zeros(nn), + desc='current Mach number', + units='unitless', + ) + self.add_input(Dynamic.Atmosphere.TEMPERATURE, val=np.zeros(nn), desc='current atmospheric temperature', units='degR') self.add_input( - Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Atmosphere.STATIC_PRESSURE, _PSLS_PSF, units="psf", shape=nn, diff --git a/aviary/utils/fortran_to_aviary.py b/aviary/utils/fortran_to_aviary.py index 11fdcc240..b783f7224 100644 --- a/aviary/utils/fortran_to_aviary.py +++ b/aviary/utils/fortran_to_aviary.py @@ -30,14 +30,23 @@ from aviary.variable_info.variables import Aircraft, Mission, Settings from aviary.variable_info.enums import LegacyCode, Verbosity, ProblemType from aviary.utils.functions import get_path -from aviary.utils.legacy_code_data.deprecated_vars import flops_deprecated_vars, gasp_deprecated_vars +from aviary.utils.legacy_code_data.deprecated_vars import ( + flops_deprecated_vars, + gasp_deprecated_vars, +) FLOPS = LegacyCode.FLOPS GASP = LegacyCode.GASP -def create_aviary_deck(fortran_deck: str, legacy_code=None, defaults_deck=None, - out_file=None, force=False, verbosity=Verbosity.BRIEF): +def create_aviary_deck( + fortran_deck: str, + legacy_code=None, + defaults_deck=None, + out_file=None, + force=False, + verbosity=Verbosity.BRIEF, +): ''' Create an Aviary CSV file from a Fortran input deck Required input is the filepath to the input deck and legacy code. Optionally, a @@ -51,8 +60,12 @@ def create_aviary_deck(fortran_deck: str, legacy_code=None, defaults_deck=None, # TODO generate both an Aviary input file and a phase_info file - vehicle_data = {'input_values': NamedValues(), 'unused_values': NamedValues(), - 'initialization_guesses': initialization_guesses, 'verbosity': verbosity} + vehicle_data = { + 'input_values': NamedValues(), + 'unused_values': NamedValues(), + 'initialization_guesses': initialization_guesses, + 'verbosity': verbosity, + } fortran_deck: Path = get_path(fortran_deck, verbose=False) @@ -80,32 +93,47 @@ def create_aviary_deck(fortran_deck: str, legacy_code=None, defaults_deck=None, deprecated_vars = flops_deprecated_vars if not defaults_deck: - defaults_filename = legacy_code.value.lower() + '_default_values' + default_extension - defaults_deck = Path(__file__).parent.resolve().joinpath( - 'legacy_code_data', defaults_filename) + defaults_filename = ( + legacy_code.value.lower() + '_default_values' + default_extension + ) + defaults_deck = ( + Path(__file__) + .parent.resolve() + .joinpath('legacy_code_data', defaults_filename) + ) # create dictionary to convert legacy code variables to Aviary variables # key: variable name, value: either None or relevant historical_name aviary_variable_dict = generate_aviary_names([legacy_code.value]) if defaults_deck: # If defaults are specified, initialize the vehicle with them - vehicle_data = input_parser(defaults_deck, vehicle_data, - aviary_variable_dict, deprecated_vars, legacy_code) - - vehicle_data = input_parser(fortran_deck, vehicle_data, - aviary_variable_dict, deprecated_vars, legacy_code) + vehicle_data = input_parser( + defaults_deck, + vehicle_data, + aviary_variable_dict, + deprecated_vars, + legacy_code, + ) + + vehicle_data = input_parser( + fortran_deck, vehicle_data, aviary_variable_dict, deprecated_vars, legacy_code + ) if legacy_code is GASP: vehicle_data = update_gasp_options(vehicle_data) elif legacy_code is FLOPS: vehicle_data = update_flops_options(vehicle_data) + vehicle_data = update_aviary_options(vehicle_data) - if not out_file.is_file(): # default outputted file to be in same directory as input + if ( + not out_file.is_file() + ): # default outputted file to be in same directory as input out_file = fortran_deck.parent / out_file if out_file.is_file(): if not force: - raise RuntimeError(f'{out_file} already exists. Choose a new name or enable ' - '--force') + raise RuntimeError( + f'{out_file} already exists. Choose a new name or enable ' '--force' + ) elif verbosity >= Verbosity.BRIEF: print(f'Overwriting existing file: {out_file.name}') @@ -191,12 +219,22 @@ def input_parser(fortran_deck, vehicle_data, alternate_names, unused_vars, legac data = line.split('=')[1] try: vehicle_data = process_and_store_data( - data, var_name, legacy_code, current_namelist, alternate_names, vehicle_data, unused_vars, comment) + data, + var_name, + legacy_code, + current_namelist, + alternate_names, + vehicle_data, + unused_vars, + comment, + ) except Exception as err: if current_namelist == '': - raise RuntimeError(line + ' could not be parsed successfully.' - '\nIf this was intended as a comment, ' - 'add an "!" at the beginning of the line.') from err + raise RuntimeError( + line + ' could not be parsed successfully.' + '\nIf this was intended as a comment, ' + 'add an "!" at the beginning of the line.' + ) from err else: raise err elif number_of_variables > 1: @@ -205,24 +243,36 @@ def input_parser(fortran_deck, vehicle_data, alternate_names, unused_vars, legac for ii in range(number_of_variables): # Each of the following elements contains all of the data for the current variable # and the last element is the name of the next variable - sub_list = sub_line[ii+1].split(',') - if ii+1 < number_of_variables: + sub_list = sub_line[ii + 1].split(',') + if ii + 1 < number_of_variables: next_var_name = sub_list.pop() if not next_var_name[0].isalpha(): - index = next((i for i, c in enumerate( - next_var_name) if c.isalpha()), len(next_var_name)) + index = next( + (i for i, c in enumerate(next_var_name) if c.isalpha()), + len(next_var_name), + ) sub_list.append(next_var_name[:index]) next_var_name = next_var_name[index:] data = ','.join(sub_list) try: vehicle_data = process_and_store_data( - data, var_name, legacy_code, current_namelist, alternate_names, vehicle_data, unused_vars, comment) + data, + var_name, + legacy_code, + current_namelist, + alternate_names, + vehicle_data, + unused_vars, + comment, + ) except Exception as err: if current_namelist == '': - raise RuntimeError(line + ' could not be parsed successfully.' - '\nIf this was intended as a comment, ' - 'add an "!" at the beginning of the line.') from err + raise RuntimeError( + line + ' could not be parsed successfully.' + '\nIf this was intended as a comment, ' + 'add an "!" at the beginning of the line.' + ) from err else: raise err var_name = next_var_name @@ -233,7 +283,16 @@ def input_parser(fortran_deck, vehicle_data, alternate_names, unused_vars, legac return vehicle_data -def process_and_store_data(data, var_name, legacy_code, current_namelist, alternate_names, vehicle_data, unused_vars, comment=''): +def process_and_store_data( + data, + var_name, + legacy_code, + current_namelist, + alternate_names, + vehicle_data, + unused_vars, + comment='', +): ''' process_and_store_data takes in a string that contains the data, the current variable's name and namelist, the dictionary of alternate names, and the current vehicle data. @@ -252,7 +311,8 @@ def process_and_store_data(data, var_name, legacy_code, current_namelist, altern data_list = [dat for dat in data.split(',') if dat != ''] if len(data_list) > 0: if valid_units(data_list[-1]): - # if the last element is a unit, remove it from the list and update the variable's units + # if the last element is a unit, remove it from the list and update the + # variable's units data_units = data_list.pop() var_values = convert_strings_to_data(data_list) else: @@ -260,7 +320,8 @@ def process_and_store_data(data, var_name, legacy_code, current_namelist, altern var_values = [] list_of_equivalent_aviary_names, var_ind = update_name( - alternate_names, current_namelist+var_name, vehicle_data['verbosity']) + alternate_names, current_namelist + var_name, vehicle_data['verbosity'] + ) # Fortran uses 1 indexing, Python uses 0 indexing fortran_offset = 1 if current_namelist else 0 @@ -268,10 +329,15 @@ def process_and_store_data(data, var_name, legacy_code, current_namelist, altern var_ind -= fortran_offset # Aviary has a reduction gearbox which is 1/gear ratio of GASP gearbox - if current_namelist+var_name == 'INPROP.GR': - var_values = [1/var for var in var_values] - vehicle_data['input_values'] = set_value(Aircraft.Engine.Gearbox.GEAR_RATIO, var_values, - vehicle_data['input_values'], var_id=var_ind, units=data_units) + if current_namelist + var_name == 'INPROP.GR': + var_values = [1 / var for var in var_values] + vehicle_data['input_values'] = set_value( + Aircraft.Engine.Gearbox.GEAR_RATIO, + var_values, + vehicle_data['input_values'], + var_ind=var_ind, + units=data_units, + ) for name in list_of_equivalent_aviary_names: if not skip_variable: @@ -281,12 +347,22 @@ def process_and_store_data(data, var_name, legacy_code, current_namelist, altern continue elif name in _MetaData: - vehicle_data['input_values'] = set_value(name, var_values, vehicle_data['input_values'], - var_ind=var_ind, units=data_units) + vehicle_data['input_values'] = set_value( + name, + var_values, + vehicle_data['input_values'], + var_ind=var_ind, + units=data_units, + ) continue - vehicle_data['unused_values'] = set_value(name, var_values, vehicle_data['unused_values'], - var_ind=var_ind, units=data_units) + vehicle_data['unused_values'] = set_value( + name, + var_values, + vehicle_data['unused_values'], + var_ind=var_ind, + units=data_units, + ) if vehicle_data['verbosity'].value >= Verbosity.VERBOSE: print('Unused:', name, var_values, comment) @@ -294,7 +370,7 @@ def process_and_store_data(data, var_name, legacy_code, current_namelist, altern def set_value(var_name, var_value, value_dict: NamedValues, var_ind=None, units=None): - ''' + ''' set_value will update the current value of a variable in a value dictionary that contains a value and it's associated units. If units are specified for the new value, they will be used, otherwise the current units in the @@ -313,19 +389,20 @@ def set_value(var_name, var_value, value_dict: NamedValues, var_ind=None, units= if not units: units = 'unitless' - if var_ind != None: + if var_ind is not None: # if an index is specified, use it, otherwise store the input as the whole value if isinstance(current_value, list): max_ind = len(current_value) - 1 if var_ind > max_ind: - current_value.extend((var_ind-max_ind)*[0]) + current_value.extend((var_ind - max_ind) * [0]) else: - current_value = [current_value]+[0]*var_ind + current_value = [current_value] + [0] * var_ind current_value[var_ind] = var_value[0] value_dict.set_val(var_name, current_value, units) else: - if current_value != None and isinstance(current_value[0], bool): - # if a variable is defined as boolean but is read in as number, set as boolean + if current_value is not None and isinstance(current_value[0], bool): + # if a variable is defined as boolean but is read in as number, set as + # boolean if var_value[0] == 1: var_value = ['True'] elif var_value[0] == 0: @@ -400,11 +477,19 @@ def update_gasp_options(vehicle_data): for var_name in gasp_scaler_variables: update_gasp_scaler_variables(var_name, input_values) - flap_types = ["plain", "split", "single_slotted", "double_slotted", - "triple_slotted", "fowler", "double_slotted_fowler"] + flap_types = [ + "plain", + "split", + "single_slotted", + "double_slotted", + "triple_slotted", + "fowler", + "double_slotted_fowler", + ] ## PROBLEM TYPE ## - # if multiple values of target_range are specified, use the one that corresponds to the problem_type + # if multiple values of target_range are specified, use the one that + # corresponds to the problem_type design_range, distance_units = input_values.get_item(Mission.Design.RANGE) try: problem_type = input_values.get_val(Settings.PROBLEM_TYPE)[0] @@ -447,58 +532,80 @@ def update_gasp_options(vehicle_data): strut_loc = abs(strut_loc) if strut_loc < 1: - input_values.set_val(Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, - [strut_loc], 'unitless') - input_values.set_val(Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, [ - False], 'unitless') + input_values.set_val( + Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, [strut_loc], 'unitless' + ) + input_values.set_val( + Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, [False], 'unitless' + ) else: input_values.set_val(Aircraft.Strut.ATTACHMENT_LOCATION, [strut_loc], 'ft') input_values.set_val( - Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, [True], 'unitless') + Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, [True], 'unitless' + ) if input_values.get_val(Aircraft.Wing.HAS_FOLD)[0]: if not input_values.get_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION)[0]: - input_values.set_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, - [True], 'unitless') + input_values.set_val( + Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, [True], 'unitless' + ) else: if input_values.get_val(Aircraft.Wing.FOLDED_SPAN, 'ft')[0] > 1: - input_values.set_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, - [True], 'unitless') + input_values.set_val( + Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, + [True], + 'unitless', + ) else: - input_values.set_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, - [False], 'unitless') + input_values.set_val( + Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, + [False], + 'unitless', + ) else: input_values.set_val(Aircraft.Wing.CHOOSE_FOLD_LOCATION, [True], 'unitless') - input_values.set_val(Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, [ - False], 'unitless') + input_values.set_val( + Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, [False], 'unitless' + ) ## FLAPS ## flap_type = input_values.get_val(Aircraft.Wing.FLAP_TYPE)[0] if not isinstance(flap_type, str): - flap_type = flap_types[flap_type-1] + flap_type = flap_types[flap_type - 1] input_values.set_val(Aircraft.Wing.FLAP_TYPE, [flap_type]) flap_ind = flap_types.index(flap_type) if input_values.get_val(Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT)[0] <= 0: - input_values.set_val(Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, - [[0.62, 1.0, 0.733, 1.2, 1.32, 0.633, 0.678][flap_ind]]) + input_values.set_val( + Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, + [[0.62, 1.0, 0.733, 1.2, 1.32, 0.633, 0.678][flap_ind]], + ) if input_values.get_val(Aircraft.Wing.OPTIMUM_FLAP_DEFLECTION, 'deg')[0] == 0: - input_values.set_val(Aircraft.Wing.OPTIMUM_FLAP_DEFLECTION, - [[60, 60, 40, 55, 55, 30, 30][flap_ind]], 'deg') + input_values.set_val( + Aircraft.Wing.OPTIMUM_FLAP_DEFLECTION, + [[60, 60, 40, 55, 55, 30, 30][flap_ind]], + 'deg', + ) if input_values.get_val(Aircraft.Wing.FLAP_LIFT_INCREMENT_OPTIMUM)[0] == 0: - input_values.set_val(Aircraft.Wing.FLAP_LIFT_INCREMENT_OPTIMUM, - [[.9, .8, 1.18, 1.4, 1.6, 1.67, 2.25][flap_ind]]) + input_values.set_val( + Aircraft.Wing.FLAP_LIFT_INCREMENT_OPTIMUM, + [[0.9, 0.8, 1.18, 1.4, 1.6, 1.67, 2.25][flap_ind]], + ) if input_values.get_val(Aircraft.Wing.FLAP_DRAG_INCREMENT_OPTIMUM)[0] == 0: - input_values.set_val(Aircraft.Wing.FLAP_DRAG_INCREMENT_OPTIMUM, - [[.12, .23, .13, .23, .23, .1, .15][flap_ind]]) + input_values.set_val( + Aircraft.Wing.FLAP_DRAG_INCREMENT_OPTIMUM, + [[0.12, 0.23, 0.13, 0.23, 0.23, 0.1, 0.15][flap_ind]], + ) res = input_values.get_val(Aircraft.Design.RESERVE_FUEL_ADDITIONAL, units='lbm')[0] if res <= 0: input_values.set_val(Aircraft.Design.RESERVE_FUEL_ADDITIONAL, [0], units='lbm') - input_values.set_val(Aircraft.Design.RESERVE_FUEL_FRACTION, - [-res], units='unitless') + input_values.set_val( + Aircraft.Design.RESERVE_FUEL_FRACTION, [-res], units='unitless' + ) elif res >= 10: - input_values.set_val(Aircraft.Design.RESERVE_FUEL_FRACTION, - [0], units='unitless') + input_values.set_val( + Aircraft.Design.RESERVE_FUEL_FRACTION, [0], units='unitless' + ) else: ValueError('"FRESF" is not valid between 0 and 10.') @@ -517,6 +624,13 @@ def update_gasp_options(vehicle_data): if input_values.get_val(Aircraft.Strut.FUSELAGE_INTERFERENCE_FACTOR)[0] < 0: input_values.delete(Aircraft.Strut.FUSELAGE_INTERFERENCE_FACTOR) + # GASP-converted engine decks have uneven throttle ranges, which require the enabling + # of global throttle range. This will result in extrapolation of the engine deck, + # but provides closer matches to legacy results. To remove use of global throttle + # (and therefore eliminate extrapolation), a T4 limit needs to be manually set for + # the mission + input_values.set_val(Aircraft.Engine.GLOBAL_THROTTLE, [True]) + vehicle_data['input_values'] = input_values return vehicle_data @@ -540,25 +654,51 @@ def update_flops_options(vehicle_data): # Additional mass fraction scaler set to zero to not add mass twice if Aircraft.Engine.ADDITIONAL_MASS_FRACTION in input_values: if input_values.get_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION)[0] >= 1: - input_values.set_val(Aircraft.Engine.ADDITIONAL_MASS, - input_values.get_val( - Aircraft.Engine.ADDITIONAL_MASS_FRACTION), - 'lbm') + input_values.set_val( + Aircraft.Engine.ADDITIONAL_MASS, + input_values.get_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION), + 'lbm', + ) input_values.set_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION, [0.0]) # Miscellaneous propulsion mass trigger point 1 instead of 5 if Aircraft.Propulsion.MISC_MASS_SCALER in input_values: if input_values.get_val(Aircraft.Propulsion.MISC_MASS_SCALER)[0] >= 1: - input_values.set_val(Aircraft.Propulsion.TOTAL_MISC_MASS, - input_values.get_val( - Aircraft.Propulsion.MISC_MASS_SCALER), - 'lbm') + input_values.set_val( + Aircraft.Propulsion.TOTAL_MISC_MASS, + input_values.get_val(Aircraft.Propulsion.MISC_MASS_SCALER), + 'lbm', + ) input_values.set_val(Aircraft.Propulsion.MISC_MASS_SCALER, [0.0]) vehicle_data['input_values'] = input_values return vehicle_data +def update_aviary_options(vehicle_data): + """ + Special handling for variables that occurs for either legacy code + """ + input_values: NamedValues = vehicle_data['input_values'] + + # if reference + scaled thrust both provided, set scale factor + try: + ref_thrust = input_values.get_val(Aircraft.Engine.REFERENCE_SLS_THRUST, 'lbf')[ + 0 + ] + scaled_thrust = input_values.get_val(Aircraft.Engine.SCALED_SLS_THRUST, 'lbf')[ + 0 + ] + except KeyError: + pass + else: + scale_factor = scaled_thrust / ref_thrust + input_values.set_val(Aircraft.Engine.SCALE_FACTOR, [scale_factor]) + + vehicle_data['input_values'] = input_values + return vehicle_data + + def update_flops_scaler_variables(var_name, input_values: NamedValues): """ The following parameters are used to modify or override @@ -658,7 +798,8 @@ def update_gasp_scaler_variables(var_name, input_values: NamedValues): ] initialization_guesses = { - # initialization_guesses is a dictionary that contains values used to initialize the trajectory + # initialization_guesses is a dictionary that contains values used to + # initialize the trajectory 'actual_takeoff_mass': 0, 'rotation_mass': 0, 'fuel_burn_per_passenger_mile': 0, @@ -666,7 +807,7 @@ def update_gasp_scaler_variables(var_name, input_values: NamedValues): 'flight_duration': 0, 'time_to_climb': 0, 'climb_range': 0, - 'reserves': 0 + 'reserves': 0, } @@ -689,7 +830,7 @@ def _setup_F2A_parser(parser): "-o", "--out_file", default=None, - help="Filename for converted input deck, including partial or complete path." + help="Filename for converted input deck, including partial or complete path.", ) parser.add_argument( "-l", @@ -697,13 +838,13 @@ def _setup_F2A_parser(parser): type=LegacyCode, help="Name of the legacy code the deck originated from", choices=set(LegacyCode), - required=True + required=True, ) parser.add_argument( "-d", "--defaults_deck", default=None, - help="Deck of default values for unspecified variables" + help="Deck of default values for unspecified variables", ) parser.add_argument( "--force", @@ -729,5 +870,11 @@ def _exec_F2A(args, user_args): # convert verbosity from int to enum verbosity = Verbosity(args.verbosity) - create_aviary_deck(filepath, args.legacy_code, args.defaults_deck, - args.out_file, args.force, verbosity) + create_aviary_deck( + filepath, + args.legacy_code, + args.defaults_deck, + args.out_file, + args.force, + verbosity, + ) diff --git a/aviary/utils/functions.py b/aviary/utils/functions.py index 2d8e102d0..0f34cb662 100644 --- a/aviary/utils/functions.py +++ b/aviary/utils/functions.py @@ -469,7 +469,7 @@ def get_path(path: Union[str, Path], verbose: bool = False) -> Path: # If the path still doesn't exist, attempt to find it in the models directory. if not path.exists(): try: - hangar_based_path = get_model(original_path) + hangar_based_path = get_model(original_path, verbose=verbose) if verbose: print( f"Unable to locate '{aviary_based_path}' as an Aviary package path, checking built-in models") diff --git a/aviary/utils/preprocessors.py b/aviary/utils/preprocessors.py index e1d2f747d..bf555c8d0 100644 --- a/aviary/utils/preprocessors.py +++ b/aviary/utils/preprocessors.py @@ -6,7 +6,7 @@ from aviary.utils.aviary_values import AviaryValues from aviary.utils.named_values import get_keys from aviary.variable_info.variable_meta_data import _MetaData -from aviary.variable_info.variables import Aircraft, Mission +from aviary.variable_info.variables import Aircraft, Mission, Settings from aviary.utils.test_utils.variable_test import get_names_from_hierarchy @@ -24,6 +24,10 @@ def preprocess_options(aviary_options: AviaryValues, **kwargs): except KeyError: engine_models = None + if Settings.VERBOSITY not in aviary_options: + aviary_options.set_val( + Settings.VERBOSITY, _MetaData[Settings.VERBOSITY]['default_value']) + preprocess_crewpayload(aviary_options) preprocess_propulsion(aviary_options, engine_models) @@ -35,30 +39,128 @@ def preprocess_crewpayload(aviary_options: AviaryValues): returns the modified collection. """ - if Aircraft.CrewPayload.NUM_PASSENGERS not in aviary_options: - passenger_count = 0 - for key in (Aircraft.CrewPayload.NUM_FIRST_CLASS, - Aircraft.CrewPayload.NUM_BUSINESS_CLASS, - Aircraft.CrewPayload.NUM_TOURIST_CLASS): - if key in aviary_options: - passenger_count += aviary_options.get_val(key) - if passenger_count == 0: - passenger_count = 1 - + verbosity = aviary_options.get_val(Settings.VERBOSITY) + + # Some tests, but not all, do not correctly set default values + # # so we need to ensure all these values are available. + + for key in ( + Aircraft.CrewPayload.NUM_PASSENGERS, + Aircraft.CrewPayload.NUM_FIRST_CLASS, + Aircraft.CrewPayload.NUM_BUSINESS_CLASS, + Aircraft.CrewPayload.NUM_TOURIST_CLASS, + Aircraft.CrewPayload.Design.NUM_PASSENGERS, + Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, + Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, + Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS,): + if key not in aviary_options: + aviary_options.set_val(key, _MetaData[key]['default_value']) + + # Sum passenger Counts for later checks and assignments + passenger_count = 0 + for key in (Aircraft.CrewPayload.NUM_FIRST_CLASS, + Aircraft.CrewPayload.NUM_BUSINESS_CLASS, + Aircraft.CrewPayload.NUM_TOURIST_CLASS): + passenger_count += aviary_options.get_val(key) + design_passenger_count = 0 + for key in (Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, + Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, + Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS): + design_passenger_count += aviary_options.get_val(key) + + # Create summary value (num_pax) if it was not assigned by the user + # or if it was set to it's default value of zero + if passenger_count != 0 and aviary_options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) == 0: + aviary_options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, passenger_count) + if verbosity >= 2: + print("User has specified supporting values for NUM_PASSENGERS but has left NUM_PASSENGERS=0. Replacing NUM_PASSENGERS with passenger_count.") + if design_passenger_count != 0 and aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS) == 0: aviary_options.set_val( - Aircraft.CrewPayload.NUM_PASSENGERS, passenger_count) - else: - passenger_count = aviary_options.get_val( - Aircraft.CrewPayload.NUM_PASSENGERS) - # check in here to ensure that in this case passenger count is the sum of the first class, business class, and tourist class counts. - passenger_check = aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS) - passenger_check += aviary_options.get_val( - Aircraft.CrewPayload.NUM_BUSINESS_CLASS) - passenger_check += aviary_options.get_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS) - # only perform check if at least one passenger class is entered - if passenger_check > 0 and passenger_count != passenger_check: - raise om.AnalysisError( - f"ERROR: In preprocesssors.py: passenger_count ({passenger_count}) does not equal the sum of first class + business class + tourist class passengers (total of {passenger_check}).") + Aircraft.CrewPayload.Design.NUM_PASSENGERS, design_passenger_count) + if verbosity >= 2: + print("User has specified supporting values for Design.NUM_PASSENGERS but has left Design.NUM_PASSENGERS=0. Replacing Design.NUM_PASSENGERS with design_passenger_count.") + + num_pax = aviary_options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) + design_num_pax = aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS) + + # Check summary data against individual data if individual data was entered + if passenger_count != 0 and num_pax != passenger_count: + raise om.AnalysisError( + f"ERROR: In preprocesssors.py: NUM_PASSENGERS ({aviary_options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS)}) does not equal the sum of first class + business class + tourist class passengers (total of {passenger_count}).") + if design_passenger_count != 0 and design_num_pax != design_passenger_count: + raise om.AnalysisError( + f"ERROR: In preprocesssors.py: Design.NUM_PASSENGERS ({aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS)}) does not equal the sum of design first class + business class + tourist class passengers (total of {design_passenger_count}).") + + # Fail if incorrect data sets were provided: + # have you give us enough info to determine where people were sitting vs. designed seats + if num_pax != 0 and design_passenger_count != 0 and passenger_count == 0: + raise om.AnalysisError( + f"ERROR: In preprocessor.py: The user has specified CrewPayload.NUM_PASSENGERS, and how many of what types of seats are on the aircraft." + f"However, the user has not specified where those passengers are sitting." + f"User must specify CrewPayload.FIRST_CLASS, CrewPayload.NUM_BUSINESS_CLASS, NUM_TOURIST_CLASS in aviary_values.") + # where are the people sitting? is first class full? We know how many seats are in each class. + if design_num_pax != 0 and passenger_count != 0 and design_passenger_count == 0: + raise om.AnalysisError( + f"ERROR: In preprocessor.py: The user has specified Design.NUM_PASSENGERS, and has specified how many people are sitting in each class of seats." + f"However, the user has not specified how many seats of each class exist in the aircraft." + f"User must specify Design.FIRST_CLASS, Design.NUM_BUSINESS_CLASS, Design.NUM_TOURIST_CLASS in aviary_values.") + # we don't know which classes this aircraft has been design for. How many 1st class seats are there? + + # Copy data over if only one set of data exists + # User has given detailed values for 1TB as flow and NO design values at all + if passenger_count != 0 and design_num_pax == 0 and design_passenger_count == 0: + if verbosity >= 2: + print( + "User has not input design passengers data. Assuming design is equal to as-flow passenger data.") + aviary_options.set_val( + Aircraft.CrewPayload.Design.NUM_PASSENGERS, passenger_count) + aviary_options.set_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, + aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS)) + aviary_options.set_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, + aviary_options.get_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS)) + aviary_options.set_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, + aviary_options.get_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS)) + # user has not supplied detailed information on design but has supplied summary information on passengers + elif num_pax != 0 and design_num_pax == 0: + if verbosity >= 2: + print("User has specified as-flown NUM_PASSENGERS but not how many passengers the aircraft was designed for in Design.NUM_PASSENGERS. Assuming they are equal.") + aviary_options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, num_pax) + elif design_passenger_count != 0 and num_pax == 0 and passenger_count == 0: + if verbosity >= 1: + print("User has specified Design.NUM_* passenger values but CrewPyaload.NUM_* has been left blank or set to zero.") + print( + "Assuming they are equal to maintain backwards compatibility with GASP and FLOPS output files.") + print("If you intended to have no passengers on this flight, please set Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS to zero in aviary_values.") + aviary_options.set_val( + Aircraft.CrewPayload.NUM_PASSENGERS, design_passenger_count) + aviary_options.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, + aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS)) + aviary_options.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, + aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS)) + aviary_options.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, + aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS)) + # user has not supplied detailed information on design but has supplied summary information on passengers + elif design_num_pax != 0 and num_pax == 0: + if verbosity >= 1: + print("User has specified Design.NUM_PASSENGERS but CrewPayload.NUM_PASSENGERS has been left blank or set to zero.") + print( + "Assuming they are equal to maintain backwards compatibility with GASP and FLOPS output files.") + print("If you intended to have no passengers on this flight, please set Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS to zero in aviary_values.") + aviary_options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, design_num_pax) + + # Performe checks on the final data tables to ensure Design is always large then As-Flow + if aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS) < aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS): + raise om.AnalysisError( + f"ERROR: In preprocesssors.py: NUM_FIRST_CLASS ({aviary_options.get_val(Aircraft.CrewPayload.NUM_FIRST_CLASS)}) is larger than the number of seats set by Design.NUM_FIRST_CLASS ({aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS)}) .") + if aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS) < aviary_options.get_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS): + raise om.AnalysisError( + f"ERROR: In preprocesssors.py: NUM_BUSINESS_CLASS ({aviary_options.get_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS)}) is larger than the number of seats set by Design.NUM_BUSINESS_CLASS ({aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS)}) .") + if aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS) < aviary_options.get_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS): + raise om.AnalysisError( + f"ERROR: In preprocesssors.py: NUM_TOURIST_CLASS ({aviary_options.get_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS)}) is larger than the number of seats set by Design.NUM_TOURIST_CLASS ({aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS)}) .") + if aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS) < aviary_options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS): + raise om.AnalysisError( + f"ERROR: In preprocesssors.py: NUM_PASSENGERS ({aviary_options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS)}) is larger than the number of seats set by Design.NUM_PASSENGERS ({aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS)}) .") if Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS not in aviary_options: flight_attendants_count = 0 # assume no passengers @@ -172,6 +274,8 @@ def preprocess_propulsion(aviary_options: AviaryValues, engine_models: list = No # if default value is a list/tuple, find type inside that if isinstance(default_value, (list, tuple)): dtype = type(default_value[0]) + elif isinstance(default_value, np.ndarray): + dtype = default_value.dtype elif default_value is None: # With no default value, we cannot determine a dtype. dtype = None @@ -214,6 +318,7 @@ def preprocess_propulsion(aviary_options: AviaryValues, engine_models: list = No # if aviary_val is an iterable, just grab val for this engine if isinstance(aviary_val, (list, np.ndarray, tuple)): aviary_val = aviary_val[i] + # add aviary_val to vec using type-appropriate syntax if isinstance(default_value, (list, np.ndarray)): vec = np.append(vec, aviary_val) elif isinstance(default_value, tuple): diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 6057925fe..67723c2a1 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -286,7 +286,7 @@ def initialization_guessing(aircraft_values: AviaryValues, initialization_guesse Updated aircraft values and initial guesses. """ problem_type = aircraft_values.get_val(Settings.PROBLEM_TYPE) - num_pax = aircraft_values.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) + num_pax = aircraft_values.get_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS) reserve_val = aircraft_values.get_val( Aircraft.Design.RESERVE_FUEL_ADDITIONAL, units='lbm') reserve_frac = aircraft_values.get_val( @@ -367,16 +367,35 @@ def initialization_guessing(aircraft_values: AviaryValues, initialization_guesse initialization_guesses['flight_duration'] = initialization_guesses['flight_duration'] * \ (60 * 60) + # TODO this does not work at all for mixed-type engines (some propeller and some not) try: - total_thrust = aircraft_values.get_val( - Aircraft.Engine.SCALED_SLS_THRUST, 'lbf') * aircraft_values.get_val(Aircraft.Engine.NUM_ENGINES) + num_engines = aircraft_values.get_val(Aircraft.Engine.NUM_ENGINES) + + # This happens before preprocessing, and we end up with the default when unspecified. + if isinstance(num_engines, list): + num_engines = num_engines[0] + + if aircraft_values.get_val(Aircraft.Engine.HAS_PROPELLERS): + # For large turboprops, 1 pound of thrust per hp at takeoff seems to be close enough + total_thrust = aircraft_values.get_val( + Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN, 'hp') * num_engines + else: + total_thrust = aircraft_values.get_val( + Aircraft.Engine.SCALED_SLS_THRUST, 'lbf') * num_engines + except KeyError: - # heterogeneous engine-model case. Get thrust from the engine decks instead. - total_thrust = 0 - for model in engine_builders: - thrust = model.get_val(Aircraft.Engine.SCALED_SLS_THRUST, 'lbf') - num_engines = model.get_val(Aircraft.Engine.NUM_ENGINES) - total_thrust += thrust * num_engines + if engine_builders is not None and len(engine_builders) > 1: + + # heterogeneous engine-model case. Get thrust from the engine models instead. + total_thrust = 0 + for model in engine_builders: + thrust = model.get_val(Aircraft.Engine.SCALED_SLS_THRUST, 'lbf') + num_engines = model.get_val(Aircraft.Engine.NUM_ENGINES) + total_thrust += thrust * num_engines + + else: + total_thrust = aircraft_values.get_val( + Aircraft.Engine.SCALED_SLS_THRUST, 'lbf') * aircraft_values.get_val(Aircraft.Engine.NUM_ENGINES) gamma_guess = np.arcsin(.5*total_thrust / mission_mass) avg_speed_guess = (.5 * 667 * cruise_mach) # kts @@ -433,7 +452,7 @@ def initialization_guessing(aircraft_values: AviaryValues, initialization_guesse [Aircraft.Design.PART25_STRUCTURAL_CATEGORY, { 'val': 0, 'relation': '<', 'target': Aircraft.Design.ULF_CALCULATED_FROM_MANEUVER, 'result': True, 'alternate': False}], [Aircraft.Engine.TYPE, { - 'val': [1, 2, 3, 4, 11, 12, 13, 14], 'relation': 'in', 'target': Aircraft.Engine.HAS_PROPELLERS, 'result': True, 'alternate': False}], + 'val': [1, 2, 3, 4, 6, 11, 12, 13, 14], 'relation': 'in', 'target': Aircraft.Engine.HAS_PROPELLERS, 'result': True, 'alternate': False}], ['JENGSZ', { 'val': 4, 'relation': '!=', 'target': Aircraft.Engine.SCALE_PERFORMANCE, 'result': True, 'alternate': False}], [Aircraft.HorizontalTail.VOLUME_COEFFICIENT, { diff --git a/aviary/utils/test/test_aviary_values.py b/aviary/utils/test/test_aviary_values.py index abc014e02..9d6fc4883 100644 --- a/aviary/utils/test/test_aviary_values.py +++ b/aviary/utils/test/test_aviary_values.py @@ -90,9 +90,9 @@ def test_aircraft(self): try: vals.set_val(Aircraft.Engine.TYPE, 'turbojet') self.assertTrue(vals.get_val(Aircraft.Engine.TYPE) - is GASPEngineType.TURBOJET) + == GASPEngineType.TURBOJET) except: - self.fail('Expecting to be able to set the value of an Enum from a string.') + self.fail('Expecting to be able to set the value of an Enum from an int.') try: vals.set_val(Aircraft.Engine.TYPE, 'TURBOJET') @@ -144,8 +144,8 @@ def test_mission(self): except TypeError as err: self.assertEqual( str(err), - f"{Mission.Design.CRUISE_ALTITUDE} is of type(s) [, ] but you have provided a value of type .") + f"{Mission.Design.CRUISE_ALTITUDE} is of type(s) (, ) but you have provided a value of type .") else: self.fail('Expecting TypeError.') @@ -154,8 +154,8 @@ def test_mission(self): except TypeError as err: self.assertEqual( str(err), - f"{Mission.Design.CRUISE_ALTITUDE} is of type(s) [, ] but you have provided a value of type .") + f"{Mission.Design.CRUISE_ALTITUDE} is of type(s) (, ) but you have provided a value of type .") else: self.fail('Expecting TypeError.') diff --git a/aviary/utils/test/test_doctape.py b/aviary/utils/test/test_doctape.py new file mode 100644 index 000000000..d13b8d1c1 --- /dev/null +++ b/aviary/utils/test/test_doctape.py @@ -0,0 +1,67 @@ +import unittest +import numpy as np + +from openmdao.utils.assert_utils import assert_near_equal, assert_equal_numstrings, assert_equal_arrays + +from aviary.utils.doctape import gramatical_list, check_value, check_contains, check_args, run_command_no_file_error, get_attribute_name, get_all_keys, get_value, get_previous_line, get_variable_name + + +class DocTAPETests(unittest.TestCase): + """ + Testing the DocTAPE functions to make sure they all run in all supported Python versions + Docs are only built with latest, but these test will be run with latest and dev as well + """ + + def test_gramatical_list(self): + string = gramatical_list(['a', 'b', 'c']) + assert_equal_numstrings(string, 'a, b, and c') + + def test_check_value(self): + check_value(1, 1.0) + + def test_check_contains(self): + check_contains(1, [1, 2, 3]) + + def test_check_args(self): + check_args(check_args, 'func') + + def test_run_command_no_file_error(self): + run_command_no_file_error('python -c "print()"') + + def test_get_attribute_name(self): + class dummy_object: + attr1 = 1 + name = get_attribute_name(dummy_object, 1) + assert_equal_numstrings(name, 'attr1') + + def test_get_all_keys(self): + keys = get_all_keys({'d1': {'d2': 2}}) + assert_equal_arrays(np.array(keys), np.array(['d1', 'd2'])) + + def test_get_value(self): + val = get_value({'d1': {'d2': 2}}, 'd1.d2') + assert_near_equal(val, 2) + + def test_get_previous_line(self): + something = "something_else" + line1 = get_previous_line() + line2 = get_previous_line(2) + assert_equal_numstrings(line1, 'something = "something_else"') + assert_equal_numstrings(line2[1].strip(), 'line1 = get_previous_line()') + + def test_get_variable_name(self): + var = 7 + name = get_variable_name(var) + assert_equal_numstrings(name, 'var') + + # requires IPython shell + # def test_glue_variable(self): + # glue_variable('plain_text') + + # requires IPython shell + # def test_glue_keys(self): + # glue_keys({'d1':{'d2':2}}) + + +if __name__ == '__main__': + unittest.main() diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_balanced_field_length.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_balanced_field_length.py index 92ae6fb52..fd66f9d75 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_balanced_field_length.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_balanced_field_length.py @@ -22,6 +22,7 @@ from aviary.utils.functions import \ set_aviary_initial_values, set_aviary_input_defaults from aviary.utils.preprocessors import preprocess_options +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Dynamic, Aircraft @@ -107,6 +108,8 @@ def _do_run(self, driver: Driver, optimizer, *args): varnames = [Aircraft.Wing.ASPECT_RATIO] set_aviary_input_defaults(takeoff.model, varnames, aviary_options) + setup_model_options(takeoff, aviary_options) + # suppress warnings: # "input variable '...' promoted using '*' was already promoted using 'aircraft:*' with warnings.catch_warnings(): diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_sizing_N3CC.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_sizing_N3CC.py index f7007f33e..3afb8330b 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_sizing_N3CC.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_sizing_N3CC.py @@ -29,12 +29,12 @@ from aviary.utils.aviary_values import AviaryValues from aviary.utils.functions import set_aviary_input_defaults from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.preprocessors import preprocess_crewpayload +from aviary.utils.preprocessors import preprocess_crewpayload, preprocess_propulsion from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.validation_cases.validation_tests import get_flops_inputs from aviary.variable_info.enums import LegacyCode -from aviary.variable_info.functions import setup_trajectory_params +from aviary.variable_info.functions import setup_trajectory_params, setup_model_options from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData @@ -188,6 +188,7 @@ def run_trajectory(sim=True): # default subsystems engine = build_engine_deck(aviary_inputs) + preprocess_propulsion(aviary_inputs, engine) default_mission_subsystems = get_default_mission_subsystems('FLOPS', engine) climb_options = EnergyPhase( @@ -308,8 +309,11 @@ def run_trajectory(sim=True): 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['mission:*']) - traj.link_phases(["climb", "cruise", "descent"], [ - "time", Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) + traj.link_phases( + ["climb", "cruise", "descent"], + ["time", Dynamic.Vehicle.MASS, Dynamic.Mission.DISTANCE], + connected=strong_couple, + ) # Need to declare dymos parameters for every input that is promoted out of the missions. externs = {'climb': {}, 'cruise': {}, 'descent': {}} @@ -433,6 +437,8 @@ def run_trajectory(sim=True): ] set_aviary_input_defaults(prob.model, varnames, aviary_inputs) + setup_model_options(prob, aviary_inputs) + prob.setup(force_alloc_complex=True) set_aviary_initial_values(prob, aviary_inputs) @@ -444,13 +450,21 @@ def run_trajectory(sim=True): prob.set_val('traj.climb.t_initial', t_i_climb, units='s') prob.set_val('traj.climb.t_duration', t_duration_climb, units='s') - prob.set_val('traj.climb.controls:altitude', climb.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m') prob.set_val( - 'traj.climb.controls:mach', climb.interp( - Dynamic.Mission.MACH, ys=[mach_i_climb, mach_f_climb]), units='unitless') - prob.set_val('traj.climb.states:mass', climb.interp( - Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') + 'traj.climb.controls:altitude', + climb.interp(Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), + units='m', + ) + prob.set_val( + 'traj.climb.controls:mach', + climb.interp(Dynamic.Atmosphere.MACH, ys=[mach_i_climb, mach_f_climb]), + units='unitless', + ) + prob.set_val( + 'traj.climb.states:mass', + climb.interp(Dynamic.Vehicle.MASS, ys=[mass_i_climb, mass_f_climb]), + units='kg', + ) prob.set_val('traj.climb.states:distance', climb.interp( Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m') @@ -462,26 +476,42 @@ def run_trajectory(sim=True): else: controls_str = 'polynomial_controls' - prob.set_val(f'traj.cruise.{controls_str}:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m') prob.set_val( - f'traj.cruise.{controls_str}:mach', cruise.interp( - Dynamic.Mission.MACH, ys=[cruise_mach, cruise_mach]), units='unitless') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') + f'traj.cruise.{controls_str}:altitude', + cruise.interp(Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), + units='m', + ) + prob.set_val( + f'traj.cruise.{controls_str}:mach', + cruise.interp(Dynamic.Atmosphere.MACH, ys=[cruise_mach, cruise_mach]), + units='unitless', + ) + prob.set_val( + 'traj.cruise.states:mass', + cruise.interp(Dynamic.Vehicle.MASS, ys=[mass_i_cruise, mass_f_cruise]), + units='kg', + ) prob.set_val('traj.cruise.states:distance', cruise.interp( Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') prob.set_val('traj.descent.t_initial', t_i_descent, units='s') prob.set_val('traj.descent.t_duration', t_duration_descent, units='s') - prob.set_val('traj.descent.controls:altitude', descent.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m') prob.set_val( - 'traj.descent.controls:mach', descent.interp( - Dynamic.Mission.MACH, ys=[mach_i_descent, mach_f_descent]), units='unitless') - prob.set_val('traj.descent.states:mass', descent.interp( - Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') + 'traj.descent.controls:altitude', + descent.interp(Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), + units='m', + ) + prob.set_val( + 'traj.descent.controls:mach', + descent.interp(Dynamic.Atmosphere.MACH, ys=[mach_i_descent, mach_f_descent]), + units='unitless', + ) + prob.set_val( + 'traj.descent.states:mass', + descent.interp(Dynamic.Vehicle.MASS, ys=[mass_i_descent, mass_f_descent]), + units='kg', + ) prob.set_val('traj.descent.states:distance', descent.interp( Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m') diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py index 950506bcf..1610ba160 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py @@ -19,6 +19,7 @@ set_aviary_initial_values, set_aviary_input_defaults from aviary.utils.preprocessors import preprocess_options from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Dynamic @@ -101,6 +102,8 @@ def _do_run(self, driver: Driver, optimizer, *args): varnames = [Aircraft.Wing.ASPECT_RATIO] set_aviary_input_defaults(landing.model, varnames, aviary_options) + setup_model_options(landing, aviary_options) + # suppress warnings: # "input variable '...' promoted using '*' was already promoted using 'aircraft:*' with warnings.catch_warnings(): diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py index 49dd1ee69..032905087 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py @@ -19,6 +19,7 @@ set_aviary_initial_values, set_aviary_input_defaults from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.utils.preprocessors import preprocess_options +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Dynamic @@ -116,6 +117,8 @@ def _do_run(self, driver: Driver, optimizer, *args): varnames = [Aircraft.Wing.ASPECT_RATIO] set_aviary_input_defaults(takeoff.model, varnames, aviary_options) + setup_model_options(takeoff, aviary_options) + # suppress warnings: # "input variable '...' promoted using '*' was already promoted using 'aircraft:*' with warnings.catch_warnings(): diff --git a/aviary/validation_cases/benchmark_tests/test_battery_in_a_mission.py b/aviary/validation_cases/benchmark_tests/test_battery_in_a_mission.py index 4ac7d0990..7fe7e744e 100644 --- a/aviary/validation_cases/benchmark_tests/test_battery_in_a_mission.py +++ b/aviary/validation_cases/benchmark_tests/test_battery_in_a_mission.py @@ -56,8 +56,7 @@ def test_subsystems_in_a_mission(self): prob = av.AviaryProblem() prob.load_inputs( - "models/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv", phase_info - ) + "models/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv", phase_info) # Preprocess inputs prob.check_and_preprocess_inputs() @@ -84,34 +83,54 @@ def test_subsystems_in_a_mission(self): prob.set_val(av.Aircraft.Battery.PACK_ENERGY_DENSITY, 550, units='kJ/kg') prob.set_val(av.Aircraft.Battery.PACK_MASS, 1000, units='lbm') prob.set_val(av.Aircraft.Battery.ADDITIONAL_MASS, 115, units='lbm') - prob.set_val(av.Aircraft.Battery.EFFICIENCY, 0.95, units='unitless') prob.run_aviary_problem() electric_energy_used = prob.get_val( 'traj.cruise.timeseries.' - f'{av.Dynamic.Mission.CUMULATIVE_ELECTRIC_ENERGY_USED}', + f'{av.Dynamic.Vehicle.CUMULATIVE_ELECTRIC_ENERGY_USED}', units='kW*h', ) - fuel_burned = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='lbm') soc = prob.get_val( - 'traj.cruise.rhs_all.battery.battery_state_of_charge', units='unitless' + 'traj.cruise.timeseries.' + f'{av.Dynamic.Vehicle.BATTERY_STATE_OF_CHARGE}', ) + fuel_burned = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='lbm') # Check outputs # indirectly check mission trajectory by checking total fuel/electric split - assert_near_equal(electric_energy_used[-1], 38.60538132, 1.e-7) - assert_near_equal(fuel_burned, 676.87235486, 1.e-7) + assert_near_equal(electric_energy_used[-1], 38.60747069, 1.e-7) + assert_near_equal(fuel_burned, 676.93670291, 1.e-7) # check battery state-of-charge over mission + assert_near_equal( - soc, - [0.99999578, 0.97551324, 0.94173584, 0.93104625, 0.93104625, - 0.8810605, 0.81210498, 0.79028433, 0.79028433, 0.73088701, - 0.64895148, 0.62302415, 0.62302415, 0.57309323, 0.50421334, - 0.48241661, 0.48241661, 0.45797918, 0.42426402, 0.41359413], + soc.ravel(), + [0.9999957806265609, + 0.975511918724275, + 0.9417326925421843, + 0.931042529806735, + 0.931042529806735, + 0.8810540781831623, + 0.8120948314123136, + 0.7902729948636958, + 0.7902729948636958, + 0.7308724676601358, + 0.6489324990486358, + 0.6230037623262401, + 0.6230037623262401, + 0.5730701397031007, + 0.5041865153698425, + 0.4823886057245942, + 0.4823886057245942, + 0.4579498542268948, + 0.4242328589510152, + 0.4135623891269744], 1e-7, ) if __name__ == "__main__": - unittest.main() + # unittest.main() + test = TestSubsystemsMission() + test.setUp() + test.test_subsystems_in_a_mission() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 1a07bb967..3e1160ae9 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -20,7 +20,7 @@ class ProblemPhaseTestCase(unittest.TestCase): """ - Setup of a large single aisle commercial transport aircraft using + Setup of a large single aisle commercial transport aircraft using FLOPS mass method and HEIGHT_ENERGY mission method. Expected outputs based on 'models/test_aircraft/aircraft_for_bench_FwFm.csv' model. """ @@ -426,7 +426,7 @@ def test_bench_FwFm_SNOPT_MPI(self): if __name__ == '__main__': - unittest.main() - # test = TestBenchFwFmSerial() - # test.setUp() - # test.test_bench_FwFm_SNOPT() + # unittest.main() + test = TestBenchFwFmSerial() + test.setUp() + test.test_bench_FwFm_SNOPT() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py index 34b883d7f..59d823bb7 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py @@ -14,7 +14,7 @@ @use_tempdirs class ProblemPhaseTestCase(unittest.TestCase): """ - Test the setup and run of a large single aisle commercial transport aircraft using + Test the setup and run of a large single aisle commercial transport aircraft using GASP mass method and TWO_DEGREES_OF_FREEDOM mission method. Expected outputs based on 'models/test_aircraft/aircraft_for_bench_FwFm.csv' model. """ @@ -212,7 +212,7 @@ def test_bench_GwGm_shooting(self): ) assert_near_equal( - prob.get_val(Mission.Summary.RANGE, units='NM'), 3774.3, tolerance=rtol + prob.get_val(Mission.Summary.RANGE, units='NM'), 3675.0, tolerance=rtol ) assert_near_equal( @@ -231,7 +231,7 @@ def test_bench_GwGm_shooting(self): if __name__ == '__main__': - # unittest.main() - test = ProblemPhaseTestCase() - test.setUp() - test.test_bench_GwGm_shooting() + unittest.main() + # test = ProblemPhaseTestCase() + # test.setUp() + # test.test_bench_GwGm_SNOPT() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_electrified_large_turboprop_freighter.py b/aviary/validation_cases/benchmark_tests/test_bench_electrified_large_turboprop_freighter.py new file mode 100644 index 000000000..054170193 --- /dev/null +++ b/aviary/validation_cases/benchmark_tests/test_bench_electrified_large_turboprop_freighter.py @@ -0,0 +1,101 @@ +import numpy as np +import unittest +import openmdao.api as om + + +from numpy.testing import assert_almost_equal +from openmdao.utils.testing_utils import use_tempdirs + +from aviary.interface.methods_for_level2 import AviaryProblem +from aviary.subsystems.propulsion.turboprop_model import TurbopropModel +from aviary.subsystems.propulsion.motor.motor_builder import MotorBuilder +from aviary.utils.process_input_decks import create_vehicle +from aviary.variable_info.variables import Aircraft, Mission, Settings + +from aviary.models.large_turboprop_freighter.phase_info import ( + two_dof_phase_info, + energy_phase_info, +) + + +@use_tempdirs +# TODO need to add asserts with "truth" values +class LargeElectrifiedTurbopropFreighterBenchmark(unittest.TestCase): + + def build_and_run_problem(self): + + # Build problem + prob = AviaryProblem() + + # load inputs from .csv to build engine + options, guesses = create_vehicle( + "models/large_turboprop_freighter/large_turboprop_freighter.csv" + ) + + options.set_val(Settings.EQUATIONS_OF_MOTION, 'height_energy') + # options.set_val(Aircraft.Engine.NUM_ENGINES, 2) + # options.set_val(Aircraft.Engine.WING_LOCATIONS, 0.385) + scale_factor = 3 + options.set_val(Aircraft.Engine.RPM_DESIGN, 6000, 'rpm') + options.set_val(Aircraft.Engine.FIXED_RPM, 6000, 'rpm') + options.set_val(Aircraft.Engine.Gearbox.GEAR_RATIO, 5.88) + options.set_val(Aircraft.Engine.Gearbox.EFFICIENCY, 1.0) + options.set_val(Aircraft.Engine.SCALE_FACTOR, scale_factor) # 11.87) + options.set_val( + Aircraft.Engine.SCALED_SLS_THRUST, + options.get_val(Aircraft.Engine.REFERENCE_SLS_THRUST, 'lbf') * scale_factor, + 'lbf', + ) + + # turboprop = TurbopropModel('turboprop', options=options) + # turboprop2 = TurbopropModel('turboprop2', options=options) + + motor = MotorBuilder( + 'motor', + ) + + electroprop = TurbopropModel( + 'electroprop', options=options, shaft_power_model=motor + ) + + # load_inputs needs to be updated to accept an already existing aviary options + prob.load_inputs( + options, # "models/large_turboprop_freighter/large_turboprop_freighter.csv", + energy_phase_info, + engine_builders=[electroprop], + ) + prob.aviary_inputs.set_val(Settings.VERBOSITY, 2) + + # FLOPS aero specific stuff? Best guesses for values here + prob.aviary_inputs.set_val(Mission.Constraints.MAX_MACH, 0.5) + prob.aviary_inputs.set_val(Aircraft.Wing.AREA, 1744.59, 'ft**2') + # prob.aviary_inputs.set_val(Aircraft.Wing.ASPECT_RATIO, 10.078) + prob.aviary_inputs.set_val( + Aircraft.Wing.THICKNESS_TO_CHORD, + 0.1500) # average between root and chord T/C + prob.aviary_inputs.set_val(Aircraft.Fuselage.MAX_WIDTH, 4.3, 'm') + prob.aviary_inputs.set_val(Aircraft.Fuselage.MAX_HEIGHT, 3.95, 'm') + prob.aviary_inputs.set_val(Aircraft.Fuselage.AVG_DIAMETER, 4.125, 'm') + + prob.check_and_preprocess_inputs() + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + prob.link_phases() + prob.add_driver("IPOPT", max_iter=0, verbosity=0) + prob.add_design_variables() + prob.add_objective() + + prob.setup() + # prob.model.list_vars(units=True, print_arrays=True) + om.n2(prob) + + prob.set_initial_guesses() + prob.run_aviary_problem("dymos_solution.db") + + om.n2(prob) + + +if __name__ == '__main__': + test = LargeElectrifiedTurbopropFreighterBenchmark() + test.build_and_run_problem() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_large_turboprop_freighter.py b/aviary/validation_cases/benchmark_tests/test_bench_large_turboprop_freighter.py new file mode 100644 index 000000000..1454af94d --- /dev/null +++ b/aviary/validation_cases/benchmark_tests/test_bench_large_turboprop_freighter.py @@ -0,0 +1,69 @@ +import numpy as np +import unittest +import openmdao.api as om + + +from numpy.testing import assert_almost_equal +from openmdao.utils.testing_utils import use_tempdirs + +from aviary.interface.methods_for_level2 import AviaryProblem +from aviary.subsystems.propulsion.turboprop_model import TurbopropModel +from aviary.subsystems.propulsion.motor.motor_builder import MotorBuilder +from aviary.utils.process_input_decks import create_vehicle +from aviary.variable_info.variables import Aircraft, Mission, Settings + +from aviary.models.large_turboprop_freighter.phase_info import ( + two_dof_phase_info, + energy_phase_info, +) + + +@use_tempdirs +@unittest.skip("Skipping until all builders are updated with get_parameters()") +# TODO need to add asserts with "truth" values +class LargeTurbopropFreighterBenchmark(unittest.TestCase): + + def build_and_run_problem(self): + + # Build problem + prob = AviaryProblem() + + # load inputs from .csv to build engine + options, _ = create_vehicle( + "models/large_turboprop_freighter/large_turboprop_freighter.csv" + ) + + turboprop = TurbopropModel('turboprop', options=options) + + # load_inputs needs to be updated to accept an already existing aviary options + prob.load_inputs( + "models/large_turboprop_freighter/large_turboprop_freighter.csv", + two_dof_phase_info, + engine_builders=[turboprop], + ) + prob.aviary_inputs.set_val(Settings.VERBOSITY, 2) + + # FLOPS aero specific stuff? Best guesses for values here + prob.aviary_inputs.set_val(Mission.Constraints.MAX_MACH, 0.5) + prob.aviary_inputs.set_val(Aircraft.Fuselage.AVG_DIAMETER, 4.125, 'm') + + prob.check_and_preprocess_inputs() + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + prob.link_phases() + prob.add_driver("IPOPT", max_iter=0, verbosity=0) + prob.add_design_variables() + prob.add_objective() + prob.setup() + # om.n2(prob) + + prob.set_initial_guesses() + prob.run_aviary_problem("dymos_solution.db") + + om.n2(prob) + + +if __name__ == '__main__': + test = LargeTurbopropFreighterBenchmark() + test.build_and_run_problem() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_multiengine.py b/aviary/validation_cases/benchmark_tests/test_bench_multiengine.py index 05093fc0b..5fd0ac36a 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_multiengine.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_multiengine.py @@ -1,5 +1,6 @@ from copy import deepcopy import unittest +import numpy as np import openmdao.api as om from openmdao.core.problem import _clear_problem_names @@ -11,6 +12,7 @@ from aviary.models.multi_engine_single_aisle.multi_engine_single_aisle_data import inputs, engine_1_inputs, engine_2_inputs from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.variable_info.enums import ThrottleAllocation +from aviary.variable_info.variables import Aircraft # Build problem @@ -33,6 +35,9 @@ local_phase_info['descent']['user_options']['no_climb'] = True local_phase_info['descent']['user_options']['use_polynomial_control'] = True +inputs.set_val(Aircraft.Nacelle.LAMINAR_FLOW_LOWER, np.zeros(2)) +inputs.set_val(Aircraft.Nacelle.LAMINAR_FLOW_UPPER, np.zeros(2)) + @use_tempdirs class MultiengineTestcase(unittest.TestCase): @@ -125,8 +130,8 @@ def test_multiengine_static(self): alloc_descent = prob.get_val('traj.descent.parameter_vals:throttle_allocations') assert_near_equal(alloc_climb[0], 0.5, tolerance=1e-2) - assert_near_equal(alloc_cruise[0], 0.64, tolerance=1e-2) - assert_near_equal(alloc_descent[0], 0.999, tolerance=1e-2) + assert_near_equal(alloc_cruise[0], 0.593, tolerance=1e-2) + assert_near_equal(alloc_descent[0], 0.408, tolerance=1e-2) @require_pyoptsparse(optimizer="SNOPT") def test_multiengine_dynamic(self): @@ -166,7 +171,7 @@ def test_multiengine_dynamic(self): alloc_descent = prob.get_val('traj.descent.controls:throttle_allocations') # Cruise is pretty constant, check exact value. - assert_near_equal(alloc_cruise[0], 0.646, tolerance=1e-2) + assert_near_equal(alloc_cruise[0], 0.595, tolerance=1e-2) # Check general trend: favors engine 1. self.assertGreater(alloc_climb[2], 0.55) diff --git a/aviary/validation_cases/validation_data/flops_data/full_mission_test_data.py b/aviary/validation_cases/validation_data/flops_data/full_mission_test_data.py index 02aca9e40..92086d0f6 100644 --- a/aviary/validation_cases/validation_data/flops_data/full_mission_test_data.py +++ b/aviary/validation_cases/validation_data/flops_data/full_mission_test_data.py @@ -62,55 +62,87 @@ data.set_val( # states:altitude Dynamic.Mission.ALTITUDE, - val=[29.3112920637369, 10668, 26.3564405194251, ], + val=[ + 29.3112920637369, + 10668, + 26.3564405194251, + ], units='m', ) data.set_val( # outputs Dynamic.Mission.ALTITUDE_RATE, - val=[29.8463233754212, -5.69941245767868E-09, -4.32644785970493, ], + val=[ + 29.8463233754212, + -5.69941245767868e-09, + -4.32644785970493, + ], units='ft/s', ) data.set_val( # outputs Dynamic.Mission.ALTITUDE_RATE_MAX, - val=[3679.0525544843, 3.86361517135375, 6557.07891846677, ], + val=[ + 3679.0525544843, + 3.86361517135375, + 6557.07891846677, + ], units='ft/min', ) data.set_val( # outputs - Dynamic.Mission.DRAG, - val=[9978.32211087097, 8769.90342254821, 7235.03338269778, ], + Dynamic.Vehicle.DRAG, + val=[ + 9978.32211087097, + 8769.90342254821, + 7235.03338269778, + ], units='lbf', ) data.set_val( # outputs - Dynamic.Mission.FUEL_FLOW_RATE, - val=[16602.302762413, 5551.61304633633, 1286, ], + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE, + val=[ + 16602.302762413, + 5551.61304633633, + 1286, + ], units='lbm/h', ) data.set_val( - Dynamic.Mission.MACH, - val=[0.482191004489294, 0.785, 0.345807620281699, ], + Dynamic.Atmosphere.MACH, + val=[ + 0.482191004489294, + 0.785, + 0.345807620281699, + ], units='unitless', ) data.set_val( # states:mass - Dynamic.Mission.MASS, - val=[81796.1389890711, 74616.9849763798, 65193.7423491884, ], + Dynamic.Vehicle.MASS, + val=[ + 81796.1389890711, + 74616.9849763798, + 65193.7423491884, + ], units='kg', ) # TODO: double check values data.set_val( - Dynamic.Mission.THROTTLE, - val=[0.5, 0.5, 0., ], + Dynamic.Vehicle.Propulsion.THROTTLE, + val=[ + 0.5, + 0.5, + 0.0, + ], units='unitless', ) @@ -131,28 +163,44 @@ data.set_val( # outputs Dynamic.Mission.SPECIFIC_ENERGY_RATE, - val=[18.4428113202544191, -1.7371801250963E-9, -5.9217623736010768, ], + val=[ + 18.4428113202544191, + -1.7371801250963e-9, + -5.9217623736010768, + ], units='m/s', ) data.set_val( # outputs Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, - val=[28.03523893220630, 3.8636151713537548, 28.706899839848, ], + val=[ + 28.03523893220630, + 3.8636151713537548, + 28.706899839848, + ], units='m/s', ) data.set_val( # outputs - Dynamic.Mission.THRUST_TOTAL, - val=[30253.9128379374, 8769.90342132054, 0, ], + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, + val=[ + 30253.9128379374, + 8769.90342132054, + 0, + ], units='lbf', ) data.set_val( # outputs - Dynamic.Mission.THRUST_MAX_TOTAL, - val=[40799.6009633346, 11500.32, 42308.2709683461, ], + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, + val=[ + 40799.6009633346, + 11500.32, + 42308.2709683461, + ], units='lbf', ) @@ -166,13 +214,21 @@ data.set_val( # states:velocity Dynamic.Mission.VELOCITY, - val=[164.029012458452, 232.775306059091, 117.638805929526, ], + val=[ + 164.029012458452, + 232.775306059091, + 117.638805929526, + ], units='m/s', ) data.set_val( # state_rates:velocity Dynamic.Mission.VELOCITY_RATE, - val=[0.558739800813549, 3.33665416459715E-17, -0.38372209277242, ], + val=[ + 0.558739800813549, + 3.33665416459715e-17, + -0.38372209277242, + ], units='m/s**2', ) diff --git a/aviary/validation_cases/validation_tests.py b/aviary/validation_cases/validation_tests.py index 9b6e25b23..bf27ac5e5 100644 --- a/aviary/validation_cases/validation_tests.py +++ b/aviary/validation_cases/validation_tests.py @@ -12,6 +12,7 @@ from aviary.utils.preprocessors import preprocess_options from aviary.validation_cases.validation_data.flops_data.FLOPS_Test_Data import \ FLOPS_Test_Data, FLOPS_Lacking_Test_Data +from aviary.variable_info.functions import extract_options from aviary.variable_info.variables import Aircraft Version = Enum('Version', ['ALL', 'TRANSPORT', 'ALTERNATE', 'BWB']) @@ -272,6 +273,9 @@ def get_flops_data(case_name: str, keys: str = None, preprocess: bool = False) - keys : str, or iter of str List of variables whose values will be transferred from the validation data. The default is all variables. + preprocess: bool + If true, the input data will be passed through preprocess_options() to + fill in any missing options before being returned. The default is False. """ flops_data_copy: AviaryValues = get_flops_inputs(case_name, preprocess=preprocess) flops_data_copy.update(get_flops_outputs(case_name)) @@ -314,6 +318,40 @@ def get_flops_inputs(case_name: str, keys: str = None, preprocess: bool = False) return AviaryValues({key: flops_inputs_copy.get_item(key) for key in keys_list}) +def get_flops_options(case_name: str, keys: str = None, preprocess: bool = False) -> AviaryValues: + """ + Returns a dictionary containing options for the named FLOPS validation case. + + Parameters + ---------- + case_name : str + Name of the case being run. Input data will be looked up from + the corresponding case in the FLOPS validation data collection. + keys : str, or iter of str + List of variables whose values will be transferred from the input data. + The default is all variables. + preprocess: bool + If true, the input data will be passed through preprocess_options() to + fill in any missing options before being returned. The default is False. + """ + try: + flops_data: dict = FLOPS_Test_Data[case_name] + except KeyError: + flops_data: dict = FLOPS_Lacking_Test_Data[case_name] + + flops_inputs_copy: AviaryValues = flops_data['inputs'].deepcopy() + if preprocess: + preprocess_options(flops_inputs_copy, + engine_models=build_engine_deck(flops_inputs_copy)) + + if keys is None: + options = extract_options(flops_inputs_copy) + else: + options = extract_options(keys) + + return options + + def get_flops_outputs(case_name: str, keys: str = None) -> AviaryValues: """ Returns an AviaryValues object containing output data for the named FLOPS validation case. diff --git a/aviary/variable_info/enums.py b/aviary/variable_info/enums.py index e4583609f..e2d2edaff 100644 --- a/aviary/variable_info/enums.py +++ b/aviary/variable_info/enums.py @@ -68,7 +68,7 @@ class GASPEngineType(Enum): """ Defines the type of engine to use in GASP-based mass calculations. Note that only the value for the first engine model will be used. - Currenly only the TURBOJET option is implemented, but other types of engines will be added in the future. + Currenly only the TURBOJET and TURBOPROP options are implemented, but other types of engines will be added in the future. """ # Reciprocating engine with carburator RECIP_CARB = 1 @@ -151,10 +151,18 @@ class ProblemType(Enum): weight and empty weight constant. Using the specified actual gross weight, it will then find the maximum distance the off-design aircraft can fly. + + MULTI_MISSION: Similar to a SIZING mission, however it varies the + design gross weight and actual gross weight across multiple missions + to and closes design range for each mission. This causes the empty + weight and the fuel weight to change. The final result will be a + single empty weight, for all the different missions, and multiple + values for fuel weight, unique to each mission. """ SIZING = 'sizing' ALTERNATE = 'alternate' FALLOUT = 'fallout' + MULTI_MISSION = 'multimission' class SpeedType(Enum): diff --git a/aviary/variable_info/functions.py b/aviary/variable_info/functions.py index 8c28147a0..9961ae891 100644 --- a/aviary/variable_info/functions.py +++ b/aviary/variable_info/functions.py @@ -1,10 +1,15 @@ -import dymos as dm +from enum import Enum + +import numpy as np + import openmdao.api as om -from dymos.utils.misc import _unspecified from openmdao.core.component import Component +from openmdao.utils.units import convert_units +import dymos as dm +from dymos.utils.misc import _unspecified from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Settings +from aviary.variable_info.variables import Aircraft, Settings from aviary.variable_info.variable_meta_data import _MetaData # --------------------------- @@ -12,14 +17,35 @@ # --------------------------- -def add_aviary_input(comp, varname, val=None, units=None, desc=None, shape_by_conn=False, meta_data=_MetaData, shape=None): - ''' +def add_aviary_input(comp, varname, val=None, units=None, desc=None, shape_by_conn=False, + meta_data=_MetaData, shape=None): + """ This function provides a clean way to add variables from the variable hierarchy into components as Aviary inputs. It takes the standard OpenMDAO inputs of the variable's name, initial value, units, and description, as well as the component which the variable is being added to. - ''' + + Parameters + ---------- + comp: Component + OpenMDAO component to add this variable. + varname: str + Name of variable. + val: float or ndarray + Default value for variable. + units: str + (Optional) when speficying val, units should also be specified. + desc: str + (Optional) description text for the variable. + shape_by_conn: bool + Set to True to infer the shape from the connected output. + meta_data: dict + (Optional) Aviary metadata dictionary. If unspecified, the built-in metadata will + be used. + shape: tuple + (Optional) shape for this input. + """ meta = meta_data[varname] if units: input_units = units @@ -38,14 +64,34 @@ def add_aviary_input(comp, varname, val=None, units=None, desc=None, shape_by_co desc=input_desc, shape_by_conn=shape_by_conn, shape=shape) -def add_aviary_output(comp, varname, val, units=None, desc=None, shape_by_conn=False, meta_data=_MetaData): - ''' +def add_aviary_output(comp, varname, val, units=None, desc=None, shape_by_conn=False, + meta_data=_MetaData): + """ This function provides a clean way to add variables from the variable hierarchy into components as Aviary outputs. It takes the standard OpenMDAO inputs of the variable's name, initial value, units, and description, as well as the component which the variable is being added to. - ''' + + Parameters + ---------- + comp: Component + OpenMDAO component to add this variable. + varname: str + Name of variable. + val: float or ndarray + (Optional) Default value for variable. If not specified, the value from metadata + is used. + units: str + (Optional) when speficying val, units should also be specified. + desc: str + (Optional) description text for the variable. + shape_by_conn: bool + Set to True to infer the shape from the connected output. + meta_data: dict + (Optional) Aviary metadata dictionary. If unspecified, the built-in metadata will + be used. + """ meta = meta_data[varname] if units: output_units = units @@ -62,6 +108,130 @@ def add_aviary_output(comp, varname, val, units=None, desc=None, shape_by_conn=F desc=output_desc, shape_by_conn=shape_by_conn) +def units_setter(opt_meta, value): + """ + Check and convert new units tuple into + + Parameters + ---------- + opt_meta : dict + Dictionary of entries for the option. + value : any + New value for the option. + + Returns + ------- + any + Post processed value to set into the option. + """ + new_val, new_units = value + old_val, units = opt_meta['val'] + + converted_val = convert_units(new_val, new_units, units) + return (converted_val, units) + + +def int_enum_setter(opt_meta, value): + """ + Support setting the option with a string or int and converting it to the + proper enum object. + + Parameters + ---------- + opt_meta : dict + Dictionary of entries for the option. + value : any + New value for the option. + + Returns + ------- + any + Post processed value to set into the option. + """ + types = opt_meta['types'] + for type_ in types: + if type_ not in (list, np.ndarray): + enum_class = type_ + break + + if isinstance(value, Enum): + return value + + elif isinstance(value, int): + return enum_class(value) + + elif isinstance(value, str): + return getattr(enum_class, value) + + elif isinstance(value, list): + values = [] + for val in value: + if isinstance(val, Enum): + values.append(val) + elif isinstance(val, int): + values.append(enum_class(val)) + elif isinstance(val, str): + values.append(getattr(enum_class, val)) + else: + break + else: + return values + + msg = f"Value '{value}' not valid for option with types {enum_class}" + raise TypeError(msg) + + +def add_aviary_option(comp, name, val=_unspecified, units=None, desc=None, meta_data=_MetaData): + """ + Adds an option to an Aviary component. Default values from the metadata are used + unless a new value is specified. + + Parameters + ---------- + comp: Component + OpenMDAO component to add this option. + name: str + Name of variable. + val: float or ndarray + (Optional) Default value for option. If not specified, the value from metadata + is used. + desc: str + (Optional) description text for the variable. + units: str + (Optional) OpenMDAO units string. This can be specified for variables with units. + meta_data: dict + (Optional) Aviary metadata dictionary. If unspecified, the built-in metadata will + be used. + """ + meta = meta_data[name] + if not desc: + desc = meta['desc'] + if val is _unspecified: + val = meta['default_value'] + + types = meta['types'] + if meta['multivalue']: + if isinstance(types, tuple): + types = (list, *types) + else: + types = (list, types) + + if units not in [None, 'unitless']: + types = tuple + comp.options.declare(name, default=(val, units), + types=types, desc=desc, + set_function=units_setter) + + elif isinstance(val, Enum): + comp.options.declare(name, default=val, + types=types, desc=desc, + set_function=int_enum_setter) + + else: + comp.options.declare(name, default=val, + types=types, desc=desc) + + def override_aviary_vars(group: om.Group, aviary_inputs: AviaryValues, manual_overrides=None, external_overrides=None): ''' @@ -256,3 +426,104 @@ def get_units(key, meta_data=None) -> str: meta_data = _MetaData return meta_data[key]['units'] + + +def extract_options(aviary_inputs: AviaryValues, metadata=_MetaData) -> dict: + """ + Extract a dictionary of options from the given aviary_inputs. + + Parameters + ---------- + aviary_inputs : AviaryValues + Instance of AviaryValues containing all initial values. + meta_data : dict + (Optional) Dictionary of aircraft metadata. Uses Aviary's built-in + metadata by default. + + Returns + ------- + dict + Dictionary of option names and values. + """ + options = {} + for key, meta in metadata.items(): + + if key not in aviary_inputs: + continue + + if not meta['option']: + continue + + val, units = aviary_inputs.get_item(key) + meta_units = meta['units'] + + if meta_units == 'unitless' or meta_units is None: + options[key] = val + + else: + # Implement as (quanitity, unit) + options[key] = (val, units) + + return options + + +def setup_model_options(prob: om.Problem, aviary_inputs: AviaryValues, + meta_data=_MetaData, engine_models=None, prefix=''): + """ + Setup the correct model options for an aviary problem. + + Parameters + ---------- + prob: Problem + OpenMDAO problem prior to setup. + aviary_inputs : AviaryValues + Instance of AviaryValues containing all initial values. + meta_data : dict + (Optional) Dictionary of aircraft metadata. Uses Aviary's built-in + metadata by default. + engine_models : List of EngineModels or None + (Optional) Engine models + prefix : str + Prefix for model options. Used for multi-mission. + """ + + # Use OpenMDAO's model options to pass all options through the system hierarchy. + prob.model_options[f'{prefix}*'] = extract_options(aviary_inputs, + meta_data) + + # Multi-engines need to index into their options. + try: + num_engine_models = len(aviary_inputs.get_val(Aircraft.Engine.NUM_ENGINES)) + except KeyError: + # No engine data. + return + + if num_engine_models > 1: + + if engine_models is None: + engine_models = prob.engine_builders + + for idx in range(num_engine_models): + eng_name = engine_models[idx].name + + # TODO: For future flexibility, need to tag the required engine options. + opt_names = [ + Aircraft.Engine.SCALE_PERFORMANCE, + Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, + Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, + Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, + Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, + ] + opt_names_units = [ + Aircraft.Engine.REFERENCE_SLS_THRUST, + Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, + ] + opts = {} + for key in opt_names: + opts[key] = aviary_inputs.get_item(key)[0][idx] + for key in opt_names_units: + val, units = aviary_inputs.get_item(key) + opts[key] = (val[idx], units) + + path = f"{prefix}*core_propulsion.{eng_name}*" + prob.model_options[path] = opts diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 06b2c52fb..b0c71ccfc 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -1,13 +1,21 @@ ''' Define meta data associated with variables in the Aviary data hierarchy. ''' + import numpy as np from copy import deepcopy from pathlib import Path from aviary.utils.develop_metadata import add_meta_data -from aviary.variable_info.enums import EquationsOfMotion, FlapType, GASPEngineType, LegacyCode, Verbosity, ProblemType +from aviary.variable_info.enums import ( + EquationsOfMotion, + FlapType, + GASPEngineType, + LegacyCode, + Verbosity, + ProblemType, +) from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings # --------------------------- @@ -51,13 +59,15 @@ # - see also: Aircraft.AirConditioning.MASS_SCALER Aircraft.AirConditioning.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(23, 2)', '~WEIGHT.WAC', '~WTSTAT.WSP(23, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._air_conditioning_group_weight', - 'aircraft.outputs.L0_weights_summary.air_conditioning_group_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(23, 2)', '~WEIGHT.WAC', '~WTSTAT.WSP(23, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._air_conditioning_group_weight', + 'aircraft.outputs.L0_weights_summary.air_conditioning_group_weight', + ], + }, units='lbm', desc='air conditioning system mass', default_value=None, @@ -66,10 +76,7 @@ add_meta_data( Aircraft.AirConditioning.MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(6)', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CW(6)', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='mass trend coefficient of air conditioning', default_value=1.0, @@ -78,11 +85,12 @@ add_meta_data( Aircraft.AirConditioning.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WAC', 'MISWT.WAC', 'MISWT.OAC'], - "FLOPS": 'WTIN.WAC', - "LEAPS1": 'aircraft.inputs.L0_overrides.air_conditioning_group_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WAC', 'MISWT.WAC', 'MISWT.OAC'], + "FLOPS": 'WTIN.WAC', + "LEAPS1": 'aircraft.inputs.L0_overrides.air_conditioning_group_weight', + }, units='unitless', desc='air conditioning system mass scaler', default_value=1.0, @@ -103,13 +111,15 @@ # - see also: Aircraft.AntiIcing.MASS_SCALER Aircraft.AntiIcing.MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(7)', - # ['WTS.WSP(24, 2)', '~WEIGHT.WAI', '~WTSTAT.WSP(24, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._aux_gear_weight', - 'aircraft.outputs.L0_weights_summary.aux_gear_weight', - ] - }, + historical_name={ + "GASP": 'INGASP.CW(7)', + # ['WTS.WSP(24, 2)', '~WEIGHT.WAI', '~WTSTAT.WSP(24, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._aux_gear_weight', + 'aircraft.outputs.L0_weights_summary.aux_gear_weight', + ], + }, units='lbm', desc='mass of anti-icing system (auxiliary gear)', default_value=None, @@ -118,11 +128,12 @@ add_meta_data( Aircraft.AntiIcing.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WAI', 'MISWT.WAI', 'MISWT.OAI'], - "FLOPS": 'WTIN.WAI', - "LEAPS1": 'aircraft.inputs.L0_overrides.aux_gear_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WAI', 'MISWT.WAI', 'MISWT.OAI'], + "FLOPS": 'WTIN.WAI', + "LEAPS1": 'aircraft.inputs.L0_overrides.aux_gear_weight', + }, units='unitless', desc='anti-icing system mass scaler', default_value=1.0, @@ -141,13 +152,15 @@ # - see also: Aircraft.APU.MASS_SCALER Aircraft.APU.MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(1)', - # ['WTS.WSP(17, 2)', '~WEIGHT.WAPU', '~WTSTAT.WSP(17, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._aux_power_weight', - 'aircraft.outputs.L0_weights_summary.aux_power_weight', - ] - }, + historical_name={ + "GASP": 'INGASP.CW(1)', + # ['WTS.WSP(17, 2)', '~WEIGHT.WAPU', '~WTSTAT.WSP(17, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._aux_power_weight', + 'aircraft.outputs.L0_weights_summary.aux_power_weight', + ], + }, units='lbm', desc='mass of auxiliary power unit', default_value=None, @@ -156,11 +169,12 @@ add_meta_data( Aircraft.APU.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WAPU', 'MISWT.WAPU', 'MISWT.OAPU'], - "FLOPS": 'WTIN.WAPU', - "LEAPS1": 'aircraft.inputs.L0_overrides.aux_power_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WAPU', 'MISWT.WAPU', 'MISWT.OAPU'], + "FLOPS": 'WTIN.WAPU', + "LEAPS1": 'aircraft.inputs.L0_overrides.aux_power_weight', + }, units='unitless', desc='mass scaler for auxiliary power unit', default_value=1.0, @@ -179,13 +193,15 @@ # - see also: Aircraft.Avionics.MASS_SCALER Aircraft.Avionics.MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(5)', - # ['WTS.WSP(21, 2)', '~WEIGHT.WAVONC', '~WTSTAT.WSP(21, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._avionics_group_weight', - 'aircraft.outputs.L0_weights_summary.avionics_group_weight', - ] - }, + historical_name={ + "GASP": 'INGASP.CW(5)', + # ['WTS.WSP(21, 2)', '~WEIGHT.WAVONC', '~WTSTAT.WSP(21, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._avionics_group_weight', + 'aircraft.outputs.L0_weights_summary.avionics_group_weight', + ], + }, units='lbm', desc='avionics mass', default_value=None, @@ -194,11 +210,12 @@ add_meta_data( Aircraft.Avionics.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WAVONC', 'MISWT.WAVONC', 'MISWT.OAVONC'], - "FLOPS": 'WTIN.WAVONC', - "LEAPS1": 'aircraft.inputs.L0_overrides.avionics_group_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WAVONC', 'MISWT.WAVONC', 'MISWT.OAVONC'], + "FLOPS": 'WTIN.WAVONC', + "LEAPS1": 'aircraft.inputs.L0_overrides.avionics_group_weight', + }, units='unitless', desc='avionics mass scaler', default_value=1.0, @@ -216,10 +233,11 @@ add_meta_data( Aircraft.Battery.ADDITIONAL_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": 'aircraft.inputs.L0_battery.weight_offset' - }, + historical_name={ + "GASP": None, + "FLOPS": None, + "LEAPS1": 'aircraft.inputs.L0_battery.weight_offset', + }, units='lbm', desc='mass of non energy-storing parts of the battery', default_value=0.0, @@ -228,13 +246,14 @@ add_meta_data( Aircraft.Battery.DISCHARGE_LIMIT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SOCMIN', - "FLOPS": None, - "LEAPS1": 'aircraft.inputs.L0_battery.depth_of_discharge' - }, + historical_name={ + "GASP": 'INGASP.SOCMIN', + "FLOPS": None, + "LEAPS1": 'aircraft.inputs.L0_battery.depth_of_discharge', + }, units='unitless', desc='default constraint on how far the battery can discharge, as a proportion of ' - 'total energy capacity', + 'total energy capacity', default_value=0.2, ) @@ -250,21 +269,19 @@ add_meta_data( Aircraft.Battery.ENERGY_CAPACITY, meta_data=_MetaData, - historical_name={"GASP": 'EBATTAVL', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'EBATTAVL', "FLOPS": None, "LEAPS1": None}, units='kJ', - desc="total energy the battery can store" + desc="total energy the battery can store", ) add_meta_data( Aircraft.Battery.MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WBATTIN', - "FLOPS": None, - "LEAPS1": 'aircraft.inputs.L0_battery.weight' - }, + historical_name={ + "GASP": 'INGASP.WBATTIN', + "FLOPS": None, + "LEAPS1": 'aircraft.inputs.L0_battery.weight', + }, units='lbm', desc='total mass of the battery', default_value=0.0, @@ -273,10 +290,11 @@ add_meta_data( Aircraft.Battery.PACK_ENERGY_DENSITY, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ENGYDEN', - "FLOPS": None, - "LEAPS1": 'aircraft.inputs.L0_battery.energy_density' - }, + historical_name={ + "GASP": 'INGASP.ENGYDEN', + "FLOPS": None, + "LEAPS1": 'aircraft.inputs.L0_battery.energy_density', + }, units='kW*h/kg', desc='specific energy density of the battery pack', default_value=1.0, @@ -286,10 +304,7 @@ add_meta_data( Aircraft.Battery.PACK_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='mass of the energy-storing components of the battery', default_value=0.0, @@ -298,10 +313,7 @@ add_meta_data( Aircraft.Battery.PACK_VOLUMETRIC_DENSITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='kW*h/L', desc='volumetric density of the battery pack', default_value=0, @@ -310,10 +322,7 @@ add_meta_data( Aircraft.Battery.VOLUME, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='ft*3', desc='total volume of the battery pack', default_value=0.0, @@ -333,13 +342,15 @@ add_meta_data( Aircraft.BWB.CABIN_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.FUSEIN.ACABIN', 'WDEF.ACABIN'], - "FLOPS": 'FUSEIN.ACABIN', - "LEAPS1": ['aircraft.inputs.L0_blended_wing_body_design.cabin_area', - 'aircraft.cached.L0_blended_wing_body_design.cabin_area', - ] - }, + historical_name={ + "GASP": None, + # ['&DEFINE.FUSEIN.ACABIN', 'WDEF.ACABIN'], + "FLOPS": 'FUSEIN.ACABIN', + "LEAPS1": [ + 'aircraft.inputs.L0_blended_wing_body_design.cabin_area', + 'aircraft.cached.L0_blended_wing_body_design.cabin_area', + ], + }, units='ft**2', desc='fixed area of passenger cabin for blended wing body transports', default_value=0.0, @@ -348,12 +359,14 @@ add_meta_data( Aircraft.BWB.NUM_BAYS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'FUSEIN.NBAY', # ['&DEFINE.FUSEIN.NBAY', 'FUSDTA.NBAY'], - "LEAPS1": ['aircraft.inputs.L0_blended_wing_body_design.bay_count', - 'aircraft.cached.L0_blended_wing_body_design.bay_count', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'FUSEIN.NBAY', # ['&DEFINE.FUSEIN.NBAY', 'FUSDTA.NBAY'], + "LEAPS1": [ + 'aircraft.inputs.L0_blended_wing_body_design.bay_count', + 'aircraft.cached.L0_blended_wing_body_design.bay_count', + ], + }, units='unitless', desc='fixed number of bays', types=int, @@ -364,11 +377,12 @@ add_meta_data( Aircraft.BWB.PASSENGER_LEADING_EDGE_SWEEP, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.FUSEIN.SWPLE', 'FUSDTA.SWPLE'], - "FLOPS": 'FUSEIN.SWPLE', - "LEAPS1": 'aircraft.inputs.L0_blended_wing_body_design.passenger_leading_edge_sweep' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.FUSEIN.SWPLE', 'FUSDTA.SWPLE'], + "FLOPS": 'FUSEIN.SWPLE', + "LEAPS1": 'aircraft.inputs.L0_blended_wing_body_design.passenger_leading_edge_sweep', + }, units='deg', desc='sweep angle of the leading edge of the passenger cabin', default_value=45.0, @@ -384,10 +398,11 @@ add_meta_data( Aircraft.Canard.AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.SCAN', # ['&DEFINE.WTIN.SCAN', 'EDETIN.SCAN'], - "LEAPS1": 'aircraft.inputs.L0_canard.area' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.SCAN', # ['&DEFINE.WTIN.SCAN', 'EDETIN.SCAN'], + "LEAPS1": 'aircraft.inputs.L0_canard.area', + }, units='ft**2', desc='canard theoretical area', default_value=0.0, @@ -396,10 +411,11 @@ add_meta_data( Aircraft.Canard.ASPECT_RATIO, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.ARCAN', # ['&DEFINE.WTIN.ARCAN', 'EDETIN.ARCAN'], - "LEAPS1": 'aircraft.inputs.L0_canard.aspect_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.ARCAN', # ['&DEFINE.WTIN.ARCAN', 'EDETIN.ARCAN'], + "LEAPS1": 'aircraft.inputs.L0_canard.aspect_ratio', + }, units='unitless', desc='canard theoretical aspect ratio', default_value=None, @@ -408,36 +424,41 @@ add_meta_data( Aircraft.Canard.CHARACTERISTIC_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.EL[-1]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[-1]', - 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[-1]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.EL[-1]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[-1]', + 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[-1]', + ], + }, units='ft', - desc='Reynolds characteristic length for the canard' + desc='Reynolds characteristic length for the canard', ) add_meta_data( Aircraft.Canard.FINENESS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.FR[-1]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[-1]', - 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[-1]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.FR[-1]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[-1]', + 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[-1]', + ], + }, units='unitless', - desc='canard fineness ratio' + desc='canard fineness ratio', ) add_meta_data( Aircraft.Canard.LAMINAR_FLOW_LOWER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRLC', # ['&DEFINE.AERIN.TRLC', 'XLAM.TRLC', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.canard_percent_laminar_flow_lower_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRLC', # ['&DEFINE.AERIN.TRLC', 'XLAM.TRLC', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.canard_percent_laminar_flow_lower_surface', + }, units='unitless', desc='define percent laminar flow for canard lower surface', default_value=0.0, @@ -446,10 +467,11 @@ add_meta_data( Aircraft.Canard.LAMINAR_FLOW_UPPER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRUC', # ['&DEFINE.AERIN.TRUC', 'XLAM.TRUC', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.canard_percent_laminar_flow_upper_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRUC', # ['&DEFINE.AERIN.TRUC', 'XLAM.TRUC', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.canard_percent_laminar_flow_upper_surface', + }, units='unitless', desc='define percent laminar flow for canard upper surface', default_value=0.0, @@ -460,13 +482,15 @@ # - see also: Aircraft.Canard.MASS_SCALER Aircraft.Canard.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(5, 2)', '~WEIGHT.WCAN', '~WTSTAT.WSP(5, 2)', '~INERT.WCAN'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._canard_weight', - 'aircraft.outputs.L0_weights_summary.canard_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(5, 2)', '~WEIGHT.WCAN', '~WTSTAT.WSP(5, 2)', '~INERT.WCAN'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._canard_weight', + 'aircraft.outputs.L0_weights_summary.canard_weight', + ], + }, units='lbm', desc='mass of canards', default_value=None, @@ -475,10 +499,11 @@ add_meta_data( Aircraft.Canard.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRCAN', # ['&DEFINE.WTIN.FRCAN', 'WTS.FRCAN', ], - "LEAPS1": 'aircraft.inputs.L0_overrides.canard_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRCAN', # ['&DEFINE.WTIN.FRCAN', 'WTS.FRCAN', ], + "LEAPS1": 'aircraft.inputs.L0_overrides.canard_weight', + }, units='unitless', desc='mass scaler for canard structure', default_value=1.0, @@ -487,10 +512,11 @@ add_meta_data( Aircraft.Canard.TAPER_RATIO, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.TRCAN', # ['&DEFINE.WTIN.TRCAN', 'WTS.TRCAN'], - "LEAPS1": 'aircraft.inputs.L0_canard.taper_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.TRCAN', # ['&DEFINE.WTIN.TRCAN', 'WTS.TRCAN'], + "LEAPS1": 'aircraft.inputs.L0_canard.taper_ratio', + }, units='unitless', desc='canard theoretical taper ratio', default_value=None, @@ -499,10 +525,11 @@ add_meta_data( Aircraft.Canard.THICKNESS_TO_CHORD, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.TCCAN', # ['&DEFINE.WTIN.TCCAN', 'EDETIN.TCCAN'], - "LEAPS1": 'aircraft.inputs.L0_canard.thickness_to_chord_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.TCCAN', # ['&DEFINE.WTIN.TCCAN', 'EDETIN.TCCAN'], + "LEAPS1": 'aircraft.inputs.L0_canard.thickness_to_chord_ratio', + }, units='unitless', desc='canard thickness-chord ratio', default_value=0.0, @@ -513,15 +540,17 @@ # - see also: Aircraft.Canard.WETTED_AREA_SCALER Aircraft.Canard.WETTED_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['ACTWET.SWTCN', 'MISSA.SWET[-1]'], - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.canard_wetted_area', - 'aircraft.outputs.L0_aerodynamics' - '.mission_component_wetted_area_table[-1]', - 'aircraft.cached.L0_aerodynamics' - '.mission_component_wetted_area_table[-1]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['ACTWET.SWTCN', 'MISSA.SWET[-1]'], + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.canard_wetted_area', + 'aircraft.outputs.L0_aerodynamics' + '.mission_component_wetted_area_table[-1]', + 'aircraft.cached.L0_aerodynamics' + '.mission_component_wetted_area_table[-1]', + ], + }, units='ft**2', desc='canard wetted area', default_value=None, @@ -530,10 +559,11 @@ add_meta_data( Aircraft.Canard.WETTED_AREA_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.SWETC', # ['&DEFINE.AERIN.SWETC', 'AWETO.SWETC', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.canard_wetted_area' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.SWETC', # ['&DEFINE.AERIN.SWETC', 'AWETO.SWETC', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.canard_wetted_area', + }, units='unitless', desc='canard wetted area scaler', default_value=1.0, @@ -550,10 +580,7 @@ add_meta_data( Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CK15', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CK15', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='technology factor on cockpit controls mass', default_value=1.0, @@ -562,10 +589,7 @@ add_meta_data( Aircraft.Controls.CONTROL_MASS_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELWFC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELWFC', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='incremental flight controls mass', default_value=0, @@ -574,10 +598,7 @@ add_meta_data( Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKSAS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKSAS', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='mass of stability augmentation system', default_value=0, @@ -586,10 +607,7 @@ add_meta_data( Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CK19', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CK19', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='technology factor on stability augmentation system mass', default_value=1, @@ -598,10 +616,7 @@ add_meta_data( Aircraft.Controls.TOTAL_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WFC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WFC', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='total mass of cockpit controls, fixed wing controls, and SAS', ) @@ -619,24 +634,27 @@ add_meta_data( Aircraft.CrewPayload.BAGGAGE_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(35,2)', '~WEIGHT.WPBAG', '~WTSTAT.WSP(35,2)', '~INERT.WPBAG'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._passenger_bag_weight', - 'aircraft.outputs.L0_weights_summary.passenger_bag_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(35,2)', '~WEIGHT.WPBAG', '~WTSTAT.WSP(35,2)', '~INERT.WPBAG'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._passenger_bag_weight', + 'aircraft.outputs.L0_weights_summary.passenger_bag_weight', + ], + }, units='lbm', - desc='mass of passenger baggage' + desc='mass of passenger baggage', ) add_meta_data( Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.BPP', # ['&DEFINE.WTIN.BPP', 'WPAB.BPP'], - "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.baggage_weight_per_passenger' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.BPP', # ['&DEFINE.WTIN.BPP', 'WPAB.BPP'], + "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.baggage_weight_per_passenger', + }, units='lbm', desc='baggage mass per passenger', option=True, @@ -648,13 +666,15 @@ # - see also: Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER Aircraft.CrewPayload.CARGO_CONTAINER_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(32,2)', '~WEIGHT.WCON', '~WTSTAT.WSP(32,2)', '~INERT.WCON',], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._cargo_containers_weight', - 'aircraft.outputs.L0_weights_summary.cargo_containers_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(32,2)', '~WEIGHT.WCON', '~WTSTAT.WSP(32,2)', '~INERT.WCON',], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._cargo_containers_weight', + 'aircraft.outputs.L0_weights_summary.cargo_containers_weight', + ], + }, units='lbm', desc='mass of cargo containers', default_value=None, @@ -663,11 +683,12 @@ add_meta_data( Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WCON', 'MISWT.WCON', 'MISWT.OCON'], - "FLOPS": 'WTIN.WCON', - "LEAPS1": 'aircraft.inputs.L0_overrides.cargo_containers_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WCON', 'MISWT.WCON', 'MISWT.OCON'], + "FLOPS": 'WTIN.WCON', + "LEAPS1": 'aircraft.inputs.L0_overrides.cargo_containers_weight', + }, units='unitless', desc='Scaler for mass of cargo containers', default_value=1.0, @@ -676,41 +697,110 @@ add_meta_data( Aircraft.CrewPayload.CARGO_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WCARGO', - # ['WTS.WSP(36,2)', '~WEIGHT.WCARGO', '~WTSTAT.WSP(36,2)', '~INERT.WCARGO',], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._cargo_weight', - 'aircraft.outputs.L0_weights_summary.cargo_weight', - ] - }, + historical_name={ + "GASP": 'INGASP.WCARGO', + # ['WTS.WSP(36,2)', '~WEIGHT.WCARGO', '~WTSTAT.WSP(36,2)', '~INERT.WCARGO',], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._cargo_weight', + 'aircraft.outputs.L0_weights_summary.cargo_weight', + ], + }, units='lbm', - desc='total mass of cargo' + desc='total mass of cargo', ) add_meta_data( Aircraft.CrewPayload.CATERING_ITEMS_MASS_PER_PASSENGER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(12)', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CW(12)', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='mass of catering items per passenger', default_value=0.7, ) +# ___ _ +# | \ ___ ___ (_) __ _ _ _ +# | |) | / -_) (_-< | | / _` | | ' \ +# |___/ \___| /__/ |_| \__, | |_||_| +# ====================== |___/ ====== + +add_meta_data( + Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, + meta_data=_MetaData, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.NPB', # ['&DEFINE.WTIN.NPB', 'WTS.NPB'], + "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.business_class_count', + }, + units='unitless', + desc='number of business class passengers that the aircraft is designed to accommodate', + types=int, + option=True, + default_value=0, # AviaryValues.get_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS), +) + +add_meta_data( + Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, + meta_data=_MetaData, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.NPF', # ['&DEFINE.WTIN.NPF', 'WTS.NPF'], + "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.first_class_count', + }, + units='unitless', + desc='number of first class passengers that the aircraft is designed to accommodate', + types=int, + option=True, + default_value=0, +) + +add_meta_data( + Aircraft.CrewPayload.Design.NUM_PASSENGERS, + meta_data=_MetaData, + historical_name={ + "GASP": 'INGASP.PAX', # number of passenger seats excluding crew + "FLOPS": None, # ['CSTDAT.NSV', '~WEIGHT.NPASS', '~WTSTAT.NPASS'], + "LEAPS1": 'aircraft.outputs.L0_crew_and_payload.passenger_count', + }, + units='unitless', + desc='total number of passengers that the aircraft is designed to accommodate', + option=True, + default_value=0, + types=int, +) + + +# TODO rename to economy? +add_meta_data( + Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, + meta_data=_MetaData, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.NPT', # ['&DEFINE.WTIN.NPT', 'WTS.NPT'], + "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.tourist_class_count', + }, + units='unitless', + desc='number of tourist class passengers that the aircraft is designed to accommodate', + types=int, + option=True, + default_value=0, +) + add_meta_data( # Note user override # - see also: Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER Aircraft.CrewPayload.FLIGHT_CREW_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(27, 2)', '~WEIGHT.WFLCRB', '~WTSTAT.WSP(27, 2)', '~INERT.WFLCRB'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._flight_crew_and_bag_weight', - 'aircraft.outputs.L0_weights_summary.flight_crew_and_bag_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(27, 2)', '~WEIGHT.WFLCRB', '~WTSTAT.WSP(27, 2)', '~INERT.WFLCRB'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._flight_crew_and_bag_weight', + 'aircraft.outputs.L0_weights_summary.flight_crew_and_bag_weight', + ], + }, units='lbm', desc='total mass of the flight crew and their baggage', default_value=None, @@ -719,11 +809,12 @@ add_meta_data( Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WFLCRB', 'MISWT.WFLCRB', 'MISWT.OFLCRB'], - "FLOPS": 'WTIN.WFLCRB', - "LEAPS1": 'aircraft.inputs.L0_overrides.flight_crew_and_bag_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WFLCRB', 'MISWT.WFLCRB', 'MISWT.OFLCRB'], + "FLOPS": 'WTIN.WFLCRB', + "LEAPS1": 'aircraft.inputs.L0_overrides.flight_crew_and_bag_weight', + }, units='unitless', desc='scaler for total mass of the flight crew and their baggage', default_value=1.0, @@ -732,10 +823,11 @@ add_meta_data( Aircraft.CrewPayload.MASS_PER_PASSENGER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.WPPASS', # ['&DEFINE.WTIN.WPPASS', 'WPAB.WPPASS'], - "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.weight_per_passenger' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.WPPASS', # ['&DEFINE.WTIN.WPPASS', 'WPAB.WPPASS'], + "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.weight_per_passenger', + }, units='lbm', desc='mass per passenger', option=True, @@ -745,10 +837,11 @@ add_meta_data( Aircraft.CrewPayload.MISC_CARGO, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.CARGOF', # ['&DEFINE.WTIN.CARGOF', 'WTS.CARGOF'], - "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.misc_cargo' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.CARGOF', # ['&DEFINE.WTIN.CARGOF', 'WTS.CARGOF'], + "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.misc_cargo', + }, units='lbm', desc='cargo (other than passenger baggage) carried in fuselage', default_value=0.0, @@ -759,13 +852,15 @@ # - see also: Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(28,2)', '~WEIGHT.WSTUAB', '~WTSTAT.WSP(28, 2)', '~INERT.WSTUAB'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._cabin_crew_and_bag_weight', - 'aircraft.outputs.L0_weights_summary.cabin_crew_and_bag_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(28,2)', '~WEIGHT.WSTUAB', '~WTSTAT.WSP(28, 2)', '~INERT.WSTUAB'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._cabin_crew_and_bag_weight', + 'aircraft.outputs.L0_weights_summary.cabin_crew_and_bag_weight', + ], + }, units='lbm', desc='total mass of the non-flight crew and their baggage', default_value=None, @@ -774,11 +869,12 @@ add_meta_data( Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WSTUAB', 'MISWT.WSTUAB', 'MISWT.OSTUAB'], - "FLOPS": 'WTIN.WSTUAB', - "LEAPS1": 'aircraft.inputs.L0_overrides.cabin_crew_and_bag_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WSTUAB', 'MISWT.WSTUAB', 'MISWT.OSTUAB'], + "FLOPS": 'WTIN.WSTUAB', + "LEAPS1": 'aircraft.inputs.L0_overrides.cabin_crew_and_bag_weight', + }, units='unitless', desc='scaler for total mass of the non-flight crew and their baggage', default_value=1.0, @@ -787,10 +883,11 @@ add_meta_data( Aircraft.CrewPayload.NUM_BUSINESS_CLASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.NPB', # ['&DEFINE.WTIN.NPB', 'WTS.NPB'], - "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.business_class_count' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['&DEFINE.WTIN.NPB', 'WTS.NPB'], + "LEAPS1": None, # 'aircraft.inputs.L0_crew_and_payload.business_class_count', + }, units='unitless', desc='number of business class passengers', types=int, @@ -801,10 +898,11 @@ add_meta_data( Aircraft.CrewPayload.NUM_FIRST_CLASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.NPF', # ['&DEFINE.WTIN.NPF', 'WTS.NPF'], - "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.first_class_count' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['&DEFINE.WTIN.NPF', 'WTS.NPF'], + "LEAPS1": None, # 'aircraft.inputs.L0_crew_and_payload.first_class_count', + }, units='unitless', desc='number of first class passengers', types=int, @@ -815,12 +913,14 @@ add_meta_data( Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.NSTU', # ['&DEFINE.WTIN.NSTU', 'WTS.NSTU'], - "LEAPS1": ['aircraft.inputs.L0_crew_and_payload.flight_attendants_count', - 'aircraft.cached.L0_crew_and_payload.flight_attendants_count', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.NSTU', # ['&DEFINE.WTIN.NSTU', 'WTS.NSTU'], + "LEAPS1": [ + 'aircraft.inputs.L0_crew_and_payload.flight_attendants_count', + 'aircraft.cached.L0_crew_and_payload.flight_attendants_count', + ], + }, units='unitless', desc='number of flight attendants', types=int, @@ -831,13 +931,15 @@ add_meta_data( Aircraft.CrewPayload.NUM_FLIGHT_CREW, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.NFLCR', 'WTS.NFLCR', '~WTSTAT.NFLCR'], - "FLOPS": 'WTIN.NFLCR', - "LEAPS1": ['aircraft.inputs.L0_crew_and_payload.flight_crew_count', - 'aircraft.cached.L0_crew_and_payload.flight_crew_count', - ] - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.NFLCR', 'WTS.NFLCR', '~WTSTAT.NFLCR'], + "FLOPS": 'WTIN.NFLCR', + "LEAPS1": [ + 'aircraft.inputs.L0_crew_and_payload.flight_crew_count', + 'aircraft.cached.L0_crew_and_payload.flight_crew_count', + ], + }, units='unitless', desc='number of flight crew', types=int, @@ -848,12 +950,14 @@ add_meta_data( Aircraft.CrewPayload.NUM_GALLEY_CREW, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.NGALC', # ['&DEFINE.WTIN.NGALC', 'WTS.NGALC'], - "LEAPS1": ['aircraft.inputs.L0_crew_and_payload.galley_crew_count', - 'aircraft.cached.L0_crew_and_payload.galley_crew_count', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.NGALC', # ['&DEFINE.WTIN.NGALC', 'WTS.NGALC'], + "LEAPS1": [ + 'aircraft.inputs.L0_crew_and_payload.galley_crew_count', + 'aircraft.cached.L0_crew_and_payload.galley_crew_count', + ], + }, units='unitless', desc='number of galley crew', types=int, @@ -864,10 +968,11 @@ add_meta_data( Aircraft.CrewPayload.NUM_PASSENGERS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.PAX', - "FLOPS": None, # ['CSTDAT.NSV', '~WEIGHT.NPASS', '~WTSTAT.NPASS'], - "LEAPS1": 'aircraft.outputs.L0_crew_and_payload.passenger_count' - }, + historical_name={ + "GASP": None, # 'INGASP.PAX' here we assume previous studies were changing Design.num_pax not as-flown + "FLOPS": None, # ['CSTDAT.NSV', '~WEIGHT.NPASS', '~WTSTAT.NPASS'], + "LEAPS1": None, # 'aircraft.outputs.L0_crew_and_payload.passenger_count', + }, units='unitless', desc='total number of passengers', option=True, @@ -879,10 +984,11 @@ add_meta_data( Aircraft.CrewPayload.NUM_TOURIST_CLASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.NPT', # ['&DEFINE.WTIN.NPT', 'WTS.NPT'], - "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.tourist_class_count' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['&DEFINE.WTIN.NPT', 'WTS.NPT'], + "LEAPS1": None, # 'aircraft.inputs.L0_crew_and_payload.tourist_class_count', + }, units='unitless', desc='number of tourist class passengers', types=int, @@ -893,13 +999,15 @@ add_meta_data( Aircraft.CrewPayload.PASSENGER_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(34, 2)', '~WEIGHT.WPASS', '~WTSTAT.WSP(34, 2)', '~INERT.WPASS'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._passenger_weight', - 'aircraft.outputs.L0_weights_summary.passenger_weight' - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(34, 2)', '~WEIGHT.WPASS', '~WTSTAT.WSP(34, 2)', '~INERT.WPASS'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._passenger_weight', + 'aircraft.outputs.L0_weights_summary.passenger_weight', + ], + }, units='lbm', desc='TBD: total mass of all passengers without their baggage', ) @@ -907,10 +1015,7 @@ add_meta_data( Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.UWPAX', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.UWPAX', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='total mass of one passenger and their bags', option=True, @@ -920,13 +1025,11 @@ add_meta_data( Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, meta_data=_MetaData, - # note: this GASP variable does not include cargo, but it does include passenger baggage - historical_name={"GASP": 'INGASP.WPL', - "FLOPS": None, - "LEAPS1": None - }, + # note: this GASP variable does not include cargo, but it does include + # passenger baggage + historical_name={"GASP": 'INGASP.WPL', "FLOPS": None, "LEAPS1": None}, units='lbm', - desc='mass of passenger payload, including passengers, passenger baggage' + desc='mass of passenger payload, including passengers, passenger baggage', ) add_meta_data( @@ -934,13 +1037,15 @@ # - see also: Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER Aircraft.CrewPayload.PASSENGER_SERVICE_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(31, 2)', '~WEIGHT.WSRV', '~WTSTAT.WSP(31, 2)', '~INERT.WSRV'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._passenger_service_weight', - 'aircraft.outputs.L0_weights_summary.passenger_service_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(31, 2)', '~WEIGHT.WSRV', '~WTSTAT.WSP(31, 2)', '~INERT.WSRV'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._passenger_service_weight', + 'aircraft.outputs.L0_weights_summary.passenger_service_weight', + ], + }, units='lbm', desc='mass of passenger service equipment', default_value=None, @@ -949,10 +1054,7 @@ add_meta_data( Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_PER_PASSENGER, meta_data=_MetaData, - historical_name={"GASP": "INGASP.CW(9)", - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": "INGASP.CW(9)", "FLOPS": None, "LEAPS1": None}, default_value=2.0, units="lbm", desc='mass of passenger service items mass per passenger', @@ -961,11 +1063,12 @@ add_meta_data( Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WSRV', 'MISWT.WSRV', 'MISWT.OSRV'], - "FLOPS": 'WTIN.WSRV', - "LEAPS1": 'aircraft.inputs.L0_overrides.passenger_service_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WSRV', 'MISWT.WSRV', 'MISWT.OSRV'], + "FLOPS": 'WTIN.WSRV', + "LEAPS1": 'aircraft.inputs.L0_overrides.passenger_service_weight', + }, units='unitless', desc='scaler for mass of passenger service equipment', default_value=1.0, @@ -974,21 +1077,15 @@ add_meta_data( Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', - desc='total mass of payload, including passengers, passenger baggage, and cargo' + desc='total mass of payload, including passengers, passenger baggage, and cargo', ) add_meta_data( Aircraft.CrewPayload.WATER_MASS_PER_OCCUPANT, meta_data=_MetaData, - historical_name={"GASP": "INGASP.CW(10)", - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": "INGASP.CW(10)", "FLOPS": None, "LEAPS1": None}, default_value=1.0, units="lbm", desc='mass of water per occupant (passengers, pilots, and flight attendants)', @@ -997,10 +1094,11 @@ add_meta_data( Aircraft.CrewPayload.WING_CARGO, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.CARGOW', # ['&DEFINE.WTIN.CARGOW', 'WTS.CARGOW'], - "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.wing_cargo' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.CARGOW', # ['&DEFINE.WTIN.CARGOW', 'WTS.CARGOW'], + "LEAPS1": 'aircraft.inputs.L0_crew_and_payload.wing_cargo', + }, units='lbm', desc='cargo carried in wing', default_value=0.0, @@ -1015,59 +1113,56 @@ # __/ | # |___/ # ========================================= - add_meta_data( Aircraft.Design.BASE_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.SBASE', - # [ # inputs - # '&DEFINE.AERIN.SBASE', 'EDETIN.SBASE', - # # outputs - # 'MISSA.SBASE', 'MISSA.SBASEX', - # ], - "LEAPS1": ['aircraft.inputs.L0_aerodynamics.base_area', - 'aircraft.outputs.L0_aerodynamics.mission_base_area', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.SBASE', + # [ # inputs + # '&DEFINE.AERIN.SBASE', 'EDETIN.SBASE', + # # outputs + # 'MISSA.SBASE', 'MISSA.SBASEX', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_aerodynamics.base_area', + 'aircraft.outputs.L0_aerodynamics.mission_base_area', + ], + }, units='ft**2', desc='Aircraft base area (total exit cross-section area minus inlet ' - 'capture areas for internally mounted engines)', + 'capture areas for internally mounted engines)', default_value=0.0, ) add_meta_data( Aircraft.Design.CG_DELTA, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELCG', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELCG', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='allowable center-of-gravity (cg) travel as a fraction of ' - 'the mean aerodynamic chord', + 'the mean aerodynamic chord', ) add_meta_data( Aircraft.Design.CHARACTERISTIC_LENGTHS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.EL', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_component_char_len_table', - 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.EL', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_component_char_len_table', + 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table', + ], + }, units='ft', - desc='Reynolds characteristic length for each component' + desc='Reynolds characteristic length for each component', ) add_meta_data( Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKCC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKCC', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of cockpit controls', ) @@ -1075,40 +1170,31 @@ add_meta_data( Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", option=True, default_value=False, types=bool, desc='if true, use empirical tail volume coefficient equation. This is ' - 'true if VBARHX is 0 in GASP.' + 'true if VBARHX is 0 in GASP.', ) add_meta_data( Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", option=True, default_value=False, types=bool, desc='if true, use empirical tail volume coefficient equation. This is ' - 'true if VBARVX is 0 in GASP.' + 'true if VBARVX is 0 in GASP.', ) add_meta_data( Aircraft.Design.DRAG_COEFFICIENT_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELCD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELCD', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='increment to the profile drag coefficient', ) @@ -1116,10 +1202,7 @@ add_meta_data( Aircraft.Design.DRAG_POLAR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='Drag polar computed during Aviary pre-mission.', ) @@ -1127,10 +1210,7 @@ add_meta_data( Aircraft.Design.EMERGENCY_EQUIPMENT_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(11)', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CW(11)', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='mass of emergency equipment', default_value=0.0, @@ -1139,11 +1219,12 @@ add_meta_data( Aircraft.Design.EMPTY_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFMSS.MISSIN.DOWE', '&FLOPS.RERUN.DOWE', 'ESB.DOWE'], - "FLOPS": 'MISSIN.DOWE', - "LEAPS1": 'aircraft.inputs.L0_mission.fixed_operating_weight_empty' - }, + historical_name={ + "GASP": None, + # ['&DEFMSS.MISSIN.DOWE', '&FLOPS.RERUN.DOWE', 'ESB.DOWE'], + "FLOPS": 'MISSIN.DOWE', + "LEAPS1": 'aircraft.inputs.L0_mission.fixed_operating_weight_empty', + }, units='lbm', desc='fixed operating empty mass', default_value=0.0, @@ -1154,10 +1235,11 @@ # - see also: Aircraft.Design.EMPTY_MASS_MARGIN_SCALER Aircraft.Design.EMPTY_MASS_MARGIN, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'DARM.WMARG', - "LEAPS1": '(WeightABC)self._weight_empty_margin' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'DARM.WMARG', + "LEAPS1": '(WeightABC)self._weight_empty_margin', + }, units='lbm', desc='empty mass margin', default_value=None, @@ -1168,10 +1250,11 @@ # discarded Aircraft.Design.EMPTY_MASS_MARGIN_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.EWMARG', # ['&DEFINE.WTIN.EWMARG', 'DARM.EWMARG'], - "LEAPS1": 'aircraft.inputs.L0_overrides.weight_empty_margin' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.EWMARG', # ['&DEFINE.WTIN.EWMARG', 'DARM.EWMARG'], + "LEAPS1": 'aircraft.inputs.L0_overrides.weight_empty_margin', + }, units='unitless', desc='empty mass margin scaler', default_value=0.0, @@ -1179,10 +1262,11 @@ add_meta_data( Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None, - }, + historical_name={ + "GASP": None, + "FLOPS": None, + "LEAPS1": None, + }, meta_data=_MetaData, units='lbm', desc='total mass of all user-defined external subsystems', @@ -1191,35 +1275,31 @@ add_meta_data( Aircraft.Design.FINENESS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.FR', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table', - 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.FR', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table', + 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table', + ], + }, units='unitless', - desc='table of component fineness ratios' + desc='table of component fineness ratios', ) add_meta_data( Aircraft.Design.FIXED_EQUIPMENT_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WFE', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WFE', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='total mass of fixed equipment: APU, Instruments, Hydraulics, Electrical, ' - 'Avionics, AC, Anti-Icing, Auxilary Equipment, and Furnishings', + 'Avionics, AC, Anti-Icing, Auxilary Equipment, and Furnishings', ) add_meta_data( Aircraft.Design.FIXED_USEFUL_LOAD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WFUL', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WFUL', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='total mass of fixed useful load: crew, service items, trapped oil, etc', ) @@ -1227,22 +1307,20 @@ add_meta_data( Aircraft.Design.IJEFF, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.IJEFF', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.IJEFF', "FLOPS": None, "LEAPS1": None}, desc="A flag used by Jeff V. Bowles to debug GASP code during his 53 years supporting the development of GASP. " - "This flag is planted here to thank him for his hard work and dedication, Aviary wouldn't be what it is today " - "without his help.", + "This flag is planted here to thank him for his hard work and dedication, Aviary wouldn't be what it is today " + "without his help.", ) add_meta_data( Aircraft.Design.LAMINAR_FLOW_LOWER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.TRL', - "LEAPS1": 'aircraft.outputs.L0_aerodynamics.mission_component_percent_laminar_flow_lower_surface_table' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.TRL', + "LEAPS1": 'aircraft.outputs.L0_aerodynamics.mission_component_percent_laminar_flow_lower_surface_table', + }, units='unitless', desc='table of percent laminar flow over lower component surfaces', default_value=None, @@ -1251,10 +1329,11 @@ add_meta_data( Aircraft.Design.LAMINAR_FLOW_UPPER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.TRU', - "LEAPS1": 'aircraft.outputs.L0_aerodynamics.mission_component_percent_laminar_flow_upper_surface_table' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.TRU', + "LEAPS1": 'aircraft.outputs.L0_aerodynamics.mission_component_percent_laminar_flow_upper_surface_table', + }, units='unitless', desc='table of percent laminar flow over upper component surfaces', default_value=None, @@ -1264,22 +1343,20 @@ # Note user override (no scaling) Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.WRATIO', # ['&DEFINE.AERIN.WRATIO', 'ESB.WRATIO'], - "LEAPS1": 'aircraft.inputs.L0_takeoff_and_landing.landing_to_takeoff_weight_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.WRATIO', # ['&DEFINE.AERIN.WRATIO', 'ESB.WRATIO'], + "LEAPS1": 'aircraft.inputs.L0_takeoff_and_landing.landing_to_takeoff_weight_ratio', + }, units='unitless', desc='ratio of maximum landing mass to maximum takeoff mass', - default_value=None, + default_value=0.9, ) add_meta_data( Aircraft.Design.LIFT_CURVE_SLOPE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CLALPH', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CLALPH', "FLOPS": None, "LEAPS1": None}, units="1/rad", desc='lift curve slope at cruise mach number', ) @@ -1287,13 +1364,14 @@ add_meta_data( Aircraft.Design.LIFT_DEPENDENT_DRAG_COEFF_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'MISSIN.FCDI', # '~DRGFCT.FCDI', - "LEAPS1": 'aircraft.outputs.L0_aerodynamics.induced_drag_coeff_fact' - }, + historical_name={ + "GASP": None, + "FLOPS": 'MISSIN.FCDI', # '~DRGFCT.FCDI', + "LEAPS1": 'aircraft.outputs.L0_aerodynamics.induced_drag_coeff_fact', + }, units='unitless', default_value=1.0, - desc='Scaling factor for lift-dependent drag coefficient' + desc='Scaling factor for lift-dependent drag coefficient', ) add_meta_data( @@ -1321,10 +1399,7 @@ add_meta_data( Aircraft.Design.LIFT_POLAR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='Lift polar computed during Aviary pre-mission.', ) @@ -1332,10 +1407,7 @@ add_meta_data( Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.THEMAX', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.THEMAX', "FLOPS": None, "LEAPS1": None}, units='deg', desc='maximum fuselage pitch allowed', default_value=15, @@ -1344,10 +1416,7 @@ add_meta_data( Aircraft.Design.MAX_STRUCTURAL_SPEED, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.VMLFSL', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.VMLFSL', "FLOPS": None, "LEAPS1": None}, units='mi/h', desc='maximum structural design flight speed in miles per hour', default_value=0, @@ -1358,24 +1427,23 @@ meta_data=_MetaData, # TODO: check with Aviary and GASPy engineers to ensure these are indeed # defined the same way - historical_name={"GASP": 'INGASP.OWE', - # ['WTS.WSP(33, 2)', '~WEIGHT.WOWE', '~WTSTAT.WSP(33, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._operating_weight_empty', - 'aircraft.outputs.L0_weights_summary.operating_weight_empty', - ] - }, + historical_name={ + "GASP": 'INGASP.OWE', + # ['WTS.WSP(33, 2)', '~WEIGHT.WOWE', '~WTSTAT.WSP(33, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._operating_weight_empty', + 'aircraft.outputs.L0_weights_summary.operating_weight_empty', + ], + }, units='lbm', - desc='operating mass empty of the aircraft' + desc='operating mass empty of the aircraft', ) add_meta_data( Aircraft.Design.PART25_STRUCTURAL_CATEGORY, meta_data=_MetaData, - historical_name={"GASP": "INGASP.CATD", - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": "INGASP.CATD", "FLOPS": None, "LEAPS1": None}, option=True, default_value=3, types=int, @@ -1386,10 +1454,7 @@ add_meta_data( Aircraft.Design.RESERVE_FUEL_ADDITIONAL, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FRESF', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.FRESF', "FLOPS": None, "LEAPS1": None}, option=True, units="lbm", desc='required fuel reserves: directly in lbm', @@ -1399,27 +1464,21 @@ add_meta_data( Aircraft.Design.RESERVE_FUEL_FRACTION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, option=True, units="unitless", desc='required fuel reserves: given as a proportion of mission fuel. This value must be nonnegative. ' - 'Mission fuel only includes normal phases and excludes reserve phases. ' - 'If it is 0.5, the reserve fuel is half of the mission fuel (one third of the total fuel). Note ' - 'it can be greater than 1. If it is 2, there would be twice as much reserve fuel as mission fuel ' - '(the total fuel carried would be 1/3 for the mission and 2/3 for the reserve)', + 'Mission fuel only includes normal phases and excludes reserve phases. ' + 'If it is 0.5, the reserve fuel is half of the mission fuel (one third of the total fuel). Note ' + 'it can be greater than 1. If it is 2, there would be twice as much reserve fuel as mission fuel ' + '(the total fuel carried would be 1/3 for the mission and 2/3 for the reserve)', default_value=0, ) add_meta_data( Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, option=True, default_value=False, types=bool, @@ -1430,10 +1489,7 @@ add_meta_data( Aircraft.Design.STATIC_MARGIN, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.STATIC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.STATIC', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='aircraft static margin as a fraction of mean aerodynamic chord', ) @@ -1441,10 +1497,7 @@ add_meta_data( Aircraft.Design.STRUCTURAL_MASS_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELWST', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELWST', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='structural mass increment that is added (or removed) after the structural mass is calculated', default_value=0, @@ -1453,65 +1506,67 @@ add_meta_data( Aircraft.Design.STRUCTURE_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(9, 2)', '~WEIGHT.WSTRCT', '~WTSTAT.WSP(9, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._total_structural_weight', - 'aircraft.outputs.L0_weights_summary.total_structural_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(9, 2)', '~WEIGHT.WSTRCT', '~WTSTAT.WSP(9, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._total_structural_weight', + 'aircraft.outputs.L0_weights_summary.total_structural_weight', + ], + }, units='lbm', - desc='Total structural group mass' + desc='Total structural group mass', ) add_meta_data( Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'MISSIN.FCDSUB', # '~DRGFCT.FCDSUB', - "LEAPS1": 'aircraft.outputs.L0_aerodynamics.sub_drag_coeff_fact' - }, + historical_name={ + "GASP": None, + "FLOPS": 'MISSIN.FCDSUB', # '~DRGFCT.FCDSUB', + "LEAPS1": 'aircraft.outputs.L0_aerodynamics.sub_drag_coeff_fact', + }, units='unitless', default_value=1.0, - desc='Scaling factor for subsonic drag' + desc='Scaling factor for subsonic drag', ) add_meta_data( Aircraft.Design.SUPERCRITICAL_DIVERGENCE_SHIFT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SCFAC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SCFAC', "FLOPS": None, "LEAPS1": None}, units='unitless', - desc='shift in drag divergence Mach number due to ' - 'supercritical design', + desc='shift in drag divergence Mach number due to ' 'supercritical design', ) add_meta_data( Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'MISSIN.FCDSUP', # '~DRGFCT.FCDSUP', - "LEAPS1": 'aircraft.outputs.L0_aerodynamics.sup_drag_coeff_fact' - }, + historical_name={ + "GASP": None, + "FLOPS": 'MISSIN.FCDSUP', # '~DRGFCT.FCDSUP', + "LEAPS1": 'aircraft.outputs.L0_aerodynamics.sup_drag_coeff_fact', + }, units='unitless', default_value=1.0, - desc='Scaling factor for supersonic drag' + desc='Scaling factor for supersonic drag', ) add_meta_data( Aircraft.Design.SYSTEMS_EQUIP_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(25, 2)', '~WEIGHT.WSYS', '~WTSTAT.WSP(25, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._equipment_group_weight', - 'aircraft.outputs.L0_weights_summary.equipment_group_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(25, 2)', '~WEIGHT.WSYS', '~WTSTAT.WSP(25, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._equipment_group_weight', + 'aircraft.outputs.L0_weights_summary.equipment_group_weight', + ], + }, units='lbm', - desc='Total systems & equipment group mass' + desc='Total systems & equipment group mass', ) add_meta_data( @@ -1520,52 +1575,52 @@ # value during calculations; in Aviary, these must be separate variables Aircraft.Design.SYSTEMS_EQUIP_MASS_BASE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', - desc='Total systems & equipment group mass without additional 1% of ' - 'empty mass' + desc='Total systems & equipment group mass without additional 1% of ' 'empty mass', ) add_meta_data( Aircraft.Design.THRUST_TO_WEIGHT_RATIO, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'CONFIN.TWR', - "LEAPS1": 'ipropulsion.req_thrust_weight_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": 'CONFIN.TWR', + "LEAPS1": 'ipropulsion.req_thrust_weight_ratio', + }, units='unitless', - desc='required thrust-to-weight ratio of aircraft' + desc='required thrust-to-weight ratio of aircraft', ) add_meta_data( Aircraft.Design.TOTAL_WETTED_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WEIGHT.TWET', - "LEAPS1": '~WeightABC._update_cycle.total_wetted_area' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WEIGHT.TWET', + "LEAPS1": '~WeightABC._update_cycle.total_wetted_area', + }, units='ft**2', - desc='total aircraft wetted area' + desc='total aircraft wetted area', ) add_meta_data( # NOTE: user override (no scaling) Aircraft.Design.TOUCHDOWN_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.WLDG', - # [ # inputs - # '&DEFINE.WTIN.WLDG', 'WTS.WLDG', - # # outputs - # 'CMODLW.WLDGO', - # ], - "LEAPS1": ['aircraft.inputs.L0_landing_gear.design_landing_weight', - 'aircraft.outputs.L0_landing_gear.design_landing_weight', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.WLDG', + # [ # inputs + # '&DEFINE.WTIN.WLDG', 'WTS.WLDG', + # # outputs + # 'CMODLW.WLDGO', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_landing_gear.design_landing_weight', + 'aircraft.outputs.L0_landing_gear.design_landing_weight', + ], + }, units='lbm', desc='design landing mass', default_value=None, @@ -1574,26 +1629,24 @@ add_meta_data( Aircraft.Design.ULF_CALCULATED_FROM_MANEUVER, meta_data=_MetaData, - historical_name={"GASP": 'CATD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'CATD', "FLOPS": None, "LEAPS1": None}, option=True, default_value=False, types=bool, units="unitless", desc='if true, ULF (ultimate load factor) is forced to be calculated from ' - 'the maneuver load factor, even if the gust load factor is larger. ' - 'This was set to true with a negative CATD in GASP.' + 'the maneuver load factor, even if the gust load factor is larger. ' + 'This was set to true with a negative CATD in GASP.', ) add_meta_data( Aircraft.Design.USE_ALT_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.IALTWT', - "LEAPS1": 'aircraft.inputs.L0_weights.use_alt_weights' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.IALTWT', + "LEAPS1": 'aircraft.inputs.L0_weights.use_alt_weights', + }, units='unitless', desc='control whether the alternate mass equations are to be used or not', option=True, @@ -1604,41 +1657,46 @@ add_meta_data( Aircraft.Design.WETTED_AREAS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.SWET', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_component_wetted_area_table', - 'aircraft.cached.L0_aerodynamics.mission_component_wetted_area_table', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.SWET', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_component_wetted_area_table', + 'aircraft.cached.L0_aerodynamics.mission_component_wetted_area_table', + ], + }, units='ft**2', - desc='table of component wetted areas' + desc='table of component wetted areas', ) add_meta_data( Aircraft.Design.ZERO_FUEL_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(37,2)', '~WEIGHT.WZF', '~WTSTAT.WSP(37,2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._zero_fuel_weight', - 'aircraft.outputs.L0_weights.zero_fuel_weight', - 'aircraft.outputs.L0_weights_summary.zero_fuel_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(37,2)', '~WEIGHT.WZF', '~WTSTAT.WSP(37,2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._zero_fuel_weight', + 'aircraft.outputs.L0_weights.zero_fuel_weight', + 'aircraft.outputs.L0_weights_summary.zero_fuel_weight', + ], + }, units='lbm', - desc='zero fuel mass' + desc='zero fuel mass', ) add_meta_data( Aircraft.Design.ZERO_LIFT_DRAG_COEFF_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'MISSIN.FCDO', # '~DRGFCT.FCDO', - "LEAPS1": 'aircraft.outputs.L0_aerodynamics.geom_drag_coeff_fact' - }, + historical_name={ + "GASP": None, + "FLOPS": 'MISSIN.FCDO', # '~DRGFCT.FCDO', + "LEAPS1": 'aircraft.outputs.L0_aerodynamics.geom_drag_coeff_fact', + }, units='unitless', default_value=1.0, - desc='Scaling factor for zero-lift drag coefficient' + desc='Scaling factor for zero-lift drag coefficient', ) # @@ -1653,10 +1711,7 @@ add_meta_data( Aircraft.Electrical.HAS_HYBRID_SYSTEM, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", option=True, default_value=True, @@ -1667,10 +1722,7 @@ add_meta_data( Aircraft.Electrical.HYBRID_CABLE_LENGTH, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.LCABLE', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.LCABLE', "FLOPS": None, "LEAPS1": None}, units='ft', desc='length of cable for hybrid electric augmented system', ) @@ -1680,13 +1732,15 @@ # - see also: Aircraft.Electrical.MASS_SCALER Aircraft.Electrical.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(20, 2)', '~WEIGHT.WELEC', '~WTSTAT.WSP(20, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._electrical_group_weight', - 'aircraft.outputs.L0_weights_summary.electrical_group_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(20, 2)', '~WEIGHT.WELEC', '~WTSTAT.WSP(20, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._electrical_group_weight', + 'aircraft.outputs.L0_weights_summary.electrical_group_weight', + ], + }, units='lbm', desc='mass of the electrical system', default_value=None, @@ -1695,11 +1749,12 @@ add_meta_data( Aircraft.Electrical.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WELEC', 'MISWT.WELEC', 'MISWT.OELEC'], - "FLOPS": 'WTIN.WELEC', - "LEAPS1": 'aircraft.inputs.L0_overrides.electrical_group_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WELEC', 'MISWT.WELEC', 'MISWT.OELEC'], + "FLOPS": 'WTIN.WELEC', + "LEAPS1": 'aircraft.inputs.L0_overrides.electrical_group_weight', + }, units='unitless', desc='mass scaler for the electrical system', default_value=1.0, @@ -1720,258 +1775,290 @@ add_meta_data( Aircraft.Engine.ADDITIONAL_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='additional propulsion system mass added to engine control and starter mass, or ' - 'engine installation mass', - default_value=0.0 + 'engine installation mass', + default_value=0.0, ) add_meta_data( Aircraft.Engine.ADDITIONAL_MASS_FRACTION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKPEI', - "FLOPS": 'WTIN.WPMISC', # ['&DEFINE.WTIN.WPMISC', 'FAWT.WPMISC'], - "LEAPS1": 'aircraft.inputs.L0_propulsion.misc_weight' - }, + historical_name={ + "GASP": 'INGASP.SKPEI', + "FLOPS": 'WTIN.WPMISC', # ['&DEFINE.WTIN.WPMISC', 'FAWT.WPMISC'], + "LEAPS1": 'aircraft.inputs.L0_propulsion.misc_weight', + }, units='unitless', + option=True, desc='fraction of (scaled) engine mass used to calculate additional propulsion ' 'system mass added to engine control and starter mass, or used to ' 'calculate engine installation mass', + types=(float, int, np.ndarray), + multivalue=True, default_value=0.0, ) -# NOTE if FT < 0, this bool is true, if >= 0, this is false and the value of FT is used -# as the installation loss factor -add_meta_data( - Aircraft.Engine.COMPUTE_PROPELLER_INSTALLATION_LOSS, - meta_data=_MetaData, - historical_name={"GASP": 'INPROP.FT', - "FLOPS": None, - "LEAPS1": None - }, - units="unitless", - option=True, - default_value=True, - types=bool, - desc='if true, compute installation loss factor based on blockage factor', -) - add_meta_data( Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'MISSIN.FLEAK', - "LEAPS1": ['iengine.fuel_leak', 'aircraft.inputs.L0_engine.fuel_leak'] - }, + historical_name={ + "GASP": None, + "FLOPS": 'MISSIN.FLEAK', + "LEAPS1": ['iengine.fuel_leak', 'aircraft.inputs.L0_engine.fuel_leak'], + }, option=True, units='lbm/h', desc='Additional constant fuel flow. This value is not scaled with the engine', - default_value=0.0 + default_value=0.0, ) add_meta_data( Aircraft.Engine.CONTROLS_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WEIGHT.WEC', - "LEAPS1": '(WeightABC)self._engine_ctrl_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WEIGHT.WEC', + "LEAPS1": '(WeightABC)self._engine_ctrl_weight', + }, units='lbm', desc='estimated mass of the engine controls', - default_value=0.0 + default_value=0.0, ) # TODO there should be a GASP name that pairs here add_meta_data( Aircraft.Engine.DATA_FILE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": "ENGDIN.EIFILE", - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": "ENGDIN.EIFILE", "LEAPS1": None}, units='unitless', types=(str, Path), default_value=None, option=True, - desc='filepath to data file containing engine performance tables' + desc='filepath to data file containing engine performance tables', +) + +add_meta_data( + Aircraft.Engine.FIXED_RPM, + meta_data=_MetaData, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='rpm', + default_value=1.0, + desc='RPM the engine is set to be running at. Overrides RPM provided by ' + 'engine model or chosen by optimizer. Typically used when pairing a motor or ' + 'turboshaft using a fixed operating RPM with a propeller.', ) add_meta_data( Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'ENGDIN.FIDMAX', - "LEAPS1": 'aircraft.L0_fuel_flow.idle_max_fract' - }, + historical_name={ + "GASP": None, + "FLOPS": 'ENGDIN.FIDMAX', + "LEAPS1": 'aircraft.L0_fuel_flow.idle_max_fract', + }, units="unitless", option=True, default_value=1.0, desc='If Aircraft.Engine.GENERATE_FLIGHT_IDLE is True, bounds engine ' - 'performance outputs (other than thrust) at flight idle to be below a ' - 'decimal fraction of the max value of that output produced by the engine ' - 'at each flight condition.' + 'performance outputs (other than thrust) at flight idle to be below a ' + 'decimal fraction of the max value of that output produced by the engine ' + 'at each flight condition.', ) add_meta_data( Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'ENGDIN.FIDMIN', - "LEAPS1": 'aircraft.L0_fuel_flow.idle_min_fract' - }, + historical_name={ + "GASP": None, + "FLOPS": 'ENGDIN.FIDMIN', + "LEAPS1": 'aircraft.L0_fuel_flow.idle_min_fract', + }, units="unitless", option=True, default_value=0.08, desc='If Aircraft.Engine.GENERATE_FLIGHT_IDLE is True, bounds engine ' - 'performance outputs (other than thrust) at flight idle to be above a ' - 'decimal fraction of the max value of that output produced by the engine ' - 'at each flight condition.' + 'performance outputs (other than thrust) at flight idle to be above a ' + 'decimal fraction of the max value of that output produced by the engine ' + 'at each flight condition.', ) add_meta_data( Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", option=True, default_value=0.0, desc='If Aircraft.Engine.GENERATE_FLIGHT_IDLE is True, defines idle thrust ' - 'condition as a decimal fraction of max thrust produced by the engine at each ' - 'flight condition.' + 'condition as a decimal fraction of max thrust produced by the engine at each ' + 'flight condition.', ) add_meta_data( Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'ENGDIN.DFFAC', - "LEAPS1": 'ifuel_flow.scaling_const_term' - }, + historical_name={ + "GASP": None, + "FLOPS": 'ENGDIN.DFFAC', + "LEAPS1": 'ifuel_flow.scaling_const_term', + }, units='unitless', option=True, desc='Constant term in fuel flow scaling equation', - default_value=0.0 + default_value=0.0, ) add_meta_data( Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'ENGDIN.FFFAC', - "LEAPS1": 'ifuel_flow.scaling_linear_term' - }, + historical_name={ + "GASP": None, + "FLOPS": 'ENGDIN.FFFAC', + "LEAPS1": 'ifuel_flow.scaling_linear_term', + }, units='unitless', desc='Linear term in fuel flow scaling equation', default_value=0.0, - option=True + option=True, ) add_meta_data( Aircraft.Engine.GENERATE_FLIGHT_IDLE, - historical_name={"GASP": None, - "FLOPS": 'ENGDIN.IDLE', - "LEAPS1": 'engine_model.imodel_info.flight_idle_index' - }, + historical_name={ + "GASP": None, + "FLOPS": 'ENGDIN.IDLE', + "LEAPS1": 'engine_model.imodel_info.flight_idle_index', + }, meta_data=_MetaData, units="unitless", option=True, default_value=False, types=bool, desc='If True, generate flight idle data by extrapolating from engine deck. Flight ' - 'idle is defined as engine performance when thrust is reduced to the level ' - 'defined by Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION. Engine outputs are ' - 'extrapolated to this thrust level, bounded by ' - 'Aircraft.Engine.FLIGHT_IDLE_MIN_FRACT and Aircraft.Engine.FLIGHT_IDLE_MIN_FRACT' + 'idle is defined as engine performance when thrust is reduced to the level ' + 'defined by Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION. Engine outputs are ' + 'extrapolated to this thrust level, bounded by ' + 'Aircraft.Engine.FLIGHT_IDLE_MIN_FRACT and Aircraft.Engine.FLIGHT_IDLE_MIN_FRACT', ) add_meta_data( Aircraft.Engine.GEOPOTENTIAL_ALT, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'ENGDIN.IGEO', - "LEAPS1": 'imodel_info.geopotential_alt' - }, + historical_name={ + "GASP": None, + "FLOPS": 'ENGDIN.IGEO', + "LEAPS1": 'imodel_info.geopotential_alt', + }, units='unitless', option=True, desc='If True, engine deck altitudes are geopotential and will be converted to ' - 'geometric altitudes. If False, engine deck altitudes are geometric.', + 'geometric altitudes. If False, engine deck altitudes are geometric.', + types=bool, + default_value=False, +) + +# Global hybrid throttle is also False by default to account for parallel-hybrid engines +# that can't operate at every power level at every condition due to other constraints +add_meta_data( + Aircraft.Engine.GLOBAL_HYBRID_THROTTLE, + meta_data=_MetaData, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='unitless', + desc='Flag for engine decks if the range of provided hybrid throttles is consistent ' + 'across all flight conditions (e.g. the maximum hybrid throttle seen in the entire ' + 'deck is 1.0, but a given flight condition only goes to 0.9 -> GLOBAL_HYBRID_THROTTLE ' + '= TRUE means the engine can be extrapolated out to 1.0 at that point. If ' + "GLOBAL_HYBRID_THROTTLE is False, then each flight condition's hybrid throttle range is " + 'individually normalized from 0 to 1 independent of other points on the deck).', + default_value=False, + types=bool, + option=True, +) + +# TODO Disabling global throttle ranges is preferred (therefore default) to prevent +# unintended extrapolation, but breaks missions using GASP-based engines that have uneven +# throttle ranges (need t4 constraint on mission to truly fix). +add_meta_data( + Aircraft.Engine.GLOBAL_THROTTLE, + meta_data=_MetaData, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='unitless', + desc='Flag for engine decks if the range of provided throttles is consistent ' + 'across all flight conditions (e.g. the maximum throttle seen in the entire ' + 'deck is 1.0, but a given flight condition only goes to 0.9 -> GLOBAL_THROTTLE ' + '= TRUE means the engine can be extrapolated out to 1.0 at that point. If ' + "GLOBAL_THROTTLE is False, then each flight condition's throttle range is " + 'individually normalized from 0 to 1 independent of other points on the deck).', + default_value=False, types=bool, - default_value=False + option=True, ) # TODO dependency on NTYE? Does this var need preprocessing? Can this mention be removed? add_meta_data( Aircraft.Engine.HAS_PROPELLERS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, option=True, units="unitless", default_value=False, types=bool, desc='if True, the aircraft has propellers, otherwise aircraft is assumed to have no ' - 'propellers. In GASP this depended on NTYE', + 'propellers. In GASP this depended on NTYE', ) add_meta_data( Aircraft.Engine.IGNORE_NEGATIVE_THRUST, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'ENGDIN.NONEG', - "LEAPS1": 'imodel_info.ignore_negative_thrust' - }, + historical_name={ + "GASP": None, + "FLOPS": 'ENGDIN.NONEG', + "LEAPS1": 'imodel_info.ignore_negative_thrust', + }, option=True, units="unitless", default_value=False, types=bool, desc='If False, all input or generated points are used, otherwise points in the ' - 'engine deck with negative net thrust are ignored.' + 'engine deck with negative net thrust are ignored.', ) add_meta_data( Aircraft.Engine.INTERPOLATION_METHOD, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", option=True, default_value='slinear', types=str, desc="method used for interpolation on an engine deck's data file, allowable values are " - 'table methods from openmdao.components.interp_util.interp', + 'table methods from openmdao.components.interp_util.interp', ) add_meta_data( Aircraft.Engine.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['WTS.WSP(10, 2)', '~WTSTAT.WSP(10, 2)'], - "LEAPS1": 'aircraft.outputs.L0_weights_summary.Engine.WEIGHT' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['WTS.WSP(10, 2)', '~WTSTAT.WSP(10, 2)'], + "LEAPS1": 'aircraft.outputs.L0_weights_summary.Engine.WEIGHT', + }, units='lbm', desc='scaled mass of a single engine or bare engine if inlet and nozzle mass are ' - 'supplied', - default_value=0.0 + 'supplied', + default_value=0.0, ) add_meta_data( Aircraft.Engine.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CK5', - "FLOPS": 'WTIN.EEXP', # '~WEIGHT.EEXP', - "LEAPS1": 'aircraft.inputs.L0_propulsion.engine_weight_scale' - }, + historical_name={ + "GASP": 'INGASP.CK5', + "FLOPS": 'WTIN.EEXP', # '~WEIGHT.EEXP', + "LEAPS1": 'aircraft.inputs.L0_propulsion.engine_weight_scale', + }, units='unitless', desc='scaler for engine mass', default_value=0.0, @@ -1980,10 +2067,7 @@ add_meta_data( Aircraft.Engine.MASS_SPECIFIC, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SWSLS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SWSLS', "FLOPS": None, "LEAPS1": None}, units="lbm/lbf", desc='specific mass of one engine (engine weight/SLS thrust)', default_value=0.0, @@ -1992,80 +2076,70 @@ add_meta_data( Aircraft.Engine.NUM_ENGINES, meta_data=_MetaData, - historical_name={"GASP": "INGASP.ENP", - "FLOPS": None, # ['~ANALYS.NENG', 'LANDG.XENG', ], - "LEAPS1": 'aircraft.outputs.L0_propulsion.total_engine_count' - }, + historical_name={ + "GASP": "INGASP.ENP", + "FLOPS": None, # ['~ANALYS.NENG', 'LANDG.XENG', ], + "LEAPS1": 'aircraft.outputs.L0_propulsion.total_engine_count', + }, units='unitless', desc='total number of engines per model on the aircraft ' - '(fuselage, wing, or otherwise)', - types=int, + '(fuselage, wing, or otherwise)', + types=(np.ndarray, int), + multivalue=True, option=True, - default_value=2 + default_value=[2] ) add_meta_data( Aircraft.Engine.NUM_FUSELAGE_ENGINES, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.NEF', # ['&DEFINE.WTIN.NEF', 'EDETIN.NEF'], - "LEAPS1": 'aircraft.inputs.L0_fuselage.engines_count' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.NEF', # ['&DEFINE.WTIN.NEF', 'EDETIN.NEF'], + "LEAPS1": 'aircraft.inputs.L0_fuselage.engines_count', + }, units='unitless', desc='number of fuselage mounted engines per model', option=True, - types=int, - default_value=0 -) - -add_meta_data( - Aircraft.Engine.NUM_PROPELLER_BLADES, - meta_data=_MetaData, - historical_name={"GASP": 'INPROP.BL', - "FLOPS": None, - "LEAPS1": None - }, - units='unitless', - desc='number of blades per propeller', - option=True, - types=int, + types=(np.ndarray, int), + multivalue=True, default_value=0 ) add_meta_data( Aircraft.Engine.NUM_WING_ENGINES, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.NEW', 'EDETIN.NEW', '~WWGHT.NEW'], - "FLOPS": 'WTIN.NEW', - "LEAPS1": 'aircraft.inputs.L0_wing.engines_count' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.NEW', 'EDETIN.NEW', '~WWGHT.NEW'], + "FLOPS": 'WTIN.NEW', + "LEAPS1": 'aircraft.inputs.L0_wing.engines_count', + }, units='unitless', desc='number of wing mounted engines per model', option=True, - types=int, - default_value=0 + types=(np.ndarray, int), + multivalue=True, + default_value=[0] ) add_meta_data( Aircraft.Engine.POD_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['~WEIGHT.WPOD', '~WWGHT.WPOD'], - "LEAPS1": '(WeightABC)self._engine_pod_weight_list' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['~WEIGHT.WPOD', '~WWGHT.WPOD'], + "LEAPS1": '(WeightABC)self._engine_pod_weight_list', + }, units='lbm', desc='engine pod mass including nacelles', - default_value=0.0 + default_value=0.0, ) add_meta_data( Aircraft.Engine.POD_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CK14', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CK14', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='technology factor on mass of engine pods', default_value=1.0, @@ -2074,112 +2148,28 @@ add_meta_data( Aircraft.Engine.POSITION_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKEPOS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKEPOS', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='engine position factor', default_value=0, ) -add_meta_data( - Aircraft.Engine.PROPELLER_ACTIVITY_FACTOR, - meta_data=_MetaData, - historical_name={"GASP": 'INPROP.AF', - "FLOPS": None, - "LEAPS1": None - }, - units="unitless", - desc='propeller actitivty factor per Blade (Range: 80 to 200)', - default_value=0.0, -) - -add_meta_data( - Aircraft.Engine.PROPELLER_DATA_FILE, - meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='unitless', - types=(str, Path), - default_value=None, - option=True, - desc='filepath to data file containing propeller data map', -) - -add_meta_data( - Aircraft.Engine.PROPELLER_DIAMETER, - meta_data=_MetaData, - historical_name={"GASP": 'INPROP.DPROP', - "FLOPS": None, - "LEAPS1": None - }, - units='ft', - desc='propeller diameter', - default_value=0.0, -) - -add_meta_data( - Aircraft.Engine.PROPELLER_INTEGRATED_LIFT_COEFFICIENT, - meta_data=_MetaData, - historical_name={"GASP": 'INPROP.CLI', - "FLOPS": None, - "LEAPS1": None - }, - units='unitless', - desc='propeller blade integrated design lift coefficient (Range: 0.3 to 0.8)', - default_value=0.5, -) - -add_meta_data( - Aircraft.Engine.PROPELLER_TIP_MACH_MAX, - meta_data=_MetaData, - historical_name={"GASP": None, # TODO this needs verification - "FLOPS": None, - "LEAPS1": None - }, - units='unitless', - desc='maximum allowable Mach number at propeller tip (based on helical speed)', - default_value=1.0, -) - -add_meta_data( - Aircraft.Engine.PROPELLER_TIP_SPEED_MAX, - meta_data=_MetaData, - historical_name={ - "GASP": ['INPROP.TSPDMX', 'INPROP.TPSPDMXe'], - "FLOPS": None, - "LEAPS1": None, - }, - units='ft/s', - desc='maximum allowable propeller linear tip speed', - default_value=800.0, -) - add_meta_data( Aircraft.Engine.PYLON_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FPYL', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.FPYL', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='factor for turbofan engine pylon mass', - default_value=.7 + default_value=0.7, ) add_meta_data( Aircraft.Engine.REFERENCE_DIAMETER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DIAM_REF', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DIAM_REF', "FLOPS": None, "LEAPS1": None}, units='ft', desc='engine reference diameter', - default_value=0.0 + default_value=0.0, ) # NOTE This unscaled turbine (engine) weight is an input provided by the user, and is not @@ -2188,13 +2178,14 @@ add_meta_data( Aircraft.Engine.REFERENCE_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.WENG', # '~WEIGHT.WENG', - "LEAPS1": '(WeightABC)self._Engine.WEIGHT' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.WENG', # '~WEIGHT.WENG', + "LEAPS1": '(WeightABC)self._Engine.WEIGHT', + }, units='lbm', desc='unscaled mass of a single engine or bare engine if inlet and nozzle mass ' - 'are supplied', + 'are supplied', default_value=None, option=True, ) @@ -2202,24 +2193,26 @@ add_meta_data( Aircraft.Engine.REFERENCE_SLS_THRUST, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FN_REF', - "FLOPS": 'WTIN.THRSO', - "LEAPS1": 'aircraft.inputs.L0_engine*.thrust' - }, + historical_name={ + "GASP": 'INGASP.FN_REF', + "FLOPS": 'WTIN.THRSO', + "LEAPS1": 'aircraft.inputs.L0_engine*.thrust', + }, units='lbf', desc='maximum thrust of an engine provided in engine model files', default_value=None, - option=True + option=True, ) add_meta_data( Aircraft.Engine.RPM_DESIGN, meta_data=_MetaData, - historical_name={"GASP": 'INPROP.XNMAX', # maximum engine speed, rpm - "FLOPS": None, - "LEAPS1": None - }, - units='rpm', + historical_name={ + "GASP": 'INPROP.XNMAX', # maximum engine speed, rpm + "FLOPS": None, + "LEAPS1": None, + }, + units='rpm', desc='the designed output RPM from the engine for fixed-RPM shafts', default_value=None, ) @@ -2227,54 +2220,58 @@ add_meta_data( Aircraft.Engine.SCALE_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='Thrust-based scaling factor used to scale engine performance data during ' - 'mission analysis', - default_value=1.0 + 'mission analysis', + default_value=1.0, ) add_meta_data( Aircraft.Engine.SCALE_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": '(types)EngineScaleModes.WEIGHT' - }, + historical_name={ + "GASP": None, + "FLOPS": None, + "LEAPS1": '(types)EngineScaleModes.WEIGHT', + }, desc='Toggle for enabling scaling of engine mass', option=True, types=bool, + multivalue=True, default_value=True, ) add_meta_data( Aircraft.Engine.SCALE_PERFORMANCE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": ['iengine.scale_mode', - '(types)EngineScaleModes.DEFAULT', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, + "LEAPS1": [ + 'iengine.scale_mode', + '(types)EngineScaleModes.DEFAULT', + ], + }, desc='Toggle for enabling scaling of engine performance including thrust, fuel flow, ' - 'and electric power', + 'and electric power', option=True, types=bool, + multivalue=True, default_value=True, ) add_meta_data( Aircraft.Engine.SCALED_SLS_THRUST, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.THIN', - "FLOPS": 'CONFIN.THRUST', - "LEAPS1": ['aircraft.outputs.L0_propulsion.max_rated_thrust', - 'aircraft.cached.L0_propulsion.max_rated_thrust', - ] - }, + historical_name={ + "GASP": 'INGASP.THIN', + "FLOPS": 'CONFIN.THRUST', + "LEAPS1": [ + 'aircraft.outputs.L0_propulsion.max_rated_thrust', + 'aircraft.cached.L0_propulsion.max_rated_thrust', + ], + }, units='lbf', desc='maximum thrust of an engine after scaling', default_value=0.0, @@ -2283,39 +2280,42 @@ add_meta_data( Aircraft.Engine.STARTER_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WEIGHT.WSTART', - "LEAPS1": '(WeightABC)self._starter_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WEIGHT.WSTART', + "LEAPS1": '(WeightABC)self._starter_weight', + }, units='lbm', desc='starter mass', - default_value=0.0 + default_value=0.0, ) add_meta_data( Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'ENGDIN.FFFSUB', - "LEAPS1": 'aircraft.L0_fuel_flow.subsonic_factor' - }, + historical_name={ + "GASP": None, + "FLOPS": 'ENGDIN.FFFSUB', + "LEAPS1": 'aircraft.L0_fuel_flow.subsonic_factor', + }, units='unitless', desc='scaling factor on fuel flow when Mach number is subsonic', default_value=1.0, - option=True + option=True, ) add_meta_data( Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'ENGDIN.FFFSUP', - "LEAPS1": 'aircraft.L0_fuel_flow.supersonic_factor' - }, + historical_name={ + "GASP": None, + "FLOPS": 'ENGDIN.FFFSUP', + "LEAPS1": 'aircraft.L0_fuel_flow.supersonic_factor', + }, units='unitless', desc='scaling factor on fuel flow when Mach number is supersonic', default_value=1.0, - option=True + option=True, ) add_meta_data( @@ -2323,13 +2323,15 @@ # - see also: Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER Aircraft.Engine.THRUST_REVERSERS_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(11, 2)', '~WEIGHT.WTHR', '~WTSTAT.WSP(11, 2)', '~INERT.WTHR'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._thrust_reversers_weight', - 'aircraft.outputs.L0_weights_summary.thrust_reversers_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(11, 2)', '~WEIGHT.WTHR', '~WTSTAT.WSP(11, 2)', '~INERT.WTHR'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._thrust_reversers_weight', + 'aircraft.outputs.L0_weights_summary.thrust_reversers_weight', + ], + }, units='lbm', desc='mass of thrust reversers on engines', default_value=0.0, @@ -2340,11 +2342,12 @@ # discarded Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WTHR', 'MISWT.WTHR', 'MISWT.OTHR'], - "FLOPS": 'WTIN.WTHR', - "LEAPS1": 'aircraft.inputs.L0_overrides.thrust_reversers_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WTHR', 'MISWT.WTHR', 'MISWT.OTHR'], + "FLOPS": 'WTIN.WTHR', + "LEAPS1": 'aircraft.inputs.L0_overrides.thrust_reversers_weight', + }, units='unitless', desc='scaler for mass of thrust reversers on engines', default_value=0.0, # FLOPS/LEAPS1 default value @@ -2353,42 +2356,27 @@ add_meta_data( Aircraft.Engine.TYPE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.NTYE', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.NTYE', "FLOPS": None, "LEAPS1": None}, option=True, default_value=GASPEngineType.TURBOJET, - types=GASPEngineType, - units="unitless", - desc='specifies engine type used for engine mass calculation', -) - -add_meta_data( - Aircraft.Engine.USE_PROPELLER_MAP, - meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - option=True, - default_value=False, - types=bool, + types=(GASPEngineType, int, str), + multivalue=True, units="unitless", - desc='flag whether to use propeller map or Hamilton-Standard model.' + desc='specifies engine type used for GASP-based engine mass calculation', ) add_meta_data( Aircraft.Engine.WING_LOCATIONS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.YP', - "FLOPS": 'WTIN.ETAE', # ['&DEFINE.WTIN.ETAE', 'WDEF.ETAE'], - "LEAPS1": 'aircraft.inputs.L0_propulsion.wing_engine_locations' - }, + historical_name={ + "GASP": 'INGASP.YP', + "FLOPS": 'WTIN.ETAE', # ['&DEFINE.WTIN.ETAE', 'WDEF.ETAE'], + "LEAPS1": 'aircraft.inputs.L0_propulsion.wing_engine_locations', + }, units='unitless', desc='Engine wing mount locations as fractions of semispan; (NUM_WING_ENGINES)/2 values ' - 'are input', - default_value=np.array([0.0]) + 'are input', + default_value=np.array([0.0]), ) # ___ _ @@ -2400,20 +2388,15 @@ add_meta_data( Aircraft.Engine.Gearbox.EFFICIENCY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='The efficiency of the gearbox.', - default_value=0.98, + default_value=1.0, ) add_meta_data( Aircraft.Engine.Gearbox.GEAR_RATIO, meta_data=_MetaData, - historical_name={"GASP": None, # 1 / INPROP.GR - "FLOPS": None, - "LEAPS1": None}, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, # 1 / INPROP.GR units='unitless', desc='Reduction gear ratio, or the ratio of the RPM_in divided by the RPM_out for the gearbox.', default_value=1.0, @@ -2422,11 +2405,8 @@ add_meta_data( Aircraft.Engine.Gearbox.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='kg', + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbm', desc='The mass of the gearbox.', default_value=0, ) @@ -2434,24 +2414,21 @@ add_meta_data( Aircraft.Engine.Gearbox.SHAFT_POWER_DESIGN, meta_data=_MetaData, - historical_name={"GASP": 'INPROP.HPMSLS', # max sea level static horsepower, hp - "FLOPS": None, - "LEAPS1": None, - }, - units='kW', - desc='A guess for the maximum power that will be transmitted through the gearbox during the mission.', + historical_name={ + "GASP": 'INPROP.HPMSLS', # max sea level static horsepower, hp + "FLOPS": None, + "LEAPS1": None, + }, + units='hp', + desc='A guess for the maximum power that will be transmitted through the gearbox during the mission (max shp input).', default_value=1.0, - option=True ) add_meta_data( Aircraft.Engine.Gearbox.SPECIFIC_TORQUE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='N*m/kg', + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbf*ft/lbm', desc='The specific torque of the gearbox, used to calculate gearbox mass. ', default_value=100, ) @@ -2466,7 +2443,7 @@ Aircraft.Engine.Motor.MASS, meta_data=_MetaData, historical_name={"GASP": 'WMOTOR', "FLOPS": None, "LEAPS1": None}, - units='kg', + units='lbm', desc='Total motor mass (considers number of motors)', default_value=0.0, ) @@ -2474,15 +2451,123 @@ add_meta_data( Aircraft.Engine.Motor.TORQUE_MAX, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='N*m', + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbf*ft', desc='Max torque value that can be output from a single motor. Used to determine ' - 'motor mass in pre-mission', + 'motor mass in pre-mission', +) + +# ___ _ _ +# | _ \ _ _ ___ _ __ ___ | | | | ___ _ _ +# | _/ | '_| / _ \ | '_ \ / -_) | | | | / -_) | '_| +# |_| |_| \___/ | .__/ \___| |_| |_| \___| |_| +# |_| +# =================================================== + +add_meta_data( + Aircraft.Engine.Propeller.ACTIVITY_FACTOR, + meta_data=_MetaData, + historical_name={"GASP": 'INPROP.AF', "FLOPS": None, "LEAPS1": None}, + units="unitless", + desc='propeller actitivty factor per Blade (Range: 80 to 200)', + default_value=0.0, +) + +# NOTE if FT < 0, this bool is true, if >= 0, this is false and the value of FT is used +# as the installation loss factor +add_meta_data( + Aircraft.Engine.Propeller.COMPUTE_INSTALLATION_LOSS, + meta_data=_MetaData, + historical_name={"GASP": 'INPROP.FT', "FLOPS": None, "LEAPS1": None}, + units="unitless", + option=True, + default_value=True, + types=bool, + multivalue=True, + desc='if true, compute installation loss factor based on blockage factor', +) + +add_meta_data( + Aircraft.Engine.Propeller.DATA_FILE, + meta_data=_MetaData, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='unitless', + types=(str, Path), + default_value=None, + option=True, + desc='filepath to data file containing propeller data map', +) + +add_meta_data( + Aircraft.Engine.Propeller.DIAMETER, + meta_data=_MetaData, + historical_name={"GASP": 'INPROP.DPROP', "FLOPS": None, "LEAPS1": None}, + units='ft', + desc='propeller diameter', + default_value=0.0, +) + +add_meta_data( + Aircraft.Engine.Propeller.INTEGRATED_LIFT_COEFFICIENT, + meta_data=_MetaData, + historical_name={"GASP": 'INPROP.CLI', "FLOPS": None, "LEAPS1": None}, + units='unitless', + desc='propeller blade integrated design lift coefficient (Range: 0.3 to 0.8)', + default_value=0.5, +) + +add_meta_data( + Aircraft.Engine.Propeller.NUM_BLADES, + meta_data=_MetaData, + historical_name={"GASP": 'INPROP.BL', "FLOPS": None, "LEAPS1": None}, + units='unitless', + desc='number of blades per propeller', + option=True, + types=(int, np.ndarray), + multivalue=True, + default_value=0 +) + +add_meta_data( + Aircraft.Engine.Propeller.TIP_MACH_MAX, + meta_data=_MetaData, + historical_name={ + "GASP": None, # TODO this needs verification + "FLOPS": None, + "LEAPS1": None, + }, + units='unitless', + desc='maximum allowable Mach number at propeller tip (based on helical speed)', + default_value=1.0, +) + +add_meta_data( + Aircraft.Engine.Propeller.TIP_SPEED_MAX, + meta_data=_MetaData, + historical_name={ + "GASP": ['INPROP.TSPDMX', 'INPROP.TPSPDMXe'], + "FLOPS": None, + "LEAPS1": None, + }, + units='ft/s', + desc='maximum allowable propeller linear tip speed', + default_value=800.0, ) +# add_meta_data( +# Aircraft.Engine.USE_PROPELLER_MAP, +# meta_data=_MetaData, +# historical_name={"GASP": None, +# "FLOPS": None, +# "LEAPS1": None +# }, +# option=True, +# default_value=False, +# types=bool, +# units="unitless", +# desc='flag whether to use propeller map or Hamilton-Standard model.' +# ) + # ______ _ # | ____| (_) # | |__ _ _ __ ___ @@ -2494,10 +2579,11 @@ add_meta_data( Aircraft.Fins.AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.SFIN', # ['&DEFINE.WTIN.SFIN', 'WTS.SFIN'], - "LEAPS1": 'aircraft.inputs.L0_fins.area' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.SFIN', # ['&DEFINE.WTIN.SFIN', 'WTS.SFIN'], + "LEAPS1": 'aircraft.inputs.L0_fins.area', + }, units='ft**2', desc='vertical fin theoretical area', default_value=0.0, @@ -2508,13 +2594,15 @@ # - see also: Aircraft.Fins.MASS_SCALER Aircraft.Fins.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(4, 2)', '~WEIGHT.WFIN', '~WTSTAT.WSP(4, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._wing_vertical_fin_weight', - 'aircraft.outputs.L0_weights_summary.wing_vertical_fin_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(4, 2)', '~WEIGHT.WFIN', '~WTSTAT.WSP(4, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._wing_vertical_fin_weight', + 'aircraft.outputs.L0_weights_summary.wing_vertical_fin_weight', + ], + }, units='lbm', desc='mass of vertical fins', default_value=None, @@ -2523,10 +2611,11 @@ add_meta_data( Aircraft.Fins.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRFIN', # ['&DEFINE.WTIN.FRFIN', 'WTS.FRFIN'], - "LEAPS1": 'aircraft.inputs.L0_overrides.wing_vertical_fin_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRFIN', # ['&DEFINE.WTIN.FRFIN', 'WTS.FRFIN'], + "LEAPS1": 'aircraft.inputs.L0_overrides.wing_vertical_fin_weight', + }, units='unitless', desc='mass scaler for fin structure', default_value=1.0, @@ -2535,10 +2624,11 @@ add_meta_data( Aircraft.Fins.NUM_FINS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.NFIN', # ['&DEFINE.WTIN.NFIN', 'WTS.NFIN'], - "LEAPS1": 'aircraft.inputs.L0_fins.fin_count' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.NFIN', # ['&DEFINE.WTIN.NFIN', 'WTS.NFIN'], + "LEAPS1": 'aircraft.inputs.L0_fins.fin_count', + }, units='unitless', desc='number of fins', types=int, @@ -2549,10 +2639,11 @@ add_meta_data( Aircraft.Fins.TAPER_RATIO, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.TRFIN', # ['&DEFINE.WTIN.TRFIN', 'WTS.TRFIN'], - "LEAPS1": 'aircraft.inputs.L0_fins.taper_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.TRFIN', # ['&DEFINE.WTIN.TRFIN', 'WTS.TRFIN'], + "LEAPS1": 'aircraft.inputs.L0_fins.taper_ratio', + }, units='unitless', desc='vertical fin theoretical taper ratio', default_value=None, @@ -2569,10 +2660,11 @@ add_meta_data( Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FULAUX', # ['&DEFINE.WTIN.FULAUX', 'FAWT.FULAUX'], - "LEAPS1": 'aircraft.inputs.L0_fuel.aux_capacity' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FULAUX', # ['&DEFINE.WTIN.FULAUX', 'FAWT.FULAUX'], + "LEAPS1": 'aircraft.inputs.L0_fuel.aux_capacity', + }, units='lbm', desc='fuel capacity of the auxiliary tank', default_value=None, @@ -2581,10 +2673,7 @@ add_meta_data( Aircraft.Fuel.BURN_PER_PASSENGER_MILE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm/NM', desc='average fuel burn per passenger per mile flown', ) @@ -2592,10 +2681,11 @@ add_meta_data( Aircraft.Fuel.CAPACITY_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISWT.FWMAX', - "LEAPS1": '(WeightABC)self._wing_fuel_capacity_factor' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISWT.FWMAX', + "LEAPS1": '(WeightABC)self._wing_fuel_capacity_factor', + }, units='unitless', desc='fuel capacity factor', default_value=23.0, @@ -2604,10 +2694,7 @@ add_meta_data( Aircraft.Fuel.DENSITY, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FUELD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.FUELD', "FLOPS": None, "LEAPS1": None}, units='lbm/galUS', desc='fuel density', default_value=6.687, @@ -2617,28 +2704,26 @@ add_meta_data( Aircraft.Fuel.DENSITY_RATIO, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FULDEN', # ['&DEFINE.WTIN.FULDEN', 'UPFUEL.FULDEN'], - "LEAPS1": 'aircraft.inputs.L0_fuel.density_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FULDEN', # ['&DEFINE.WTIN.FULDEN', 'UPFUEL.FULDEN'], + "LEAPS1": 'aircraft.inputs.L0_fuel.density_ratio', + }, units='unitless', desc='Fuel density ratio for alternate fuels compared to jet fuel (typical ' - 'density of 6.7 lbm/gal), used in the calculation of wing_capacity (if ' - 'wing_capacity is not input) and in the calculation of fuel system ' - 'weight.', + 'density of 6.7 lbm/gal), used in the calculation of wing_capacity (if ' + 'wing_capacity is not input) and in the calculation of fuel system ' + 'weight.', default_value=1.0, ) add_meta_data( Aircraft.Fuel.FUEL_MARGIN, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FVOL_MRG', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.FVOL_MRG', "FLOPS": None, "LEAPS1": None}, units='unitless', # percent desc='excess fuel volume required, essentially the amount of fuel above ' - 'the design point that there has to be volume to carry', + 'the design point that there has to be volume to carry', ) add_meta_data( @@ -2646,13 +2731,15 @@ # - see also: Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER Aircraft.Fuel.FUEL_SYSTEM_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(13, 2)', '~WEIGHT.WFSYS', '~WTSTAT.WSP(13, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._fuel_sys_weight', - 'aircraft.outputs.L0_weights_summary.fuel_sys_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(13, 2)', '~WEIGHT.WFSYS', '~WTSTAT.WSP(13, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._fuel_sys_weight', + 'aircraft.outputs.L0_weights_summary.fuel_sys_weight', + ], + }, units='lbm', desc='fuel system mass', default_value=None, @@ -2661,10 +2748,7 @@ add_meta_data( Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKFS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKFS', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of fuel system', ) @@ -2672,11 +2756,12 @@ add_meta_data( Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CK21', - # ['&DEFINE.WTIN.WFSYS', 'MISWT.WFSYS', 'MISWT.OFSYS'], - "FLOPS": 'WTIN.WFSYS', - "LEAPS1": 'aircraft.inputs.L0_overrides.fuel_sys_weight' - }, + historical_name={ + "GASP": 'INGASP.CK21', + # ['&DEFINE.WTIN.WFSYS', 'MISWT.WFSYS', 'MISWT.OFSYS'], + "FLOPS": 'WTIN.WFSYS', + "LEAPS1": 'aircraft.inputs.L0_overrides.fuel_sys_weight', + }, units='unitless', desc='scaler for fuel system mass', default_value=1.0, @@ -2685,13 +2770,15 @@ add_meta_data( Aircraft.Fuel.FUSELAGE_FUEL_CAPACITY, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.FULFMX', 'WTS.FULFMX', '~WEIGHT.FUFU'], - "FLOPS": 'WTIN.FULFMX', - "LEAPS1": ['aircraft.inputs.L0_fuel.fuselage_capacity', - '(WeightABC)self._fuselage_fuel_capacity' - ] - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.FULFMX', 'WTS.FULFMX', '~WEIGHT.FUFU'], + "FLOPS": 'WTIN.FULFMX', + "LEAPS1": [ + 'aircraft.inputs.L0_fuel.fuselage_capacity', + '(WeightABC)self._fuselage_fuel_capacity', + ], + }, units='lbm', desc='fuel capacity of the fuselage', default_value=None, @@ -2700,10 +2787,11 @@ add_meta_data( Aircraft.Fuel.NUM_TANKS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.NTANK', # ['&DEFINE.WTIN.NTANK', 'WTS.NTANK'], - "LEAPS1": 'aircraft.inputs.L0_fuel.tank_count' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.NTANK', # ['&DEFINE.WTIN.NTANK', 'WTS.NTANK'], + "LEAPS1": 'aircraft.inputs.L0_fuel.tank_count', + }, units='unitless', desc='number of fuel tanks', types=int, @@ -2714,32 +2802,36 @@ add_meta_data( Aircraft.Fuel.TOTAL_CAPACITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FMXTOT', # ['&DEFINE.WTIN.FMXTOT', 'PLRNG.FMXTOT'], - "LEAPS1": ['aircraft.inputs.L0_fuel.total_capacity', - 'aircraft.cached.L0_fuel.total_capacity', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FMXTOT', # ['&DEFINE.WTIN.FMXTOT', 'PLRNG.FMXTOT'], + "LEAPS1": [ + 'aircraft.inputs.L0_fuel.total_capacity', + 'aircraft.cached.L0_fuel.total_capacity', + ], + }, units='lbm', desc='Total fuel capacity of the aircraft including wing, fuselage and ' - 'auxiliary tanks. Used in generating payload-range diagram (Default = ' - 'wing_capacity + fuselage_capacity + aux_capacity)', + 'auxiliary tanks. Used in generating payload-range diagram (Default = ' + 'wing_capacity + fuselage_capacity + aux_capacity)', default_value=None, ) add_meta_data( Aircraft.Fuel.TOTAL_VOLUME, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WEIGHT.ZFEQ', - "LEAPS1": ['(WeightABC)self._total_fuel_vol', - '~WeightABC.calc_unusable_fuel.total_fuel_vol', - '~WeightABC._pre_unusable_fuel.total_fuel_vol', - '~BasicTransportWeight._pre_unusable_fuel.total_fuel_vol', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WEIGHT.ZFEQ', + "LEAPS1": [ + '(WeightABC)self._total_fuel_vol', + '~WeightABC.calc_unusable_fuel.total_fuel_vol', + '~WeightABC._pre_unusable_fuel.total_fuel_vol', + '~BasicTransportWeight._pre_unusable_fuel.total_fuel_vol', + ], + }, units='galUS', # need to check this - desc='Total fuel volume' + desc='Total fuel volume', ) add_meta_data( @@ -2747,13 +2839,15 @@ # - see also: Aircraft.Fuel.UNUSABLE_FUEL_MASS_SCALER Aircraft.Fuel.UNUSABLE_FUEL_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(29, 2)', '~WEIGHT.WUF', '~WTSTAT.WSP(29, 2)', '~INERT.WUF'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._unusable_fuel_weight', - 'aircraft.outputs.L0_weights_summary.unusable_fuel_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(29, 2)', '~WEIGHT.WUF', '~WTSTAT.WSP(29, 2)', '~INERT.WUF'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._unusable_fuel_weight', + 'aircraft.outputs.L0_weights_summary.unusable_fuel_weight', + ], + }, units='lbm', desc='unusable fuel mass', default_value=None, @@ -2762,10 +2856,7 @@ add_meta_data( Aircraft.Fuel.UNUSABLE_FUEL_MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": "INGASP.CW(13)", - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": "INGASP.CW(13)", "FLOPS": None, "LEAPS1": None}, default_value=6.0, units="unitless", desc='mass trend coefficient of trapped fuel factor', @@ -2774,11 +2865,12 @@ add_meta_data( Aircraft.Fuel.UNUSABLE_FUEL_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WUF', 'MISWT.WUF', 'MISWT.OUF'], - "FLOPS": 'WTIN.WUF', - "LEAPS1": 'aircraft.inputs.L0_overrides.unusable_fuel_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WUF', 'MISWT.WUF', 'MISWT.OUF'], + "FLOPS": 'WTIN.WUF', + "LEAPS1": 'aircraft.inputs.L0_overrides.unusable_fuel_weight', + }, units='unitless', desc='scaler for Unusable fuel mass', default_value=1.0, @@ -2787,10 +2879,11 @@ add_meta_data( Aircraft.Fuel.WING_FUEL_CAPACITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FULWMX', # ['&DEFINE.WTIN.FULWMX', 'WTS.FULWMX'], - "LEAPS1": 'aircraft.inputs.L0_fuel.wing_capacity' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FULWMX', # ['&DEFINE.WTIN.FULWMX', 'WTS.FULWMX'], + "LEAPS1": 'aircraft.inputs.L0_fuel.wing_capacity', + }, units='lbm', desc='fuel capacity of the auxiliary tank', default_value=None, @@ -2799,10 +2892,7 @@ add_meta_data( Aircraft.Fuel.WING_FUEL_FRACTION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKWF', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKWF', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='fraction of total theoretical wing volume used for wing fuel', ) @@ -2810,10 +2900,11 @@ add_meta_data( Aircraft.Fuel.WING_REF_CAPACITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FUELRF', # ['&DEFINE.WTIN.FUELRF', 'WPAB.FUELRF'], - "LEAPS1": 'aircraft.inputs.L0_fuel.wing_ref_capacity' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FUELRF', # ['&DEFINE.WTIN.FUELRF', 'WPAB.FUELRF'], + "LEAPS1": 'aircraft.inputs.L0_fuel.wing_ref_capacity', + }, units='lbm', # TODO FLOPS says lbm, sfwate.f line 827 desc='reference fuel volume', default_value=0.0, @@ -2822,10 +2913,11 @@ add_meta_data( Aircraft.Fuel.WING_REF_CAPACITY_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FSWREF', # ['&DEFINE.WTIN.FSWREF', 'WPAB.FSWREF'], - "LEAPS1": 'aircraft.inputs.L0_fuel.wing_ref_capacity_area' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FSWREF', # ['&DEFINE.WTIN.FSWREF', 'WPAB.FSWREF'], + "LEAPS1": 'aircraft.inputs.L0_fuel.wing_ref_capacity_area', + }, units='unitless', # TODO FLOPS says unitless, sfwate.f line 828 desc='reference wing area for fuel capacity', default_value=0.0, @@ -2834,10 +2926,11 @@ add_meta_data( Aircraft.Fuel.WING_REF_CAPACITY_TERM_A, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FUSCLA', # ['&DEFINE.WTIN.FUSCLA', 'WPAB.FUSCLA'], - "LEAPS1": 'aircraft.inputs.L0_fuel.wing_ref_capacity_1_5_term' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FUSCLA', # ['&DEFINE.WTIN.FUSCLA', 'WPAB.FUSCLA'], + "LEAPS1": 'aircraft.inputs.L0_fuel.wing_ref_capacity_1_5_term', + }, units='unitless', desc='scaling factor A', default_value=0.0, @@ -2846,10 +2939,11 @@ add_meta_data( Aircraft.Fuel.WING_REF_CAPACITY_TERM_B, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FUSCLB', # ['&DEFINE.WTIN.FUSCLB', 'WPAB.FUSCLB'], - "LEAPS1": 'aircraft.inputs.L0_fuel.wing_ref_capacity_linear_term' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FUSCLB', # ['&DEFINE.WTIN.FUSCLB', 'WPAB.FUSCLB'], + "LEAPS1": 'aircraft.inputs.L0_fuel.wing_ref_capacity_linear_term', + }, units='unitless', desc='scaling factor B', default_value=0.0, @@ -2872,10 +2966,7 @@ add_meta_data( Aircraft.Fuel.WING_VOLUME_DESIGN, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FVOLW_DES', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.FVOLW_DES', "FLOPS": None, "LEAPS1": None}, units='ft**3', desc='wing tank fuel volume when carrying design fuel plus fuel margin', ) @@ -2883,10 +2974,7 @@ add_meta_data( Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FVOLW_GEOM', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.FVOLW_GEOM', "FLOPS": None, "LEAPS1": None}, units='ft**3', desc='wing tank fuel volume based on geometry', ) @@ -2894,10 +2982,7 @@ add_meta_data( Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FVOLW_MAX', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.FVOLW_MAX', "FLOPS": None, "LEAPS1": None}, units='ft**3', desc='wing tank volume based on maximum wing fuel weight', ) @@ -2919,13 +3004,15 @@ # - see also: Aircraft.Furnishings.MASS_SCALER Aircraft.Furnishings.MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(8)', - # ['WTS.WSP(22, 2)', '~WEIGHT.WFURN', '~WTSTAT.WSP(22, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._furnishings_group_weight', - 'aircraft.outputs.L0_weights_summary.furnishings_group_weight', - ] - }, + historical_name={ + "GASP": 'INGASP.CW(8)', + # ['WTS.WSP(22, 2)', '~WEIGHT.WFURN', '~WTSTAT.WSP(22, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._furnishings_group_weight', + 'aircraft.outputs.L0_weights_summary.furnishings_group_weight', + ], + }, units='lbm', desc='Total furnishings system mass', default_value=None, @@ -2934,22 +3021,20 @@ add_meta_data( Aircraft.Furnishings.MASS_BASE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', - desc='Base furnishings system mass without additional 1% empty mass' + desc='Base furnishings system mass without additional 1% empty mass', ) add_meta_data( Aircraft.Furnishings.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WFURN', 'MISWT.WFURN', 'MISWT.OFURN'], - "FLOPS": 'WTIN.WFURN', - "LEAPS1": 'aircraft.inputs.L0_overrides.furnishings_group_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WFURN', 'MISWT.WFURN', 'MISWT.OFURN'], + "FLOPS": 'WTIN.WFURN', + "LEAPS1": 'aircraft.inputs.L0_overrides.furnishings_group_weight', + }, units='unitless', desc='Furnishings system mass scaler', default_value=1.0, @@ -2968,10 +3053,7 @@ add_meta_data( Aircraft.Fuselage.AISLE_WIDTH, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WAS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WAS', "FLOPS": None, "LEAPS1": None}, units='inch', desc='width of the aisles in the passenger cabin', option=True, @@ -2983,45 +3065,46 @@ add_meta_data( Aircraft.Fuselage.AVG_DIAMETER, meta_data=_MetaData, - historical_name={"GASP": ['INGASP.WC', 'INGASP.SWF'], - "FLOPS": None, # 'EDETIN.XD', - "LEAPS1": 'aircraft.outputs.L0_fuselage.avg_diam' - }, + historical_name={ + "GASP": ['INGASP.WC', 'INGASP.SWF'], + "FLOPS": None, # 'EDETIN.XD', + "LEAPS1": 'aircraft.outputs.L0_fuselage.avg_diam', + }, units='ft', - desc='average fuselage diameter' + desc='average fuselage diameter', ) add_meta_data( Aircraft.Fuselage.CHARACTERISTIC_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.EL[4]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[3]', - 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[3]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.EL[4]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[3]', + 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[3]', + ], + }, units='ft', - desc='Reynolds characteristic length for the fuselage' + desc='Reynolds characteristic length for the fuselage', ) add_meta_data( Aircraft.Fuselage.CROSS_SECTION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['MISSA.SPI', '~CDCC.SPI'], - "LEAPS1": 'aircraft.outputs.L0_fuselage.mission_cross_sect_area' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['MISSA.SPI', '~CDCC.SPI'], + "LEAPS1": 'aircraft.outputs.L0_fuselage.mission_cross_sect_area', + }, units='ft**2', - desc='fuselage cross sectional area' + desc='fuselage cross sectional area', ) add_meta_data( Aircraft.Fuselage.DELTA_DIAMETER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.HCK', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.HCK', "FLOPS": None, "LEAPS1": None}, units='ft', desc='mean fuselage cabin diameter minus mean fuselage nose diameter', default_value=4.5, @@ -3030,34 +3113,34 @@ add_meta_data( Aircraft.Fuselage.DIAMETER_TO_WING_SPAN, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['MISSA.DB', '~CDCC.DB'], - "LEAPS1": 'aircraft.outputs.L0_fuselage.mission_diam_to_wing_span_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['MISSA.DB', '~CDCC.DB'], + "LEAPS1": 'aircraft.outputs.L0_fuselage.mission_diam_to_wing_span_ratio', + }, units='unitless', - desc='fuselage diameter to wing span ratio' + desc='fuselage diameter to wing span ratio', ) add_meta_data( Aircraft.Fuselage.FINENESS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.FR[4]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[3]', - 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[3]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.FR[4]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[3]', + 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[3]', + ], + }, units='unitless', - desc='fuselage fineness ratio' + desc='fuselage fineness ratio', ) add_meta_data( Aircraft.Fuselage.FLAT_PLATE_AREA_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELFE', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELFE', "FLOPS": None, "LEAPS1": None}, units='ft**2', desc='increment to fuselage flat plate area', ) @@ -3065,22 +3148,20 @@ add_meta_data( Aircraft.Fuselage.FORM_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CKF', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CKF', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='fuselage form factor', - default_value=1 + default_value=1, ) add_meta_data( Aircraft.Fuselage.LAMINAR_FLOW_LOWER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRLB', # ['&DEFINE.AERIN.TRLB', 'XLAM.TRLB', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.fuselage_percent_laminar_flow_lower_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRLB', # ['&DEFINE.AERIN.TRLB', 'XLAM.TRLB', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.fuselage_percent_laminar_flow_lower_surface', + }, units='unitless', desc='define percent laminar flow for fuselage lower surface', default_value=0.0, @@ -3089,10 +3170,11 @@ add_meta_data( Aircraft.Fuselage.LAMINAR_FLOW_UPPER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRUB', # ['&DEFINE.AERIN.TRUB', 'XLAM.TRUB', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.fuselage_percent_laminar_flow_upper_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRUB', # ['&DEFINE.AERIN.TRUB', 'XLAM.TRUB', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.fuselage_percent_laminar_flow_upper_surface', + }, units='unitless', desc='define percent laminar flow for fuselage upper surface', default_value=0.0, @@ -3102,35 +3184,38 @@ add_meta_data( Aircraft.Fuselage.LENGTH, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ELF', - "FLOPS": 'WTIN.XL', - # [ # inputs - # '&DEFINE.WTIN.XL', 'WTS.XL', - # # outputs - # 'EDETIN.BL', '~DEFAER.BL', - # ], - "LEAPS1": ['aircraft.inputs.L0_fuselage.total_length', - 'aircraft.outputs.L0_fuselage.total_length', - # other - 'aircraft.cached.L0_fuselage.total_length', - ] - }, + historical_name={ + "GASP": 'INGASP.ELF', + "FLOPS": 'WTIN.XL', + # [ # inputs + # '&DEFINE.WTIN.XL', 'WTS.XL', + # # outputs + # 'EDETIN.BL', '~DEFAER.BL', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_fuselage.total_length', + 'aircraft.outputs.L0_fuselage.total_length', + # other + 'aircraft.cached.L0_fuselage.total_length', + ], + }, units='ft', desc='Define the Fuselage total length. If total_length is not input for a ' - 'passenger transport, LEAPS will calculate the fuselage length, width and ' - 'depth and the length of the passenger compartment.', + 'passenger transport, LEAPS will calculate the fuselage length, width and ' + 'depth and the length of the passenger compartment.', default_value=0.0, ) add_meta_data( Aircraft.Fuselage.LENGTH_TO_DIAMETER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['MISSA.BODYLD', '~CDCC.BODYLD'], - "LEAPS1": 'aircraft.outputs.L0_fuselage.mission_len_to_diam_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['MISSA.BODYLD', '~CDCC.BODYLD'], + "LEAPS1": 'aircraft.outputs.L0_fuselage.mission_len_to_diam_ratio', + }, units='unitless', - desc='fuselage length to diameter ratio' + desc='fuselage length to diameter ratio', ) add_meta_data( @@ -3138,13 +3223,15 @@ # - see also: Aircraft.Fuselage.MASS_SCALER Aircraft.Fuselage.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(6, 2)', '~WEIGHT.WFUSE', '~WTSTAT.WSP(6, 2)', '~INERT.WFUSE', ], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._fuselage_weight', - 'aircraft.outputs.L0_weights_summary.fuselage_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(6, 2)', '~WEIGHT.WFUSE', '~WTSTAT.WSP(6, 2)', '~INERT.WFUSE', ], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._fuselage_weight', + 'aircraft.outputs.L0_weights_summary.fuselage_weight', + ], + }, units='lbm', desc='mass of the fuselage structure', default_value=None, @@ -3153,10 +3240,7 @@ add_meta_data( Aircraft.Fuselage.MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKB', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKB', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of fuselage', default_value=136, @@ -3165,10 +3249,11 @@ add_meta_data( Aircraft.Fuselage.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRFU', # ['&DEFINE.WTIN.FRFU', 'WTS.FRFU'], - "LEAPS1": 'aircraft.inputs.L0_overrides.fuselage_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRFU', # ['&DEFINE.WTIN.FRFU', 'WTS.FRFU'], + "LEAPS1": 'aircraft.inputs.L0_overrides.fuselage_weight', + }, units='unitless', desc='mass scaler of the fuselage structure', default_value=1.0, @@ -3177,30 +3262,33 @@ add_meta_data( Aircraft.Fuselage.MAX_HEIGHT, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.DF', # ['&DEFINE.WTIN.DF', 'WTS.DF'], - "LEAPS1": 'aircraft.inputs.L0_fuselage.max_height' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.DF', # ['&DEFINE.WTIN.DF', 'WTS.DF'], + "LEAPS1": 'aircraft.inputs.L0_fuselage.max_height', + }, units='ft', - desc='maximum fuselage height' + desc='maximum fuselage height', ) add_meta_data( Aircraft.Fuselage.MAX_WIDTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.WF', - # [ # inputs - # '&DEFINE.WTIN.WF', 'WTS.WF', - # # outputs - # 'MIMOD.FWID', - # ], - "LEAPS1": ['aircraft.inputs.L0_fuselage.max_width', - 'aircraft.outputs.L0_fuselage.max_width', - # other - 'aircraft.cached.L0_fuselage.max_width', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.WF', + # [ # inputs + # '&DEFINE.WTIN.WF', 'WTS.WF', + # # outputs + # 'MIMOD.FWID', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_fuselage.max_width', + 'aircraft.outputs.L0_fuselage.max_width', + # other + 'aircraft.cached.L0_fuselage.max_width', + ], + }, units='ft', desc='maximum fuselage width', default_value=0.0, @@ -3210,12 +3298,14 @@ add_meta_data( Aircraft.Fuselage.MILITARY_CARGO_FLOOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.CARGF', # ['&DEFINE.WTIN.CARGF', 'WTS.CARGF'], - "LEAPS1": ['aircraft.inputs.L0_crew_and_payload.military_cargo', - 'aircraft.cached.L0_crew_and_payload.military_cargo', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.CARGF', # ['&DEFINE.WTIN.CARGF', 'WTS.CARGF'], + "LEAPS1": [ + 'aircraft.inputs.L0_crew_and_payload.military_cargo', + 'aircraft.cached.L0_crew_and_payload.military_cargo', + ], + }, units='unitless', desc='indicate whether or not there is a military cargo aircraft floor', option=True, @@ -3226,10 +3316,7 @@ add_meta_data( Aircraft.Fuselage.NOSE_FINENESS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ELODN', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.ELODN', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='length to diameter ratio of nose cone', default_value=1, @@ -3238,10 +3325,7 @@ add_meta_data( Aircraft.Fuselage.NUM_AISLES, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.AS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.AS', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='number of aisles in the passenger cabin', types=int, @@ -3252,14 +3336,16 @@ add_meta_data( Aircraft.Fuselage.NUM_FUSELAGES, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.NFUSE', 'EDETIN.NFUSE', '~WWGHT.NFUSE'], - "FLOPS": 'WTIN.NFUSE', - "LEAPS1": ['aircraft.inputs.L0_fuselage.count', - # other - 'aircraft.cached.L0_fuselage.count', - ] - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.NFUSE', 'EDETIN.NFUSE', '~WWGHT.NFUSE'], + "FLOPS": 'WTIN.NFUSE', + "LEAPS1": [ + 'aircraft.inputs.L0_fuselage.count', + # other + 'aircraft.cached.L0_fuselage.count', + ], + }, units='unitless', desc='number of fuselages', types=int, @@ -3270,10 +3356,7 @@ add_meta_data( Aircraft.Fuselage.NUM_SEATS_ABREAST, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SAB', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SAB', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='seats abreast in fuselage', types=int, @@ -3284,12 +3367,14 @@ add_meta_data( Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.XLP', # ['&DEFINE.WTIN.XLP', 'WTS.XLP'], - "LEAPS1": ['aircraft.inputs.L0_fuselage.passenger_compartment_length', - 'aircraft.cached.L0_fuselage.passenger_compartment_length', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.XLP', # ['&DEFINE.WTIN.XLP', 'WTS.XLP'], + "LEAPS1": [ + 'aircraft.inputs.L0_fuselage.passenger_compartment_length', + 'aircraft.cached.L0_fuselage.passenger_compartment_length', + ], + }, units='ft', desc='length of passenger compartment', default_value=0.0, @@ -3298,10 +3383,7 @@ add_meta_data( Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ELPC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.ELPC', "FLOPS": None, "LEAPS1": None}, units='ft', desc='length of the pilot compartment', ) @@ -3309,21 +3391,19 @@ add_meta_data( Aircraft.Fuselage.PLANFORM_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WEIGHT.FPAREA', - "LEAPS1": '(WeightABC)self._fuselage_planform_area' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WEIGHT.FPAREA', + "LEAPS1": '(WeightABC)self._fuselage_planform_area', + }, units='ft**2', - desc='fuselage planform area' + desc='fuselage planform area', ) add_meta_data( Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELP', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELP', "FLOPS": None, "LEAPS1": None}, units='psi', desc='fuselage pressure differential during cruise', default_value=7.5, @@ -3332,10 +3412,7 @@ add_meta_data( Aircraft.Fuselage.SEAT_PITCH, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.PS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.PS', "FLOPS": None, "LEAPS1": None}, units='inch', desc='pitch of the economy class seats', option=True, @@ -3345,10 +3422,7 @@ add_meta_data( Aircraft.Fuselage.SEAT_WIDTH, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WS', "FLOPS": None, "LEAPS1": None}, units='inch', desc='width of the economy class seats', option=True, @@ -3358,10 +3432,7 @@ add_meta_data( Aircraft.Fuselage.TAIL_FINENESS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ELODT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.ELODT', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='length to diameter ratio of tail cone', default_value=1, @@ -3372,15 +3443,16 @@ # - see also: Aircraft.Fuselage.WETTED_AREA_SCALER Aircraft.Fuselage.WETTED_AREA, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SF', - "FLOPS": None, # ['ACTWET.SWTFU', 'MISSA.SWET[4]'], - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.fuselage_wetted_area', - 'aircraft.outputs.L0_aerodynamics' - '.mission_component_wetted_area_table[3]', - 'aircraft.cached.L0_aerodynamics' - '.mission_component_wetted_area_table[3]', - ] - }, + historical_name={ + "GASP": 'INGASP.SF', + "FLOPS": None, # ['ACTWET.SWTFU', 'MISSA.SWET[4]'], + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.fuselage_wetted_area', + 'aircraft.outputs.L0_aerodynamics' + '.mission_component_wetted_area_table[3]', + 'aircraft.cached.L0_aerodynamics' '.mission_component_wetted_area_table[3]', + ], + }, units='ft**2', desc='fuselage wetted area', default_value=None, @@ -3389,10 +3461,11 @@ add_meta_data( Aircraft.Fuselage.WETTED_AREA_SCALER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SF_FAC', - "FLOPS": 'AERIN.SWETF', # ['&DEFINE.AERIN.SWETF', 'AWETO.SWETF', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.fuselage_wetted_area' - }, + historical_name={ + "GASP": 'INGASP.SF_FAC', + "FLOPS": 'AERIN.SWETF', # ['&DEFINE.AERIN.SWETF', 'AWETO.SWETF', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.fuselage_wetted_area', + }, units='unitless', desc='fuselage wetted area scaler', default_value=1.0, @@ -3409,25 +3482,28 @@ add_meta_data( Aircraft.HorizontalTail.AREA, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SHT', - "FLOPS": 'WTIN.SHT', # ['&DEFINE.WTIN.SHT', 'EDETIN.SHT'], - "LEAPS1": ['aircraft.inputs.L0_horizontal_tail.area', - 'aircraft.cached.L0_horizontal_tail.area', - ] - }, + historical_name={ + "GASP": 'INGASP.SHT', + "FLOPS": 'WTIN.SHT', # ['&DEFINE.WTIN.SHT', 'EDETIN.SHT'], + "LEAPS1": [ + 'aircraft.inputs.L0_horizontal_tail.area', + 'aircraft.cached.L0_horizontal_tail.area', + ], + }, units='ft**2', desc='horizontal tail theoretical area; overridden by vol_coeff, if ' - 'vol_coeff > 0.0', # this appears to never be calculated in Aviary, need to show users the overriding capability of Aviary + 'vol_coeff > 0.0', # this appears to never be calculated in Aviary, need to show users the overriding capability of Aviary default_value=0.0, ) add_meta_data( Aircraft.HorizontalTail.ASPECT_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ARHT', - "FLOPS": 'WTIN.ARHT', # ['&DEFINE.WTIN.ARHT', 'EDETIN.ARHT'], - "LEAPS1": 'aircraft.inputs.L0_horizontal_tail.aspect_ratio' - }, + historical_name={ + "GASP": 'INGASP.ARHT', + "FLOPS": 'WTIN.ARHT', # ['&DEFINE.WTIN.ARHT', 'EDETIN.ARHT'], + "LEAPS1": 'aircraft.inputs.L0_horizontal_tail.aspect_ratio', + }, units='unitless', desc='horizontal tail theoretical aspect ratio', default_value=None, @@ -3436,10 +3512,7 @@ add_meta_data( Aircraft.HorizontalTail.AVERAGE_CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CBARHT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CBARHT', "FLOPS": None, "LEAPS1": None}, units='ft', desc='mean aerodynamic chord of horizontal tail', ) @@ -3447,47 +3520,50 @@ add_meta_data( Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.EL[2]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[1]', - 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[1]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.EL[2]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[1]', + 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[1]', + ], + }, units='ft', - desc='Reynolds characteristic length for the horizontal tail' + desc='Reynolds characteristic length for the horizontal tail', ) add_meta_data( Aircraft.HorizontalTail.FINENESS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.FR[2]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[1]', - 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[1]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.FR[2]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[1]', + 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[1]', + ], + }, units='unitless', - desc='horizontal tail fineness ratio' + desc='horizontal tail fineness ratio', ) add_meta_data( Aircraft.HorizontalTail.FORM_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CKHT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CKHT', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='horizontal tail form factor', + default_value=1.25, ) add_meta_data( Aircraft.HorizontalTail.LAMINAR_FLOW_LOWER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRLH', # ['&DEFINE.AERIN.TRLH', 'XLAM.TRLH', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.horizontal_tail_percent_laminar_flow_lower_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRLH', # ['&DEFINE.AERIN.TRLH', 'XLAM.TRLH', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.horizontal_tail_percent_laminar_flow_lower_surface', + }, units='unitless', desc='define percent laminar flow for horizontal tail lower surface', default_value=0.0, @@ -3496,10 +3572,11 @@ add_meta_data( Aircraft.HorizontalTail.LAMINAR_FLOW_UPPER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRUH', # ['&DEFINE.AERIN.TRUH', 'XLAM.TRUH', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.horizontal_tail_percent_laminar_flow_upper_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRUH', # ['&DEFINE.AERIN.TRUH', 'XLAM.TRUH', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.horizontal_tail_percent_laminar_flow_upper_surface', + }, units='unitless', desc='define percent laminar flow for horizontal tail upper surface', default_value=0.0, @@ -3510,13 +3587,15 @@ # - see also: Aircraft.HorizontalTail.MASS_SCALER Aircraft.HorizontalTail.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(2, 2)', '~WEIGHT.WHT', '~WTSTAT.WSP(2, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._horizontal_tail_weight', - 'aircraft.outputs.L0_weights_summary.horizontal_tail_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(2, 2)', '~WEIGHT.WHT', '~WTSTAT.WSP(2, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._horizontal_tail_weight', + 'aircraft.outputs.L0_weights_summary.horizontal_tail_weight', + ], + }, units='lbm', desc='mass of horizontal tail', default_value=None, @@ -3525,22 +3604,20 @@ add_meta_data( Aircraft.HorizontalTail.MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKY', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKY', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of horizontal tail', - default_value=.18, + default_value=0.18, ) add_meta_data( Aircraft.HorizontalTail.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRHT', # ['&DEFINE.WTIN.FRHT', 'WTS.FRHT'], - "LEAPS1": 'aircraft.inputs.L0_overrides.horizontal_tail_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRHT', # ['&DEFINE.WTIN.FRHT', 'WTS.FRHT'], + "LEAPS1": 'aircraft.inputs.L0_overrides.horizontal_tail_weight', + }, units='unitless', desc='mass scaler of the horizontal tail structure', default_value=1.0, @@ -3549,10 +3626,7 @@ add_meta_data( Aircraft.HorizontalTail.MOMENT_ARM, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ELTH', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.ELTH', "FLOPS": None, "LEAPS1": None}, units='ft', desc='moment arm of horizontal tail', ) @@ -3560,10 +3634,7 @@ add_meta_data( Aircraft.HorizontalTail.MOMENT_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.COELTH', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.COELTH', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='Ratio of wing chord to horizontal tail moment arm', ) @@ -3571,10 +3642,7 @@ add_meta_data( Aircraft.HorizontalTail.ROOT_CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CRCLHT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CRCLHT', "FLOPS": None, "LEAPS1": None}, units='ft', desc='horizontal tail root chord', ) @@ -3582,10 +3650,7 @@ add_meta_data( Aircraft.HorizontalTail.SPAN, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.BHT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.BHT', "FLOPS": None, "LEAPS1": None}, units='ft', desc='span of horizontal tail', ) @@ -3593,12 +3658,14 @@ add_meta_data( Aircraft.HorizontalTail.SWEEP, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DWPQCH', - "FLOPS": 'WTIN.SWPHT', # , 'WTS.SWPHT'], - "LEAPS1": ['aircraft.inputs.L0_horizontal_tail.sweep_at_quarter_chord', - 'aircraft.cached.L0_horizontal_tail.sweep_at_quarter_chord' - ] - }, + historical_name={ + "GASP": 'INGASP.DWPQCH', + "FLOPS": 'WTIN.SWPHT', # , 'WTS.SWPHT'], + "LEAPS1": [ + 'aircraft.inputs.L0_horizontal_tail.sweep_at_quarter_chord', + 'aircraft.cached.L0_horizontal_tail.sweep_at_quarter_chord', + ], + }, units='deg', desc='quarter-chord sweep of horizontal tail', ) @@ -3606,10 +3673,11 @@ add_meta_data( Aircraft.HorizontalTail.TAPER_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SLMH', - "FLOPS": 'WTIN.TRHT', # , 'EDETIN.TRHT'], - "LEAPS1": 'aircraft.inputs.L0_horizontal_tail.taper_ratio' - }, + historical_name={ + "GASP": 'INGASP.SLMH', + "FLOPS": 'WTIN.TRHT', # , 'EDETIN.TRHT'], + "LEAPS1": 'aircraft.inputs.L0_horizontal_tail.taper_ratio', + }, units='unitless', desc='horizontal tail theoretical taper ratio', default_value=None, @@ -3618,10 +3686,11 @@ add_meta_data( Aircraft.HorizontalTail.THICKNESS_TO_CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.TCHT', - "FLOPS": 'WTIN.TCHT', # , 'EDETIN.TCHT'], - "LEAPS1": 'aircraft.inputs.L0_horizontal_tail.thickness_to_chord_ratio' - }, + historical_name={ + "GASP": 'INGASP.TCHT', + "FLOPS": 'WTIN.TCHT', # , 'EDETIN.TCHT'], + "LEAPS1": 'aircraft.inputs.L0_horizontal_tail.thickness_to_chord_ratio', + }, units='unitless', desc='horizontal tail thickness-chord ratio', default_value=0.0, @@ -3631,25 +3700,23 @@ add_meta_data( Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SAH', - "FLOPS": 'WTIN.HHT', # ['&DEFINE.WTIN.HHT', 'EDETIN.HHT'], - "LEAPS1": 'aircraft.inputs.L0_horizontal_tail.vertical_tail_fraction' - }, + historical_name={ + "GASP": 'INGASP.SAH', + "FLOPS": 'WTIN.HHT', # ['&DEFINE.WTIN.HHT', 'EDETIN.HHT'], + "LEAPS1": 'aircraft.inputs.L0_horizontal_tail.vertical_tail_fraction', + }, units='unitless', desc='Define the decimal fraction of vertical tail span where horizontal ' - 'tail is mounted. Defaults: 0.0 == for body mounted (default for ' - 'transport with all engines on wing); 1.0 == for T tail ' - '(default for transport with multiple engines on fuselage)', + 'tail is mounted. Defaults: 0.0 == for body mounted (default for ' + 'transport with all engines on wing); 1.0 == for T tail ' + '(default for transport with multiple engines on fuselage)', default_value=None, ) add_meta_data( Aircraft.HorizontalTail.VOLUME_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.VBARHX', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.VBARHX', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='tail volume coefficicient of horizontal tail', ) @@ -3659,15 +3726,16 @@ # - see also: Aircraft.HorizontalTail.WETTED_AREA_SCALER Aircraft.HorizontalTail.WETTED_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['ACTWET.SWTHT', 'MISSA.SWET[2]'], - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.horizontal_tail_wetted_area', - 'aircraft.outputs.L0_aerodynamics' - '.mission_component_wetted_area_table[1]', - 'aircraft.cached.L0_aerodynamics' - '.mission_component_wetted_area_table[1]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['ACTWET.SWTHT', 'MISSA.SWET[2]'], + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.horizontal_tail_wetted_area', + 'aircraft.outputs.L0_aerodynamics' + '.mission_component_wetted_area_table[1]', + 'aircraft.cached.L0_aerodynamics' '.mission_component_wetted_area_table[1]', + ], + }, units='ft**2', desc='horizontal tail wetted area', default_value=None, @@ -3676,10 +3744,11 @@ add_meta_data( Aircraft.HorizontalTail.WETTED_AREA_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.SWETH', # ['&DEFINE.AERIN.SWETH', 'AWETO.SWETH', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.horizontal_tail_wetted_area' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.SWETH', # ['&DEFINE.AERIN.SWETH', 'AWETO.SWETH', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.horizontal_tail_wetted_area', + }, units='unitless', desc='horizontal tail wetted area scaler', default_value=1.0, @@ -3698,10 +3767,7 @@ add_meta_data( Aircraft.Hydraulics.FLIGHT_CONTROL_MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(3)', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CW(3)', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='mass trend coefficient of hydraulics for flight control system', default_value=0.10, @@ -3710,10 +3776,7 @@ add_meta_data( Aircraft.Hydraulics.GEAR_MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(4)', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CW(4)', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='mass trend coefficient of hydraulics for landing gear', default_value=0.16, @@ -3724,13 +3787,15 @@ # - see also: Aircraft.Hydraulics.MASS_SCALER Aircraft.Hydraulics.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(19, 2)', '~WEIGHT.WHYD', '~WTSTAT.WSP(19, 2)', '~INERT.WHYD'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._hydraulics_group_weight', - 'aircraft.outputs.L0_weights_summary.hydraulics_group_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(19, 2)', '~WEIGHT.WHYD', '~WTSTAT.WSP(19, 2)', '~INERT.WHYD'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._hydraulics_group_weight', + 'aircraft.outputs.L0_weights_summary.hydraulics_group_weight', + ], + }, units='lbm', desc='mass of hydraulic system', default_value=None, @@ -3739,11 +3804,12 @@ add_meta_data( Aircraft.Hydraulics.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WHYD', 'MISWT.WHYD', 'MISWT.OHYD'], - "FLOPS": 'WTIN.WHYD', - "LEAPS1": 'aircraft.inputs.L0_overrides.hydraulics_group_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WHYD', 'MISWT.WHYD', 'MISWT.OHYD'], + "FLOPS": 'WTIN.WHYD', + "LEAPS1": 'aircraft.inputs.L0_overrides.hydraulics_group_weight', + }, units='unitless', desc='mass scaler of the hydraulic system', default_value=1.0, @@ -3752,10 +3818,11 @@ add_meta_data( Aircraft.Hydraulics.SYSTEM_PRESSURE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.HYDPR', # ['&DEFINE.WTIN.HYDPR', 'WTS.HYDPR'], - "LEAPS1": 'aircraft.inputs.L0_weights.hydraulic_sys_press' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.HYDPR', # ['&DEFINE.WTIN.HYDPR', 'WTS.HYDPR'], + "LEAPS1": 'aircraft.inputs.L0_weights.hydraulic_sys_press', + }, units='psi', desc='hydraulic system pressure', default_value=3000.0, @@ -3775,13 +3842,15 @@ # - see also: Aircraft.Instruments.MASS_SCALER Aircraft.Instruments.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(18, 2)', '~WEIGHT.WIN', '~WTSTAT.WSP(18, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._instrument_group_weight', - 'aircraft.outputs.L0_weights_summary.instrument_group_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(18, 2)', '~WEIGHT.WIN', '~WTSTAT.WSP(18, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._instrument_group_weight', + 'aircraft.outputs.L0_weights_summary.instrument_group_weight', + ], + }, units='lbm', desc='instrument group mass', default_value=None, @@ -3790,10 +3859,7 @@ add_meta_data( Aircraft.Instruments.MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CW(2)', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CW(2)', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='mass trend coefficient of instruments', default_value=0.0862, @@ -3802,11 +3868,12 @@ add_meta_data( Aircraft.Instruments.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WIN', 'MISWT.WIN', 'MISWT.OIN'], - "FLOPS": 'WTIN.WIN', - "LEAPS1": 'aircraft.inputs.L0_overrides.instrument_group_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WIN', 'MISWT.WIN', 'MISWT.OIN'], + "FLOPS": 'WTIN.WIN', + "LEAPS1": 'aircraft.inputs.L0_overrides.instrument_group_weight', + }, units='unitless', desc='mass scaler of the instrument group', default_value=1.0, @@ -3825,14 +3892,15 @@ add_meta_data( Aircraft.LandingGear.CARRIER_BASED, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.CARBAS', # ['&DEFINE.WTIN.CARBAS', 'FAWT.CARBAS'], - "LEAPS1": 'aircraft.inputs.L0_landing_gear.carrier_based' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.CARBAS', # ['&DEFINE.WTIN.CARBAS', 'FAWT.CARBAS'], + "LEAPS1": 'aircraft.inputs.L0_landing_gear.carrier_based', + }, units='unitless', desc='carrier based aircraft switch, affects mass of flight crew, ' - 'avionics, and nose gear where true is carrier based and false is land ' - 'based', + 'avionics, and nose gear where true is carrier based and false is land ' + 'based', option=True, types=bool, default_value=False, @@ -3845,34 +3913,30 @@ # ['&DEFTOL.TOLIN.CDGEAR', '~DEFTOL.CDGEAR', 'ROTDAT.CDGEAR'], 'FLOPS': 'TOLIN.CDGEAR', 'GASP': None, - 'LEAPS1': None}, + 'LEAPS1': None, + }, option=True, - default_value=0., + default_value=0.0, units='unitless', - desc='landing gear drag coefficient') + desc='landing gear drag coefficient', +) add_meta_data( Aircraft.LandingGear.FIXED_GEAR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.IGEAR', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.IGEAR', "FLOPS": None, "LEAPS1": None}, option=True, default_value=True, types=bool, units="unitless", - desc='Type of landing gear. In GASP, 0 is retractable and 1 is deployed (fixed). Here, ' - 'false is retractable and true is deployed (fixed).', + desc='Type of landing gear. In GASP, 0 is retractable and 1 is fixed. Here, ' + 'false is retractable and true is fixed.', ) add_meta_data( Aircraft.LandingGear.MAIN_GEAR_LOCATION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.YMG', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.YMG', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='span fraction of main gear on wing (0=on fuselage, 1=at tip)', default_value=0, @@ -3883,47 +3947,49 @@ # - see also: Aircraft.LandingGear.MAIN_GEAR_MASS_SCALER Aircraft.LandingGear.MAIN_GEAR_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'INI.WLGM', - "LEAPS1": '(WeightABC)self._landing_gear_main_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'INI.WLGM', + "LEAPS1": '(WeightABC)self._landing_gear_main_weight', + }, units='lbm', - desc='mass of main landing gear' + desc='mass of main landing gear', ) add_meta_data( Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKMG', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKMG', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of main gear, fraction of total landing gear', - default_value=.85, + default_value=0.85, ) add_meta_data( Aircraft.LandingGear.MAIN_GEAR_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRLGM', # ['&DEFINE.WTIN.FRLGM', 'WTS.FRLGM'], - "LEAPS1": 'aircraft.inputs.L0_overrides.landing_gear_main_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRLGM', # ['&DEFINE.WTIN.FRLGM', 'WTS.FRLGM'], + "LEAPS1": 'aircraft.inputs.L0_overrides.landing_gear_main_weight', + }, units='unitless', - desc='mass scaler of the main landing gear structure' + desc='mass scaler of the main landing gear structure', + default_value=1.0, ) add_meta_data( Aircraft.LandingGear.MAIN_GEAR_OLEO_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.XMLG', # ['&DEFINE.WTIN.XMLG', 'WTS.XMLG'], - "LEAPS1": ['aircraft.inputs.L0_landing_gear.extend_main_gear_oleo_len', - 'aircraft.outputs.L0_landing_gear.extend_main_gear_oleo_len', - 'aircraft.cached.L0_landing_gear.extend_main_gear_oleo_len', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.XMLG', # ['&DEFINE.WTIN.XMLG', 'WTS.XMLG'], + "LEAPS1": [ + 'aircraft.inputs.L0_landing_gear.extend_main_gear_oleo_len', + 'aircraft.outputs.L0_landing_gear.extend_main_gear_oleo_len', + 'aircraft.cached.L0_landing_gear.extend_main_gear_oleo_len', + ], + }, units='inch', desc='length of extended main landing gear oleo', default_value=0.0, @@ -3932,10 +3998,7 @@ add_meta_data( Aircraft.LandingGear.MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKLG', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKLG', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of landing gear', ) @@ -3945,10 +4008,11 @@ # - see also: Aircraft.LandingGear.NOSE_GEAR_MASS_SCALER Aircraft.LandingGear.NOSE_GEAR_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WEIGHT.WLGN', - "LEAPS1": '(WeightABC)self._landing_gear_nose_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WEIGHT.WLGN', + "LEAPS1": '(WeightABC)self._landing_gear_nose_weight', + }, units='lbm', desc='mass of nose landing gear', default_value=None, @@ -3957,10 +4021,11 @@ add_meta_data( Aircraft.LandingGear.NOSE_GEAR_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRLGN', # ['&DEFINE.WTIN.FRLGN', 'WTS.FRLGN'], - "LEAPS1": 'aircraft.inputs.L0_overrides.landing_gear_nose_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRLGN', # ['&DEFINE.WTIN.FRLGN', 'WTS.FRLGN'], + "LEAPS1": 'aircraft.inputs.L0_overrides.landing_gear_nose_weight', + }, units='unitless', desc='mass scaler of the nose landing gear structure', default_value=1.0, @@ -3969,13 +4034,15 @@ add_meta_data( Aircraft.LandingGear.NOSE_GEAR_OLEO_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.XNLG', # ['&DEFINE.WTIN.XNLG', 'WTS.XNLG'], - "LEAPS1": ['aircraft.inputs.L0_landing_gear.extend_nose_gear_oleo_len', - 'aircraft.outputs.L0_landing_gear.extend_nose_gear_oleo_len', - 'aircraft.cached.L0_landing_gear.extend_nose_gear_oleo_len', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.XNLG', # ['&DEFINE.WTIN.XNLG', 'WTS.XNLG'], + "LEAPS1": [ + 'aircraft.inputs.L0_landing_gear.extend_nose_gear_oleo_len', + 'aircraft.outputs.L0_landing_gear.extend_nose_gear_oleo_len', + 'aircraft.cached.L0_landing_gear.extend_nose_gear_oleo_len', + ], + }, units='inch', desc='length of extended nose landing gear oleo', default_value=0.0, @@ -3984,10 +4051,7 @@ add_meta_data( Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKTL', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKTL', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='factor on tail mass for arresting hook', default_value=1, @@ -3996,10 +4060,7 @@ add_meta_data( Aircraft.LandingGear.TOTAL_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WLG', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WLG', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='total mass of landing gear', default_value=0, @@ -4008,10 +4069,7 @@ add_meta_data( Aircraft.LandingGear.TOTAL_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CK12', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CK12', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='technology factor on landing gear mass', default_value=1, @@ -4028,12 +4086,13 @@ add_meta_data( Aircraft.Nacelle.AVG_DIAMETER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DBARN', - "FLOPS": 'WTIN.DNAC', # ['&DEFINE.WTIN.DNAC', 'EDETIN.DNAC'], - "LEAPS1": 'aircraft.inputs.L0_engine.nacelle_avg_diam' - }, + historical_name={ + "GASP": 'INGASP.DBARN', + "FLOPS": 'WTIN.DNAC', # ['&DEFINE.WTIN.DNAC', 'EDETIN.DNAC'], + "LEAPS1": 'aircraft.inputs.L0_engine.nacelle_avg_diam', + }, units='ft', - desc='Average diameter of engine nacelles for each engine model' + desc='Average diameter of engine nacelles for each engine model', ) add_meta_data( @@ -4041,34 +4100,34 @@ meta_data=_MetaData, # NOTE this is not specified as an average in GASP, but calculations make # it appear to be one - historical_name={"GASP": 'INGASP.ELN', - "FLOPS": 'WTIN.XNAC', # ['&DEFINE.WTIN.XNAC', 'EDETIN.XNAC'], - "LEAPS1": 'aircraft.inputs.L0_engine.nacelle_avg_length' - }, + historical_name={ + "GASP": 'INGASP.ELN', + "FLOPS": 'WTIN.XNAC', # ['&DEFINE.WTIN.XNAC', 'EDETIN.XNAC'], + "LEAPS1": 'aircraft.inputs.L0_engine.nacelle_avg_length', + }, units='ft', - desc='Average length of nacelles for each engine model' + desc='Average length of nacelles for each engine model', ) add_meta_data( Aircraft.Nacelle.CHARACTERISTIC_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.EL[5]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[4]', - 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[4]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.EL[5]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[4]', + 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[4]', + ], + }, units='ft', - desc='Reynolds characteristic length for nacelle for each engine model' + desc='Reynolds characteristic length for nacelle for each engine model', ) add_meta_data( Aircraft.Nacelle.CLEARANCE_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CLEARqDN', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CLEARqDN', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='the minimum number of nacelle diameters above the ground that the bottom of the nacelle must be', default_value=0.2, @@ -4077,10 +4136,7 @@ add_meta_data( Aircraft.Nacelle.CORE_DIAMETER_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DNQDE', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DNQDE', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='ratio of nacelle diameter to engine core diameter', default_value=1.25, @@ -4089,34 +4145,35 @@ add_meta_data( Aircraft.Nacelle.FINENESS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.XLQDE', - "FLOPS": None, # 'MISSA.FR[5]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[4]', - 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[4]', - ] - }, + historical_name={ + "GASP": 'INGASP.XLQDE', + "FLOPS": None, # 'MISSA.FR[5]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[4]', + 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[4]', + ], + }, units='unitless', - desc='nacelle fineness ratio' + desc='nacelle fineness ratio', ) add_meta_data( Aircraft.Nacelle.FORM_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CKN', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CKN', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='nacelle form factor', + default_value=1.5, ) add_meta_data( Aircraft.Nacelle.LAMINAR_FLOW_LOWER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRLN', # ['&DEFINE.AERIN.TRLN', 'XLAM.TRLN', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.nacelle_percent_laminar_flow_lower_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRLN', # ['&DEFINE.AERIN.TRLN', 'XLAM.TRLN', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.nacelle_percent_laminar_flow_lower_surface', + }, units='unitless', desc='define percent laminar flow for nacelle lower surface for each engine model', default_value=0.0, @@ -4125,10 +4182,11 @@ add_meta_data( Aircraft.Nacelle.LAMINAR_FLOW_UPPER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRUN', # ['&DEFINE.AERIN.TRUN', 'XLAM.TRUN', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.nacelle_percent_laminar_flow_upper_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRUN', # ['&DEFINE.AERIN.TRUN', 'XLAM.TRUN', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.nacelle_percent_laminar_flow_upper_surface', + }, units='unitless', desc='define percent laminar flow for nacelle upper surface for each engine model', default_value=0.0, @@ -4139,13 +4197,15 @@ # - see also: Aircraft.Nacelle.MASS_SCALER Aircraft.Nacelle.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(8, 2)', '~WEIGHT.WNAC', '~WTSTAT.WSP(8, 2)', '~INERT.WNAC'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._nacelle_weight', - 'aircraft.outputs.L0_weights_summary.nacelle_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(8, 2)', '~WEIGHT.WNAC', '~WTSTAT.WSP(8, 2)', '~INERT.WNAC'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._nacelle_weight', + 'aircraft.outputs.L0_weights_summary.nacelle_weight', + ], + }, units='lbm', desc='estimated mass of the nacelles for each engine model', default_value=None, @@ -4154,10 +4214,11 @@ add_meta_data( Aircraft.Nacelle.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRNA', # ['&DEFINE.WTIN.FRNA', 'WTS.FRNA'], - "LEAPS1": 'aircraft.inputs.L0_overrides.nacelle_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRNA', # ['&DEFINE.WTIN.FRNA', 'WTS.FRNA'], + "LEAPS1": 'aircraft.inputs.L0_overrides.nacelle_weight', + }, units='unitless', desc='mass scaler of the nacelle structure for each engine model', default_value=1.0, @@ -4166,10 +4227,7 @@ add_meta_data( Aircraft.Nacelle.MASS_SPECIFIC, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.UWNAC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.UWNAC', "FLOPS": None, "LEAPS1": None}, units='lbm/ft**2', desc='nacelle mass/nacelle surface area; lbm per sq ft.', default_value=0.0, @@ -4178,49 +4236,50 @@ add_meta_data( Aircraft.Nacelle.SURFACE_AREA, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SN', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SN', "FLOPS": None, "LEAPS1": None}, units='ft**2', desc='surface area of the outside of one entire nacelle, ' - 'not just the wetted area', + 'not just the wetted area', ) add_meta_data( Aircraft.Nacelle.TOTAL_WETTED_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'ACTWET.SWTNA', - "LEAPS1": 'aircraft.outputs.L0_aerodynamics.nacelle_wetted_area' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'ACTWET.SWTNA', + "LEAPS1": 'aircraft.outputs.L0_aerodynamics.nacelle_wetted_area', + }, units='ft**2', - desc='total nacelles wetted area' + desc='total nacelles wetted area', ) add_meta_data( Aircraft.Nacelle.WETTED_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.SWET[5]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_component_wetted_area_table[4]', - 'aircraft.cached.L0_aerodynamics.mission_component_wetted_area_table[4]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.SWET[5]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_component_wetted_area_table[4]', + 'aircraft.cached.L0_aerodynamics.mission_component_wetted_area_table[4]', + ], + }, units='ft**2', - desc='wetted area of a single nacelle for each engine model' + desc='wetted area of a single nacelle for each engine model', ) add_meta_data( Aircraft.Nacelle.WETTED_AREA_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.SWETN', # ['&DEFINE.AERIN.SWETN', 'AWETO.SWETN', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.nacelle_wetted_area' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.SWETN', # ['&DEFINE.AERIN.SWETN', 'AWETO.SWETN', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.nacelle_wetted_area', + }, units='unitless', desc='nacelle wetted area scaler for each engine model', - default_value=1.0 + default_value=1.0, ) # _____ _ _ @@ -4234,23 +4293,26 @@ add_meta_data( Aircraft.Paint.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'DARM.WTPNT', - "LEAPS1": ['(WeightABC)self._total_paint_weight', - 'aircraft.outputs.L0_weights_summary.total_paint_weight', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'DARM.WTPNT', + "LEAPS1": [ + '(WeightABC)self._total_paint_weight', + 'aircraft.outputs.L0_weights_summary.total_paint_weight', + ], + }, units='lbm', - desc='mass of paint for all wetted area' + desc='mass of paint for all wetted area', ) add_meta_data( Aircraft.Paint.MASS_PER_UNIT_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.WPAINT', # ['&DEFINE.WTIN.WPAINT', 'DARM.WPAINT'], - "LEAPS1": 'aircraft.inputs.L0_weights.paint_per_unit_area' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.WPAINT', # ['&DEFINE.WTIN.WPAINT', 'DARM.WPAINT'], + "LEAPS1": 'aircraft.inputs.L0_weights.paint_per_unit_area', + }, units='lbm/ft**2', desc='mass of paint per unit area for all wetted area', default_value=0.0, @@ -4270,11 +4332,12 @@ add_meta_data( Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WOIL', 'MISWT.WOIL', 'MISWT.OOIL'], - "FLOPS": 'WTIN.WOIL', - "LEAPS1": 'aircraft.inputs.L0_overrides.engine_oil_weight' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WOIL', 'MISWT.WOIL', 'MISWT.OOIL'], + "FLOPS": 'WTIN.WOIL', + "LEAPS1": 'aircraft.inputs.L0_overrides.engine_oil_weight', + }, units='unitless', desc='Scaler for engine oil mass', default_value=1.0, @@ -4283,52 +4346,49 @@ add_meta_data( Aircraft.Propulsion.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(15, 2)', '~WEIGHT.WPRO', '~WTSTAT.WSP(15, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._prop_sys_weight', - 'aircraft.outputs.L0_weights_summary.prop_sys_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(15, 2)', '~WEIGHT.WPRO', '~WTSTAT.WSP(15, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._prop_sys_weight', + 'aircraft.outputs.L0_weights_summary.prop_sys_weight', + ], + }, units='lbm', - desc='Total propulsion group mass' + desc='Total propulsion group mass', ) # TODO clash with per-engine scaling, need to resolve w/ heterogeneous engine add_meta_data( Aircraft.Propulsion.MISC_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.WPMSC', 'MISWT.WPMSC', 'MISWT.OPMSC'], - "FLOPS": 'WTIN.WPMSC', - "LEAPS1": ['aircraft.inputs.L0_overrides.misc_propulsion_weight'] - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.WPMSC', 'MISWT.WPMSC', 'MISWT.OPMSC'], + "FLOPS": 'WTIN.WPMSC', + "LEAPS1": ['aircraft.inputs.L0_overrides.misc_propulsion_weight'], + }, units='unitless', desc='scaler applied to miscellaneous engine mass (sum of engine control, starter, ' - 'and additional mass)', + 'and additional mass)', default_value=1.0, ) add_meta_data( Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', - desc='total estimated mass of the engine controls for all engines on aircraft' + desc='total estimated mass of the engine controls for all engines on aircraft', ) add_meta_data( Aircraft.Propulsion.TOTAL_ENGINE_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WEP', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WEP', "FLOPS": None, "LEAPS1": None}, units='lbm', - desc='total mass of all engines on aircraft' + desc='total mass of all engines on aircraft', ) add_meta_data( @@ -4336,13 +4396,15 @@ # - see also: Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(30, 2)', '~WEIGHT.WOIL', '~WTSTAT.WSP(30, 2)', '~INERT.WOIL'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._engine_oil_weight', - 'aircraft.outputs.L0_weights_summary.engine_oil_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(30, 2)', '~WEIGHT.WOIL', '~WTSTAT.WSP(30, 2)', '~INERT.WOIL'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._engine_oil_weight', + 'aircraft.outputs.L0_weights_summary.engine_oil_weight', + ], + }, units='lbm', desc='engine oil mass', default_value=None, @@ -4351,12 +4413,9 @@ add_meta_data( Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', - desc='total engine pod mass for all engines on aircraft' + desc='total engine pod mass for all engines on aircraft', ) add_meta_data( @@ -4364,26 +4423,19 @@ # - see also: Aircraft.Propulsion.MISC_WEIGHT_SCALER Aircraft.Propulsion.TOTAL_MISC_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='sum of engine control, starter, and additional mass for all engines ' - 'on aircraft', + 'on aircraft', default_value=None, ) add_meta_data( Aircraft.Propulsion.TOTAL_NUM_ENGINES, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', - desc='total number of engines for the aircraft ' - '(fuselage, wing, or otherwise)', + desc='total number of engines for the aircraft ' '(fuselage, wing, or otherwise)', types=int, option=True, default_value=None, @@ -4392,10 +4444,7 @@ add_meta_data( Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='total number of fuselage-mounted engines for the aircraft', types=int, @@ -4406,10 +4455,7 @@ add_meta_data( Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='total number of wing-mounted engines for the aircraft', types=int, @@ -4420,10 +4466,7 @@ add_meta_data( Aircraft.Propulsion.TOTAL_REFERENCE_SLS_THRUST, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbf', desc='total maximum thrust of all unscalsed engines on aircraft, sea-level static', option=True, @@ -4433,10 +4476,7 @@ add_meta_data( Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbf', desc='total maximum thrust of all scaled engines on aircraft, sea-level static', default_value=0.0, @@ -4445,10 +4485,7 @@ add_meta_data( Aircraft.Propulsion.TOTAL_STARTER_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='total mass of starters for all engines on aircraft', default_value=0.0, @@ -4459,10 +4496,7 @@ # - see also: Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER Aircraft.Propulsion.TOTAL_THRUST_REVERSERS_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='total mass of thrust reversers for all engines on aircraft', default_value=None, @@ -4479,10 +4513,7 @@ add_meta_data( Aircraft.Strut.AREA, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.STRTWS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.STRTWS', "FLOPS": None, "LEAPS1": None}, units='ft**2', desc='strut area', default_value=0, @@ -4491,10 +4522,7 @@ add_meta_data( Aircraft.Strut.AREA_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SSTQSW', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SSTQSW', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='ratio of strut area to wing area', ) @@ -4502,10 +4530,11 @@ add_meta_data( Aircraft.Strut.ATTACHMENT_LOCATION, meta_data=_MetaData, - historical_name={"GASP": ['INGASP.STRUT', 'INGASP.STRUTX', 'INGASP.XSTRUT'], - "FLOPS": None, - "LEAPS1": None - }, + historical_name={ + "GASP": ['INGASP.STRUT', 'INGASP.STRUTX', 'INGASP.XSTRUT'], + "FLOPS": None, + "LEAPS1": None, + }, units='ft', desc='attachment location of strut the full attachment-to-attachment span', ) @@ -4514,10 +4543,7 @@ add_meta_data( Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='attachment location of strut as fraction of the half-span', ) @@ -4525,10 +4551,7 @@ add_meta_data( Aircraft.Strut.CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.STRTCHD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.STRTCHD', "FLOPS": None, "LEAPS1": None}, units='ft', desc='chord of the strut', ) @@ -4536,36 +4559,28 @@ add_meta_data( Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", option=True, default_value=True, types=bool, desc='if true the location of the strut is given dimensionally, otherwise ' - 'it is given non-dimensionally. In GASP this depended on STRUT', + 'it is given non-dimensionally. In GASP this depended on STRUT', ) add_meta_data( Aircraft.Strut.FUSELAGE_INTERFERENCE_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CKSTRT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CKSTRT', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='strut/fuselage interference factor', + default_value=0.0, ) add_meta_data( Aircraft.Strut.LENGTH, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.STRTLNG', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.STRTLNG', "FLOPS": None, "LEAPS1": None}, units='ft', desc='length of the strut', default_value=0, @@ -4574,10 +4589,7 @@ add_meta_data( Aircraft.Strut.MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WSTRUT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WSTRUT', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='mass of the strut', default_value=0, @@ -4586,10 +4598,7 @@ add_meta_data( Aircraft.Strut.MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKSTRUT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKSTRUT', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of the strut', default_value=0, @@ -4598,10 +4607,7 @@ add_meta_data( Aircraft.Strut.THICKNESS_TO_CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.TCSTRT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.TCSTRT', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='thickness to chord ratio of the strut', default_value=0, @@ -4618,10 +4624,7 @@ add_meta_data( Aircraft.TailBoom.LENGTH, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ELFFC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.ELFFC', "FLOPS": None, "LEAPS1": None}, units='ft', desc='cabin length for the tail boom fuselage', ) @@ -4638,15 +4641,17 @@ add_meta_data( Aircraft.VerticalTail.AREA, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SVT', - "FLOPS": 'WTIN.SVT', # ['&DEFINE.WTIN.SVT', 'EDETIN.SVT'], - "LEAPS1": ['aircraft.inputs.L0_vertical_tails.area', - 'aircraft.cached.L0_vertical_tails.area', - ] - }, + historical_name={ + "GASP": 'INGASP.SVT', + "FLOPS": 'WTIN.SVT', # ['&DEFINE.WTIN.SVT', 'EDETIN.SVT'], + "LEAPS1": [ + 'aircraft.inputs.L0_vertical_tails.area', + 'aircraft.cached.L0_vertical_tails.area', + ], + }, units='ft**2', desc='vertical tail theoretical area (per tail); overridden by vol_coeff ' - 'if vol_coeff > 0.0', + 'if vol_coeff > 0.0', # this appears to never be calculated in Aviary, need to make user aware # of Aviary overriding support default_value=0.0, @@ -4655,13 +4660,15 @@ add_meta_data( Aircraft.VerticalTail.ASPECT_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ARVT', - "FLOPS": 'WTIN.ARVT', # ['&DEFINE.WTIN.ARVT', 'EDETIN.ARVT'], - "LEAPS1": ['aircraft.inputs.L0_vertical_tails.aspect_ratio', - # ??? where is this assigned; potential error??? - 'aircraft.cached.L0_vertical_tails.aspect_ratio', - ] - }, + historical_name={ + "GASP": 'INGASP.ARVT', + "FLOPS": 'WTIN.ARVT', # ['&DEFINE.WTIN.ARVT', 'EDETIN.ARVT'], + "LEAPS1": [ + 'aircraft.inputs.L0_vertical_tails.aspect_ratio', + # ??? where is this assigned; potential error??? + 'aircraft.cached.L0_vertical_tails.aspect_ratio', + ], + }, units='unitless', desc='vertical tail theoretical aspect ratio', default_value=None, @@ -4670,10 +4677,7 @@ add_meta_data( Aircraft.VerticalTail.AVERAGE_CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CBARVT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CBARVT', "FLOPS": None, "LEAPS1": None}, units='ft', desc='mean aerodynamic chord of vertical tail', ) @@ -4681,47 +4685,50 @@ add_meta_data( Aircraft.VerticalTail.CHARACTERISTIC_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.EL[3]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[2]', - 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[2]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.EL[3]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[2]', + 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[2]', + ], + }, units='ft', - desc='Reynolds characteristic length for the vertical tail' + desc='Reynolds characteristic length for the vertical tail', ) add_meta_data( Aircraft.VerticalTail.FINENESS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.FR[3]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[2]', - 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[2]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.FR[3]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[2]', + 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[2]', + ], + }, units='unitless', - desc='vertical tail fineness ratio' + desc='vertical tail fineness ratio', ) add_meta_data( Aircraft.VerticalTail.FORM_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CKVT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CKVT', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='vertical tail form factor', + default_value=1.25, ) add_meta_data( Aircraft.VerticalTail.LAMINAR_FLOW_LOWER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRLV', # ['&DEFINE.AERIN.TRLV', 'XLAM.TRLV', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.vertical_tail_percent_laminar_flow_lower_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRLV', # ['&DEFINE.AERIN.TRLV', 'XLAM.TRLV', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.vertical_tail_percent_laminar_flow_lower_surface', + }, units='unitless', desc='define percent laminar flow for vertical tail lower surface', default_value=0.0, @@ -4730,10 +4737,11 @@ add_meta_data( Aircraft.VerticalTail.LAMINAR_FLOW_UPPER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRUV', # ['&DEFINE.AERIN.TRUV', 'XLAM.TRUV', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.vertical_tail_percent_laminar_flow_upper_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRUV', # ['&DEFINE.AERIN.TRUV', 'XLAM.TRUV', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.vertical_tail_percent_laminar_flow_upper_surface', + }, units='unitless', desc='define percent laminar flow for vertical tail upper surface', default_value=0.0, @@ -4744,13 +4752,15 @@ # - see also: Aircraft.VerticalTail.MASS_SCALER Aircraft.VerticalTail.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(3, 2)', '~WEIGHT.WVT', '~WTSTAT.WSP(3, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._vertical_tail_weight', - 'aircraft.outputs.L0_weights_summary.vertical_tail_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(3, 2)', '~WEIGHT.WVT', '~WTSTAT.WSP(3, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._vertical_tail_weight', + 'aircraft.outputs.L0_weights_summary.vertical_tail_weight', + ], + }, units='lbm', desc='mass of vertical tail', default_value=None, @@ -4759,10 +4769,7 @@ add_meta_data( Aircraft.VerticalTail.MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKZ', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKZ', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of the vertical tail', default_value=0.22, @@ -4771,10 +4778,11 @@ add_meta_data( Aircraft.VerticalTail.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRVT', # ['&DEFINE.WTIN.FRVT', 'WTS.FRVT'], - "LEAPS1": 'aircraft.inputs.L0_overrides.vertical_tail_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRVT', # ['&DEFINE.WTIN.FRVT', 'WTS.FRVT'], + "LEAPS1": 'aircraft.inputs.L0_overrides.vertical_tail_weight', + }, units='unitless', desc='mass scaler of the vertical tail structure', default_value=1.0, @@ -4783,10 +4791,7 @@ add_meta_data( Aircraft.VerticalTail.MOMENT_ARM, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ELTV', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.ELTV', "FLOPS": None, "LEAPS1": None}, units='ft', desc='moment arm of vertical tail', ) @@ -4794,10 +4799,7 @@ add_meta_data( Aircraft.VerticalTail.MOMENT_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.BOELTV', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.BOELTV', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='ratio of wing span to vertical tail moment arm', ) @@ -4805,10 +4807,11 @@ add_meta_data( Aircraft.VerticalTail.NUM_TAILS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.NVERT', # ['&DEFINE.WTIN.NVERT', 'EDETIN.NVERT'], - "LEAPS1": 'aircraft.inputs.L0_vertical_tails.count' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.NVERT', # ['&DEFINE.WTIN.NVERT', 'EDETIN.NVERT'], + "LEAPS1": 'aircraft.inputs.L0_vertical_tails.count', + }, units='unitless', desc='number of vertical tails', types=int, @@ -4819,10 +4822,7 @@ add_meta_data( Aircraft.VerticalTail.ROOT_CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CRCLVT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CRCLVT', "FLOPS": None, "LEAPS1": None}, units='ft', desc='root chord of vertical tail', ) @@ -4830,10 +4830,7 @@ add_meta_data( Aircraft.VerticalTail.SPAN, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.BVT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.BVT', "FLOPS": None, "LEAPS1": None}, units='ft', desc='span of vertical tail', ) @@ -4841,12 +4838,14 @@ add_meta_data( Aircraft.VerticalTail.SWEEP, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DWPQCV', - "FLOPS": 'WTIN.SWPVT', # ['&DEFINE.WTIN.SWPVT', 'WTS.SWPVT'], - "LEAPS1": ['aircraft.inputs.L0_vertical_tail.sweep_at_quarter_chord', - 'aircraft.cached.L0_vertical_tail.sweep_at_quarter_chord' - ] - }, + historical_name={ + "GASP": 'INGASP.DWPQCV', + "FLOPS": 'WTIN.SWPVT', # ['&DEFINE.WTIN.SWPVT', 'WTS.SWPVT'], + "LEAPS1": [ + 'aircraft.inputs.L0_vertical_tail.sweep_at_quarter_chord', + 'aircraft.cached.L0_vertical_tail.sweep_at_quarter_chord', + ], + }, units='deg', desc='quarter-chord sweep of vertical tail', ) @@ -4854,10 +4853,11 @@ add_meta_data( Aircraft.VerticalTail.TAPER_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SLMV', - "FLOPS": 'WTIN.TRVT', # ['&DEFINE.WTIN.TRVT', 'EDETIN.TRVT'], - "LEAPS1": 'aircraft.inputs.L0_vertical_tails.taper_ratio' - }, + historical_name={ + "GASP": 'INGASP.SLMV', + "FLOPS": 'WTIN.TRVT', # ['&DEFINE.WTIN.TRVT', 'EDETIN.TRVT'], + "LEAPS1": 'aircraft.inputs.L0_vertical_tails.taper_ratio', + }, units='unitless', desc='vertical tail theoretical taper ratio', default_value=None, @@ -4866,12 +4866,14 @@ add_meta_data( Aircraft.VerticalTail.THICKNESS_TO_CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.TCVT', - "FLOPS": 'WTIN.TCVT', # ['&DEFINE.WTIN.TCVT', 'EDETIN.TCVT', ], - "LEAPS1": ['aircraft.inputs.L0_vertical_tails.thickness_to_chord_ratio', - 'aircraft.cached.L0_vertical_tails.thickness_to_chord_ratio', - ] - }, + historical_name={ + "GASP": 'INGASP.TCVT', + "FLOPS": 'WTIN.TCVT', # ['&DEFINE.WTIN.TCVT', 'EDETIN.TCVT', ], + "LEAPS1": [ + 'aircraft.inputs.L0_vertical_tails.thickness_to_chord_ratio', + 'aircraft.cached.L0_vertical_tails.thickness_to_chord_ratio', + ], + }, units='unitless', desc='vertical tail thickness-chord ratio', default_value=0.0, @@ -4880,10 +4882,7 @@ add_meta_data( Aircraft.VerticalTail.VOLUME_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.VBARVX', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.VBARVX', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='tail volume coefficient of the vertical tail', ) @@ -4893,13 +4892,15 @@ # - see also: Aircraft.VerticalTail.WETTED_AREA_SCALER Aircraft.VerticalTail.WETTED_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['ACTWET.SWTVT', 'MISSA.SWET[3]', ], - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.vertical_tail_wetted_area', - 'aircraft.outputs.L0_aerodynamics.mission_component_wetted_area_table[2]', - 'aircraft.cached.L0_aerodynamics.mission_component_wetted_area_table[2]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['ACTWET.SWTVT', 'MISSA.SWET[3]', ], + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.vertical_tail_wetted_area', + 'aircraft.outputs.L0_aerodynamics.mission_component_wetted_area_table[2]', + 'aircraft.cached.L0_aerodynamics.mission_component_wetted_area_table[2]', + ], + }, units='ft**2', desc='vertical tails wetted area', default_value=None, @@ -4908,10 +4909,11 @@ add_meta_data( Aircraft.VerticalTail.WETTED_AREA_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.SWETV', # ['&DEFINE.AERIN.SWETV', 'AWETO.SWETV', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.vertical_tail_wetted_area' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.SWETV', # ['&DEFINE.AERIN.SWETV', 'AWETO.SWETV', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.vertical_tail_wetted_area', + }, units='unitless', desc='vertical tail wetted area scaler', default_value=1.0, @@ -4930,59 +4932,65 @@ add_meta_data( Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.FAERT', 'WTS.FAERT', '~WWGHT.FAERT', '~BNDMAT.FAERT'], - "FLOPS": 'WTIN.FAERT', - "LEAPS1": 'aircraft.inputs.L0_wing.aeroelastic_fraction' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.FAERT', 'WTS.FAERT', '~WWGHT.FAERT', '~BNDMAT.FAERT'], + "FLOPS": 'WTIN.FAERT', + "LEAPS1": 'aircraft.inputs.L0_wing.aeroelastic_fraction', + }, units='unitless', desc='Define the decimal fraction of amount of aeroelastic tailoring used ' - 'in design of wing where: 0.0 == no aeroelastic tailoring; ' - '1.0 == maximum aeroelastic tailoring.', + 'in design of wing where: 0.0 == no aeroelastic tailoring; ' + '1.0 == maximum aeroelastic tailoring.', default_value=0.0, ) add_meta_data( Aircraft.Wing.AIRFOIL_TECHNOLOGY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.AITEK', - # [ # inputs - # '&DEFINE.AERIN.AITEK', 'EDETIN.AITEK', - # # outputs - # 'MISSA.AITEK', 'MISSA.AITEKX', - # ], - "LEAPS1": ['aircraft.inputs.L0_aerodynamics.airfoil', - 'aircraft.outputs.L0_aerodynamics.mission_airfoil', - 'aircraft.cached.L0_aerodynamics.mission_airfoil', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.AITEK', + # [ # inputs + # '&DEFINE.AERIN.AITEK', 'EDETIN.AITEK', + # # outputs + # 'MISSA.AITEK', 'MISSA.AITEKX', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_aerodynamics.airfoil', + 'aircraft.outputs.L0_aerodynamics.mission_airfoil', + 'aircraft.cached.L0_aerodynamics.mission_airfoil', + ], + }, units='unitless', desc='Airfoil technology parameter. Limiting values are: 1.0 represents ' - 'conventional technology wing (Default); 2.0 represents advanced ' - 'technology wing.', + 'conventional technology wing (Default); 2.0 represents advanced ' + 'technology wing.', default_value=1.0, + types=float, option=True, ) add_meta_data( Aircraft.Wing.AREA, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SW', - "FLOPS": 'CONFIN.SW', - # [ # inputs - # '&DEFINE.CONFIN.SW', 'PARVAR.DVD(1,4)', - # # outputs - # 'CONFIG.SW', 'CONFIG.DVA(4)', '~FLOPS.DVA(4)', '~ANALYS.DVA(4)', - # '~TOFF.SW', '~LNDING.SW', '~PROFIL.SW', '~INMDAT.SW', '~WWGHT.SW', - # # other - # 'MISSA.SREF', '~CDCC.SREF', - # ], - "LEAPS1": ['aircraft.inputs.L0_design_variables.wing_ref_area', - 'aircraft.outputs.L0_design_variables.wing_ref_area', - 'aircraft.outputs.L0_design_variables.mission_wing_ref_area', - ] - }, + historical_name={ + "GASP": 'INGASP.SW', + "FLOPS": 'CONFIN.SW', + # [ # inputs + # '&DEFINE.CONFIN.SW', 'PARVAR.DVD(1,4)', + # # outputs + # 'CONFIG.SW', 'CONFIG.DVA(4)', '~FLOPS.DVA(4)', '~ANALYS.DVA(4)', + # '~TOFF.SW', '~LNDING.SW', '~PROFIL.SW', '~INMDAT.SW', '~WWGHT.SW', + # # other + # 'MISSA.SREF', '~CDCC.SREF', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_design_variables.wing_ref_area', + 'aircraft.outputs.L0_design_variables.wing_ref_area', + 'aircraft.outputs.L0_design_variables.mission_wing_ref_area', + ], + }, units='ft**2', desc='reference wing area', default_value=0.0, @@ -4991,22 +4999,24 @@ add_meta_data( Aircraft.Wing.ASPECT_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.AR', - "FLOPS": 'CONFIN.AR', - # [ # inputs - # '&DEFINE.CONFIN.AR', 'PARVAR.DVD(1, 2)', '~BUFFET.AR', '~CDPP.AR', - # '~DPREP.ARX', - # # outputs - # 'CONFIG.AR', 'CONFIG.DVA(2)', '~FLOPS.DVA(2)', '~ANALYS.DVA(2)', - # '~TOFF.ARN', '~LNDING.ARN', '~PROFIL.ARN', '~WWGHT.ARN', '~INERT.ARN', - # # other - # 'MISSA.AR', 'MISSA.ARX', '~CDCC.AR', '~CLDESN.AR', '~MDESN.AR', - # ], - "LEAPS1": ['aircraft.inputs.L0_design_variables.wing_aspect_ratio', - 'aircraft.outputs.L0_design_variables.wing_aspect_ratio', - 'aircraft.outputs.L0_design_variables.mission_wing_aspect_ratio', - ] - }, + historical_name={ + "GASP": 'INGASP.AR', + "FLOPS": 'CONFIN.AR', + # [ # inputs + # '&DEFINE.CONFIN.AR', 'PARVAR.DVD(1, 2)', '~BUFFET.AR', '~CDPP.AR', + # '~DPREP.ARX', + # # outputs + # 'CONFIG.AR', 'CONFIG.DVA(2)', '~FLOPS.DVA(2)', '~ANALYS.DVA(2)', + # '~TOFF.ARN', '~LNDING.ARN', '~PROFIL.ARN', '~WWGHT.ARN', '~INERT.ARN', + # # other + # 'MISSA.AR', 'MISSA.ARX', '~CDCC.AR', '~CLDESN.AR', '~MDESN.AR', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_design_variables.wing_aspect_ratio', + 'aircraft.outputs.L0_design_variables.wing_aspect_ratio', + 'aircraft.outputs.L0_design_variables.mission_wing_aspect_ratio', + ], + }, units='unitless', desc='ratio of the wing span to its mean chord', default_value=0.0, @@ -5015,57 +5025,59 @@ add_meta_data( Aircraft.Wing.ASPECT_RATIO_REF, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.ARREF', # ['&DEFINE.WTIN.ARREF'], - "LEAPS1": 'aircraft.inputs.L0_detailed_wing.ref_aspect_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.ARREF', # ['&DEFINE.WTIN.ARREF'], + "LEAPS1": 'aircraft.inputs.L0_detailed_wing.ref_aspect_ratio', + }, units='unitless', - desc='Reference aspect ratio, used for detailed wing bending.' + desc='Reference aspect ratio, used for detailed wing mass estimation.', ) add_meta_data( Aircraft.Wing.AVERAGE_CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CBARW', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CBARW', "FLOPS": None, "LEAPS1": None}, units='ft', desc='mean aerodynamic chord of the wing', ) add_meta_data( - Aircraft.Wing.BENDING_FACTOR, + Aircraft.Wing.BENDING_MATERIAL_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['~WWGHT.BT', '~BNDMAT.W'], - "LEAPS1": 'aircraft.outputs.L0_wing.bending_material_factor' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['~WWGHT.BT', '~BNDMAT.W'], + "LEAPS1": 'aircraft.outputs.L0_wing.bending_material_factor', + }, units='unitless', - desc='wing bending factor' + desc='Wing bending material factor with sweep adjustment. Used to compute ' + 'Aircraft.Wing.BENDING_MATERIAL_MASS', ) add_meta_data( # Note user override - # - see also: Aircraft.Wing.BENDING_MASS_SCALER - Aircraft.Wing.BENDING_MASS, + # - see also: Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER + Aircraft.Wing.BENDING_MATERIAL_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WWGHT.W1', - "LEAPS1": 'aircraft.outputs.L0_wing.bending_mat_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WWGHT.W1', + "LEAPS1": 'aircraft.outputs.L0_wing.bending_mat_weight', + }, units='lbm', desc='wing mass breakdown term 1', default_value=None, ) add_meta_data( - Aircraft.Wing.BENDING_MASS_SCALER, + Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRWI1', # ['&DEFINE.WTIN.FRWI1', 'WIOR3.FRWI1'], - "LEAPS1": 'aircraft.inputs.L0_overrides.wing_bending_mat_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRWI1', # ['&DEFINE.WTIN.FRWI1', 'WIOR3.FRWI1'], + "LEAPS1": 'aircraft.inputs.L0_overrides.wing_bending_mat_weight', + }, units='unitless', desc='mass scaler of the bending wing mass term', default_value=1.0, @@ -5076,10 +5088,11 @@ # - see also: Aircraft.Wing.BWB_AFTBODY_MASS_SCALER Aircraft.Wing.BWB_AFTBODY_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WWGHT.W4', - "LEAPS1": 'aircraft.outputs.L0_wing.bwb_aft_body_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WWGHT.W4', + "LEAPS1": 'aircraft.outputs.L0_wing.bwb_aft_body_weight', + }, units='lbm', desc='wing mass breakdown term 4', default_value=None, @@ -5088,10 +5101,11 @@ add_meta_data( Aircraft.Wing.BWB_AFTBODY_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRWI4', # ['&DEFINE.WTIN.FRWI4', 'WIOR3.FRWI4'], - "LEAPS1": 'aircraft.inputs.L0_overrides.bwb_aft_body_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRWI4', # ['&DEFINE.WTIN.FRWI4', 'WIOR3.FRWI4'], + "LEAPS1": 'aircraft.inputs.L0_overrides.bwb_aft_body_weight', + }, units='unitless', desc='mass scaler of the blended-wing-body aft-body wing mass term', default_value=1.0, @@ -5100,10 +5114,7 @@ add_meta_data( Aircraft.Wing.CENTER_CHORD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CRCLW', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CRCLW', "FLOPS": None, "LEAPS1": None}, units='ft', desc='wing chord at fuselage centerline', ) @@ -5111,108 +5122,107 @@ add_meta_data( Aircraft.Wing.CENTER_DISTANCE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.XWQLF', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.XWQLF', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='distance (percent fuselage length) from nose to the wing ' - 'aerodynamic center', + 'aerodynamic center', ) add_meta_data( Aircraft.Wing.CHARACTERISTIC_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.EL[1]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[0]', - 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[0]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.EL[1]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_component_char_len_table[0]', + 'aircraft.cached.L0_aerodynamics.mission_component_char_len_table[0]', + ], + }, units='ft', - desc='Reynolds characteristic length for the wing' + desc='Reynolds characteristic length for the wing', ) add_meta_data( Aircraft.Wing.CHOOSE_FOLD_LOCATION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", default_value=True, types=bool, option=True, desc='if true, fold location is based on your chosen value, otherwise it is ' - 'based on strut location. In GASP this depended on STRUT or YWFOLD', + 'based on strut location. In GASP this depended on STRUT or YWFOLD', ) add_meta_data( # see also: station_chord_lengths Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.CHD', # ['&DEFINE.WTIN.CHD', 'WDEF.CHD'], - "LEAPS1": 'aircraft.inputs.L0_detailed_wing.wing_station_chord_lengths' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.CHD', # ['&DEFINE.WTIN.CHD', 'WDEF.CHD'], + "LEAPS1": 'aircraft.inputs.L0_detailed_wing.wing_station_chord_lengths', + }, units='unitless', desc='chord lengths as fractions of semispan at station locations; ' - 'overwrites station_chord_lengths', + 'overwrites station_chord_lengths', default_value=None, ) add_meta_data( Aircraft.Wing.COMPOSITE_FRACTION, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.FCOMP', 'WTS.FCOMP', '~WWGHT.FCOMP'], - "FLOPS": 'WTIN.FCOMP', - "LEAPS1": 'aircraft.inputs.L0_wing.composite_fraction' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.FCOMP', 'WTS.FCOMP', '~WWGHT.FCOMP'], + "FLOPS": 'WTIN.FCOMP', + "LEAPS1": 'aircraft.inputs.L0_wing.composite_fraction', + }, units='unitless', desc='Define the decimal fraction of amount of composites used in wing ' - 'structure where: 0.0 == no composites; 1.0 == maximum use of composites, ' - 'approximately equivalent bending_mat_weight=.6, ' - 'struct_weights=.83, misc_weight=.7 ' - '(not necessarily all composite).', + 'structure where: 0.0 == no composites; 1.0 == maximum use of composites, ' + 'approximately equivalent bending_mat_weight=.6, ' + 'struct_weights=.83, misc_weight=.7 ' + '(not necessarily all composite).', default_value=0.0, ) add_meta_data( Aircraft.Wing.CONTROL_SURFACE_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WEIGHT.SFLAP', # TODO ~WWGHT.SFLAP: similar, but separate calculation - "LEAPS1": ['~WeightABC._pre_surface_ctrls.surface_flap_area', # TODO ~WingWeight.__call__.flap_ratio: see ~WWGHT.SFLAP - '~WeightABC.calc_surface_ctrls.surface_flap_area', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WEIGHT.SFLAP', # TODO ~WWGHT.SFLAP: similar, but separate calculation + "LEAPS1": [ + # TODO ~WingWeight.__call__.flap_ratio: see ~WWGHT.SFLAP + '~WeightABC._pre_surface_ctrls.surface_flap_area', + '~WeightABC.calc_surface_ctrls.surface_flap_area', + ], + }, units='ft**2', - desc='area of wing control surfaces' + desc='area of wing control surfaces', ) add_meta_data( Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.FLAPR', 'WTS.FLAPR', '~WWGHT.FLAPR'], - "FLOPS": 'WTIN.FLAPR', - "LEAPS1": 'aircraft.inputs.L0_wing.flap_ratio' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.FLAPR', 'WTS.FLAPR', '~WWGHT.FLAPR'], + "FLOPS": 'WTIN.FLAPR', + "LEAPS1": 'aircraft.inputs.L0_wing.flap_ratio', + }, units='unitless', desc='Defines the ratio of total moveable wing control surface areas ' - '(flaps, elevators, spoilers, etc.) to reference wing area.', + '(flaps, elevators, spoilers, etc.) to reference wing area.', default_value=0.333, ) add_meta_data( Aircraft.Wing.DETAILED_WING, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='use a detailed wing model', option=True, @@ -5223,49 +5233,52 @@ add_meta_data( Aircraft.Wing.DIHEDRAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.DIH', # ['&DEFINE.WTIN.DIH', 'WTS.DIH', ], - "LEAPS1": ['aircraft.inputs.L0_wing.dihedral', - # unit converted value for reporting - 'aircraft.cached.L0_wing.dihedral', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.DIH', # ['&DEFINE.WTIN.DIH', 'WTS.DIH', ], + "LEAPS1": [ + 'aircraft.inputs.L0_wing.dihedral', + # unit converted value for reporting + 'aircraft.cached.L0_wing.dihedral', + ], + }, units='deg', desc='wing dihedral (positive) or anhedral (negative) angle', - default_value=0.0 + default_value=0.0, ) add_meta_data( Aircraft.Wing.ENG_POD_INERTIA_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WWGHT.CAYE', - "LEAPS1": 'aircraft.outputs.L0_wing.engine_inertia_relief_factor' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WWGHT.CAYE', + "LEAPS1": 'aircraft.outputs.L0_wing.engine_inertia_relief_factor', + }, units='unitless', - desc='engine inertia relief factor' + desc='Engine inertia relief factor for wingspan inboard of engine locations. Used ' + 'to compute Aircraft.Wing.BENDING_MATERIAL_MASS', ) add_meta_data( Aircraft.Wing.FINENESS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # 'MISSA.FR[1]', - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[0]', - 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[0]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # 'MISSA.FR[1]', + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.mission_fineness_ratio_table[0]', + 'aircraft.cached.L0_aerodynamics.mission_fineness_ratio_table[0]', + ], + }, units='unitless', - desc='wing fineness ratio' + desc='wing fineness ratio', ) add_meta_data( Aircraft.Wing.FLAP_CHORD_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CFOC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CFOC', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='ratio of flap chord to wing chord', ) @@ -5273,32 +5286,23 @@ add_meta_data( Aircraft.Wing.FLAP_DEFLECTION_LANDING, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DFLPLD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DFLPLD', "FLOPS": None, "LEAPS1": None}, units='deg', - desc='Deflection of flaps for landing' + desc='Deflection of flaps for landing', ) add_meta_data( Aircraft.Wing.FLAP_DEFLECTION_TAKEOFF, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DFLPTO', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DFLPTO', "FLOPS": None, "LEAPS1": None}, units='deg', - desc='Deflection of flaps for takeoff' + desc='Deflection of flaps for takeoff', ) add_meta_data( Aircraft.Wing.FLAP_DRAG_INCREMENT_OPTIMUM, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DCDOTE', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DCDOTE', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='drag coefficient increment due to optimally deflected trailing edge flaps (default depends on flap type)', ) @@ -5306,10 +5310,7 @@ add_meta_data( Aircraft.Wing.FLAP_LIFT_INCREMENT_OPTIMUM, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DCLMTE', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DCLMTE', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='lift coefficient increment due to optimally deflected trailing edge flaps (default depends on flap type)', ) @@ -5317,10 +5318,7 @@ add_meta_data( Aircraft.Wing.FLAP_SPAN_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.BTEOB', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.BTEOB', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='fraction of wing trailing edge with flaps', default_value=0.65, @@ -5329,41 +5327,33 @@ add_meta_data( Aircraft.Wing.FLAP_TYPE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.JFLTYP', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.JFLTYP', "FLOPS": None, "LEAPS1": None}, units="unitless", default_value=FlapType.DOUBLE_SLOTTED, - types=FlapType, + types=(FlapType, int, str), + multivalue=True, option=True, desc='Set the flap type. Available choices are: plain, split, single_slotted, ' - 'double_slotted, triple_slotted, fowler, and double_slotted_fowler. ' - 'In GASP this was JFLTYP and was provided as an int from 1-7', + 'double_slotted, triple_slotted, fowler, and double_slotted_fowler. ' + 'In GASP this was JFLTYP and was provided as an int from 1-7', ) add_meta_data( Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", default_value=False, types=bool, option=True, desc='if true, fold location from the chosen input is an actual fold span, ' - 'if false it is normalized to the half span. In GASP this depended on STRUT or YWFOLD' + 'if false it is normalized to the half span. In GASP this depended on STRUT or YWFOLD', ) add_meta_data( Aircraft.Wing.FOLD_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WWFOLD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WWFOLD', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='mass of the folding area of the wing', default_value=0, @@ -5372,10 +5362,7 @@ add_meta_data( Aircraft.Wing.FOLD_MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKWFOLD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKWFOLD', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of the wing fold', default_value=0, @@ -5384,10 +5371,7 @@ add_meta_data( Aircraft.Wing.FOLDED_SPAN, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.YWFOLD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.YWFOLD', "FLOPS": None, "LEAPS1": None}, units='ft', desc='folded wingspan', default_value=118, @@ -5396,10 +5380,7 @@ add_meta_data( Aircraft.Wing.FOLDED_SPAN_DIMENSIONLESS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", desc='folded wingspan', default_value=1, @@ -5408,46 +5389,40 @@ add_meta_data( Aircraft.Wing.FOLDING_AREA, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SWFOLD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SWFOLD', "FLOPS": None, "LEAPS1": None}, units='ft**2', - desc='wing area of folding part of wings' + desc='wing area of folding part of wings', ) add_meta_data( Aircraft.Wing.FORM_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CKW', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CKW', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='wing form factor', + default_value=1.25, ) add_meta_data( Aircraft.Wing.FUSELAGE_INTERFERENCE_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CKI', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CKI', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='wing/fuselage interference factor', + default_value=1.1, ) add_meta_data( Aircraft.Wing.GLOVE_AND_BAT, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.GLOV', - # ['&DEFINE.WTIN.GLOV', 'EDETIN.GLOV', '~TOFF.GLOV', '~LNDING.GLOV', - # '~PROFIL.GLOV' - # ], - "LEAPS1": 'aircraft.inputs.L0_wing.glove_and_bat' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.GLOV', + # ['&DEFINE.WTIN.GLOV', 'EDETIN.GLOV', '~TOFF.GLOV', '~LNDING.GLOV', + # '~PROFIL.GLOV' + # ], + "LEAPS1": 'aircraft.inputs.L0_wing.glove_and_bat', + }, units='ft**2', desc='total glove and bat area beyond theoretical wing', default_value=0.0, @@ -5456,10 +5431,7 @@ add_meta_data( Aircraft.Wing.HAS_FOLD, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", option=True, desc='if true a fold will be included in the wing', @@ -5470,10 +5442,7 @@ add_meta_data( Aircraft.Wing.HAS_STRUT, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, option=True, units="unitless", default_value=False, @@ -5484,22 +5453,16 @@ add_meta_data( Aircraft.Wing.HEIGHT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.HTG', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.HTG', "FLOPS": None, "LEAPS1": None}, units='ft', desc='wing height above ground during ground run, measured at roughly ' - 'location of mean aerodynamic chord at the mid plane of the wing', + 'location of mean aerodynamic chord at the mid plane of the wing', ) add_meta_data( Aircraft.Wing.HIGH_LIFT_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WHLDEV', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WHLDEV', "FLOPS": None, "LEAPS1": None}, units='lbm', desc='mass of the high lift devices', ) @@ -5507,10 +5470,7 @@ add_meta_data( Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WCFLAP', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.WCFLAP', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of high lift devices (default depends on flap type)', ) @@ -5518,10 +5478,7 @@ add_meta_data( Aircraft.Wing.INCIDENCE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.EYEW', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.EYEW', "FLOPS": None, "LEAPS1": None}, units='deg', desc='incidence angle of the wings with respect to the fuselage', default_value=0.0, @@ -5532,13 +5489,14 @@ # NOTE required for blended-wing-body type aircraft Aircraft.Wing.INPUT_STATION_DIST, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.ETAW', # ['&DEFINE.WTIN.ETAW', 'WDEF.ETAW'], - "LEAPS1": 'aircraft.inputs.L0_detailed_wing.wing_station_locations' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.ETAW', # ['&DEFINE.WTIN.ETAW', 'WDEF.ETAW'], + "LEAPS1": 'aircraft.inputs.L0_detailed_wing.wing_station_locations', + }, units='unitless', desc='wing station locations as fractions of semispan; overwrites ' - 'station_locations', + 'station_locations', option=True, default_value=None, ) @@ -5546,10 +5504,11 @@ add_meta_data( Aircraft.Wing.LAMINAR_FLOW_LOWER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRLW', # ['&DEFINE.AERIN.TRLW', 'XLAM.TRLW', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_percent_laminar_flow_lower_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRLW', # ['&DEFINE.AERIN.TRLW', 'XLAM.TRLW', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_percent_laminar_flow_lower_surface', + }, units='unitless', desc='define percent laminar flow for wing lower surface', default_value=0.0, @@ -5558,10 +5517,11 @@ add_meta_data( Aircraft.Wing.LAMINAR_FLOW_UPPER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.TRUW', # ['&DEFINE.AERIN.TRUW', 'XLAM.TRUW', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_percent_laminar_flow_upper_surface' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.TRUW', # ['&DEFINE.AERIN.TRUW', 'XLAM.TRUW', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_percent_laminar_flow_upper_surface', + }, units='unitless', desc='define percent laminar flow for wing upper surface', default_value=0.0, @@ -5570,10 +5530,7 @@ add_meta_data( Aircraft.Wing.LEADING_EDGE_SWEEP, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SWPLE', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SWPLE', "FLOPS": None, "LEAPS1": None}, units='rad', desc='sweep angle at leading edge of wing', ) @@ -5581,13 +5538,13 @@ add_meta_data( Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.PDIST', # ['&DEFINE.WTIN.PDIST', 'WDEF.PDIST'], - "LEAPS1": 'aircraft.inputs.L0_detailed_wing.pressure_dist' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.PDIST', # ['&DEFINE.WTIN.PDIST', 'WDEF.PDIST'], + "LEAPS1": 'aircraft.inputs.L0_detailed_wing.pressure_dist', + }, units='unitless', - desc='controls spatial distribution of integratin stations for detailed' - ' wing', + desc='controls spatial distribution of integratin stations for detailed' ' wing', default_value=2.0, option=True, ) @@ -5595,10 +5552,11 @@ add_meta_data( Aircraft.Wing.LOAD_FRACTION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.PCTL', # ['&DEFINE.WTIN.PCTL', 'WDEF.PCTL'], - "LEAPS1": 'aircraft.inputs.L0_detailed_wing.carried_load_fraction' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.PCTL', # ['&DEFINE.WTIN.PCTL', 'WDEF.PCTL'], + "LEAPS1": 'aircraft.inputs.L0_detailed_wing.carried_load_fraction', + }, units='unitless', desc='fraction of load carried by defined wing', default_value=1.0, @@ -5607,24 +5565,26 @@ add_meta_data( Aircraft.Wing.LOAD_PATH_SWEEP_DIST, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.SWL', # ['&DEFINE.WTIN.SWL', 'WDEF.SWL'], - "LEAPS1": 'aircraft.inputs.L0_detailed_wing.wing_station_load_path_sweeps' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.SWL', # ['&DEFINE.WTIN.SWL', 'WDEF.SWL'], + "LEAPS1": 'aircraft.inputs.L0_detailed_wing.wing_station_load_path_sweeps', + }, units='deg', desc='Define the sweep of load path at station locations. Typically ' - 'parallel to rear spar tending toward max t/c of airfoil. The Ith value ' - 'is used between wing stations I and I+1.', + 'parallel to rear spar tending toward max t/c of airfoil. The Ith value ' + 'is used between wing stations I and I+1.', default_value=None, ) add_meta_data( Aircraft.Wing.LOADING, meta_data=_MetaData, - historical_name={"GASP": ['INGASP.WGS', 'INGASP.WOS'], - "FLOPS": None, - "LEAPS1": None - }, + historical_name={ + "GASP": ['INGASP.WGS', 'INGASP.WOS'], + "FLOPS": None, + "LEAPS1": None, + }, units='lbf/ft**2', desc='wing loading', ) @@ -5632,10 +5592,7 @@ add_meta_data( Aircraft.Wing.LOADING_ABOVE_20, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", desc='if true the wing loading is stated to be above 20 psf. In GASP this depended on WGS', option=True, @@ -5648,13 +5605,15 @@ # - see also: Aircraft.Wing.MASS_SCALER Aircraft.Wing.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(1, 2)', '~WEIGHT.WWING', '~WTSTAT.WSP(1, 2)', '~WWGHT.WWING'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._total_wing_weight', - 'aircraft.outputs.L0_weights_summary.total_wing_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(1, 2)', '~WEIGHT.WWING', '~WTSTAT.WSP(1, 2)', '~WWGHT.WWING'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._total_wing_weight', + 'aircraft.outputs.L0_weights_summary.total_wing_weight', + ], + }, units='lbm', desc='wing total mass', default_value=None, @@ -5663,10 +5622,7 @@ add_meta_data( Aircraft.Wing.MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKWW', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKWW', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='mass trend coefficient of the wing without high lift devices', default_value=133.4, @@ -5675,10 +5631,11 @@ add_meta_data( Aircraft.Wing.MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRWI', # ['&DEFINE.WTIN.FRWI', 'WTS.FRWI'], - "LEAPS1": 'aircraft.inputs.L0_overrides.total_wing_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRWI', # ['&DEFINE.WTIN.FRWI', 'WTS.FRWI'], + "LEAPS1": 'aircraft.inputs.L0_overrides.total_wing_weight', + }, units='unitless', desc='mass scaler of the overall wing', default_value=1.0, @@ -5687,10 +5644,7 @@ add_meta_data( Aircraft.Wing.MATERIAL_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKNO', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKNO', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='correction factor for the use of non optimum material', default_value=0, @@ -5699,17 +5653,19 @@ add_meta_data( Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.CAM', - # [ # inputs - # '&DEFINE.AERIN.CAM', 'EDETIN.CAM', - # # outputs - # 'MISSA.CAM', 'MISSA.CAMX', - # ], - "LEAPS1": ['aircraft.inputs.L0_aerodynamics.max_camber_at_70_semispan', - 'aircraft.outputs.L0_aerodynamics.mission_max_camber_at_70_semispan', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.CAM', + # [ # inputs + # '&DEFINE.AERIN.CAM', 'EDETIN.CAM', + # # outputs + # 'MISSA.CAM', 'MISSA.CAMX', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_aerodynamics.max_camber_at_70_semispan', + 'aircraft.outputs.L0_aerodynamics.mission_max_camber_at_70_semispan', + ], + }, units='unitless', desc='Maximum camber at 70 percent semispan, percent of local chord', default_value=0.0, @@ -5718,10 +5674,7 @@ add_meta_data( Aircraft.Wing.MAX_LIFT_REF, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.RCLMAX', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.RCLMAX', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='input reference maximum lift coefficient for basic wing', ) @@ -5729,10 +5682,7 @@ add_meta_data( Aircraft.Wing.MAX_SLAT_DEFLECTION_LANDING, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELLED', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELLED', "FLOPS": None, "LEAPS1": None}, units='deg', desc='leading edge slat deflection during landing', default_value=10, @@ -5741,10 +5691,7 @@ add_meta_data( Aircraft.Wing.MAX_SLAT_DEFLECTION_TAKEOFF, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELLED', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELLED', "FLOPS": None, "LEAPS1": None}, units='deg', desc='leading edge slat deflection during takeoff', default_value=10, @@ -5753,10 +5700,7 @@ add_meta_data( Aircraft.Wing.MAX_THICKNESS_LOCATION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.XCTCMX', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.XCTCMX', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='location (percent chord) of max wing thickness', ) @@ -5764,10 +5708,7 @@ add_meta_data( Aircraft.Wing.MIN_PRESSURE_LOCATION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.XCPS', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.XCPS', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='location (percent chord) of peak suction', ) @@ -5777,10 +5718,11 @@ # - see also: Aircraft.Wing.MISC_MASS_SCALER Aircraft.Wing.MISC_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WWGHT.W3', - "LEAPS1": 'aircraft.outputs.L0_wing.misc_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WWGHT.W3', + "LEAPS1": 'aircraft.outputs.L0_wing.misc_weight', + }, units='lbm', desc='wing mass breakdown term 3', default_value=None, @@ -5789,10 +5731,11 @@ add_meta_data( Aircraft.Wing.MISC_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRWI3', # ['&DEFINE.WTIN.FRWI3', 'WIOR3.FRWI3'], - "LEAPS1": 'aircraft.inputs.L0_overrides.wing_misc_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRWI3', # ['&DEFINE.WTIN.FRWI3', 'WIOR3.FRWI3'], + "LEAPS1": 'aircraft.inputs.L0_overrides.wing_misc_weight', + }, units='unitless', desc='mass scaler of the miscellaneous wing mass term', default_value=1.0, @@ -5801,10 +5744,7 @@ add_meta_data( Aircraft.Wing.MOUNTING_TYPE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.HWING', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.HWING', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='wing location on fuselage (0 = low wing, 1 = high wing)', ) @@ -5812,10 +5752,7 @@ add_meta_data( Aircraft.Wing.NUM_FLAP_SEGMENTS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FLAPN', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.FLAPN', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='number of flap segments per wing panel', types=int, @@ -5826,11 +5763,12 @@ add_meta_data( Aircraft.Wing.NUM_INTEGRATION_STATIONS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.NSTD', 'WDEF.NSTD', '~BNDMAT.NSD', '~DETA.NSD'], - "FLOPS": 'WTIN.NSTD', - "LEAPS1": 'aircraft.inputs.L0_detailed_wing.integration_station_count' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.NSTD', 'WDEF.NSTD', '~BNDMAT.NSD', '~DETA.NSD'], + "FLOPS": 'WTIN.NSTD', + "LEAPS1": 'aircraft.inputs.L0_detailed_wing.integration_station_count', + }, units='unitless', desc='number of integration stations', types=int, @@ -5841,10 +5779,7 @@ add_meta_data( Aircraft.Wing.OPTIMUM_FLAP_DEFLECTION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELTEO', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELTEO', "FLOPS": None, "LEAPS1": None}, units='deg', desc='optimum flap deflection angle (default depends on flap type)', ) @@ -5852,10 +5787,7 @@ add_meta_data( Aircraft.Wing.OPTIMUM_SLAT_DEFLECTION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELLEO', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELLEO', "FLOPS": None, "LEAPS1": None}, units='deg', desc='optimum slat deflection angle', default_value=20, @@ -5864,10 +5796,11 @@ add_meta_data( Aircraft.Wing.ROOT_CHORD, meta_data=_MetaData, - historical_name={"GASP": ['INGASP.CROOT', 'INGASP.CROOTW'], - "FLOPS": None, - "LEAPS1": None - }, + historical_name={ + "GASP": ['INGASP.CROOT', 'INGASP.CROOTW'], + "FLOPS": None, + "LEAPS1": None, + }, units='ft', desc='wing chord length at wing root', ) @@ -5877,10 +5810,11 @@ # - see also: Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER Aircraft.Wing.SHEAR_CONTROL_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~WWGHT.W2', - "LEAPS1": 'aircraft.outputs.L0_wing.struct_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~WWGHT.W2', + "LEAPS1": 'aircraft.outputs.L0_wing.struct_weight', + }, units='lbm', desc='wing mass breakdown term 2', default_value=None, @@ -5889,10 +5823,11 @@ add_meta_data( Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRWI2', # ['&DEFINE.WTIN.FRWI2', 'WIOR3.FRWI2'], - "LEAPS1": 'aircraft.inputs.L0_overrides.wing_struct_weights' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRWI2', # ['&DEFINE.WTIN.FRWI2', 'WIOR3.FRWI2'], + "LEAPS1": 'aircraft.inputs.L0_overrides.wing_struct_weights', + }, units='unitless', desc='mass scaler of the shear and control term', default_value=1.0, @@ -5901,10 +5836,7 @@ add_meta_data( Aircraft.Wing.SLAT_CHORD_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CLEOC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.CLEOC', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='ratio of slat chord to wing chord', default_value=0.15, @@ -5913,10 +5845,7 @@ add_meta_data( Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DCLMLE', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DCLMLE', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='lift coefficient increment due to optimally deflected LE slats', ) @@ -5924,10 +5853,7 @@ add_meta_data( Aircraft.Wing.SLAT_SPAN_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.BLEOB', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.BLEOB', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='fraction of wing leading edge with slats', default_value=0.9, @@ -5936,18 +5862,20 @@ add_meta_data( Aircraft.Wing.SPAN, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.B', - "FLOPS": 'WTIN.SPAN', - # [ # inputs - # '&DEFINE.WTIN.SPAN', - # # outputs - # '~WEIGHT.B', '~WWGHT.B', '~GESURF.B' - # ], - "LEAPS1": ['aircraft.inputs.L0_wing.span', - 'aircraft.outputs.L0_wing.span', - 'BasicTransportWeight.wing_span' - ] - }, + historical_name={ + "GASP": 'INGASP.B', + "FLOPS": 'WTIN.SPAN', + # [ # inputs + # '&DEFINE.WTIN.SPAN', + # # outputs + # '~WEIGHT.B', '~WWGHT.B', '~GESURF.B' + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_wing.span', + 'aircraft.outputs.L0_wing.span', + 'BasicTransportWeight.wing_span', + ], + }, units='ft', desc='span of main wing', default_value=0.0, @@ -5956,10 +5884,11 @@ add_meta_data( Aircraft.Wing.SPAN_EFFICIENCY_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.E', # ['&DEFINE.AERIN.E', 'OSWALD.E', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_span_efficiency_factor' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.E', # ['&DEFINE.AERIN.E', 'OSWALD.E', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_span_efficiency_factor', + }, units='unitless', desc='coefficient for calculating span efficiency for extreme taper ratios', default_value=1.0, @@ -5968,32 +5897,34 @@ add_meta_data( Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.MIKE', # ['&DEFINE.AERIN.MIKE', 'MIMOD.MIKE'], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_span_efficiency_reduction' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.MIKE', # ['&DEFINE.AERIN.MIKE', 'MIMOD.MIKE'], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_span_efficiency_reduction', + }, units='unitless', desc='Define a switch for span efficiency reduction for extreme taper ' - 'ratios: True == a span efficiency factor ' - '(*wing_span_efficiency_factor0*) is calculated based on wing taper ratio ' - 'and aspect ratio; False == a span efficiency factor ' - '(*wing_span_efficiency_factor0*) is set to 1.0.', + 'ratios: True == a span efficiency factor ' + '(*wing_span_efficiency_factor0*) is calculated based on wing taper ratio ' + 'and aspect ratio; False == a span efficiency factor ' + '(*wing_span_efficiency_factor0*) is set to 1.0.', option=True, types=bool, - default_value=False + default_value=False, ) add_meta_data( Aircraft.Wing.STRUT_BRACING_FACTOR, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.FSTRT', 'WTS.FSTRT', '~WWGHT.FSTRT', '~BNDMAT.FSTRT'], - "FLOPS": 'WTIN.FSTRT', - "LEAPS1": 'aircraft.inputs.L0_wing.struct_bracing_factor' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.FSTRT', 'WTS.FSTRT', '~WWGHT.FSTRT', '~BNDMAT.FSTRT'], + "FLOPS": 'WTIN.FSTRT', + "LEAPS1": 'aircraft.inputs.L0_wing.struct_bracing_factor', + }, units='unitless', desc='Define the wing strut-bracing factor where: 0.0 == no wing-strut; ' - '1.0 == full benefit from strut bracing.', + '1.0 == full benefit from strut bracing.', default_value=0.0, ) @@ -6002,13 +5933,15 @@ # - see also: Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER Aircraft.Wing.SURFACE_CONTROL_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - # ['WTS.WSP(16, 2)', '~WEIGHT.WSC', '~WTSTAT.WSP(16, 2)'], - "FLOPS": None, - "LEAPS1": ['(WeightABC)self._surface_ctrls_weight', - 'aircraft.outputs.L0_weights_summary.surface_ctrls_weight', - ] - }, + historical_name={ + "GASP": None, + # ['WTS.WSP(16, 2)', '~WEIGHT.WSC', '~WTSTAT.WSP(16, 2)'], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._surface_ctrls_weight', + 'aircraft.outputs.L0_weights_summary.surface_ctrls_weight', + ], + }, units='lbm', desc='mass of surface controls', default_value=None, @@ -6017,10 +5950,7 @@ add_meta_data( Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SKFW', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SKFW', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='Surface controls weight coefficient', default_value=0.404, @@ -6029,10 +5959,11 @@ add_meta_data( Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.FRSC', # ['&DEFINE.WTIN.FRSC', 'WTS.FRSC'], - "LEAPS1": 'aircraft.inputs.L0_overrides.surface_ctrls_weight' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.FRSC', # ['&DEFINE.WTIN.FRSC', 'WTS.FRSC'], + "LEAPS1": 'aircraft.inputs.L0_overrides.surface_ctrls_weight', + }, units='unitless', desc='Surface controls mass scaler', default_value=1.0, @@ -6041,22 +5972,24 @@ add_meta_data( Aircraft.Wing.SWEEP, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DLMC4', - "FLOPS": "CONFIN.SWEEP", - # [ # inputs - # '&DEFINE.CONFIN.SWEEP', 'PARVAR.DVD(1,6)', - # # outputs - # 'CONFIG.SWEEP', 'CONFIG.DVA(6)', '~FLOPS.DVA(6)', '~ANALYS.DVA(6)', - # '~WWGHT.SWEEP', '~INERT.SWEEP', - # # other - # 'MISSA.SW25', '~BUFFET.SW25', '~CDCC.SW25', '~CLDESN.SW25', - # '~MDESN.SW25', - # ], - "LEAPS1": ['aircraft.inputs.L0_design_variables.wing_sweep_at_quarter_chord', - 'aircraft.outputs.L0_design_variables.wing_sweep_at_quarter_chord', - 'aircraft.outputs.L0_design_variables.mission_wing_sweep_at_quarter_chord', - ] - }, + historical_name={ + "GASP": 'INGASP.DLMC4', + "FLOPS": "CONFIN.SWEEP", + # [ # inputs + # '&DEFINE.CONFIN.SWEEP', 'PARVAR.DVD(1,6)', + # # outputs + # 'CONFIG.SWEEP', 'CONFIG.DVA(6)', '~FLOPS.DVA(6)', '~ANALYS.DVA(6)', + # '~WWGHT.SWEEP', '~INERT.SWEEP', + # # other + # 'MISSA.SW25', '~BUFFET.SW25', '~CDCC.SW25', '~CLDESN.SW25', + # '~MDESN.SW25', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_design_variables.wing_sweep_at_quarter_chord', + 'aircraft.outputs.L0_design_variables.wing_sweep_at_quarter_chord', + 'aircraft.outputs.L0_design_variables.mission_wing_sweep_at_quarter_chord', + ], + }, units='deg', desc='quarter-chord sweep angle of the wing', default_value=0.0, # TODO required @@ -6065,21 +5998,23 @@ add_meta_data( Aircraft.Wing.TAPER_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SLM', - "FLOPS": "CONFIN.TR", - # [ # inputs - # '&DEFINE.CONFIN.TR', 'PARVAR.DVD(1,5)', - # # outputs - # 'CONFIG.TR', 'CONFIG.DVA(5)', 'CONFIG.TR1', '~FLOPS.DVA(5)', - # '~ANALYS.DVA(5)', '~GESURF.TR', '~WWGHT.TR', '~INERT.TR', - # # other - # 'MISSA.TAPER', '~CDCC.TAPER', '~MDESN.TAPER', - # ], - "LEAPS1": ['aircraft.inputs.L0_design_variables.wing_taper_ratio', - 'aircraft.outputs.L0_design_variables.wing_taper_ratio', - 'aircraft.outputs.L0_design_variables.mission_wing_taper_ratio', - ] - }, + historical_name={ + "GASP": 'INGASP.SLM', + "FLOPS": "CONFIN.TR", + # [ # inputs + # '&DEFINE.CONFIN.TR', 'PARVAR.DVD(1,5)', + # # outputs + # 'CONFIG.TR', 'CONFIG.DVA(5)', 'CONFIG.TR1', '~FLOPS.DVA(5)', + # '~ANALYS.DVA(5)', '~GESURF.TR', '~WWGHT.TR', '~INERT.TR', + # # other + # 'MISSA.TAPER', '~CDCC.TAPER', '~MDESN.TAPER', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_design_variables.wing_taper_ratio', + 'aircraft.outputs.L0_design_variables.wing_taper_ratio', + 'aircraft.outputs.L0_design_variables.mission_wing_taper_ratio', + ], + }, units='unitless', desc='taper ratio of the wing', default_value=0.0, # TODO required @@ -6088,22 +6023,24 @@ add_meta_data( Aircraft.Wing.THICKNESS_TO_CHORD, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'CONFIN.TCA', - # [ # inputs - # '&DEFINE.CONFIN.TCA', 'PARVAR.DVD(1,7)', - # # outputs - # 'CONFIG.TCA', 'CONFIG.DVA(7)', '~FLOPS.DVA(7)', '~ANALYS.DVA(7)', - # '~WWGHT.TCA', - # # other - # 'MISSA.TC', '~BUFFET.TC', '~CDCC.TC', '~CDPP.TC', '~CLDESN.TC', - # '~MDESN.TC', - # ], - "LEAPS1": ['aircraft.inputs.L0_design_variables.wing_thickness_to_chord_ratio', - 'aircraft.outputs.L0_design_variables.wing_thickness_to_chord_ratio', - 'aircraft.outputs.L0_design_variables.mission_wing_thickness_to_chord_ratio', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'CONFIN.TCA', + # [ # inputs + # '&DEFINE.CONFIN.TCA', 'PARVAR.DVD(1,7)', + # # outputs + # 'CONFIG.TCA', 'CONFIG.DVA(7)', '~FLOPS.DVA(7)', '~ANALYS.DVA(7)', + # '~WWGHT.TCA', + # # other + # 'MISSA.TC', '~BUFFET.TC', '~CDCC.TC', '~CDPP.TC', '~CLDESN.TC', + # '~MDESN.TC', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_design_variables.wing_thickness_to_chord_ratio', + 'aircraft.outputs.L0_design_variables.wing_thickness_to_chord_ratio', + 'aircraft.outputs.L0_design_variables.mission_wing_thickness_to_chord_ratio', + ], + }, units='unitless', desc='wing thickness-chord ratio (weighted average)', default_value=0.0, # TODO required @@ -6112,10 +6049,11 @@ add_meta_data( Aircraft.Wing.THICKNESS_TO_CHORD_DIST, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.TOC', # ['&DEFINE.WTIN.TOC', 'WDEF.TOC'], - "LEAPS1": 'aircraft.inputs.L0_detailed_wing.wing_station_thickness_to_chord_ratios' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.TOC', # ['&DEFINE.WTIN.TOC', 'WDEF.TOC'], + "LEAPS1": 'aircraft.inputs.L0_detailed_wing.wing_station_thickness_to_chord_ratios', + }, units='unitless', desc='the thickeness-chord ratios at station locations', default_value=None, @@ -6124,22 +6062,20 @@ add_meta_data( Aircraft.Wing.THICKNESS_TO_CHORD_REF, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.TCREF', # ['&DEFINE.WTIN.TCREF'], - "LEAPS1": 'aircraft.inputs.L0_detailed_wing.ref_thickness_to_chord_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.TCREF', # ['&DEFINE.WTIN.TCREF'], + "LEAPS1": 'aircraft.inputs.L0_detailed_wing.ref_thickness_to_chord_ratio', + }, units='unitless', - desc='Reference thickness-to-chord ratio, used for detailed wing bending.', - default_value=0.0 + desc='Reference thickness-to-chord ratio, used for detailed wing mass estimation.', + default_value=0.0, ) add_meta_data( Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.TCR', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.TCR', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='thickness-to-chord ratio at the root of the wing', ) @@ -6147,10 +6083,7 @@ add_meta_data( Aircraft.Wing.THICKNESS_TO_CHORD_TIP, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.TCT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.TCT', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='thickness-to-chord ratio at the tip of the wing', ) @@ -6158,21 +6091,20 @@ add_meta_data( Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.TC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.TC', "FLOPS": None, "LEAPS1": None}, units='unitless', - desc='wing thickness-chord ratio at the wing station of the mean aerodynamic chord') + desc='wing thickness-chord ratio at the wing station of the mean aerodynamic chord', +) add_meta_data( Aircraft.Wing.ULTIMATE_LOAD_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ULF', - # ['&DEFINE.WTIN.ULF', 'WTS.ULF', '~WWGHT.ULF'], - "FLOPS": 'WTIN.ULF', - "LEAPS1": 'aircraft.inputs.L0_weights.struct_ult_load_factor' - }, + historical_name={ + "GASP": 'INGASP.ULF', + # ['&DEFINE.WTIN.ULF', 'WTS.ULF', '~WWGHT.ULF'], + "FLOPS": 'WTIN.ULF', + "LEAPS1": 'aircraft.inputs.L0_weights.struct_ult_load_factor', + }, units='unitless', desc='structural ultimate load factor', default_value=3.75, @@ -6181,14 +6113,15 @@ add_meta_data( Aircraft.Wing.VAR_SWEEP_MASS_PENALTY, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFINE.WTIN.VARSWP', 'FAWT.VARSWP', '~WWGHT.VARSWP'], - "FLOPS": 'WTIN.VARSWP', - "LEAPS1": 'aircraft.inputs.L0_wing.var_sweep_weight_penalty' - }, + historical_name={ + "GASP": None, + # ['&DEFINE.WTIN.VARSWP', 'FAWT.VARSWP', '~WWGHT.VARSWP'], + "FLOPS": 'WTIN.VARSWP', + "LEAPS1": 'aircraft.inputs.L0_wing.var_sweep_weight_penalty', + }, units='unitless', desc='Define the fraction of wing variable sweep mass penalty where: ' - '0.0 == fixed-geometry wing; 1.0 == full variable-sweep wing.', + '0.0 == fixed-geometry wing; 1.0 == full variable-sweep wing.', default_value=0.0, ) @@ -6197,13 +6130,15 @@ # - see also: Aircraft.Wing.WETTED_AREA_SCALER Aircraft.Wing.WETTED_AREA, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['ACTWET.SWTWG', 'MISSA.SWET[1]'], - "LEAPS1": ['aircraft.outputs.L0_aerodynamics.wing_wetted_area', - 'aircraft.outputs.L0_aerodynamics.mission_component_wetted_area_table[0]', - 'aircraft.cached.L0_aerodynamics.mission_component_wetted_area_table[0]', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['ACTWET.SWTWG', 'MISSA.SWET[1]'], + "LEAPS1": [ + 'aircraft.outputs.L0_aerodynamics.wing_wetted_area', + 'aircraft.outputs.L0_aerodynamics.mission_component_wetted_area_table[0]', + 'aircraft.cached.L0_aerodynamics.mission_component_wetted_area_table[0]', + ], + }, units='ft**2', desc='wing wetted area', default_value=None, @@ -6212,10 +6147,11 @@ add_meta_data( Aircraft.Wing.WETTED_AREA_SCALER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.SWETW', # ['&DEFINE.AERIN.SWETW', 'AWETO.SWETW', ], - "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_wetted_area' - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.SWETW', # ['&DEFINE.AERIN.SWETW', 'AWETO.SWETW', ], + "LEAPS1": 'aircraft.inputs.L0_aerodynamics.wing_wetted_area', + }, units='unitless', desc='wing wetted area scaler', default_value=1.0, @@ -6224,10 +6160,7 @@ add_meta_data( Aircraft.Wing.ZERO_LIFT_ANGLE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ALPHL0', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.ALPHL0', "FLOPS": None, "LEAPS1": None}, units='deg', desc='zero lift angle of attack', ) @@ -6246,552 +6179,430 @@ # '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' # ============================================================================================================================================ -# __ __ _ _ -# | \/ | (_) (_) -# | \ / | _ ___ ___ _ ___ _ __ -# | |\/| | | | / __| / __| | | / _ \ | '_ \ -# | | | | | | \__ \ \__ \ | | | (_) | | | | | -# |_| |_| |_| |___/ |___/ |_| \___/ |_| |_| -# ============================================ +# _ _ +# /\ | | | | +# / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ ___ +# / /\ \ | __| | '_ ` _ \ / _ \ / __| | '_ \ | '_ \ / _ \ | '__| / _ \ +# / ____ \ | |_ | | | | | | | (_) | \__ \ | |_) | | | | | | __/ | | | __/ +# /_/ \_\ \__| |_| |_| |_| \___/ |___/ | .__/ |_| |_| \___| |_| \___| +# | | +# |_| +# ================================================================================ add_meta_data( - Dynamic.Mission.ALTITUDE, + Dynamic.Atmosphere.DENSITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='ft', - desc='Current altitude of the vehicle' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbm/ft**3', + desc="Atmospheric density at the vehicle's current altitude", ) add_meta_data( - Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Atmosphere.DYNAMIC_PRESSURE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='ft/s', - desc='Current rate of altitude change (climb rate) of the vehicle' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbf/ft**2', + desc="Atmospheric dynamic pressure at the vehicle's current flight condition", ) add_meta_data( - Dynamic.Mission.ALTITUDE_RATE_MAX, + Dynamic.Atmosphere.KINEMATIC_VISCOSITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='ft/s', - desc='Current maximum possible rate of altitude change (climb rate) of the vehicle ' - '(at hypothetical maximum thrust condition)' + historical_name={"GASP": 'XKV', "FLOPS": None, "LEAPS1": None}, + units='ft**2/s', + desc="Atmospheric kinematic viscosity at the vehicle's current flight condition", ) add_meta_data( - Dynamic.Mission.BATTERY_STATE_OF_CHARGE, + Dynamic.Atmosphere.MACH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', - desc="battery's current state of charge" + desc='Current Mach number of the vehicle', ) add_meta_data( - Dynamic.Mission.CUMULATIVE_ELECTRIC_ENERGY_USED, + Dynamic.Atmosphere.MACH_RATE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='kJ', - desc='Total amount of electric energy consumed by the vehicle up until this point in the mission', + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='unitless', + desc='Current rate at which the Mach number of the vehicle is changing', ) add_meta_data( - Dynamic.Mission.DENSITY, + Dynamic.Atmosphere.SPEED_OF_SOUND, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbm/ft**3', - desc="Atmospheric density at the vehicle's current altitude" + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='ft/s', + desc="Atmospheric speed of sound at vehicle's current flight condition", ) add_meta_data( - Dynamic.Mission.DISTANCE, + Dynamic.Atmosphere.STATIC_PRESSURE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'range', - "LEAPS1": None - }, - units='NM', - desc="The total distance the vehicle has traveled since brake release at the current time" + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbf/ft**2', + desc="Atmospheric static pressure at the vehicle's current flight condition", ) add_meta_data( - Dynamic.Mission.DISTANCE_RATE, + Dynamic.Atmosphere.TEMPERATURE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'range_rate', - "LEAPS1": None - }, - units='NM/s', - desc="The rate at which the distance traveled is changing at the current time" + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='degR', + desc="Atmospheric temperature at vehicle's current flight condition", ) + +# __ __ _ _ +# | \/ | (_) (_) +# | \ / | _ ___ ___ _ ___ _ __ +# | |\/| | | | / __| / __| | | / _ \ | '_ \ +# | | | | | | \__ \ \__ \ | | | (_) | | | | | +# |_| |_| |_| |___/ |___/ |_| \___/ |_| |_| +# ============================================ add_meta_data( - Dynamic.Mission.DRAG, + Dynamic.Mission.ALTITUDE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbf', - desc='Current total drag experienced by the vehicle' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='ft', + desc='Current altitude of the vehicle', ) add_meta_data( - Dynamic.Mission.DYNAMIC_PRESSURE, + Dynamic.Mission.ALTITUDE_RATE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbf/ft**2', - desc="Atmospheric dynamic pressure at the vehicle's current flight condition" + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='ft/s', + desc='Current rate of altitude change (climb rate) of the vehicle', ) add_meta_data( - Dynamic.Mission.ELECTRIC_POWER_IN, + Dynamic.Mission.ALTITUDE_RATE_MAX, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='kW', - desc='Current electric power consumption of each engine', + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='ft/s', + desc='Current maximum possible rate of altitude change (climb rate) of the vehicle ' + '(at hypothetical maximum thrust condition)', ) add_meta_data( - Dynamic.Mission.ELECTRIC_POWER_IN_TOTAL, + Dynamic.Mission.DISTANCE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='kW', - desc='Current total electric power consumption of the vehicle' + historical_name={"GASP": None, "FLOPS": 'range', "LEAPS1": None}, + units='NM', + desc="The total distance the vehicle has traveled since brake release at the current time", ) -# add_meta_data( -# Dynamic.Mission.EXIT_AREA, -# meta_data=_MetaData, -# historical_name={"GASP": None, -# "FLOPS": None, -# "LEAPS1": None -# }, -# units='kW', -# desc='Current nozzle exit area of engines, per single instance of each ' -# 'engine model' -# ) +add_meta_data( + Dynamic.Mission.DISTANCE_RATE, + meta_data=_MetaData, + historical_name={"GASP": None, "FLOPS": 'range_rate', "LEAPS1": None}, + units='NM/s', + desc="The rate at which the distance traveled is changing at the current time", +) add_meta_data( Dynamic.Mission.FLIGHT_PATH_ANGLE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='rad', - desc='Current flight path angle' + desc='Current flight path angle', ) add_meta_data( Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='rad/s', - desc='Current rate at which flight path angle is changing' + desc='Current rate at which flight path angle is changing', ) add_meta_data( - Dynamic.Mission.FUEL_FLOW_RATE, + Dynamic.Mission.SPECIFIC_ENERGY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbm/h', - desc='Current rate of fuel consumption of the vehicle, per single instance of ' - 'each engine model. Consumption (i.e. mass reduction) of fuel is defined as ' - 'positive.' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='m/s', + desc='Rate of change in specific energy (energy per unit weight) of the vehicle at current ' + 'flight condition', ) add_meta_data( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbm/h', - desc='Current rate of fuel consumption of the vehicle, per single instance of each ' - 'engine model. Consumption (i.e. mass reduction) of fuel is defined as negative.' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='m/s', + desc='Rate of change in specific energy (specific power) of the vehicle at current ' + 'flight condition', ) add_meta_data( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbm/h', - desc='Current rate of total fuel consumption of the vehicle. Consumption (i.e. ' - 'mass reduction) of fuel is defined as negative.' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='m/s', + desc='Specific excess power of the vehicle at current flight condition and at ' + 'hypothetical maximum thrust', ) add_meta_data( - Dynamic.Mission.FUEL_FLOW_RATE_TOTAL, + Dynamic.Mission.VELOCITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbm/h', - desc='Current rate of total fuel consumption of the vehicle. Consumption (i.e. ' - 'mass reduction) of fuel is defined as positive.' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='ft/s', + desc='Current velocity of the vehicle along its body axis', ) add_meta_data( - Dynamic.Mission.HYBRID_THROTTLE, + Dynamic.Mission.VELOCITY_RATE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='unitless', - desc='Current secondary throttle setting of each individual engine model on the ' - 'vehicle, used as an additional degree of control for hybrid engines' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='ft/s**2', + desc='Current rate of change in velocity (acceleration) of the vehicle along its ' + 'body axis', ) +# __ __ _ _ _ +# \ \ / / | | (_) | | +# \ \ / / ___ | |__ _ ___ | | ___ +# \ \/ / / _ \ | '_ \ | | / __| | | / _ \ +# \ / | __/ | | | | | | | (__ | | | __/ +# \/ \___| |_| |_| |_| \___| |_| \___| +# ================================================ + add_meta_data( - Dynamic.Mission.KINEMATIC_VISCOSITY, + Dynamic.Vehicle.BATTERY_STATE_OF_CHARGE, meta_data=_MetaData, - historical_name={"GASP": 'XKV', - "FLOPS": None, - "LEAPS1": None - }, - units='ft**2/s', - desc="Atmospheric kinematic viscosity at the vehicle's current flight condition" + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='unitless', + desc="battery's current state of charge", ) add_meta_data( - Dynamic.Mission.LIFT, + Dynamic.Vehicle.CUMULATIVE_ELECTRIC_ENERGY_USED, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbf', - desc='Current total lift produced by the vehicle' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='kJ', + desc='Total amount of electric energy consumed by the vehicle up until this point in the mission', ) add_meta_data( - Dynamic.Mission.MACH, + Dynamic.Vehicle.DRAG, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='unitless', - desc='Current Mach number of the vehicle' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbf', + desc='Current total drag experienced by the vehicle', ) add_meta_data( - Dynamic.Mission.MACH_RATE, + Dynamic.Vehicle.LIFT, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='unitless', - desc='Current rate at which the Mach number of the vehicle is changing' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbf', + desc='Current total lift produced by the vehicle', ) add_meta_data( - Dynamic.Mission.MASS, + Dynamic.Vehicle.MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', - desc='Current total mass of the vehicle' + desc='Current total mass of the vehicle', ) add_meta_data( - Dynamic.Mission.MASS_RATE, + Dynamic.Vehicle.MASS_RATE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm/s', - desc='Current rate at which the mass of the vehicle is changing' + desc='Current rate at which the mass of the vehicle is changing', ) +# ___ _ _ +# | _ \ _ _ ___ _ __ _ _ | | ___ (_) ___ _ _ +# | _/ | '_| / _ \ | '_ \ | || | | | (_-< | | / _ \ | ' \ +# |_| |_| \___/ | .__/ \_,_| |_| /__/ |_| \___/ |_||_| +# |_| +# ========================================================== + add_meta_data( - Dynamic.Mission.NOX_RATE, + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbm/h', - desc='Current rate of nitrous oxide (NOx) production by the vehicle, per single ' - 'instance of each engine model' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='kW', + desc='Current electric power consumption of each engine', ) add_meta_data( - Dynamic.Mission.NOX_RATE_TOTAL, + Dynamic.Vehicle.Propulsion.ELECTRIC_POWER_IN_TOTAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbm/h', - desc='Current total rate of nitrous oxide (NOx) production by the vehicle' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='kW', + desc='Current total electric power consumption of the vehicle', ) # add_meta_data( -# Dynamic.Mission.PERCENT_ROTOR_RPM_CORRECTED, +# Dynamic.Vehicle.Propulsion.EXIT_AREA, # meta_data=_MetaData, # historical_name={"GASP": None, -# "FLOPS": None, -# "LEAPS1": None -# }, -# units='unitless', -# desc='percent of the corrected rotor speed', -# default_value=0.9, +# "FLOPS": None, +# "LEAPS1": None +# }, +# units='kW', +# desc='Current nozzle exit area of engines, per single instance of each ' +# 'engine model' # ) add_meta_data( - Dynamic.Mission.PROPELLER_TIP_SPEED, - meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='ft/s', - desc='linear propeller tip speed due to rotation (not airspeed at propeller tip)', - default_value=500.0, -) - -add_meta_data( - Dynamic.Mission.RPM, - meta_data=_MetaData, - historical_name={"GASP": ['RPM', 'RPMe'], "FLOPS": None, "LEAPS1": None}, - units='rpm', - desc='Rotational rate of shaft, per engine.', -) - -add_meta_data( - Dynamic.Mission.RPM_GEARBOX, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None}, - units='rpm', - desc='Rotational rate of shaft coming out of the gearbox and into the prop.', + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbm/h', + desc='Current rate of fuel consumption of the vehicle, per single instance of ' + 'each engine model. Consumption (i.e. mass reduction) of fuel is defined as ' + 'positive.', ) add_meta_data( - Dynamic.Mission.SPECIFIC_ENERGY, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='m/s', - desc='Rate of change in specific energy (energy per unit weight) of the vehicle at current ' - 'flight condition' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbm/h', + desc='Current rate of fuel consumption of the vehicle, per single instance of each ' + 'engine model. Consumption (i.e. mass reduction) of fuel is defined as negative.', ) add_meta_data( - Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='m/s', - desc='Rate of change in specific energy (specific power) of the vehicle at current ' - 'flight condition' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbm/h', + desc='Current rate of total fuel consumption of the vehicle. Consumption (i.e. ' + 'mass reduction) of fuel is defined as negative.', ) add_meta_data( - Dynamic.Mission.SHAFT_POWER, + Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_TOTAL, meta_data=_MetaData, - historical_name={"GASP": ['SHP, EHP'], "FLOPS": None, "LEAPS1": None}, - units='hp', - desc='current shaft power, per engine', + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbm/h', + desc='Current rate of total fuel consumption of the vehicle. Consumption (i.e. ' + 'mass reduction) of fuel is defined as positive.', ) add_meta_data( - Dynamic.Mission.SHAFT_POWER_GEARBOX, + Dynamic.Vehicle.Propulsion.HYBRID_THROTTLE, meta_data=_MetaData, historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, - units='kW', - desc='current shaft power coming out of the gearbox, per gearbox', + units='unitless', + desc='Current secondary throttle setting of each individual engine model on the ' + 'vehicle, used as an additional degree of control for hybrid engines', ) add_meta_data( - Dynamic.Mission.SHAFT_POWER_MAX, + Dynamic.Vehicle.Propulsion.NOX_RATE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='hp', - desc='The maximum possible shaft power currently producible, per engine' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbm/h', + desc='Current rate of nitrous oxide (NOx) production by the vehicle, per single ' + 'instance of each engine model', ) add_meta_data( - Dynamic.Mission.SHAFT_POWER_MAX_GEARBOX, + Dynamic.Vehicle.Propulsion.NOX_RATE_TOTAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='hp', - desc='The maximum possible shaft power the gearbox can currently produce, per gearbox' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='lbm/h', + desc='Current total rate of nitrous oxide (NOx) production by the vehicle', ) add_meta_data( - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, + Dynamic.Vehicle.Propulsion.PROPELLER_TIP_SPEED, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='m/s', - desc='Specific excess power of the vehicle at current flight condition and at ' - 'hypothetical maximum thrust' + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='ft/s', + desc='linear propeller tip speed due to rotation (not airspeed at propeller tip)', + default_value=500.0, ) add_meta_data( - Dynamic.Mission.SPEED_OF_SOUND, + Dynamic.Vehicle.Propulsion.RPM, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='ft/s', - desc="Atmospheric speed of sound at vehicle's current flight condition" + historical_name={"GASP": ['RPM', 'RPMe'], "FLOPS": None, "LEAPS1": None}, + units='rpm', + desc='Rotational rate of shaft, per engine.', ) add_meta_data( - Dynamic.Mission.STATIC_PRESSURE, + Dynamic.Vehicle.Propulsion.SHAFT_POWER, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='lbf/ft**2', - desc="Atmospheric static pressure at the vehicle's current flight condition" + historical_name={"GASP": ['SHP, EHP'], "FLOPS": None, "LEAPS1": None}, + units='hp', + desc='current shaft power, per engine', ) add_meta_data( - Dynamic.Mission.TEMPERATURE, + Dynamic.Vehicle.Propulsion.SHAFT_POWER_MAX, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='degR', - desc="Atmospheric temperature at vehicle's current flight condition" + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='hp', + desc='The maximum possible shaft power currently producible, per engine', ) add_meta_data( - Dynamic.Mission.TEMPERATURE_T4, + Dynamic.Vehicle.Propulsion.TEMPERATURE_T4, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='degR', desc='Current turbine exit temperature (T4) of turbine engines on vehicle, per ' - 'single instance of each engine model' + 'single instance of each engine model', ) add_meta_data( - Dynamic.Mission.THROTTLE, + Dynamic.Vehicle.Propulsion.THROTTLE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', - desc='Current throttle setting for each individual engine model on the vehicle' + desc='Current throttle setting for each individual engine model on the vehicle', ) add_meta_data( - Dynamic.Mission.THRUST, + Dynamic.Vehicle.Propulsion.THRUST, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbf', desc='Current net thrust produced by engines, per single instance of each engine ' - 'model' + 'model', ) add_meta_data( - Dynamic.Mission.THRUST_MAX, + Dynamic.Vehicle.Propulsion.THRUST_MAX, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbf', desc="Hypothetical maximum possible net thrust that can be produced per single " - "instance of each engine model at the vehicle's current flight condition" + "instance of each engine model at the vehicle's current flight condition", ) add_meta_data( - Dynamic.Mission.THRUST_MAX_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_MAX_TOTAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbf', desc='Hypothetical maximum possible net thrust produced by the vehicle at its ' - 'current flight condition' + 'current flight condition', ) add_meta_data( - Dynamic.Mission.THRUST_TOTAL, + Dynamic.Vehicle.Propulsion.THRUST_TOTAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbf', - desc='Current total net thrust produced by the vehicle' + desc='Current total net thrust produced by the vehicle', ) add_meta_data( - Dynamic.Mission.TORQUE, + Dynamic.Vehicle.Propulsion.TORQUE, meta_data=_MetaData, historical_name={"GASP": 'TORQUE', "FLOPS": None, "LEAPS1": None}, units='N*m', @@ -6799,7 +6610,7 @@ ) add_meta_data( - Dynamic.Mission.TORQUE_MAX, + Dynamic.Vehicle.Propulsion.TORQUE_MAX, meta_data=_MetaData, historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='N*m', @@ -6807,37 +6618,6 @@ 'condition, per engine', ) -add_meta_data( - Dynamic.Mission.TORQUE_GEARBOX, - meta_data=_MetaData, - historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, - units='N*m', - desc='Current torque being produced, per gearbox', -) - -add_meta_data( - Dynamic.Mission.VELOCITY, - meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='ft/s', - desc='Current velocity of the vehicle along its body axis' -) - -add_meta_data( - Dynamic.Mission.VELOCITY_RATE, - meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='ft/s**2', - desc='Current rate of change in velocity (acceleration) of the vehicle along its ' - 'body axis' -) - # ============================================================================================================================================ # .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .-----------------. # | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | @@ -6860,33 +6640,40 @@ # \_____| \___/ |_| |_| |___/ \__| |_| \__,_| |_| |_| |_| \__| |___/ # =========================================================================== +add_meta_data( + Mission.Constraints.GEARBOX_SHAFT_POWER_RESIDUAL, + meta_data=_MetaData, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, + units='kW', + desc='Must be zero or positive to ensure that the gearbox is sized large enough to handle the maximum shaft power the engine could output during any part of the mission', +) + add_meta_data( Mission.Constraints.MASS_RESIDUAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='residual to make sure aircraft mass closes on actual ' - 'gross takeoff mass, value should be zero at convergence ' - '(within acceptable tolerance)', + 'gross takeoff mass, value should be zero at convergence ' + '(within acceptable tolerance)', ) add_meta_data( Mission.Constraints.MAX_MACH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'WTIN.VMMO', - # [ # inputs - # '&DEFINE.WTIN.VMMO', 'VLIMIT.VMMO', - # # outputs - # 'VLIMIT.VMAX', - # ], - "LEAPS1": ['aircraft.inputs.L0_weights.max_mach', - 'aircraft.outputs.L0_weights.max_mach', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'WTIN.VMMO', + # [ # inputs + # '&DEFINE.WTIN.VMMO', 'VLIMIT.VMMO', + # # outputs + # 'VLIMIT.VMAX', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_weights.max_mach', + 'aircraft.outputs.L0_weights.max_mach', + ], + }, units='unitless', desc='aircraft cruise mach number', # TODO: derived default value: Mission.Summary.CRUISE_MACH ??? @@ -6897,35 +6684,21 @@ add_meta_data( Mission.Constraints.RANGE_RESIDUAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='NM', desc='residual to make sure aircraft range is equal to the targeted ' - 'range, value should be zero at convergence (within acceptable ' - 'tolerance)', + 'range, value should be zero at convergence (within acceptable ' + 'tolerance)', ) add_meta_data( Mission.Constraints.RANGE_RESIDUAL_RESERVE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='NM', desc='residual to make sure aircraft reserve mission range is equal to the targeted ' - 'range, value should be zero at convergence (within acceptable ' - 'tolerance)', -) - -add_meta_data( - Mission.Constraints.SHAFT_POWER_RESIDUAL, - meta_data=_MetaData, - historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, - units='kW', - desc='Must be zero or positive to ensure that the gearbox is sized large enough to handle the maximum shaft power the engine could output during any part of the mission', + 'range, value should be zero at convergence (within acceptable ' + 'tolerance)', ) # _____ _ @@ -6941,23 +6714,18 @@ add_meta_data( Mission.Design.CRUISE_ALTITUDE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CRALT', - "FLOPS": None, - "LEAPS1": None - }, - option=True, + historical_name={"GASP": 'INGASP.CRALT', "FLOPS": None, "LEAPS1": None}, units='ft', - default_value=25000, + option=True, + default_value=25000.0, + types=(int, float), desc='design mission cruise altitude', - types=[int, float] ) add_meta_data( Mission.Design.CRUISE_RANGE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None}, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='NM', desc='the distance flown by the aircraft during cruise', default_value=0.0, @@ -6966,45 +6734,45 @@ add_meta_data( Mission.Design.FUEL_MASS, meta_data=_MetaData, - historical_name={"GASP": "INGASP.WFADES", - "FLOPS": None, # ['WSP(38, 2)', '~WEIGHT.FUELM', '~INERT.FUELM'], - "LEAPS1": ['(WeightABC)self._fuel_weight', - 'aircraft.outputs.L0_weights_summary.fuel_weight' - ] - }, + historical_name={ + "GASP": "INGASP.WFADES", + "FLOPS": None, # ['WSP(38, 2)', '~WEIGHT.FUELM', '~INERT.FUELM'], + "LEAPS1": [ + '(WeightABC)self._fuel_weight', + 'aircraft.outputs.L0_weights_summary.fuel_weight', + ], + }, units='lbm', desc='fuel carried by the aircraft when it is on the ramp at the ' - 'beginning of the design mission', + 'beginning of the design mission', ) add_meta_data( Mission.Design.FUEL_MASS_REQUIRED, meta_data=_MetaData, - historical_name={"GASP": "INGASP.WFAREQ", - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": "INGASP.WFAREQ", "FLOPS": None, "LEAPS1": None}, units='lbm', desc='fuel carried by the aircraft when it is on the ramp at the ' - 'beginning of the design mission', + 'beginning of the design mission', ) add_meta_data( Mission.Design.GROSS_MASS, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WG', - # ['&DEFINE.WTIN.DGW', 'WTS.DGW', '~WEIGHT.DG', '~WWGHT.DG'], - "FLOPS": 'WTIN.DGW', - "LEAPS1": [ # TODO: 'aircraft.inputs.L0_weights.design_ramp_weight_fraction' ??? - # - design_ramp_weight_fraction has a default: 1.0 - # - design_ramp_weight does not have an explicit default - # - design_ramp_weight has an implicit default, by way of - # design_ramp_weight_fraction: - # [L0_design_variables] ramp_weight - 'aircraft.inputs.L0_weights.design_ramp_weight', - '(weightABC)self._design_gross_weight' - ] - }, + historical_name={ + "GASP": 'INGASP.WG', + # ['&DEFINE.WTIN.DGW', 'WTS.DGW', '~WEIGHT.DG', '~WWGHT.DG'], + "FLOPS": 'WTIN.DGW', + "LEAPS1": [ # TODO: 'aircraft.inputs.L0_weights.design_ramp_weight_fraction' ??? + # - design_ramp_weight_fraction has a default: 1.0 + # - design_ramp_weight does not have an explicit default + # - design_ramp_weight has an implicit default, by way of + # design_ramp_weight_fraction: + # [L0_design_variables] ramp_weight + 'aircraft.inputs.L0_weights.design_ramp_weight', + '(weightABC)self._design_gross_weight', + ], + }, units='lbm', desc='design gross mass of the aircraft', default_value=None, @@ -7014,50 +6782,55 @@ # NOTE: user override (no scaling) Mission.Design.LIFT_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.FCLDES', - # [ # inputs - # '&DEFINE.AERIN.FCLDES', 'OSWALD.FCLDES', - # # outputs - # '~EDET.CLDES', '~CLDESN.CLDES', '~MDESN.CLDES' - # ], - "LEAPS1": ['aircraft.inputs.L0_aerodynamics.design_lift_coeff', - 'aircraft.outputs.L0_aerodynamics.design_lift_coeff' - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.FCLDES', + # [ # inputs + # '&DEFINE.AERIN.FCLDES', 'OSWALD.FCLDES', + # # outputs + # '~EDET.CLDES', '~CLDESN.CLDES', '~MDESN.CLDES' + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_aerodynamics.design_lift_coeff', + 'aircraft.outputs.L0_aerodynamics.design_lift_coeff', + ], + }, units='unitless', desc='Fixed design lift coefficient. If input, overrides design lift ' - 'coefficient computed by EDET.', + 'coefficient computed by EDET.', default_value=None, ) add_meta_data( Mission.Design.LIFT_COEFFICIENT_MAX_FLAPS_UP, meta_data=_MetaData, - historical_name={"GASP": ['INGASP.CLMWFU', 'INGASP.CLMAX'], - "FLOPS": None, - "LEAPS1": None - }, + historical_name={ + "GASP": ['INGASP.CLMWFU', 'INGASP.CLMAX'], + "FLOPS": None, + "LEAPS1": None, + }, units='unitless', desc='maximum lift coefficient from flaps model when flaps are up ' - '(not deployed)', + '(not deployed)', ) add_meta_data( # NOTE: user override (no scaling) Mission.Design.MACH, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CRMACH', - "FLOPS": 'AERIN.FMDES', - # [ # inputs - # '&DEFINE.AERIN.FMDES', 'OSWALD.FMDES' - # # outputs - # '~EDET.DESM', '~MDESN.DESM' - # ], - "LEAPS1": ['aircraft.inputs.L0_design_variables.design_mach', - 'aircraft.outputs.L0_design_variables.design_mach', - ] - }, + historical_name={ + "GASP": 'INGASP.CRMACH', + "FLOPS": 'AERIN.FMDES', + # [ # inputs + # '&DEFINE.AERIN.FMDES', 'OSWALD.FMDES' + # # outputs + # '~EDET.DESM', '~MDESN.DESM' + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_design_variables.design_mach', + 'aircraft.outputs.L0_design_variables.design_mach', + ], + }, units='unitless', desc='aircraft design Mach number', ) @@ -7065,11 +6838,12 @@ add_meta_data( Mission.Design.RANGE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ARNGE', - # ['&DEFINE.CONFIN.DESRNG', 'CONFIG.DESRNG'], - "FLOPS": 'CONFIN.DESRNG', - "LEAPS1": 'aircraft.inputs.L0_configuration.design_range' - }, + historical_name={ + "GASP": 'INGASP.ARNGE', + # ['&DEFINE.CONFIN.DESRNG', 'CONFIG.DESRNG'], + "FLOPS": 'CONFIN.DESRNG', + "LEAPS1": 'aircraft.inputs.L0_configuration.design_range', + }, units='NM', desc='the aircraft target distance', default_value=0.0, @@ -7078,10 +6852,7 @@ add_meta_data( Mission.Design.RATE_OF_CLIMB_AT_TOP_OF_CLIMB, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ROCTOC', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.ROCTOC', "FLOPS": None, "LEAPS1": None}, option=True, units='ft/min', desc='The required rate of climb at top of climb', @@ -7089,15 +6860,12 @@ ) add_meta_data( - Mission.Design.RESERVE_FUEL, - meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + Mission.Design.RESERVE_FUEL, + meta_data=_MetaData, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="lbm", desc='the total fuel reserves which is the sum of: ' - 'RESERVE_FUEL_BURNED, RESERVE_FUEL_ADDITIONAL, RESERVE_FUEL_FRACTION', + 'RESERVE_FUEL_BURNED, RESERVE_FUEL_ADDITIONAL, RESERVE_FUEL_FRACTION', default_value=0, ) @@ -7105,17 +6873,19 @@ # TODO move to Engine? Mission.Design.THRUST_TAKEOFF_PER_ENG, meta_data=_MetaData, - historical_name={"GASP": None, - # FLOPS may scale the input value as it resizes the engine if requested by - # the user - # ['&DEFINE.AERIN.THROFF', 'LANDG.THROF', 'LANDG.THROFF'], - "FLOPS": 'AERIN.THROFF', - # LEAPS1 uses the average thrust_takeoff of all operational engines - # actually on the airplane, possibly after resizing (as with FLOPS) - "LEAPS1": ['aircraft.inputs.L0_engine.thrust_takeoff', - '(SimpleTakeoff)self.thrust', - ] - }, + historical_name={ + "GASP": None, + # FLOPS may scale the input value as it resizes the engine if requested by + # the user + # ['&DEFINE.AERIN.THROFF', 'LANDG.THROF', 'LANDG.THROFF'], + "FLOPS": 'AERIN.THROFF', + # LEAPS1 uses the average thrust_takeoff of all operational engines + # actually on the airplane, possibly after resizing (as with FLOPS) + "LEAPS1": [ + 'aircraft.inputs.L0_engine.thrust_takeoff', + '(SimpleTakeoff)self.thrust', + ], + }, units='lbf', # need better description of what state. rolling takeoff condition? alt? mach? desc='thrust on the aircraft for takeoff', @@ -7135,10 +6905,7 @@ add_meta_data( Mission.Landing.AIRPORT_ALTITUDE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ALTLND', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.ALTLND', "FLOPS": None, "LEAPS1": None}, units='ft', desc='altitude of airport where aircraft lands', default_value=0, @@ -7147,10 +6914,7 @@ add_meta_data( Mission.Landing.BRAKING_DELAY, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.TDELAY', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.TDELAY', "FLOPS": None, "LEAPS1": None}, units='s', desc='time delay between touchdown and the application of brakes', default_value=1, @@ -7164,17 +6928,16 @@ # 'FLOPS': ['&DEFTOL.TOLIN.BRAKMU', 'BALFLD.BRAKMU'], # 'GASP': None, # 'LEAPS1': 'aircraft.inputs.L0_takeoff_and_landing.braking_mu'}, - historical_name={'FLOPS': None, 'GASP': None, 'LEAPS1': None}, default_value=0.3, + historical_name={'FLOPS': None, 'GASP': None, 'LEAPS1': None}, + default_value=0.3, units='unitless', - desc='landing coefficient of friction, with brakes on') + desc='landing coefficient of friction, with brakes on', +) add_meta_data( Mission.Landing.DRAG_COEFFICIENT_FLAP_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DCD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DCD', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='drag coefficient increment at landing due to flaps', ) @@ -7182,10 +6945,11 @@ add_meta_data( Mission.Landing.DRAG_COEFFICIENT_MIN, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.CDMLD', # ['&DEFINE.AERIN.CDMLD', 'LANDG.CDMLD'], - "LEAPS1": None - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.CDMLD', # ['&DEFINE.AERIN.CDMLD', 'LANDG.CDMLD'], + "LEAPS1": None, + }, units='unitless', desc='Minimum drag coefficient for takeoff. Typically this is CD at zero lift.', default_value=0.0, @@ -7194,21 +6958,19 @@ add_meta_data( Mission.Landing.FIELD_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~ANALYS.FARLDG', - "LEAPS1": '(SimpleLanding)self.landing_distance' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~ANALYS.FARLDG', + "LEAPS1": '(SimpleLanding)self.landing_distance', + }, units='ft', - desc='FAR landing field length' + desc='FAR landing field length', ) add_meta_data( Mission.Landing.FLARE_RATE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'TOLIN.VANGLD', - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": 'TOLIN.VANGLD', "LEAPS1": None}, units="deg/s", desc='flare rate in detailed landing', default_value=2.0, @@ -7217,10 +6979,7 @@ add_meta_data( Mission.Landing.GLIDE_TO_STALL_RATIO, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.VRATT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.VRATT', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='ratio of glide (approach) speed to stall speed', default_value=1.3, @@ -7229,55 +6988,48 @@ add_meta_data( Mission.Landing.GROUND_DISTANCE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DLT', # Is DLT actual landing distance or field length? - "FLOPS": None, - "LEAPS1": None - }, + historical_name={ + "GASP": 'INGASP.DLT', # Is DLT actual landing distance or field length? + "FLOPS": None, + "LEAPS1": None, + }, units='ft', - desc='distance covered over the ground during landing' + desc='distance covered over the ground during landing', ) add_meta_data( Mission.Landing.INITIAL_ALTITUDE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.HIN', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.HIN', "FLOPS": None, "LEAPS1": None}, units='ft', - desc='altitude where landing calculations begin' + desc='altitude where landing calculations begin', ) add_meta_data( Mission.Landing.INITIAL_MACH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", desc='approach mach number', - default_value=0.1 + default_value=0.1, ) add_meta_data( Mission.Landing.INITIAL_VELOCITY, meta_data=_MetaData, - historical_name={"GASP": "INGASP.VGL", - "FLOPS": 'AERIN.VAPPR', - "LEAPS1": '(SimpleLanding)self.vapp' - }, + historical_name={ + "GASP": "INGASP.VGL", + "FLOPS": 'AERIN.VAPPR', + "LEAPS1": '(SimpleLanding)self.vapp', + }, units='ft/s', - desc='approach velocity' + desc='approach velocity', ) add_meta_data( Mission.Landing.LIFT_COEFFICIENT_FLAP_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DCL', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DCL', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='lift coefficient increment at landing due to flaps', ) @@ -7288,10 +7040,11 @@ # CLLDM (this variable) Mission.Landing.LIFT_COEFFICIENT_MAX, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CLMWLD', - "FLOPS": 'AERIN.CLLDM', # ['&DEFINE.AERIN.CLLDM', 'LANDG.CLLDM'], - "LEAPS1": 'aircraft.inputs.L0_takeoff_and_landing.max_landing_lift_coeff' - }, + historical_name={ + "GASP": 'INGASP.CLMWLD', + "FLOPS": 'AERIN.CLLDM', # ['&DEFINE.AERIN.CLLDM', 'LANDG.CLLDM'], + "LEAPS1": 'aircraft.inputs.L0_takeoff_and_landing.max_landing_lift_coeff', + }, units='unitless', desc='maximum lift coefficient for landing', default_value=3.0, @@ -7300,10 +7053,7 @@ add_meta_data( Mission.Landing.MAXIMUM_FLARE_LOAD_FACTOR, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.XLFMX', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.XLFMX', "FLOPS": None, "LEAPS1": None}, units="unitless", desc='maximum load factor during landing flare', default_value=1.15, @@ -7312,10 +7062,7 @@ add_meta_data( Mission.Landing.MAXIMUM_SINK_RATE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.RSMX', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.RSMX', "FLOPS": None, "LEAPS1": None}, units='ft/min', desc='maximum rate of sink during glide', default_value=1000, @@ -7324,10 +7071,7 @@ add_meta_data( Mission.Landing.OBSTACLE_HEIGHT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.HAPP', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.HAPP', "FLOPS": None, "LEAPS1": None}, units='ft', desc='landing obstacle height above the ground at airport altitude', default_value=50, @@ -7346,8 +7090,7 @@ # }, historical_name={'FLOPS': None, 'GASP': None, 'LEAPS1': None}, units='unitless', - desc='coefficient of rolling friction for groundroll ' - 'portion of takeoff', + desc='coefficient of rolling friction for groundroll ' 'portion of takeoff', default_value=0.025, ) @@ -7380,10 +7123,7 @@ add_meta_data( Mission.Landing.STALL_VELOCITY, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.VST', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.VST', "FLOPS": None, "LEAPS1": None}, units='ft/s', desc='stall speed during approach', ) @@ -7391,24 +7131,22 @@ add_meta_data( Mission.Landing.TOUCHDOWN_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # ['~ANALYS.WLDG', '~LNDING.GROSWT'], - "LEAPS1": '(SimpleLanding)self.weight' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # ['~ANALYS.WLDG', '~LNDING.GROSWT'], + "LEAPS1": '(SimpleLanding)self.weight', + }, units='lbm', desc='computed mass of aircraft for landing, is only ' - 'required to be equal to Aircraft.Design.TOUCHDOWN_MASS ' - 'when the design case is being run ' - 'for HEIGHT_ENERGY missions this is the mass at the end of the last regular phase (non-reserve phase)', + 'required to be equal to Aircraft.Design.TOUCHDOWN_MASS ' + 'when the design case is being run ' + 'for HEIGHT_ENERGY missions this is the mass at the end of the last regular phase (non-reserve phase)', ) add_meta_data( Mission.Landing.TOUCHDOWN_SINK_RATE, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.SINKTD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.SINKTD', "FLOPS": None, "LEAPS1": None}, units='ft/s', desc='sink rate at touchdown', default_value=3, @@ -7427,25 +7165,19 @@ add_meta_data( Mission.Objectives.FUEL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='regularized objective that minimizes total fuel mass subject ' - 'to other necessary additions', + 'to other necessary additions', ) add_meta_data( Mission.Objectives.RANGE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='unitless', desc='regularized objective that maximizes range subject to other ' - 'necessary additions', + 'necessary additions', ) # _____ @@ -7461,20 +7193,22 @@ add_meta_data( Mission.Summary.CRUISE_MACH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'CONFIN.VCMN', - # [ # inputs - # '&DEFINE.CONFIN.VCMN', 'PARVAR.DVD(1,8)', - # # outputs - # 'CONFIG.VCMN', 'CONFIG.DVA(8)', '~FLOPS.DVA(8)', '~ANALYS.DVA(8)', - # # other - # 'MISSA.VCMIN', - # ], - "LEAPS1": ['aircraft.inputs.L0_design_variables.cruise_mach', - 'aircraft.outputs.L0_design_variables.cruise_mach', - 'aircraft.outputs.L0_design_variables.mission_cruise_mach', - ] - }, + historical_name={ + "GASP": None, + "FLOPS": 'CONFIN.VCMN', + # [ # inputs + # '&DEFINE.CONFIN.VCMN', 'PARVAR.DVD(1,8)', + # # outputs + # 'CONFIG.VCMN', 'CONFIG.DVA(8)', '~FLOPS.DVA(8)', '~ANALYS.DVA(8)', + # # other + # 'MISSA.VCMIN', + # ], + "LEAPS1": [ + 'aircraft.inputs.L0_design_variables.cruise_mach', + 'aircraft.outputs.L0_design_variables.cruise_mach', + 'aircraft.outputs.L0_design_variables.mission_cruise_mach', + ], + }, units='unitless', desc='aircraft cruise mach number', default_value=0.0, # TODO: required @@ -7483,10 +7217,7 @@ add_meta_data( Mission.Summary.CRUISE_MASS_FINAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='mass of the aircraft at the end of cruise', default_value=0.0, @@ -7495,13 +7226,10 @@ add_meta_data( Mission.Summary.FUEL_BURNED, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='fuel burned during regular phases, this ' - 'does not include fuel burned in reserve phases' + 'does not include fuel burned in reserve phases', ) # NOTE if per-mission level scaling is not best mapping for GASP's 'CKFF', map @@ -7511,65 +7239,54 @@ add_meta_data( Mission.Summary.FUEL_FLOW_SCALER, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CKFF', - "FLOPS": 'MISSIN.FACT', # ['&DEFMSS.MISSIN.FACT', 'TRNSF.FACT'], - "LEAPS1": ['aircraft.inputs.L0_fuel_flow.overall_factor'] - }, + historical_name={ + "GASP": 'INGASP.CKFF', + "FLOPS": 'MISSIN.FACT', # ['&DEFMSS.MISSIN.FACT', 'TRNSF.FACT'], + "LEAPS1": ['aircraft.inputs.L0_fuel_flow.overall_factor'], + }, units='unitless', desc='scale factor on overall fuel flow', default_value=1.0, - option=True + option=True, ) add_meta_data( Mission.Summary.GROSS_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='gross takeoff mass of aircraft for that specific mission, not ' - 'necessarily the value for the aircraft`s design mission' + 'necessarily the value for the aircraft`s design mission', ) add_meta_data( Mission.Summary.RANGE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='NM', desc='actual range that the aircraft flies, whether ' - 'it is a design case or an off design case. Equal ' - 'to Mission.Design.RANGE value in the design case.' + 'it is a design case or an off design case. Equal ' + 'to Mission.Design.RANGE value in the design case.', ) add_meta_data( Mission.Summary.RESERVE_FUEL_BURNED, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', desc='fuel burned during reserve phases, this ' - 'does not include fuel burned in regular phases', - default_value=0., + 'does not include fuel burned in regular phases', + default_value=0.0, ) add_meta_data( Mission.Summary.TOTAL_FUEL_MASS, meta_data=_MetaData, - historical_name={"GASP": "INGASP.WFA", - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": "INGASP.WFA", "FLOPS": None, "LEAPS1": None}, units='lbm', desc='total fuel carried at the beginnning of a mission ' - 'includes fuel burned in the mission, reserve fuel ' - 'and fuel margin', + 'includes fuel burned in the mission, reserve fuel ' + 'and fuel margin', ) @@ -7584,12 +7301,9 @@ add_meta_data( Mission.Takeoff.AIRPORT_ALTITUDE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='ft', - desc='altitude of airport where aircraft takes off' + desc='altitude of airport where aircraft takes off', ) add_meta_data( @@ -7599,19 +7313,18 @@ # ['&DEFTOL.TOLIN.ALPRUN', 'BALFLD.ALPRUN', '~CLGRAD.ALPRUN'], 'FLOPS': 'TOLIN.ALPRUN', 'GASP': None, - 'LEAPS1': 'aircraft.inputs.L0_takeoff_and_landing.alpha_runway'}, + 'LEAPS1': 'aircraft.inputs.L0_takeoff_and_landing.alpha_runway', + }, option=True, - default_value=0., + default_value=0.0, units='deg', - desc='angle of attack on ground') + desc='angle of attack on ground', +) add_meta_data( Mission.Takeoff.ASCENT_DURATION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='s', desc='duration of the ascent phase of takeoff', ) @@ -7619,10 +7332,7 @@ add_meta_data( Mission.Takeoff.ASCENT_T_INTIIAL, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='s', desc='time that the ascent phase of takeoff starts at', default_value=10, @@ -7635,18 +7345,17 @@ historical_name={ 'FLOPS': 'TOLIN.BRAKMU', # ['&DEFTOL.TOLIN.BRAKMU', 'BALFLD.BRAKMU'], 'GASP': None, - 'LEAPS1': 'aircraft.inputs.L0_takeoff_and_landing.braking_mu'}, + 'LEAPS1': 'aircraft.inputs.L0_takeoff_and_landing.braking_mu', + }, default_value=0.3, units='unitless', - desc='takeoff coefficient of friction, with brakes on') + desc='takeoff coefficient of friction, with brakes on', +) add_meta_data( Mission.Takeoff.DECISION_SPEED_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DV1', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DV1', "FLOPS": None, "LEAPS1": None}, units='kn', desc='increment of engine failure decision speed above stall speed', default_value=5, @@ -7655,10 +7364,7 @@ add_meta_data( Mission.Takeoff.DRAG_COEFFICIENT_FLAP_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DCD', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DCD', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='drag coefficient increment at takeoff due to flaps', ) @@ -7666,10 +7372,11 @@ add_meta_data( Mission.Takeoff.DRAG_COEFFICIENT_MIN, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'AERIN.CDMTO', # ['&DEFINE.AERIN.CDMTO', 'LANDG.CDMTO'], - "LEAPS1": None - }, + historical_name={ + "GASP": None, + "FLOPS": 'AERIN.CDMTO', # ['&DEFINE.AERIN.CDMTO', 'LANDG.CDMTO'], + "LEAPS1": None, + }, units='unitless', desc='Minimum drag coefficient for takeoff. Typically this is CD at zero lift.', default_value=0.0, @@ -7678,22 +7385,24 @@ add_meta_data( Mission.Takeoff.FIELD_LENGTH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~ANALYS.FAROFF', - "LEAPS1": '(SimpleTakeoff)self.takeoff_distance' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~ANALYS.FAROFF', + "LEAPS1": '(SimpleTakeoff)self.takeoff_distance', + }, units='ft', - desc='FAR takeoff field length' + desc='FAR takeoff field length', ) add_meta_data( Mission.Takeoff.FINAL_ALTITUDE, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFTOL.TOLIN.OBSTO', 'TOCOMM.OBSTO', 'TOCOMM.DUMC(8)'], - "FLOPS": 'TOLIN.OBSTO', - "LEAPS1": 'aircraft.inputs.L0_takeoff_and_landing.obstacle_height' - }, + historical_name={ + "GASP": None, + # ['&DEFTOL.TOLIN.OBSTO', 'TOCOMM.OBSTO', 'TOCOMM.DUMC(8)'], + "FLOPS": 'TOLIN.OBSTO', + "LEAPS1": 'aircraft.inputs.L0_takeoff_and_landing.obstacle_height', + }, units='ft', desc='altitude of aircraft at the end of takeoff', # Note default value is aircraft type dependent @@ -7705,24 +7414,21 @@ add_meta_data( Mission.Takeoff.FINAL_MACH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None, - }, + historical_name={ + "GASP": None, + "FLOPS": None, + "LEAPS1": None, + }, units='unitless', - desc='Mach number of aircraft after taking off and ' - 'clearing a 35 foot obstacle' + desc='Mach number of aircraft after taking off and ' 'clearing a 35 foot obstacle', ) add_meta_data( Mission.Takeoff.FINAL_MASS, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='lbm', - desc='mass after aircraft has cleared 35 ft obstacle' + desc='mass after aircraft has cleared 35 ft obstacle', ) add_meta_data( @@ -7731,13 +7437,13 @@ # - correct Aviary equations? Mission.Takeoff.FINAL_VELOCITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~TOFF.V2', - "LEAPS1": '(ClimbToObstacle)self.V2' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~TOFF.V2', + "LEAPS1": '(ClimbToObstacle)self.V2', + }, units='m/s', - desc='velocity of aircraft after taking off and ' - 'clearing a 35 foot obstacle' + desc='velocity of aircraft after taking off and ' 'clearing a 35 foot obstacle', ) add_meta_data( @@ -7746,13 +7452,15 @@ # part of takeoff Mission.Takeoff.FUEL_SIMPLE, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFMSS.MISSIN.FTKOFL', 'FFLALL.FTKOFL', '~MISSON.TAKOFL'], - "FLOPS": 'MISSIN.FTKOFL', - "LEAPS1": ['aircraft.inputs.L0_mission.fixed_takeoff_fuel', - 'aircraft.outputs.L0_takeoff_and_landing.takeoff_fuel', - ] - }, + historical_name={ + "GASP": None, + # ['&DEFMSS.MISSIN.FTKOFL', 'FFLALL.FTKOFL', '~MISSON.TAKOFL'], + "FLOPS": 'MISSIN.FTKOFL', + "LEAPS1": [ + 'aircraft.inputs.L0_mission.fixed_takeoff_fuel', + 'aircraft.outputs.L0_takeoff_and_landing.takeoff_fuel', + ], + }, units='lbm', desc='fuel burned during simple takeoff calculation', default_value=None, @@ -7761,21 +7469,15 @@ add_meta_data( Mission.Takeoff.GROUND_DISTANCE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units='ft', - desc='ground distance covered by takeoff with all engines operating' + desc='ground distance covered by takeoff with all engines operating', ) add_meta_data( Mission.Takeoff.LIFT_COEFFICIENT_FLAP_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DCL', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DCL', "FLOPS": None, "LEAPS1": None}, units='unitless', desc='lift coefficient increment at takeoff due to flaps', ) @@ -7783,11 +7485,12 @@ add_meta_data( Mission.Takeoff.LIFT_COEFFICIENT_MAX, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.CLMWTO', - # ['&DEFINE.AERIN.CLTOM', 'LANDG.CLTOM', '~DEFTOL.CLTOA'], - "FLOPS": 'AERIN.CLTOM', - "LEAPS1": 'aircraft.inputs.L0_takeoff_and_landing.max_takeoff_lift_coeff' - }, + historical_name={ + "GASP": 'INGASP.CLMWTO', + # ['&DEFINE.AERIN.CLTOM', 'LANDG.CLTOM', '~DEFTOL.CLTOA'], + "FLOPS": 'AERIN.CLTOM', + "LEAPS1": 'aircraft.inputs.L0_takeoff_and_landing.max_takeoff_lift_coeff', + }, units='unitless', desc='maximum lift coefficient for takeoff', default_value=2.0, @@ -7796,12 +7499,13 @@ add_meta_data( Mission.Takeoff.LIFT_OVER_DRAG, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, # '~ANALYS.CLOD', - "LEAPS1": '(SimpleTakeoff)self.lift_over_drag_ratio' - }, + historical_name={ + "GASP": None, + "FLOPS": None, # '~ANALYS.CLOD', + "LEAPS1": '(SimpleTakeoff)self.lift_over_drag_ratio', + }, units='unitless', - desc='ratio of lift to drag at takeoff' + desc='ratio of lift to drag at takeoff', ) add_meta_data( @@ -7816,36 +7520,34 @@ # Note default value is aircraft type dependent # - transport: 35 ft # assume transport for now - default_value=35., + default_value=35.0, units='ft', - desc='takeoff obstacle height above the ground at airport altitude' + desc='takeoff obstacle height above the ground at airport altitude', ) add_meta_data( Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": None, - # ['&DEFTOL.TOLIN.ROLLMU', 'BALFLD.ROLLMU'], - "FLOPS": 'TOLIN.ROLLMU', - "LEAPS1": ['aircraft.inputs.L0_takeoff_and_landing.rolling_mu', - '(GroundRoll)self.mu', - '(Rotate)self.mu', - '(GroundBrake)self.rolling_mu', - ] - }, + historical_name={ + "GASP": None, + # ['&DEFTOL.TOLIN.ROLLMU', 'BALFLD.ROLLMU'], + "FLOPS": 'TOLIN.ROLLMU', + "LEAPS1": [ + 'aircraft.inputs.L0_takeoff_and_landing.rolling_mu', + '(GroundRoll)self.mu', + '(Rotate)self.mu', + '(GroundBrake)self.rolling_mu', + ], + }, units='unitless', - desc='coefficient of rolling friction for groundroll ' - 'portion of takeoff', + desc='coefficient of rolling friction for groundroll ' 'portion of takeoff', default_value=0.025, ) add_meta_data( Mission.Takeoff.ROTATION_SPEED_INCREMENT, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DVR', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DVR', "FLOPS": None, "LEAPS1": None}, units='kn', desc='increment of takeoff rotation speed above engine failure decision speed', default_value=5, @@ -7854,10 +7556,7 @@ add_meta_data( Mission.Takeoff.ROTATION_VELOCITY, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.VR', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.VR', "FLOPS": None, "LEAPS1": None}, units='kn', desc='rotation velocity', ) @@ -7865,10 +7564,11 @@ add_meta_data( Mission.Takeoff.SPOILER_DRAG_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'TOLIN.CDSPOL', # '&DEFTOL.TOLIN.CDSPOL', - "LEAPS1": None - }, + historical_name={ + "GASP": None, + "FLOPS": 'TOLIN.CDSPOL', # '&DEFTOL.TOLIN.CDSPOL', + "LEAPS1": None, + }, units='unitless', desc='drag coefficient for spoilers during takeoff abort', default_value=0.0, @@ -7877,10 +7577,11 @@ add_meta_data( Mission.Takeoff.SPOILER_LIFT_COEFFICIENT, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": 'TOLIN.CLSPOL', # '&DEFTOL.TOLIN.CLSPOL', - "LEAPS1": None - }, + historical_name={ + "GASP": None, + "FLOPS": 'TOLIN.CLSPOL', # '&DEFTOL.TOLIN.CLSPOL', + "LEAPS1": None, + }, units='unitless', desc='lift coefficient for spoilers during takeoff abort', default_value=0.0, @@ -7892,11 +7593,13 @@ historical_name={ 'FLOPS': 'TOLIN.TINC', # ['&DEFTOL.TOLIN.TINC', 'BALFLD.TINC', '~CLGRAD.TINC'], 'GASP': None, - 'LEAPS1': 'aircraft.inputs.L0_takeoff_and_landing.thrust_incidence_angle'}, + 'LEAPS1': 'aircraft.inputs.L0_takeoff_and_landing.thrust_incidence_angle', + }, option=True, - default_value=0., + default_value=0.0, units='deg', - desc='thrust incidence on ground') + desc='thrust incidence on ground', +) # _______ _ # |__ __| (_) @@ -7909,10 +7612,7 @@ add_meta_data( Mission.Taxi.DURATION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.DELTT', - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": 'INGASP.DELTT', "FLOPS": None, "LEAPS1": None}, units='h', desc='time spent taxiing before takeoff', option=True, @@ -7922,10 +7622,7 @@ add_meta_data( Mission.Taxi.MACH, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, units="unitless", desc='speed during taxi, must be nonzero if pycycle is enabled', option=True, @@ -7947,10 +7644,7 @@ add_meta_data( Settings.EQUATIONS_OF_MOTION, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, desc='Sets which equations of motion Aviary will use in mission analysis', option=True, types=EquationsOfMotion, @@ -7960,45 +7654,41 @@ add_meta_data( Settings.MASS_METHOD, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, desc="Sets which legacy code's methods will be used for mass estimation", option=True, types=LegacyCode, - default_value=None + default_value=None, ) add_meta_data( Settings.PROBLEM_TYPE, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, desc="Select from Aviary's built in problem types: Sizing, Alternate, and Fallout", option=True, types=ProblemType, - default_value=None + default_value=None, ) add_meta_data( Settings.VERBOSITY, meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None}, desc='Sets how much information Aviary outputs when run. Options include:' - '0. QUIET: All output except errors are suppressed' - '1. BRIEF: Only important information is output, in human-readable format' - '2. VERBOSE: All user-relevant information is output, in human-readable format' - '3. DEBUG: Any information can be outtputed, including warnings, intermediate calculations, etc., with no formatting requirement', + '0. QUIET: All output except errors are suppressed' + '1. BRIEF: Only important information is output, in human-readable format' + '2. VERBOSE: All user-relevant information is output, in human-readable format' + '3. DEBUG: Any information can be outtputed, including warnings, intermediate calculations, etc., with no formatting requirement', option=True, types=Verbosity, - default_value=Verbosity.BRIEF + default_value=Verbosity.BRIEF, ) -# here we create a copy of the Aviary-core metadata. The reason for this copy is that if we simply imported the Aviary _MetaData in all the external subsystem extensions, we would be modifying the original and the original _MetaData in the core of Aviary could get altered in undesirable ways. By importing this copy to the API the user modifies a new MetaData designed just for their purposes. +# here we create a copy of the Aviary-core metadata. The reason for this +# copy is that if we simply imported the Aviary _MetaData in all the +# external subsystem extensions, we would be modifying the original and +# the original _MetaData in the core of Aviary could get altered in +# undesirable ways. By importing this copy to the API the user modifies a +# new MetaData designed just for their purposes. CoreMetaData = deepcopy(_MetaData) diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index b3488defb..038a50eb9 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -39,8 +39,9 @@ class BWB: CABIN_AREA = 'aircraft:blended_wing_body_design:cabin_area' NUM_BAYS = 'aircraft:blended_wing_body_design:num_bays' - PASSENGER_LEADING_EDGE_SWEEP = \ + PASSENGER_LEADING_EDGE_SWEEP = ( 'aircraft:blended_wing_body_design:passenger_leading_edge_sweep' + ) class Canard: AREA = 'aircraft:canard:area' @@ -59,48 +60,50 @@ class Canard: class Controls: COCKPIT_CONTROL_MASS_SCALER = 'aircraft:controls:cockpit_control_mass_scaler' CONTROL_MASS_INCREMENT = 'aircraft:controls:control_mass_increment' - STABILITY_AUGMENTATION_SYSTEM_MASS = \ + STABILITY_AUGMENTATION_SYSTEM_MASS = ( 'aircraft:controls:stability_augmentation_system_mass' - STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER = \ + ) + STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER = ( 'aircraft:controls:stability_augmentation_system_mass_scaler' + ) TOTAL_MASS = 'aircraft:controls:total_mass' class CrewPayload: BAGGAGE_MASS = 'aircraft:crew_and_payload:baggage_mass' - BAGGAGE_MASS_PER_PASSENGER = \ + BAGGAGE_MASS_PER_PASSENGER = ( 'aircraft:crew_and_payload:baggage_mass_per_passenger' + ) - CARGO_CONTAINER_MASS = \ - 'aircraft:crew_and_payload:cargo_container_mass' + CARGO_CONTAINER_MASS = 'aircraft:crew_and_payload:cargo_container_mass' - CARGO_CONTAINER_MASS_SCALER = \ + CARGO_CONTAINER_MASS_SCALER = ( 'aircraft:crew_and_payload:cargo_container_mass_scaler' + ) CARGO_MASS = 'aircraft:crew_and_payload:cargo_mass' - CATERING_ITEMS_MASS_PER_PASSENGER = \ + CATERING_ITEMS_MASS_PER_PASSENGER = ( 'aircraft:crew_and_payload:catering_items_mass_per_passenger' + ) FLIGHT_CREW_MASS = 'aircraft:crew_and_payload:flight_crew_mass' - FLIGHT_CREW_MASS_SCALER = \ - 'aircraft:crew_and_payload:flight_crew_mass_scaler' + FLIGHT_CREW_MASS_SCALER = 'aircraft:crew_and_payload:flight_crew_mass_scaler' MASS_PER_PASSENGER = 'aircraft:crew_and_payload:mass_per_passenger' MISC_CARGO = 'aircraft:crew_and_payload:misc_cargo' - NON_FLIGHT_CREW_MASS = \ - 'aircraft:crew_and_payload:non_flight_crew_mass' + NON_FLIGHT_CREW_MASS = 'aircraft:crew_and_payload:non_flight_crew_mass' - NON_FLIGHT_CREW_MASS_SCALER = \ + NON_FLIGHT_CREW_MASS_SCALER = ( 'aircraft:crew_and_payload:non_flight_crew_mass_scaler' + ) NUM_BUSINESS_CLASS = 'aircraft:crew_and_payload:num_business_class' NUM_FIRST_CLASS = 'aircraft:crew_and_payload:num_first_class' - NUM_FLIGHT_ATTENDANTS = \ - 'aircraft:crew_and_payload:num_flight_attendants' + NUM_FLIGHT_ATTENDANTS = 'aircraft:crew_and_payload:num_flight_attendants' NUM_FLIGHT_CREW = 'aircraft:crew_and_payload:num_flight_crew' NUM_GALLEY_CREW = 'aircraft:crew_and_payload:num_galley_crew' @@ -108,26 +111,31 @@ class CrewPayload: NUM_PASSENGERS = 'aircraft:crew_and_payload:num_passengers' NUM_TOURIST_CLASS = 'aircraft:crew_and_payload:num_tourist_class' - PASSENGER_MASS = \ - 'aircraft:crew_and_payload:passenger_mass' - PASSENGER_MASS_WITH_BAGS = \ - 'aircraft:crew_and_payload:passenger_mass_with_bags' + PASSENGER_MASS = 'aircraft:crew_and_payload:passenger_mass' + PASSENGER_MASS_WITH_BAGS = 'aircraft:crew_and_payload:passenger_mass_with_bags' PASSENGER_PAYLOAD_MASS = 'aircraft:crew_and_payload:passenger_payload_mass' - PASSENGER_SERVICE_MASS = \ - 'aircraft:crew_and_payload:passenger_service_mass' + PASSENGER_SERVICE_MASS = 'aircraft:crew_and_payload:passenger_service_mass' - PASSENGER_SERVICE_MASS_PER_PASSENGER = \ + PASSENGER_SERVICE_MASS_PER_PASSENGER = ( 'aircraft:crew_and_payload:passenger_service_mass_per_passenger' + ) - PASSENGER_SERVICE_MASS_SCALER = \ + PASSENGER_SERVICE_MASS_SCALER = ( 'aircraft:crew_and_payload:passenger_service_mass_scaler' + ) TOTAL_PAYLOAD_MASS = 'aircraft:crew_and_payload:total_payload_mass' WATER_MASS_PER_OCCUPANT = 'aircraft:crew_and_payload:water_mass_per_occupant' WING_CARGO = 'aircraft:crew_and_payload:wing_cargo' + class Design: + NUM_BUSINESS_CLASS = 'aircraft:crew_and_payload:design:num_business_class' + NUM_FIRST_CLASS = 'aircraft:crew_and_payload:design:num_first_class' + NUM_TOURIST_CLASS = 'aircraft:crew_and_payload:design:num_tourist_class' + NUM_PASSENGERS = 'aircraft:crew_and_payload:design:num_passengers' + class Design: # These variables are values that do not fall into a particular aircraft # component. @@ -135,8 +143,9 @@ class Design: BASE_AREA = 'aircraft:design:base_area' CG_DELTA = 'aircraft:design:cg_delta' CHARACTERISTIC_LENGTHS = 'aircraft:design:characteristic_lengths' - COCKPIT_CONTROL_MASS_COEFFICIENT = \ + COCKPIT_CONTROL_MASS_COEFFICIENT = ( 'aircraft:design:cockpit_control_mass_coefficient' + ) COMPUTE_HTAIL_VOLUME_COEFF = 'aircraft:design:compute_htail_volume_coeff' COMPUTE_VTAIL_VOLUME_COEFF = 'aircraft:design:compute_vtail_volume_coeff' DRAG_COEFFICIENT_INCREMENT = 'aircraft:design:drag_increment' @@ -146,8 +155,7 @@ class Design: EMPTY_MASS = 'aircraft:design:empty_mass' EMPTY_MASS_MARGIN = 'aircraft:design:empty_mass_margin' - EMPTY_MASS_MARGIN_SCALER = \ - 'aircraft:design:empty_mass_margin_scaler' + EMPTY_MASS_MARGIN_SCALER = 'aircraft:design:empty_mass_margin_scaler' EXTERNAL_SUBSYSTEMS_MASS = 'aircraft:design:external_subsystems_mass' FINENESS = 'aircraft:design:fineness' @@ -157,12 +165,12 @@ class Design: LAMINAR_FLOW_LOWER = 'aircraft:design:laminar_flow_lower' LAMINAR_FLOW_UPPER = 'aircraft:design:laminar_flow_upper' - LANDING_TO_TAKEOFF_MASS_RATIO = \ - 'aircraft:design:landing_to_takeoff_mass_ratio' + LANDING_TO_TAKEOFF_MASS_RATIO = 'aircraft:design:landing_to_takeoff_mass_ratio' LIFT_CURVE_SLOPE = 'aircraft:design:lift_curve_slope' - LIFT_DEPENDENT_DRAG_COEFF_FACTOR = \ + LIFT_DEPENDENT_DRAG_COEFF_FACTOR = ( 'aircraft:design:lift_dependent_drag_coeff_factor' + ) LIFT_DEPENDENT_DRAG_POLAR = 'aircraft:design:lift_dependent_drag_polar' LIFT_INDEPENDENT_DRAG_POLAR = 'aircraft:design:lift_independent_drag_polar' @@ -180,13 +188,11 @@ class Design: STRUCTURAL_MASS_INCREMENT = 'aircraft:design:structural_mass_increment' STRUCTURE_MASS = 'aircraft:design:structure_mass' - SUBSONIC_DRAG_COEFF_FACTOR = \ - 'aircraft:design:subsonic_drag_coeff_factor' + SUBSONIC_DRAG_COEFF_FACTOR = 'aircraft:design:subsonic_drag_coeff_factor' SUPERCRITICAL_DIVERGENCE_SHIFT = 'aircraft:design:supercritical_drag_shift' - SUPERSONIC_DRAG_COEFF_FACTOR = \ - 'aircraft:design:supersonic_drag_coeff_factor' + SUPERSONIC_DRAG_COEFF_FACTOR = 'aircraft:design:supersonic_drag_coeff_factor' SYSTEMS_EQUIP_MASS = 'aircraft:design:systems_equip_mass' SYSTEMS_EQUIP_MASS_BASE = 'aircraft:design:systems_equip_mass_base' @@ -197,8 +203,7 @@ class Design: USE_ALT_MASS = 'aircraft:design:use_alt_mass' WETTED_AREAS = 'aircraft:design:wetted_areas' ZERO_FUEL_MASS = 'aircraft:design:zero_fuel_mass' - ZERO_LIFT_DRAG_COEFF_FACTOR = \ - 'aircraft:design:zero_lift_drag_coeff_factor' + ZERO_LIFT_DRAG_COEFF_FACTOR = 'aircraft:design:zero_lift_drag_coeff_factor' class Electrical: HAS_HYBRID_SYSTEM = 'aircraft:electrical:has_hybrid_system' @@ -209,18 +214,21 @@ class Electrical: class Engine: ADDITIONAL_MASS = 'aircraft:engine:additional_mass' ADDITIONAL_MASS_FRACTION = 'aircraft:engine:additional_mass_fraction' - COMPUTE_PROPELLER_INSTALLATION_LOSS = \ - 'aircraft:engine:compute_propeller_installation_loss' CONSTANT_FUEL_CONSUMPTION = 'aircraft:engine:constant_fuel_consumption' CONTROLS_MASS = 'aircraft:engine:controls_mass' DATA_FILE = 'aircraft:engine:data_file' + FIXED_RPM = 'aircraft:engine:fixed_rpm' FLIGHT_IDLE_MAX_FRACTION = 'aircraft:engine:flight_idle_max_fraction' FLIGHT_IDLE_MIN_FRACTION = 'aircraft:engine:flight_idle_min_fraction' FLIGHT_IDLE_THRUST_FRACTION = 'aircraft:engine:flight_idle_thrust_fraction' - FUEL_FLOW_SCALER_CONSTANT_TERM = 'aircraft:engine:fuel_flow_scaler_constant_term' + FUEL_FLOW_SCALER_CONSTANT_TERM = ( + 'aircraft:engine:fuel_flow_scaler_constant_term' + ) FUEL_FLOW_SCALER_LINEAR_TERM = 'aircraft:engine:fuel_flow_scaler_linear_term' GENERATE_FLIGHT_IDLE = 'aircraft:engine:generate_flight_idle' GEOPOTENTIAL_ALT = 'aircraft:engine:geopotential_alt' + GLOBAL_HYBRID_THROTTLE = 'aircraft:engine:global_hybrid_throttle' + GLOBAL_THROTTLE = 'aircraft:engine:global_throttle' HAS_PROPELLERS = 'aircraft:engine:has_propellers' IGNORE_NEGATIVE_THRUST = 'aircraft:engine:ignore_negative_thrust' INTERPOLATION_METHOD = 'aircraft:engine:interpolation_method' @@ -229,18 +237,10 @@ class Engine: MASS_SPECIFIC = 'aircraft:engine:mass_specific' NUM_ENGINES = 'aircraft:engine:num_engines' NUM_FUSELAGE_ENGINES = 'aircraft:engine:num_fuselage_engines' - NUM_PROPELLER_BLADES = 'aircraft:engine:num_propeller_blades' NUM_WING_ENGINES = 'aircraft:engine:num_wing_engines' POD_MASS = 'aircraft:engine:pod_mass' POD_MASS_SCALER = 'aircraft:engine:pod_mass_scaler' POSITION_FACTOR = 'aircraft:engine:position_factor' - PROPELLER_ACTIVITY_FACTOR = 'aircraft:engine:propeller_activity_factor' - PROPELLER_DATA_FILE = 'aircraft:engine:propeller_data_file' - PROPELLER_DIAMETER = 'aircraft:engine:propeller_diameter' - PROPELLER_INTEGRATED_LIFT_COEFFICIENT = \ - 'aircraft:engine:propeller_integrated_lift_coefficient' - PROPELLER_TIP_MACH_MAX = 'propeller_tip_mach_max' - PROPELLER_TIP_SPEED_MAX = 'aircraft:engine:propeller_tip_speed_max' PYLON_FACTOR = 'aircraft:engine:pylon_factor' REFERENCE_DIAMETER = 'aircraft:engine:reference_diameter' REFERENCE_MASS = 'aircraft:engine:reference_mass' @@ -256,20 +256,33 @@ class Engine: THRUST_REVERSERS_MASS = 'aircraft:engine:thrust_reversers_mass' THRUST_REVERSERS_MASS_SCALER = 'aircraft:engine:thrust_reversers_mass_scaler' TYPE = 'aircraft:engine:type' - USE_PROPELLER_MAP = 'aircraft:engine:use_propeller_map' WING_LOCATIONS = 'aircraft:engine:wing_locations' class Gearbox: - EFFICIENCY = "aircraft:engine:gearbox:efficiency" - GEAR_RATIO = "aircraft:engine:gearbox:gear_ratio" - MASS = "aircraft:engine:gearbox:mass" - SHAFT_POWER_DESIGN = 'aircraft:engine:shaft_power_design' + EFFICIENCY = 'aircraft:engine:gearbox:efficiency' + GEAR_RATIO = 'aircraft:engine:gearbox:gear_ratio' + MASS = 'aircraft:engine:gearbox:mass' + SHAFT_POWER_DESIGN = 'aircraft:engine:gearbox:shaft_power_design' SPECIFIC_TORQUE = "aircraft:engine:gearbox:specific_torque" class Motor: MASS = 'aircraft:engine:motor:mass' TORQUE_MAX = 'aircraft:engine:motor:torque_max' + class Propeller: + ACTIVITY_FACTOR = 'aircraft:engine:propeller:activity_factor' + COMPUTE_INSTALLATION_LOSS = ( + 'aircraft:engine:propeller:compute_installation_loss' + ) + DATA_FILE = 'aircraft:engine:propeller:data_file' + DIAMETER = 'aircraft:engine:propeller:diameter' + INTEGRATED_LIFT_COEFFICIENT = ( + 'aircraft:engine:propeller:integrated_lift_coefficient' + ) + NUM_BLADES = 'aircraft:engine:propeller:num_blades' + TIP_MACH_MAX = 'aircraft:engine:propeller:tip_mach_max' + TIP_SPEED_MAX = 'aircraft:engine:propeller:tip_speed_max' + class Fins: AREA = 'aircraft:fins:area' MASS = 'aircraft:fins:mass' @@ -335,8 +348,7 @@ class Fuselage: NUM_FUSELAGES = 'aircraft:fuselage:num_fuselages' NUM_SEATS_ABREAST = 'aircraft:fuselage:num_seats_abreast' - PASSENGER_COMPARTMENT_LENGTH = \ - 'aircraft:fuselage:passenger_compartment_length' + PASSENGER_COMPARTMENT_LENGTH = 'aircraft:fuselage:passenger_compartment_length' PILOT_COMPARTMENT_LENGTH = 'aircraft:fuselage:pilot_compartment_length' PLANFORM_AREA = 'aircraft:fuselage:planform_area' @@ -352,8 +364,7 @@ class HorizontalTail: ASPECT_RATIO = 'aircraft:horizontal_tail:aspect_ratio' AVERAGE_CHORD = 'aircraft:horizontal_tail:average_chord' - CHARACTERISTIC_LENGTH = \ - 'aircraft:horizontal_tail:characteristic_length' + CHARACTERISTIC_LENGTH = 'aircraft:horizontal_tail:characteristic_length' FINENESS = 'aircraft:horizontal_tail:fineness' FORM_FACTOR = 'aircraft:horizontal_tail:form_factor' @@ -370,16 +381,16 @@ class HorizontalTail: TAPER_RATIO = 'aircraft:horizontal_tail:taper_ratio' THICKNESS_TO_CHORD = 'aircraft:horizontal_tail:thickness_to_chord' - VERTICAL_TAIL_FRACTION = \ - 'aircraft:horizontal_tail:vertical_tail_fraction' + VERTICAL_TAIL_FRACTION = 'aircraft:horizontal_tail:vertical_tail_fraction' VOLUME_COEFFICIENT = 'aircraft:horizontal_tail:volume_coefficient' WETTED_AREA = 'aircraft:horizontal_tail:wetted_area' WETTED_AREA_SCALER = 'aircraft:horizontal_tail:wetted_area_scaler' class Hydraulics: - FLIGHT_CONTROL_MASS_COEFFICIENT = \ + FLIGHT_CONTROL_MASS_COEFFICIENT = ( 'aircraft:hydraulics:flight_control_mass_coefficient' + ) GEAR_MASS_COEFFICIENT = 'aircraft:hydraulics:gear_mass_coefficient' MASS = 'aircraft:hydraulics:mass' MASS_SCALER = 'aircraft:hydraulics:mass_scaler' @@ -397,15 +408,13 @@ class LandingGear: MAIN_GEAR_LOCATION = 'aircraft:landing_gear:main_gear_location' MAIN_GEAR_MASS = 'aircraft:landing_gear:main_gear_mass' MAIN_GEAR_MASS_COEFFICIENT = 'aircraft:landing_gear:main_gear_mass_coefficient' - MAIN_GEAR_MASS_SCALER = \ - 'aircraft:landing_gear:main_gear_mass_scaler' + MAIN_GEAR_MASS_SCALER = 'aircraft:landing_gear:main_gear_mass_scaler' MAIN_GEAR_OLEO_LENGTH = 'aircraft:landing_gear:main_gear_oleo_length' MASS_COEFFICIENT = 'aircraft:landing_gear:mass_coefficient' NOSE_GEAR_MASS = 'aircraft:landing_gear:nose_gear_mass' - NOSE_GEAR_MASS_SCALER = \ - 'aircraft:landing_gear:nose_gear_mass_scaler' + NOSE_GEAR_MASS_SCALER = 'aircraft:landing_gear:nose_gear_mass_scaler' NOSE_GEAR_OLEO_LENGTH = 'aircraft:landing_gear:nose_gear_oleo_length' TAIL_HOOK_MASS_SCALER = 'aircraft:landing_gear:tail_hook_mass_scaler' @@ -435,8 +444,7 @@ class Paint: MASS_PER_UNIT_AREA = 'aircraft:paint:mass_per_unit_area' class Propulsion: - ENGINE_OIL_MASS_SCALER = \ - 'aircraft:propulsion:engine_oil_mass_scaler' + ENGINE_OIL_MASS_SCALER = 'aircraft:propulsion:engine_oil_mass_scaler' MASS = 'aircraft:propulsion:mass' MISC_MASS_SCALER = 'aircraft:propulsion:misc_mass_scaler' @@ -452,15 +460,15 @@ class Propulsion: TOTAL_SCALED_SLS_THRUST = 'aircraft:propulsion:total_scaled_sls_thrust' TOTAL_STARTER_MASS = 'aircraft:propulsion:total_starter_mass' - TOTAL_THRUST_REVERSERS_MASS = \ - 'aircraft:propulsion:total_thrust_reversers_mass' + TOTAL_THRUST_REVERSERS_MASS = 'aircraft:propulsion:total_thrust_reversers_mass' class Strut: AREA = 'aircraft:strut:area' AREA_RATIO = 'aircraft:strut:area_ratio' ATTACHMENT_LOCATION = 'aircraft:strut:attachment_location' - ATTACHMENT_LOCATION_DIMENSIONLESS = \ + ATTACHMENT_LOCATION_DIMENSIONLESS = ( 'aircraft:strut:attachment_location_dimensionless' + ) CHORD = 'aircraft:strut:chord' DIMENSIONAL_LOCATION_SPECIFIED = 'aircraft:strut:dimensional_location_specified' FUSELAGE_INTERFERENCE_FACTOR = 'aircraft:strut:fuselage_interference_factor' @@ -497,19 +505,18 @@ class VerticalTail: WETTED_AREA_SCALER = 'aircraft:vertical_tail:wetted_area_scaler' class Wing: - AEROELASTIC_TAILORING_FACTOR = \ - 'aircraft:wing:aeroelastic_tailoring_factor' + AEROELASTIC_TAILORING_FACTOR = 'aircraft:wing:aeroelastic_tailoring_factor' AIRFOIL_TECHNOLOGY = 'aircraft:wing:airfoil_technology' AREA = 'aircraft:wing:area' ASPECT_RATIO = 'aircraft:wing:aspect_ratio' ASPECT_RATIO_REF = 'aircraft:wing:aspect_ratio_reference' AVERAGE_CHORD = 'aircraft:wing:average_chord' - BENDING_FACTOR = 'aircraft:wing:bending_factor' - BENDING_MASS = 'aircraft:wing:bending_mass' + BENDING_MATERIAL_FACTOR = 'aircraft:wing:bending_material_factor' + BENDING_MATERIAL_MASS = 'aircraft:wing:bending_material_mass' # Not defined in metadata! # BENDING_MASS_NO_INERTIA = 'aircraft:wing:bending_mass_no_inertia' - BENDING_MASS_SCALER = 'aircraft:wing:bending_mass_scaler' + BENDING_MATERIAL_MASS_SCALER = 'aircraft:wing:bending_material_mass_scaler' BWB_AFTBODY_MASS = 'aircraft:wing:bwb_aft_body_mass' BWB_AFTBODY_MASS_SCALER = 'aircraft:wing:bwb_aft_body_mass_scaler' CENTER_CHORD = 'aircraft:wing:center_chord' @@ -531,8 +538,9 @@ class Wing: FLAP_LIFT_INCREMENT_OPTIMUM = 'aircraft:wing:flap_lift_increment_optimum' FLAP_SPAN_RATIO = 'aircraft:wing:flap_span_ratio' FLAP_TYPE = 'aircraft:wing:flap_type' - FOLD_DIMENSIONAL_LOCATION_SPECIFIED = \ + FOLD_DIMENSIONAL_LOCATION_SPECIFIED = ( 'aircraft:wing:fold_dimensional_location_specified' + ) FOLD_MASS = 'aircraft:wing:fold_mass' FOLD_MASS_COEFFICIENT = 'aircraft:wing:fold_mass_coefficient' FOLDED_SPAN = 'aircraft:wing:folded_span' @@ -576,8 +584,7 @@ class Wing: ROOT_CHORD = 'aircraft:wing:root_chord' SHEAR_CONTROL_MASS = 'aircraft:wing:shear_control_mass' - SHEAR_CONTROL_MASS_SCALER = \ - 'aircraft:wing:shear_control_mass_scaler' + SHEAR_CONTROL_MASS_SCALER = 'aircraft:wing:shear_control_mass_scaler' SLAT_CHORD_RATIO = 'aircraft:wing:slat_chord_ratio' SLAT_LIFT_INCREMENT_OPTIMUM = 'aircraft:wing:slat_lift_increment_optimum' @@ -589,8 +596,7 @@ class Wing: SURFACE_CONTROL_MASS = 'aircraft:wing:surface_ctrl_mass' SURFACE_CONTROL_MASS_COEFFICIENT = 'aircraft:wing:surface_ctrl_mass_coefficient' - SURFACE_CONTROL_MASS_SCALER = \ - 'aircraft:wing:surface_ctrl_mass_scaler' + SURFACE_CONTROL_MASS_SCALER = 'aircraft:wing:surface_ctrl_mass_scaler' SWEEP = 'aircraft:wing:sweep' TAPER_RATIO = 'aircraft:wing:taper_ratio' @@ -608,76 +614,89 @@ class Wing: class Dynamic: - """Dynamic mission data hierarchy""" + """All time-dependent variables used during mission analysis""" + + class Atmosphere: + """Atmospheric and freestream conditions""" + + DENSITY = 'density' + DYNAMIC_PRESSURE = 'dynamic_pressure' + KINEMATIC_VISCOSITY = 'kinematic_viscosity' + MACH = 'mach' + MACH_RATE = 'mach_rate' + SPEED_OF_SOUND = 'speed_of_sound' + STATIC_PRESSURE = 'static_pressure' + TEMPERATURE = 'temperature' class Mission: - # all time-dependent variables used during mission analysis + """ + Kinematic description of vehicle states in a ground-fixed axis. + These values are typically used by the Equations of Motion to determine + vehicle states at other timesteps. + """ + + # TODO Vehicle summary forces, torques, etc. in X,Y,Z axes should also go here ALTITUDE = 'altitude' ALTITUDE_RATE = 'altitude_rate' ALTITUDE_RATE_MAX = 'altitude_rate_max' - BATTERY_STATE_OF_CHARGE = 'battery_state_of_charge' - CUMULATIVE_ELECTRIC_ENERGY_USED = 'cumulative_electric_energy_used' - DENSITY = 'density' + # TODO Angle of Attack DISTANCE = 'distance' DISTANCE_RATE = 'distance_rate' - DRAG = 'drag' - DYNAMIC_PRESSURE = 'dynamic_pressure' - ELECTRIC_POWER_IN = 'electric_power_in' - ELECTRIC_POWER_IN_TOTAL = 'electric_power_in_total' - # EXIT_AREA = 'exit_area' FLIGHT_PATH_ANGLE = 'flight_path_angle' FLIGHT_PATH_ANGLE_RATE = 'flight_path_angle_rate' - FUEL_FLOW_RATE = 'fuel_flow_rate' - FUEL_FLOW_RATE_NEGATIVE = 'fuel_flow_rate_negative' - FUEL_FLOW_RATE_NEGATIVE_TOTAL = 'fuel_flow_rate_negative_total' - FUEL_FLOW_RATE_TOTAL = 'fuel_flow_rate_total' - HYBRID_THROTTLE = 'hybrid_throttle' - KINEMATIC_VISCOSITY = 'kinematic_viscosity' - LIFT = 'lift' - MACH = 'mach' - MACH_RATE = 'mach_rate' - MASS = 'mass' - MASS_RATE = 'mass_rate' - NOX_RATE = 'nox_rate' - NOX_RATE_TOTAL = 'nox_rate_total' - # PERCENT_ROTOR_RPM_CORRECTED = 'percent_rotor_rpm_corrected' - PROPELLER_TIP_SPEED = 'propeller_tip_speed' - RPM = 'rotations_per_minute' - RPM_GEARBOX = 'rotations_per_minute_gearbox' - SHAFT_POWER = 'shaft_power' - SHAFT_POWER_GEARBOX = 'shaft_power_gearbox' - SHAFT_POWER_MAX = 'shaft_power_max' - SHAFT_POWER_MAX_GEARBOX = 'shaft_power_max_gearbox' SPECIFIC_ENERGY = 'specific_energy' SPECIFIC_ENERGY_RATE = 'specific_energy_rate' SPECIFIC_ENERGY_RATE_EXCESS = 'specific_energy_rate_excess' - SPEED_OF_SOUND = 'speed_of_sound' - STATIC_PRESSURE = 'static_pressure' - TEMPERATURE = 'temperature' - TEMPERATURE_T4 = 't4' - THROTTLE = 'throttle' - THRUST = 'thrust_net' - THRUST_MAX = 'thrust_net_max' - THRUST_MAX_TOTAL = 'thrust_net_max_total' - THRUST_TOTAL = 'thrust_net_total' - TORQUE = 'torque' - TORQUE_GEARBOX = 'torque_gearbox' - TORQUE_MAX = 'torque_max' VELOCITY = 'velocity' VELOCITY_RATE = 'velocity_rate' + class Vehicle: + """Vehicle properties and states in a vehicle-fixed reference frame.""" + + BATTERY_STATE_OF_CHARGE = 'battery_state_of_charge' + CUMULATIVE_ELECTRIC_ENERGY_USED = 'cumulative_electric_energy_used' + DRAG = 'drag' + LIFT = 'lift' + MASS = 'mass' + MASS_RATE = 'mass_rate' + + class Propulsion: + # variables specific to the propulsion subsystem + ELECTRIC_POWER_IN = 'electric_power_in' + ELECTRIC_POWER_IN_TOTAL = 'electric_power_in_total' + # EXIT_AREA = 'exit_area' + FUEL_FLOW_RATE = 'fuel_flow_rate' + FUEL_FLOW_RATE_NEGATIVE = 'fuel_flow_rate_negative' + FUEL_FLOW_RATE_NEGATIVE_TOTAL = 'fuel_flow_rate_negative_total' + FUEL_FLOW_RATE_TOTAL = 'fuel_flow_rate_total' + HYBRID_THROTTLE = 'hybrid_throttle' + NOX_RATE = 'nox_rate' + NOX_RATE_TOTAL = 'nox_rate_total' + PROPELLER_TIP_SPEED = 'propeller_tip_speed' + RPM = 'rotations_per_minute' + SHAFT_POWER = 'shaft_power' + SHAFT_POWER_MAX = 'shaft_power_max' + TEMPERATURE_T4 = 't4' + THROTTLE = 'throttle' + THRUST = 'thrust_net' + THRUST_MAX = 'thrust_net_max' + THRUST_MAX_TOTAL = 'thrust_net_max_total' + THRUST_TOTAL = 'thrust_net_total' + TORQUE = 'torque' + TORQUE_MAX = 'torque_max' + class Mission: - """mission data hierarchy""" + """Mission data hierarchy""" class Constraints: # these can be residuals (for equality constraints), # upper bounds, or lower bounds + GEARBOX_SHAFT_POWER_RESIDUAL = 'mission:constraints:gearbox_shaft_power_residual' MASS_RESIDUAL = 'mission:constraints:mass_residual' MAX_MACH = 'mission:constraints:max_mach' RANGE_RESIDUAL = 'mission:constraints:range_residual' RANGE_RESIDUAL_RESERVE = 'mission:constraints:range_residual_reserve' - SHAFT_POWER_RESIDUAL = 'shaft_power_residual' class Design: # These values MAY change in design mission, but in off-design @@ -703,8 +722,9 @@ class Landing: BRAKING_DELAY = 'mission:landing:braking_delay' BRAKING_FRICTION_COEFFICIENT = 'mission:landing:braking_friction_coefficient' - DRAG_COEFFICIENT_FLAP_INCREMENT = \ + DRAG_COEFFICIENT_FLAP_INCREMENT = ( 'mission:landing:drag_coefficient_flap_increment' + ) DRAG_COEFFICIENT_MIN = 'mission:landing:drag_coefficient_min' FIELD_LENGTH = 'mission:landing:field_length' @@ -715,8 +735,9 @@ class Landing: INITIAL_MACH = 'mission:landing:initial_mach' INITIAL_VELOCITY = 'mission:landing:initial_velocity' - LIFT_COEFFICIENT_FLAP_INCREMENT = \ + LIFT_COEFFICIENT_FLAP_INCREMENT = ( 'mission:landing:lift_coefficient_flap_increment' + ) LIFT_COEFFICIENT_MAX = 'mission:landing:lift_coefficient_max' MAXIMUM_FLARE_LOAD_FACTOR = 'mission:landing:maximum_flare_load_factor' @@ -759,8 +780,9 @@ class Takeoff: BRAKING_FRICTION_COEFFICIENT = 'mission:takeoff:braking_friction_coefficient' DECISION_SPEED_INCREMENT = 'mission:takeoff:decision_speed_increment' - DRAG_COEFFICIENT_FLAP_INCREMENT = \ + DRAG_COEFFICIENT_FLAP_INCREMENT = ( 'mission:takeoff:drag_coefficient_flap_increment' + ) DRAG_COEFFICIENT_MIN = 'mission:takeoff:drag_coefficient_min' FIELD_LENGTH = 'mission:takeoff:field_length' @@ -771,8 +793,9 @@ class Takeoff: FUEL_SIMPLE = 'mission:takeoff:fuel_simple' GROUND_DISTANCE = 'mission:takeoff:ground_distance' - LIFT_COEFFICIENT_FLAP_INCREMENT = \ + LIFT_COEFFICIENT_FLAP_INCREMENT = ( 'mission:takeoff:lift_coefficient_flap_increment' + ) LIFT_COEFFICIENT_MAX = 'mission:takeoff:lift_coefficient_max' LIFT_OVER_DRAG = 'mission:takeoff:lift_over_drag' @@ -791,6 +814,7 @@ class Taxi: class Settings: """Setting data hierarchy""" + EQUATIONS_OF_MOTION = 'settings:equations_of_motion' MASS_METHOD = 'settings:mass_method' PROBLEM_TYPE = 'settings:problem_type' diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index bf68c8362..15c208bed 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -5,6 +5,7 @@ import json import os import pathlib +from pathlib import Path import re import shutil import warnings @@ -12,22 +13,21 @@ import numpy as np -import bokeh.palettes as bp -from bokeh.models import Legend, CheckboxGroup, CustomJS +import pandas as pd + +from bokeh.models import Legend, LegendItem, CheckboxGroup, CustomJS, TextInput, ColumnDataSource, CustomJS, Div, Range1d, LinearAxis, PrintfTickFormatter from bokeh.plotting import figure -from bokeh.models import ColumnDataSource +from bokeh.layouts import column +from bokeh.palettes import Category10, Category20, d3 -import hvplot.pandas # noqa # need this ! Otherwise hvplot using DataFrames does not work -import pandas as pd import panel as pn -from panel.theme import DefaultTheme import openmdao.api as om from openmdao.utils.general_utils import env_truthy from openmdao.utils.units import conversion_to_base_units try: from openmdao.utils.gui_testing_utils import get_free_port -except: +except BaseException: # If get_free_port is unavailable, the default port will be used def get_free_port(): return 5000 @@ -43,8 +43,8 @@ def get_free_port(): from openmdao.utils.array_utils import convert_ndarray_to_support_nans_in_json except ImportError: from openmdao.visualization.n2_viewer.n2_viewer import ( - _convert_ndarray_to_support_nans_in_json as convert_ndarray_to_support_nans_in_json, - ) + _convert_ndarray_to_support_nans_in_json + as convert_ndarray_to_support_nans_in_json,) import aviary.api as av @@ -135,17 +135,19 @@ 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( + "--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( + "--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): @@ -175,15 +177,18 @@ def _dashboard_cmd(options, user_args): # if yes, then unzip into reports directory and run dashboard on it if zipfile.is_zipfile(options.script_name): report_dir_name = Path(options.script_name).stem - report_dir_path = Path("reports") / report_dir_name + report_dir_path = Path(f"{report_dir_name}_out") # need to check to see if that directory already exists if not options.force and report_dir_path.is_dir(): raise RuntimeError( - f"The reports directory {report_dir_name} already exists. If you wish to overrite the existing directory, use the --force option") - if report_dir_path.is_dir(): # need to delete it. The unpacking will just add to what is there, not do a clean unpack + f"The reports directory {report_dir_path} already exists. If you wish " + "to overrite the existing directory, use the --force option" + ) + if report_dir_path.is_dir( + ): # need to delete it. The unpacking will just add to what is there, not do a clean unpack shutil.rmtree(report_dir_path) - shutil.unpack_archive(options.script_name, f"reports/{report_dir_name}") + shutil.unpack_archive(options.script_name, report_dir_path) dashboard( report_dir_name, options.problem_recorder, @@ -200,7 +205,7 @@ def _dashboard_cmd(options, user_args): else: save_filename_stem = Path(options.save).stem print(f"Saving to {save_filename_stem}.zip") - shutil.make_archive(save_filename_stem, "zip", f"reports/{options.script_name}") + shutil.make_archive(save_filename_stem, "zip", f"{options.script_name}_out") return dashboard( @@ -212,7 +217,7 @@ def _dashboard_cmd(options, user_args): ) -def create_table_pane_from_json(json_filepath): +def create_table_pane_from_json(json_filepath, documentation): """ Create a Tabulator Pane with Name and Value columns using tabular data from a JSON file. @@ -242,10 +247,20 @@ def create_table_pane_from_json(json_filepath): 'Name': '', 'Value': '', }) + table_pane_with_doc = pn.Column( + pn.pane.HTML(f"

{documentation}

", + styles={'text-align': documentation_text_align}), + table_pane + ) except Exception as err: - warnings.warn(f"Unable to generate table due to: {err}.") - table_pane = None - return table_pane + table_pane_with_doc = pn.Column( + pn.pane.HTML(f"

{documentation}

", + styles={'text-align': documentation_text_align}), + pn.pane.Markdown( + f"# Table not shown because data source JSON file, '{json_filepath}', not found.") + ) + + return table_pane_with_doc # functions for creating Panel Panes given different kinds of @@ -466,7 +481,7 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): ) aviary_variables_file_path = ( - f"reports/{script_name}/aviary_vars/{aviary_variables_json_file_name}" + f"{script_name}_out/reports/aviary_vars/{aviary_variables_json_file_name}" ) with open(aviary_variables_file_path, "w") as fp: json.dump(table_data_nested, fp) @@ -474,7 +489,7 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): return table_data_nested -def convert_case_recorder_file_to_df(recorder_file_name): +def convert_driver_case_recorder_file_to_df(recorder_file_name): """ Convert a case recorder file into a Pandas data frame. @@ -560,7 +575,7 @@ def create_aircraft_3d_file(recorder_file, reports_dir, outfilepath): The path to the location where the file should be created. """ # Get the location of the HTML template file for this HTML file - aviary_dir = pathlib.Path(importlib.util.find_spec("aviary").origin).parent + aviary_dir = Path(importlib.util.find_spec("aviary").origin).parent aircraft_3d_template_filepath = aviary_dir.joinpath( "visualization/assets/aircraft_3d_file_template.html" ) @@ -569,7 +584,7 @@ def create_aircraft_3d_file(recorder_file, reports_dir, outfilepath): # next to the HTML file shutil.copy( aviary_dir.joinpath("visualization/assets/aviary_airlines.png"), - f"{reports_dir}/aviary_airlines.png", + Path(reports_dir) / "aviary_airlines.png", ) aircraft_3d_model = Aircraft3DModel(recorder_file) @@ -579,7 +594,8 @@ def create_aircraft_3d_file(recorder_file, reports_dir, outfilepath): aircraft_3d_model.write_file(aircraft_3d_template_filepath, outfilepath) -def _get_interactive_plot_sources(data_by_varname_and_phase, x_varname, y_varname, phase): +def _get_interactive_plot_sources( + data_by_varname_and_phase, x_varname, y_varname, phase): x = data_by_varname_and_phase[x_varname][phase] y = data_by_varname_and_phase[y_varname][phase] if len(x) > 0 and len(x) == len(y): @@ -588,8 +604,210 @@ def _get_interactive_plot_sources(data_by_varname_and_phase, x_varname, y_varnam return [], [] +def create_optimization_history_plot(case_recorder, df): + + # Create a ColumnDataSource + source = ColumnDataSource(df) + + # Create a Bokeh figure + plotting_figure = figure(title='Optimization History', + width=1000, + height=600, + ) + plotting_figure.title.align = 'center' + plotting_figure.yaxis.visible = False + plotting_figure.xaxis.axis_label = 'Iterations' + plotting_figure.yaxis.formatter = PrintfTickFormatter(format="%5.2e") + plotting_figure.title.text_font_size = "25px" + + # Choose a palette + palette = Category20[20] + + # Plot each time series and keep references to the renderers + renderers = {} + variable_names = list(df.columns)[1:] + for i, variable_name in enumerate(variable_names): + color = palette[i % 20] + + renderers[variable_name] = plotting_figure.line( + x='iter_count', + y=variable_name, + source=source, + y_range_name=f"extra_y_{variable_name}", + color=color, + line_width=2, + visible=False, # hide them all initially. clicking checkboxes makes them visible + ) + + # create axes both to the right and left of the plot. + # hide them initially + # as the user selects/deselects variables to be plotted, they get turned on/off + extra_y_axis = LinearAxis(y_range_name=f"extra_y_{variable_name}", + axis_label=f"{variable_name}", + axis_label_text_color=color) + plotting_figure.add_layout(extra_y_axis, 'right') + plotting_figure.right[i].visible = False + + extra_y_axis = LinearAxis(y_range_name=f"extra_y_{variable_name}", + axis_label=f"{variable_name}", + axis_label_text_color=color) + plotting_figure.add_layout(extra_y_axis, 'left') + plotting_figure.left[i + 1].visible = False + + # set the range + y_min = df[variable_name].min() + y_max = df[variable_name].max() + # if the range is zero, the axis will not be displayed. Plus need some range to make it + # look good. Some other code seems to do +- 1 for the range in this case. + if y_min == y_max: + y_min = y_min - 1 + y_max = y_max + 1 + plotting_figure.extra_y_ranges[f"extra_y_{variable_name}"] = Range1d( + y_min, y_max) + + # Make a Legend with no items in it. those will be added in JavaScript + # as users select variables to be plotted + legend = Legend(items=[], location=(-50, -5), border_line_width=0) + + # make the legend items in Python. Pass them to JavaScript where they can + # be added to the Legend + legend_items = [] + for variable_name in variable_names: + units = case_recorder.problem_metadata['variables'][variable_name]['units'] + legend_item = LegendItem(label=f"{variable_name} ({units})", renderers=[ + renderers[variable_name]]) + legend_items.append(legend_item) + + plotting_figure.add_layout(legend, 'below') + + # make the list of variables with checkboxes + data_source = ColumnDataSource( + data=dict(options=variable_names, checked=[False] * len(variable_names))) + # Create a Div to act as a scrollable container + variable_scroll_box = Div( + styles={ + 'overflow-y': 'scroll', + 'height': '500px', + 'border': '1px solid #ddd', + 'padding': '10px' + } + ) + + # make the text box used to filter variables + filter_variables_text_box = TextInput(placeholder='Variable name filter') + + # CustomJS callback for checkbox changes + variable_checkbox_callback = CustomJS(args=dict(data_source=data_source, + plotting_figure=plotting_figure, + renderers=renderers, + legend=legend, + legend_items=legend_items), + code=""" + // Three things happen in this code. + // 1. turn on/off the plot lines + // 2. show the legend items for the items being plotted + // 3. show the y axes for each of the lines being plotted + // The incoming Legend is empty. The items are passed in separately + + // 1. Plots + // turn off or on the line plot for the clicked on variable + const checkedIndex = cb_obj.index; + const isChecked = cb_obj.checked; + data_source.data['checked'][checkedIndex] = isChecked; + renderers[data_source.data['options'][checkedIndex]].visible = isChecked; + + // 2. Legend + // empty the Legend items and then add in the ones for the variables that are checked + legend.items = []; + for (let i =0; i < legend_items.length; i++){ + if ( data_source.data['checked'][i] ) { + legend.items.push(legend_items[i]); + } + } + + // 3. Y axes + // first hide all of them + for (let i =0; i < legend_items.length; i++){ + var extra_y_axis = plotting_figure.left[i + 1]; + extra_y_axis.visible = false ; + + var extra_y_axis = plotting_figure.right[i]; + extra_y_axis.visible = false ; + } + // alternate between making visible the axes on the left and the right to make it more even. + // this variable keeps track of which side to add the axes to. + let put_on_left_side = true; + for (let i =0; i < legend_items.length; i++){ + if (data_source.data['checked'][i]){ + if (put_on_left_side){ + plotting_figure.left[i + 1].visible = true; + } else { + plotting_figure.right[i].visible = true; + } + put_on_left_side = ! put_on_left_side ; + } + } + data_source.change.emit(); + """) + + # CustomJS callback for the variable filtering + filter_variables_callback = CustomJS( + args=dict( + data_source=data_source, + variable_scroll_box=variable_scroll_box, + variable_checkbox_callback=variable_checkbox_callback), + code=""" + + const filter_text = cb_obj.value.toLowerCase(); + const all_options = data_source.data['options']; + const checked_states = data_source.data['checked']; + + // Filter options + const filtered_options = all_options.filter(option => + option.toLowerCase().includes(filter_text) + ); + + // Update the scroll box content + let checkboxes_html = ''; + filtered_options.forEach((label) => { + const index = all_options.indexOf(label); + checkboxes_html += ` + + `; + }); + variable_scroll_box.text = checkboxes_html; + """) + + filter_variables_text_box.js_on_change('value', filter_variables_callback) + + # Initial population of the scroll box + initial_html = ''.join( + f""" + + """ + for i, variable_name in enumerate(variable_names) + ) + variable_scroll_box.text = initial_html + + # Arrange the layout using Panel + layout = pn.Row(pn.Column(filter_variables_text_box, + variable_scroll_box), plotting_figure) + + return layout + # The main script that generates all the tabs in the dashboard -def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_background=False): + + +def dashboard(script_name, problem_recorder, driver_recorder, + port, run_in_background=False): """ Generate the dashboard app display. @@ -604,27 +822,29 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg port : int HTTP port used for the dashboard webapp. If 0, use any free port """ - if "reports/" not in script_name: - reports_dir = f"reports/{script_name}" - else: - reports_dir = script_name + reports_dir = f"{script_name}_out/reports/" + out_dir = f"{script_name}_out/" - if not pathlib.Path(reports_dir).is_dir(): + if not Path(reports_dir).is_dir(): raise ValueError( - f"The script name, '{script_name}', does not have a reports folder associated with it. " - f"The directory '{reports_dir}' does not exist." + f"The script name, '{script_name}', does not have a reports folder " + f"associated with it. The directory '{reports_dir}' does not exist." ) - if not os.path.isfile(problem_recorder): + problem_recorder_path = Path(out_dir) / problem_recorder + driver_recorder_path = Path(out_dir) / driver_recorder + + if not os.path.isfile(problem_recorder_path): issue_warning( - f"Given Problem case recorder file {problem_recorder} does not exist.") + f"Given Problem case recorder file {problem_recorder_path} does not exist.") # TODO - use lists and functions to do this with a lot less code ####### Model Tab ####### model_tabs_list = [] # Debug Input List - input_list_pane = create_report_frame("text", "input_list.txt", ''' + input_list_pane = create_report_frame( + "text", Path(reports_dir) / "input_list.txt", ''' A plain text display of the model inputs. Recommended for beginners. Only created if Settings.VERBOSITY is set to at least 2 in the input deck. The variables are listed in a tree structure. There are three columns. The left column is a list of variable names, the middle column is the value, and the right column is the @@ -635,7 +855,8 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg model_tabs_list.append(("Debug Input List", input_list_pane)) # Debug Output List - output_list_pane = create_report_frame("text", "output_list.txt", ''' + output_list_pane = create_report_frame( + "text", Path(reports_dir) / "output_list.txt", ''' A plain text display of the model outputs. Recommended for beginners. Only created if Settings.VERBOSITY is set to at least 2 in the input deck. The variables are listed in a tree structure. There are three columns. The left column is a list of variable names, the middle column is the value, and the right column is the @@ -647,11 +868,13 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg # Inputs inputs_pane = create_report_frame( - "html", f"{reports_dir}/inputs.html", "Detailed report on the model inputs.") + "html", + Path(reports_dir) / "inputs.html", + "Detailed report on the model inputs.") model_tabs_list.append(("Inputs", inputs_pane)) # N2 - n2_pane = create_report_frame("html", f"{reports_dir}/n2.html", ''' + n2_pane = create_report_frame("html", Path(reports_dir) / "n2.html", ''' The N2 diagram, sometimes referred to as an eXtended Design Structure Matrix (XDSM), is a powerful tool for understanding your model in OpenMDAO. It is an N-squared diagram in the shape of a matrix representing functional or physical interfaces between system elements. @@ -661,7 +884,7 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg # Trajectory Linkage traj_linkage_report_pane = create_report_frame( - "html", f"{reports_dir}/traj_linkage_report.html", ''' + "html", Path(reports_dir) / "traj_linkage_report.html", ''' This is a Dymos linkage report in a customized N2 diagram. It provides a report detailing how phases are linked together via constraint or connection. The diagram clearly shows how mission phases are linked. It can be used to identify errant linkages between fixed quantities. @@ -669,12 +892,9 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg ) model_tabs_list.append(("Trajectory Linkage", traj_linkage_report_pane)) - ####### Optimization Tab ####### - optimization_tabs_list = [] - # Driver scaling driver_scaling_report_pane = create_report_frame( - "html", f"{reports_dir}/driver_scaling_report.html", ''' + "html", Path(reports_dir) / "driver_scaling_report.html", ''' This report is a summary of driver scaling information. After all design variables, objectives, and constraints are declared and the problem has been set up, this report presents all the design variables and constraints in all phases as well as the objectives. It also shows Jacobian information showing responses with respect to @@ -683,126 +903,93 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg ) model_tabs_list.append(("Driver Scaling", driver_scaling_report_pane)) - # Desvars, cons, opt interactive plot + ####### Optimization Tab ####### + optimization_tabs_list = [] + + # Optimization History Plot if driver_recorder: if os.path.isfile(driver_recorder): - df = convert_case_recorder_file_to_df(f"{driver_recorder}") - if df is not None: - variables = pn.widgets.CheckBoxGroup( - name="Variables", - options=list(df.columns), - # just so all of them aren't plotted from the beginning. Skip the iter count - value=list(df.columns)[1:2], - ) - ipipeline = df.interactive() - ihvplot = ipipeline.hvplot( - y=variables, - responsive=True, - min_height=400, - color=list(bp.Category10[10]), - yformatter="%.0f", - title="Model Optimization using OpenMDAO", - ) - optimization_plot_pane = pn.Column( - pn.Row( - pn.Column( - variables, - pn.VSpacer(height=30), - pn.VSpacer(height=30), - width=300, - ), - ihvplot.panel(), - ) - ) - else: - optimization_plot_pane = pn.pane.Markdown( - f"# Recorder file '{driver_recorder}' does not have Driver case recordings." - ) - else: - optimization_plot_pane = pn.pane.Markdown( - f"# Recorder file containing optimization history,'{driver_recorder}', not found.") - - optimization_plot_pane_with_doc = pn.Column( - pn.pane.HTML(f"

Plot of design variables, constraints, and objectives.

", - styles={'text-align': documentation_text_align}), - optimization_plot_pane - ) - optimization_tabs_list.append( - ("History", optimization_plot_pane_with_doc) - ) + df = convert_driver_case_recorder_file_to_df(f"{driver_recorder}") + cr = om.CaseReader(f"{driver_recorder}") + opt_history_pane = create_optimization_history_plot(cr, df) + optimization_tabs_list.append(("Optimization History", opt_history_pane)) # IPOPT report - if os.path.isfile(f"{reports_dir}/IPOPT.out"): - ipopt_pane = create_report_frame("text", f"{reports_dir}/IPOPT.out", ''' + if os.path.isfile(Path(reports_dir) / "IPOPT.out"): + ipopt_pane = create_report_frame("text", Path(reports_dir) / "IPOPT.out", ''' This report is generated by the IPOPT optimizer. ''') optimization_tabs_list.append(("IPOPT Output", ipopt_pane)) # Optimization report - opt_report_pane = create_report_frame("html", f"{reports_dir}/opt_report.html", ''' + opt_report_pane = create_report_frame( + "html", Path(reports_dir) / "opt_report.html", ''' This report is an OpenMDAO optimization report. All values are in unscaled, physical units. On the top is a summary of the optimization, followed by the objective, design variables, constraints, and optimizer settings. This report is important when dissecting optimal results produced by Aviary.''') optimization_tabs_list.append(("Summary", opt_report_pane)) # PyOpt report - if os.path.isfile(f"{reports_dir}/pyopt_solution.out"): + if os.path.isfile(Path(reports_dir) / "pyopt_solution.out"): pyopt_solution_pane = create_report_frame( - "text", f"{reports_dir}/pyopt_solution.txt", ''' + "text", Path(reports_dir) / "pyopt_solution.txt", ''' This report is generated by the pyOptSparse optimizer. ''' ) optimization_tabs_list.append(("PyOpt Solution", pyopt_solution_pane)) # SNOPT report - if os.path.isfile(f"{reports_dir}/SNOPT_print.out"): - snopt_pane = create_report_frame("text", f"{reports_dir}/SNOPT_print.out", ''' + if os.path.isfile(Path(reports_dir) / "SNOPT_print.out"): + snopt_pane = create_report_frame( + "text", Path(reports_dir) / "SNOPT_print.out", ''' This report is generated by the SNOPT optimizer. ''') optimization_tabs_list.append(("SNOPT Output", snopt_pane)) # SNOPT summary - if os.path.isfile(f"{reports_dir}/SNOPT_summary.out"): - snopt_summary_pane = create_report_frame("text", f"{reports_dir}/SNOPT_summary.out", ''' + if os.path.isfile(Path(reports_dir) / "SNOPT_summary.out"): + snopt_summary_pane = create_report_frame( + "text", Path(reports_dir) / "SNOPT_summary.out", ''' This is a report generated by the SNOPT optimizer that summarizes the optimization results.''') optimization_tabs_list.append(("SNOPT Summary", snopt_summary_pane)) # Coloring report coloring_report_pane = create_report_frame( - "html", f"{reports_dir}/total_coloring.html", "The report shows metadata associated with the creation of the coloring." - ) + "html", Path(reports_dir) / "total_coloring.html", + "The report shows metadata associated with the creation of the coloring.") optimization_tabs_list.append(("Total Coloring", coloring_report_pane)) ####### Results Tab ####### results_tabs_list = [] # Aircraft 3d model display - if problem_recorder: - if os.path.isfile(problem_recorder): + if problem_recorder_path: + if os.path.isfile(problem_recorder_path): try: + aircraft_3d_file = Path(reports_dir) / "aircraft_3d.html" create_aircraft_3d_file( - problem_recorder, reports_dir, f"{reports_dir}/aircraft_3d.html" + problem_recorder_path, reports_dir, aircraft_3d_file ) aircraft_3d_pane = create_report_frame( - "html", f"{reports_dir}/aircraft_3d.html", + "html", aircraft_3d_file, "3D model view of designed aircraft." ) except Exception as e: aircraft_3d_pane = create_report_frame( - "simple_message", f"Unable to create aircraft 3D model display due to error: {e}", - "3D model view of designed aircraft." - ) + "simple_message", + f"Unable to create aircraft 3D model display due to error: {e}", + "3D model view of designed aircraft.") results_tabs_list.append(("Aircraft 3d model", aircraft_3d_pane)) # Make the Aviary variables table pane - if os.path.isfile(problem_recorder): + if os.path.isfile(problem_recorder_path): # Make dir reports/script_name/aviary_vars if needed - aviary_vars_dir = pathlib.Path(f"reports/{script_name}/aviary_vars") + aviary_vars_dir = Path(reports_dir) / "aviary_vars" aviary_vars_dir.mkdir(parents=True, exist_ok=True) # copy index.html file to reports/script_name/aviary_vars/index.html - aviary_dir = pathlib.Path(importlib.util.find_spec("aviary").origin).parent + aviary_dir = Path(importlib.util.find_spec("aviary").origin).parent shutil.copy( aviary_dir.joinpath("visualization/assets/aviary_vars/index.html"), @@ -814,35 +1001,38 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg ) # copy script.js file to reports/script_name/aviary_vars/index.html. # mod the script.js file to point at the json file - # create the json file and put it in reports/script_name/aviary_vars/aviary_vars.json + # create the json file and put it in + # reports/script_name/aviary_vars/aviary_vars.json try: create_aviary_variables_table_data_nested( - script_name, problem_recorder + script_name, problem_recorder_path ) # create the json file aviary_vars_pane = create_report_frame( - "html", f"{reports_dir}/aviary_vars/index.html", + "html", Path(reports_dir) / "aviary_vars/index.html", "Table showing Aviary variables" ) results_tabs_list.append(("Aviary Variables", aviary_vars_pane)) except Exception as e: issue_warning( - f'Unable to create Aviary Variables tab in dashboard due to the error: {e}' - ) + f'Unable to create Aviary Variables tab in dashboard due to the error: {e}') # Mission Summary mission_summary_pane = create_report_frame( - "markdown", f"{reports_dir}/mission_summary.md", "A report of mission results from an Aviary problem") + "markdown", Path(reports_dir) / "mission_summary.md", + "A report of mission results from an Aviary problem") results_tabs_list.append(("Mission Summary", mission_summary_pane)) # Run status pane - status_pane = create_table_pane_from_json(f"{reports_dir}/status.json") + status_pane = create_table_pane_from_json( + Path(reports_dir) / "status.json", + "A high level overview of the status of the run") results_tabs_list.append(("Run status pane", status_pane)) run_status_pane_tab_number = len(results_tabs_list) - 1 # Timeseries Mission Output Report mission_timeseries_pane = create_csv_frame( - f"{reports_dir}/mission_timeseries_data.csv", ''' + Path(reports_dir) / "mission_timeseries_data.csv", ''' The outputs of the aircraft trajectory. Any value that is included in the timeseries data is included in this report. This data is useful for post-processing, especially those used for acoustic analysis. @@ -853,7 +1043,7 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg # Trajectory results traj_results_report_pane = create_report_frame( - "html", f"{reports_dir}/traj_results_report.html", ''' + "html", Path(reports_dir) / "traj_results_report.html", ''' This is one of the most important reports produced by Aviary. It will help you visualize and understand the optimal trajectory produced by Aviary. Users should play with it and try to grasp all possible features. @@ -868,17 +1058,21 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg ) # Interactive XY plot of mission variables - if problem_recorder: - if os.path.exists(problem_recorder): - cr = om.CaseReader(problem_recorder) + if problem_recorder_path: + if os.path.exists(problem_recorder_path): + cr = om.CaseReader(problem_recorder_path) # determine what trajectories there are - traj_nodes = [n for n in _meta_tree_subsys_iter( - cr.problem_metadata['tree'], cls='dymos.trajectory.trajectory:Trajectory')] + traj_nodes = [ + n + for n in _meta_tree_subsys_iter( + cr.problem_metadata['tree'], + cls='dymos.trajectory.trajectory:Trajectory')] if len(traj_nodes) == 0: - raise ValueError("No trajectories available in case recorder file for use " - "in generating interactive XY plot of mission variables") + raise ValueError( + "No trajectories available in case recorder file for use " + "in generating interactive XY plot of mission variables") traj_name = traj_nodes[0]["name"] if len(traj_nodes) > 1: issue_warning("More than one trajectory found in problem case recorder file. Only using " @@ -935,8 +1129,8 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg # need to create ColumnDataSource for each phase sources = {} for phase in phases: - x, y = _get_interactive_plot_sources(data_by_varname_and_phase, - x_varname_default, y_varname_default, phase) + x, y = _get_interactive_plot_sources( + data_by_varname_and_phase, x_varname_default, y_varname_default, phase) sources[phase] = ColumnDataSource(data=dict( x=x, y=y)) @@ -951,7 +1145,7 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg ], ) - colors = bp.d3['Category20'][20][0::2] + bp.d3['Category20'][20][1::2] + colors = d3['Category20'][20][0::2] + d3['Category20'][20][1::2] legend_data = [] phases = sorted(phases, key=str.casefold) for i, phase in enumerate(phases): @@ -969,7 +1163,8 @@ def dashboard(script_name, problem_recorder, driver_recorder, port, run_in_backg # Make the Legend legend = Legend(items=legend_data, location='center', label_text_font_size='8pt') - # so users can click on the dot in the legend to turn off/on that phase in the plot + # so users can click on the dot in the legend to turn off/on that phase in + # the plot legend.click_policy = "hide" p.add_layout(legend, 'right') @@ -1007,29 +1202,34 @@ def update_plot(x_varname, y_varname): ) else: interactive_mission_var_plot_pane = pn.pane.Markdown( - f"# Recorder file '{problem_recorder}' not found.") + f"# Recorder file '{problem_recorder_path}' not found.") interactive_mission_var_plot_pane_with_doc = pn.Column( - pn.pane.HTML(f"

Plot of mission variables allowing user to select X and Y plot values.

", - styles={'text-align': documentation_text_align}), - interactive_mission_var_plot_pane - ) + pn.pane.HTML( + f"

Plot of mission variables allowing user to select X and Y plot values.

", + styles={ + 'text-align': documentation_text_align}), + interactive_mission_var_plot_pane) results_tabs_list.append( - ("Interactive Mission Variable Plot", interactive_mission_var_plot_pane_with_doc) - ) + ("Interactive Mission Variable Plot", + interactive_mission_var_plot_pane_with_doc)) ####### Subsystems Tab ####### subsystem_tabs_list = [] # Look through subsystems directory for markdown files - # The subsystems report tab shows selected results for every major subsystem in the Aviary problem + # The subsystems report tab shows selected results for every major + # subsystem in the Aviary problem - for md_file in sorted(pathlib.Path(f"{reports_dir}subsystems").glob("*.md"), key=str): - subsystems_pane = create_report_frame("markdown", str( - md_file), + for md_file in sorted(Path(f"{reports_dir}subsystems").glob("*.md"), key=str): + subsystems_pane = create_report_frame( + "markdown", str(md_file), f''' + The subsystems report tab shows selected results for every major subsystem in the Aviary problem. - This report is for the {md_file.stem} subsystem. Reports available currently are mass, geometry, and propulsion. + This report is for the + {md_file.stem} + subsystem. Reports available currently are mass, geometry, and propulsion. ''') subsystem_tabs_list.append((md_file.stem, subsystems_pane)) @@ -1068,14 +1268,14 @@ def update_plot(x_varname, y_varname): def save_dashboard(event): print(f"Saving dashboard files to {script_name}.zip") - shutil.make_archive(script_name, "zip", f"reports/{script_name}") + shutil.make_archive(script_name, "zip", f"{script_name}_out") save_dashboard_button.on_click(save_dashboard) tabs.active = 0 # make the Results tab active initially # get status of run for display in the header of each page - status_string_for_header = get_run_status(f"{reports_dir}/status.json") + status_string_for_header = get_run_status(Path(reports_dir) / "status.json") template = pn.template.FastListTemplate( title=f"Aviary Dashboard for {script_name}: {status_string_for_header}", @@ -1086,7 +1286,7 @@ def save_dashboard(event): header_background="rgb(0, 212, 169)", header=header, background_color="white", - theme=DefaultTheme, + theme=pn.theme.DefaultTheme, theme_toggle=False, main_layout=None, css_files=["assets/aviary_styles.css"], @@ -1103,12 +1303,13 @@ def save_dashboard(event): if run_in_background: show = False - assets_dir = pathlib.Path( + assets_dir = Path( importlib.util.find_spec("aviary").origin ).parent.joinpath("visualization/assets/") home_dir = "." if port == 0: port = get_free_port() + server = pn.serve( template, port=port,