Skip to content

Commit

Permalink
Merge branch 'main' into issue_587
Browse files Browse the repository at this point in the history
  • Loading branch information
jkirk5 authored Jan 22, 2025
2 parents 74e2fef + 169c66a commit ad241ce
Show file tree
Hide file tree
Showing 80 changed files with 1,267 additions and 929 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.9.4-dev
current_version = 0.9.7-dev
commit = False
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ body:
attributes:
label: Aviary Version
description: What version of Aviary is being used.
placeholder: "0.9.4-dev"
placeholder: "0.9.7-dev"
validations:
required: true
- type: textarea
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ identifiers:
repository-code: 'https://github.com/OpenMDAO/Aviary'
repository: 'https://github.com/OpenMDAO/Aviary_Community'
license: Apache-2.0
version: 0.9.3
version: 0.9.7
2 changes: 1 addition & 1 deletion aviary/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.9.4-dev"
__version__ = "0.9.7-dev"
24 changes: 0 additions & 24 deletions aviary/docs/developer_guide/doctape.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -82,41 +82,17 @@
" 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 = '<details>\\n\\n<summary>Function Docs</summary>\\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</details>'\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",
Expand Down
73 changes: 69 additions & 4 deletions aviary/docs/developer_guide/doctape_examples.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -407,12 +407,12 @@
"outputs": [],
"source": [
"# Testing Cell\n",
"from aviary.api import Mission\n",
"from aviary.api import Aircraft\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('value', Aircraft.Design.EMPTY_MASS, 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(get_variable_name(Aircraft.Design.EMPTY_MASS), md_code=True)\n",
"glue_variable('var_name_code', get_previous_line(), md_code=True)\n"
]
},
Expand All @@ -423,7 +423,7 @@
"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",
"Using {glue:md}`var_value_code` will result in {glue:md}`value`, whereas using {glue:md}`var_name_code` will result in {glue:md}`Aircraft.Design.EMPTY_MASS`\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."
Expand Down Expand Up @@ -482,6 +482,71 @@
"p1_alt = get_value(simplified_dict, 'phase1.altitude.val')\n",
"print(p1_alt)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [
"remove-cell"
]
},
"outputs": [],
"source": [
"# Testing Cell\n",
"from aviary.utils.doctape import glue_variable, check_args, get_all_keys, get_previous_line\n",
"from aviary.api import Aircraft, Mission\n",
"\n",
"glue_variable(Aircraft.__name__)\n",
"glue_variable(Mission.__name__)\n",
"\n",
"track_layers = 'track_layers'\n",
"check_args(get_all_keys, track_layers)\n",
"glue_variable(track_layers)\n",
"\n",
"get_all_keys(Mission, track_layers='Mission')\n",
"track_layers_with_name = get_previous_line().split(', ')[1].split(')')[0]\n",
"glue_variable('track_layers_with_Mission', track_layers_with_name, display=False)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"These can also be used to recursively get all of the attributes from a complex object, like the {glue:md}`Aircraft` or {glue:md}`Mission` hierarchies.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from aviary.utils.doctape import get_all_keys, get_value, glue_keys\n",
"from aviary.api import Mission\n",
"\n",
"k1=get_all_keys(Mission)\n",
"print(k1[:5]) # Display the first 5 keys in Mission\n",
"k2=get_all_keys(Mission, track_layers=True)\n",
"print(k2[:5]) # Display the first 5 keys in Mission\n",
"k3=get_all_keys(Mission, track_layers='Mission')\n",
"print(k3[:5]) # Display the first 5 keys in Mission\n",
"\n",
"glue_keys(Mission, False)\n",
"\n",
"print(get_value(Mission,'Constraints.GEARBOX_SHAFT_POWER_RESIDUAL'))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If {glue:md}`get_all_keys` is used on an object like {glue:md}`Mission` without specifying a value for {glue:md}`track_layers` will return all of the uniquely named attributes of the object (such as {glue:md}GEARBOX_SHAFT_POWER_RESIDUAL). Setting {glue:md}`track_layers` to `True` will get all of the attributes in dot notation, but will not include the name of the original object ({glue:md}Constraints.GEARBOX_SHAFT_POWER_RESIDUAL). If you want the full name of the attribute, including the name of the original object, you can use that name as the value of {glue:md}`track_layers` (using {glue:md}track_layers_with_Mission gives us access to {glue:md}Mission.Constraints.GEARBOX_SHAFT_POWER_RESIDUAL)\n",
"\n",
"Using {glue:md}`glue_keys` handles this for us automatically by using the `__name__` attribute of the object passed to it as the value of {glue:md}`track_layers`.\n",
"\n",
"As with the dict_of_dicts, we can recusively get the value of an attribute using the full path along with {glue:md}`get_value`."
]
}
],
"metadata": {
Expand Down
10 changes: 7 additions & 3 deletions aviary/docs/user_guide/aerodynamics.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"- `computed`: uses regression-based techniques to estimate lift and drag\n",
"- `low_speed`: for use in detailed takeoff analysis, and includes high-lift devices and considers angle-of-attack\n",
"- `tabular`: allows the user to substitute the lift and drag coefficient calculations in `computed` with data tables\n",
"- `external`: disables Aviary's core aerodynamics computation, intended for use with external subsystems to replace all aerodynamic calculations.\n",
"\n",
"### Computed Aerodynamics\n",
"The FLOPS based aerodynamics subsystem uses a modified version of algorithms from the EDET (Empirical Drag Estimation Technique) program [^edet] to internally compute drag polars. FLOPS improvements to EDET as implemented in Aviary include smoothing of drag polars, more accurate Reynolds number calculations, and use of the Sommer and Short T' method [^tprime] for skin friction calculations.\n",
Expand All @@ -124,7 +125,10 @@
"- The lift-dependent drag coefficient table must include Mach number and lift coefficient as independent variables.\n",
"- The zero-lift drag coefficient table must include altitude and Mach number as independent variables.\n",
"\n",
"Tabular aerodynamics uses Aviary's [data_interpolator_builder](../_srcdocs/packages/utils/data_interpolator_builder) interface. This component is unique as it requires two data tables to be provided. All configuration options, such as the choice to use a structured metamodel or training data, are applied to both tables."
"Tabular aerodynamics uses Aviary's [data_interpolator_builder](../_srcdocs/packages/utils/data_interpolator_builder) interface. This component is unique as it requires two data tables to be provided. All configuration options, such as the choice to use a structured metamodel or training data, are applied to both tables.\n",
"\n",
"### External Aerodynamics\n",
"Selecting the `external` aerodynamics method disables Aviary's core aerodynamics group. This allows for external subsystems to completely replace these calculations."
]
},
{
Expand All @@ -142,7 +146,7 @@
"cab = CoreAerodynamicsBuilder(code_origin=LegacyCode.FLOPS)\n",
"# here we are only checking that the CoreAerodynamicsBuilder has a build_mission for a given method\n",
"# we know this will fail when it attempts to build the aero groups\n",
"for method in (None,'computed','low_speed','tabular','solved_alpha'):\n",
"for method in (None,'computed','low_speed','tabular','solved_alpha','external'):\n",
" try:\n",
" cab.build_mission(1,AviaryValues(),method=method)\n",
" except ValueError as e:\n",
Expand Down Expand Up @@ -191,7 +195,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.1.-1"
"version": "3.12.3"
}
},
"nbformat": 4,
Expand Down
Empty file.
107 changes: 107 additions & 0 deletions aviary/examples/external_subsystems/custom_aero/custom_aero_builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""
Builder for a simple drag calculation that replaces Aviary's calculation.
"""
import openmdao.api as om

from aviary.examples.external_subsystems.custom_aero.simple_drag import SimpleAeroGroup
from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase
from aviary.variable_info.variables import Aircraft, Dynamic


class CustomAeroBuilder(SubsystemBuilderBase):
"""
Prototype of a subsystem that overrides an aviary internally computed var.
It also provides a method to build OpenMDAO systems for the pre-mission and mission computations of the subsystem.
Attributes
----------
name : str ('simple_aero')
object label
"""

def __init__(self, name='simple_aero'):
super().__init__(name)

def build_mission(self, num_nodes, aviary_inputs, **kwargs):
"""
Build an OpenMDAO system for the mission computations of the subsystem.
Returns
-------
Returns
-------
mission_sys : openmdao.core.System
An OpenMDAO system containing all computations that need to happen
during the mission. This includes time-dependent states that are
being integrated as well as any other variables that vary during
the mission.
"""
aero_group = SimpleAeroGroup(
num_nodes=num_nodes,
)
return aero_group

def mission_inputs(self, **kwargs):
promotes = [
Dynamic.Atmosphere.STATIC_PRESSURE,
Dynamic.Atmosphere.MACH,
Dynamic.Vehicle.MASS,
'aircraft:*',
]
return promotes

def mission_outputs(self, **kwargs):
promotes = [
Dynamic.Vehicle.DRAG,
Dynamic.Vehicle.LIFT,
]
return promotes

def get_parameters(self, aviary_inputs=None, phase_info=None):
"""
Return a dictionary of fixed values for the subsystem.
Optional, used if subsystems have fixed values.
Used in the phase builders (e.g. cruise_phase.py) when other parameters are added to the phase.
This is distinct from `get_design_vars` in a nuanced way. Design variables
are variables that are optimized by the problem that are not at the phase level.
An example would be something that occurs in the pre-mission level of the problem.
Parameters are fixed values that are held constant throughout a phase, but if
`opt=True`, they are able to change during the optimization.
Parameters
----------
phase_info : dict
The phase_info subdict for this phase.
Returns
-------
fixed_values : dict
A dictionary where the keys are the names of the fixed variables
and the values are dictionaries with the following keys:
- 'value': float or array
The fixed value for the variable.
- 'units': str
The units for the fixed value (optional).
- any additional keyword arguments required by OpenMDAO for the fixed
variable.
"""
params = {}
params[Aircraft.Wing.AREA] = {
'shape': (1, ),
'static_target': True,
'units': 'ft**2',
}
return params

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 False
60 changes: 60 additions & 0 deletions aviary/examples/external_subsystems/custom_aero/run_simple_aero.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"""
Run the a mission with a simple external component that computes the wing
and horizontal tail mass.
"""
from copy import deepcopy

import aviary.api as av
from aviary.examples.external_subsystems.custom_aero.custom_aero_builder import CustomAeroBuilder


phase_info = deepcopy(av.default_height_energy_phase_info)

# Just do cruise in this example.
phase_info.pop('climb')
phase_info.pop('descent')

# Add custom aero.
# TODO: This API for replacing aero will be changed an upcoming release.
phase_info['cruise']['external_subsystems'] = [CustomAeroBuilder()]

# Disable internal aero
# TODO: This API for replacing aero will be changed an upcoming release.
phase_info['cruise']['subsystem_options']['core_aerodynamics'] = {
'method': 'external',
}


if __name__ == '__main__':
prob = av.AviaryProblem()

# 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)

# 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()

# Note, SLSQP might have troubles here.
prob.add_driver("SLSQP")

prob.add_design_variables()

prob.add_objective()

prob.setup()

prob.set_initial_guesses()

prob.run_aviary_problem(suppress_solver_print=True)

print('done')
Loading

0 comments on commit ad241ce

Please sign in to comment.