Skip to content

Commit

Permalink
Merge branch 'main' into od_docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jkirk5 authored Sep 10, 2024
2 parents 011e367 + f904f26 commit 74d709b
Show file tree
Hide file tree
Showing 151 changed files with 3,978 additions and 1,671 deletions.
5 changes: 2 additions & 3 deletions aviary/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'''
This module is the API for Aviary aircraft analysis code
For users: All built-in Aviary functions, code, and objects
For users: All built-in Aviary functions, code, and objects
should be imported from this file.
For developers: All Aviary code which is intended to be
Expand Down Expand Up @@ -41,7 +41,7 @@
from aviary.interface.utils.check_phase_info import check_phase_info
from aviary.utils.engine_deck_conversion import EngineDeckConverter
from aviary.utils.fortran_to_aviary import create_aviary_deck
from aviary.utils.functions import set_aviary_initial_values, get_path
from aviary.utils.functions import set_aviary_input_defaults, set_aviary_initial_values, get_path
from aviary.utils.options import list_options
from aviary.constants import GRAV_METRIC_GASP, GRAV_ENGLISH_GASP, GRAV_METRIC_FLOPS, GRAV_ENGLISH_FLOPS, GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH, RHO_SEA_LEVEL_METRIC, MU_TAKEOFF, MU_LANDING, PSLS_PSF, TSLS_DEGR, RADIUS_EARTH_METRIC
from aviary.subsystems.test.subsystem_tester import TestSubsystemBuilderBase, skipIfMissingDependencies
Expand All @@ -58,7 +58,6 @@
from aviary.utils.preprocessors import preprocess_options, preprocess_propulsion
from aviary.utils.process_input_decks import create_vehicle
from aviary.utils.functions import create_opts2vals, add_opts2vals, Null
from aviary.variable_info.variables_in import VariablesIn
from aviary.utils.preprocessors import preprocess_crewpayload

# ODEs
Expand Down
13 changes: 12 additions & 1 deletion aviary/docs/developer_guide/coding_standards.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,18 @@
"The Aviary repository contains a configuration file that defines what is run when commits are made and with what options enabled. Currently this is limited to autopep8 with a max line length restriction.\n",
"\n",
"### Controlling Display Levels\n",
"To make debugging issues easier, it is strongly recommended to make use of the `VERBOSITY` setting. This allows control over how much information is displayed to a user; too much information makes finding relevant information difficult and not enough information can make tracking difficult. `Brief` should be the default in most cases; however, `Quiet` should be the default for tests."
"To make debugging issues easier, it is strongly recommended to make use of the option `Settings.Verbosity`. This allows control over how much information is displayed to a user; too much information makes finding relevant information difficult and not enough information can make tracking difficult. Aviary uses a sliding scale of possible verbosity settings:\n",
"| Verbosity Level | Numerical Value | Description |\n",
"| :--- | :--- | :--- |\n",
"| `QUIET` | 0 | All output except errors are suppressed |\n",
"| `BRIEF` | 1 | Only important information is output, in human-readable format |\n",
"| `VERBOSE` | 2 | All user-relevant information is output, in human-readable format |\n",
"| `DEBUG` | 3 | Any information can be outputted, including warnings, intermediate calculations, etc., with no formatting requirement |\n",
"\n",
"Verbosity levels are defined in Aviary using the `Verbosity` Enum. Each verbosity level is paired with an integer value. In source code, verbosity level can be checked either through comparison with the Enum, or through equality or inequality comparisons with the matching integer value. This allows for code to be triggered not just at a specific level, but for any level above or below the desired setting. Numerical comparisons are recommended for several reasons: they don't require importing the `Verbosity` Enum, and activation is more flexible through the use of inequality comparators, preventing issues like a message only being outputted during `BRIEF` but not `VERBOSE` or `DEBUG`, which a user would expect to also see in higher verbosity settings.\n",
"`BRIEF` is default setting and is used in most cases; however, `QUIET` should be used for tests.\n",
"\n",
"It is preferred that within source code, the full Enums are used for better readability (e.g. `Verbosity.BRIEF`). For tests, scripts, examples, and other places where Aviary is called (rather than defined), it is ok to use the integer representations of verbosity to shorten lines and remove the need to import the `Verbosity` Enum (e.g. passing `0` as the verbosity argument to a function when `QUIET` is desired). Of course, it is always acceptable to use the full Enum in these cases for the same readability reasons."
]
},
{
Expand Down
79 changes: 79 additions & 0 deletions aviary/docs/developer_guide/unit_tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,85 @@ Ran 888 tests using 16 processes
Wall clock time: 00:00:54.15
```

## Current Unit Tests

### assert_near_equal

The unit test that Aviary uses most is `assert_near_equal` from the OpenMDAO utility [assert_near_equal](https://openmdao.org/newdocs/versions/latest/_srcdocs/packages/utils/assert_utils.html). This assertion takes about 70% of all the assertions. It has the following format:

```
assert_near_equal(actual_value, expected_value, tolerance=1e-15, tol_type='rel')
```

where the `actual_value` is the value from Aviary and `expected_value` is what the developer expects. Ideally, the `expected_value` should come from computation by another tool (e.g. GASP, FLOPS or LEAPS1) or hand computation. When it is not possible, one can accept an Aviary computed value as expected. This guarantees that future development will not alter the outputs by mistake. As for the tolerance, it is good practice to take 1.e-6. By default, it checks relative error. If the `expected_value` is 0.0, it checks the absolute error.

One can find examples mostly in `subsystems` and `mission` The purpose is to make sure that a variable in an object (namely a component and/or a group) is computed as expected. It is advised that `assert_near_equal` test is carried for all outputs both in components and groups.

### assert_almost_equal and similar assertions

A similar unit test is NumPy's utility is `assert_almost_equal`. It checks whether the absolute difference of `actual_value` from `expected_value` is within certain tolerance. As [documented](https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_almost_equal.html) by NumPy, it is not recommended.
For strings and integers, `assertEqual` of `unittest` is used.

There are other similar assertions like `assertIsNone`, `assertIsNotNone`, `assertNotEqual`, `assertGreater`, `assertIn`, `assertNotIn`, `assertTrue`, and `assertFalse`. They together represent about 15% of all the assertions.


### assert_check_partials

The second most used assertion is `assert_check_partials` from the OpenMDAO utility. This is critically important because it checks whether the partial derivatives coded by develops are correct. It is the key in optimization. To use this test, you first prepare the partial derivative `data` by calling `check_partials` on an object. Then call `assert_check_partials` function with the `data`.

```
data = prob.check_partials(out_stream=None)
assert_check_partials(data, atol=1e-06, rtol=1e-06)
```

This assert makes sure that the computed derivatives in the code match those computed numerically within the given absolute and relative tolerances.

In Aviary, there are two ways to compute a component's derivatives: analytically or numerically. When the derivatives are analytic, it is best practice to use `check_partials` to compare them against the complex step (`cs`) or finite difference (`fd`) estimates.
Complex step is much more acurate, but all code in your component's `compute` method must be complex-safe to use this -- in other words, no calculation that squelches the imaginary part of the calculation (like `abs`.)
Note that there are some complex-safe alternatives to commonly-used calculations in the openmdao library. If your code is not complex-safe, or it wraps an external component that doesn't support complex numbers, then finite difference should be used.

If your component computes its derivatives numerically, there is less reason to test it because you are testing one numerical method against another. If you choose to do this, you will need to use a different method, form, or step.
For example, if the partial derivatives are computed using `cs` method, you need to use `fd` method, or use `cs` method but with a different stepsize (e.g. `step=1.01e-40`):

```
data = prob.check_partials(out_stream=None, method="cs", step=1.01e-40)
assert_check_partials(data, atol=1e-06, rtol=1e-06)
```

Although the default method of `check_partials` is `fd` (finite difference), we prefer `cs` ([complex step](https://openmdao.org/newdocs/versions/latest/advanced_user_guide/complex_step.html) because it usally gives more accurate results.

````{margin}
```{note}
In general, we really don't have to check partials that are computed with complex step, since you expect that you should already be getting cs level of accuracy from them. Checks are primarily for analytic derivatives, where you can make mistakes.
```
````

`check_partials` allows you to exclude some components in a group. For example `excludes=["*atmosphere*"]` means that atmosphere component will not be included.

Sometimes, you may need to exclude a particular partial derivative. You need to write your own code to do so. One example is in `subsystems/propulsion/test/test_propeller_performance.py`.

````{margin}
```{note}
Some of the partials in Aviary use table look up and interpolations. In the openmdao interpolation, the derivatives aren't always continuous if you interpolate right on one of the table points. You may need to tune the points you choose. For example, if 0.04 is a point in your test, you can change it to 0.04000001 and try again.
```
````

### assert_warning

This assertion checks that a warning is issued as expected. Currently, there is only one usage in Aviary but we should add more.

### assert_match_varnames

Another assertion used in tests is `assert_match_varnames` (about 4%). All of them are in `test_IO()` functions. It tests that all of the variables in an object (component or group) that are declared as inputs or outputs exist in the Aviary variable hierarchy. Exceptions are allowed by specifying `exclude_inputs` and `exclude_outputs`. For details, see [assert_utils.py](https://github.com/OpenMDAO/Aviary/blob/main/aviary/utils/test_utils/assert_utils.py).

### Other Assertions

Aviary has built several utility functions for unit tests:

- `assert_no_duplicates`
- `assert_structure_alphabetization`
- `assert_metadata_alphabetization`

## Adding Unit Tests

Whenever you add to Aviary, you should add a unit test to check its functionality.
Expand Down
2 changes: 1 addition & 1 deletion aviary/docs/examples/OAS_subsystem.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
" -------\n",
" pre_mission_sys : openmdao.core.System\n",
" An OpenMDAO system containing all computations that need to happen in\n",
" the pre-mission (formerly statics) part of the Aviary problem. This\n",
" the pre-mission part of the Aviary problem. This\n",
" includes sizing, design, and other non-mission parameters.\n",
" '''\n",
"\n",
Expand Down
2 changes: 1 addition & 1 deletion aviary/docs/getting_started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Quick start installation

```{note}
If you do not already have Python installed, we recommend installing [miniconda](https://docs.anaconda.com/miniconda/miniconda-install/).
If you do not already have Python installed, we recommend installing [condaforge](https://github.com/conda-forge/miniforge?tab=readme-ov-file#download).
The minimum supported version of Python is 3.9; we recommend using the latest release of Python.
```

Expand Down
4 changes: 2 additions & 2 deletions aviary/docs/getting_started/onboarding_level2.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
"# Preprocess inputs\n",
"prob.check_and_preprocess_inputs()\n",
"\n",
"# adds a pre-mission group (propulsion, geometry, static aerodynamics, and mass)\n",
"# adds a pre-mission group (propulsion, geometry, aerodynamics, and mass)\n",
"prob.add_pre_mission_systems()\n",
"\n",
"# adds a sequence of core mission phases.\n",
Expand Down Expand Up @@ -371,7 +371,7 @@
"id": "12d71c79",
"metadata": {},
"source": [
"This call adds a pre-mission group (also called static analysis group) which includes pre-mission propulsion, geometry, pre-mission aerodynamics, and mass subsystems. \n",
"This call adds a pre-mission group which includes propulsion, geometry, aerodynamics, and mass subsystems. \n",
"\n",
"For `height_energy` missions, aviary currently models FLOPS' \"simplified\" takeoff as defined in [mission/flops_based/phases/simplified_takeoff.py](https://github.com/OpenMDAO/Aviary/blob/main/aviary/mission/flops_based/phases/simplified_takeoff.py).\n",
"\n",
Expand Down
23 changes: 13 additions & 10 deletions aviary/docs/getting_started/onboarding_level3.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@
" av.Mission.Landing.LIFT_COEFFICIENT_MAX) # no units\n",
")\n",
"\n",
"# Upstream static analysis for aero\n",
"# Upstream pre-mission analysis for aero\n",
"prob.model.add_subsystem(\n",
" 'pre_mission',\n",
" av.CorePreMission(aviary_options=aviary_inputs,\n",
Expand Down Expand Up @@ -351,7 +351,7 @@
"external_parameters['cruise'] = params\n",
"external_parameters['descent'] = params\n",
"\n",
"traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs, \n",
"traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs,\n",
" external_parameters=external_parameters)\n",
"\n",
"##################################\n",
Expand Down Expand Up @@ -449,17 +449,20 @@
"prob.model.add_objective('reg_objective', ref=1)\n",
"\n",
"# Set initial default values for all LEAPS aircraft variables.\n",
"av.set_aviary_initial_values(prob.model, aviary_inputs)\n",
"\n",
"prob.model.add_subsystem(\n",
" 'input_sink',\n",
" av.VariablesIn(aviary_options=aviary_inputs),\n",
" promotes_inputs=['*'],\n",
" promotes_outputs=['*']\n",
")\n",
"varnames = [\n",
" av.Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN,\n",
" av.Aircraft.Wing.SWEEP,\n",
" av.Aircraft.Wing.TAPER_RATIO,\n",
" av.Aircraft.Wing.THICKNESS_TO_CHORD,\n",
" av.Mission.Design.GROSS_MASS,\n",
" av.Mission.Summary.GROSS_MASS,\n",
"]\n",
"av.set_aviary_input_defaults(prob.model, varnames, aviary_inputs)\n",
"\n",
"prob.setup(force_alloc_complex=True)\n",
"\n",
"av.set_aviary_initial_values(prob, aviary_inputs)\n",
"\n",
"############################################\n",
"# Initial Settings for States and Controls #\n",
"############################################\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,22 +346,22 @@
" 'traj.takeoff_decision_speed.states:velocity',\n",
" equals=155.36, units='kn', ref=159.0, indices=[-1])\n",
"\n",
"takeoff.model.add_subsystem(\n",
" 'input_sink',\n",
" av.VariablesIn(aviary_options=aviary_options),\n",
" promotes_inputs=['*'],\n",
" promotes_outputs=['*']\n",
")\n",
" \n",
"varnames = [\n",
" av.Aircraft.Wing.AREA,\n",
" av.Aircraft.Wing.ASPECT_RATIO,\n",
" av.Aircraft.Wing.SPAN,\n",
"]\n",
"av.set_aviary_input_defaults(takeoff.model, varnames, aviary_options)\n",
" \n",
"# suppress warnings:\n",
"# \"input variable '...' promoted using '*' was already promoted using 'aircraft:*'\n",
"with warnings.catch_warnings():\n",
" # Set initial default values for all aircraft variables.\n",
" av.set_aviary_initial_values(takeoff.model, aviary_options)\n",
"\n",
" warnings.simplefilter(\"ignore\", om.PromotionWarning)\n",
" takeoff.setup(check=True)\n",
"\n",
"av.set_aviary_initial_values(takeoff, aviary_options)\n",
"\n",
"takeoff_trajectory_builder.apply_initial_guesses(takeoff, 'traj')\n",
"\n"
]
Expand Down Expand Up @@ -610,22 +610,22 @@
"\n",
"fullstop.add_objective(Dynamic.Mission.DISTANCE, loc='final', ref=distance_max, units=units)\n",
"\n",
"landing.model.add_subsystem(\n",
" 'input_sink',\n",
" av.VariablesIn(aviary_options=aviary_options),\n",
" promotes_inputs=['*'],\n",
" promotes_outputs=['*']\n",
")\n",
"\n",
"varnames = [\n",
" av.Aircraft.Wing.AREA,\n",
" av.Aircraft.Wing.ASPECT_RATIO,\n",
" av.Aircraft.Wing.SPAN,\n",
"]\n",
"av.set_aviary_input_defaults(landing.model, varnames, aviary_options)\n",
" \n",
"# suppress warnings:\n",
"# \"input variable '...' promoted using '*' was already promoted using 'aircraft:*'\n",
"with warnings.catch_warnings():\n",
" # Set initial default values for all aircraft variables.\n",
" av.set_aviary_initial_values(landing.model, aviary_options)\n",
"\n",
" warnings.simplefilter(\"ignore\", om.PromotionWarning)\n",
" landing.setup(check=True)\n",
"\n",
"av.set_aviary_initial_values(landing, aviary_options)\n",
"\n",
"landing_trajectory_builder.apply_initial_guesses(landing, 'traj')\n",
"\n"
]
Expand All @@ -647,7 +647,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
"version": "3.12.3"
}
},
"nbformat": 4,
Expand Down
5 changes: 2 additions & 3 deletions aviary/docs/user_guide/SGM_capabilities.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@
"outputs": [],
"source": [
"from aviary.mission.gasp_based.ode.base_ode import BaseODE\n",
"from aviary.variable_info.variables import Dynamic, Settings, Mission, Aircraft\n",
"from aviary.variable_info.enums import AnalysisScheme, Verbosity, LegacyCode\n",
"from aviary.variable_info.variables import Dynamic, Mission, Aircraft\n",
"from aviary.variable_info.enums import AnalysisScheme, LegacyCode\n",
"from aviary.mission.gasp_based.ode.time_integration_base_classes import SimuPyProblem\n",
"from aviary.mission.gasp_based.ode.rotation_ode import RotationODE\n",
"from aviary.utils.aviary_values import AviaryValues\n",
"\n",
"from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder\n",
"from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder\n",
Expand Down
Loading

0 comments on commit 74d709b

Please sign in to comment.