Skip to content

Commit

Permalink
Merge branch 'OpenMDAO:main' into mount_location
Browse files Browse the repository at this point in the history
  • Loading branch information
xjjiang authored Jan 31, 2025
2 parents 462f906 + 7472c64 commit 9fc63b0
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .github/actions/prepare_environment/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ runs:
conda env export --file ${{ inputs.NAME }}_environment.yml
- name: 'Upload environment artifact'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.NAME }}_environment
path: ${{ inputs.NAME }}_environment.yml
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test_workflow_no_dev_install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
conda env export --file ${{ matrix.NAME }}_environment.yml
- name: 'Upload environment artifact'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.NAME }}_environment
path: ${{ matrix.NAME }}_environment.yml
Expand Down
2 changes: 1 addition & 1 deletion aviary/api.py
Original file line number Diff line number Diff line change
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 fortran_to_aviary
from aviary.utils.functions import set_aviary_input_defaults, set_aviary_initial_values, get_path
from aviary.utils.functions import set_aviary_input_defaults, set_aviary_initial_values, get_path, top_dir
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 Down
2 changes: 1 addition & 1 deletion aviary/docs/developer_guide/doctape_examples.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@
"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",
"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` function 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}`Aircraft.Design.EMPTY_MASS`\n",
Expand Down
2 changes: 0 additions & 2 deletions aviary/docs/getting_started/onboarding_level1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,6 @@
"source": [
"Let us discuss these in more detail:\n",
"\n",
"- `-o ––outdir`: Use specified directory to write output. The default is the current directory.\n",
"\n",
"- `--optimizer`: Name of optimizer. Choices are: `SNOPT`, `IPOPT`, `SLSQP`, and `None`. The default is `SNOPT`. If optimizer is `None`, it will be set to `IPOPT` or `SNOPT` depending on the analysis scheme. The optimization objective is fuel burn for level 1 runs. The objective is\n",
" - `mission:objectives:fuel` if `mission_method` is `GASP` \n",
" - `fuel_burned` if `mission_method` is `FLOPS`.\n",
Expand Down
42 changes: 12 additions & 30 deletions aviary/interface/methods_for_level1.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
"""
This file contains functions needed to run Aviary using the Level 1 interface.
"""
import os

from importlib.machinery import SourceFileLoader
from pathlib import Path

import openmdao.api as om
from aviary.variable_info.enums import AnalysisScheme, Verbosity
from aviary.interface.methods_for_level2 import AviaryProblem
from aviary.utils.functions import get_path
Expand Down Expand Up @@ -110,7 +109,6 @@ def run_aviary(aircraft_filename, phase_info, optimizer=None,

def run_level_1(
input_deck,
outdir='output',
optimizer='SNOPT',
phase_info=None,
max_iter=50,
Expand Down Expand Up @@ -144,32 +142,23 @@ def run_level_1(

prob = run_aviary(input_deck, phase_info, **kwargs)

# update n2 diagram after run.
outfile = os.path.join(outdir, "n2.html")
if outdir != '':
os.makedirs(outdir, exist_ok=True)
om.n2(
prob,
outfile=outfile,
show_browser=False,
)

return prob


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(
"-o", "--outdir", default=def_outdir, help="Directory to write outputs"
'input_deck',
metavar='indeck',
type=str,
nargs=1,
help='Name of vehicle input deck file',
)
parser.add_argument(
"--optimizer",
type=str,
default='SNOPT',
default='IPOPT',
help="Name of optimizer",
choices=("SNOPT", "IPOPT", "SLSQP", "None")
choices=("SNOPT", "IPOPT", "SLSQP", "None"),
)
parser.add_argument(
"--phase_info",
Expand All @@ -178,10 +167,8 @@ def _setup_level1_parser(parser):
help="Path to phase info file"
)
parser.add_argument(
"--max_iter",
type=int,
default=50,
help="maximum number of iterations")
"--max_iter", type=int, default=50, help="maximum number of iterations"
)
parser.add_argument(
"--shooting",
action="store_true",
Expand All @@ -192,7 +179,8 @@ def _setup_level1_parser(parser):
type=int,
default=1,
help="verbosity settings: 0=quiet, 1=brief, 2=verbose, 3=debug",
choices=(0, 1, 2, 3))
choices=(0, 1, 2, 3),
)


def _exec_level1(args, user_args):
Expand All @@ -208,14 +196,8 @@ def _exec_level1(args, user_args):
if isinstance(args.input_deck, list):
args.input_deck = args.input_deck[0]

if args.outdir == os.path.join(os.getcwd(), "output"):
# if default outdir, add the input deck name
file_name_stem = Path(args.input_deck).stem
args.outdir = args.outdir + os.sep + file_name_stem

prob = run_level_1(
input_deck=args.input_deck,
outdir=args.outdir,
optimizer=args.optimizer,
phase_info=args.phase_info,
max_iter=args.max_iter,
Expand Down
10 changes: 10 additions & 0 deletions aviary/interface/methods_for_level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import sys
import json
import enum
import os

import numpy as np

Expand Down Expand Up @@ -2541,6 +2542,15 @@ def run_aviary_problem(self, record_filename="problem_history.db",
failed = self.run_model()
warnings.filterwarnings('default', category=UserWarning)

# update n2 diagram after run.
outdir = Path(self.get_reports_dir(force=True))
outfile = os.path.join(outdir, "n2.html")
om.n2(
self,
outfile=outfile,
show_browser=False,
)

if self.aviary_inputs.get_val(Settings.VERBOSITY).value >= 2:
with open('output_list.txt', 'w') as outfile:
self.model.list_outputs(out_stream=outfile)
Expand Down
6 changes: 0 additions & 6 deletions aviary/interface/test/test_cmd_entry_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ def bench_test_IPOPT_cmd(self):
cmd = 'aviary run_mission models/test_aircraft/aircraft_for_bench_GwGm.csv --optimizer IPOPT --max_iter 1'
self.run_and_test_cmd(cmd)

@require_pyoptsparse(optimizer="IPOPT")
def bench_test_IPOPT_cmd(self):
cmd = 'aviary run_mission models/test_aircraft/aircraft_for_bench_GwGm.csv' \
' --optimizer IPOPT --max_iter 1 --shooting'
self.run_and_test_cmd(cmd)

@require_pyoptsparse(optimizer="IPOPT")
def bench_test_phase_info_cmd(self):
cmd = 'aviary run_mission models/test_aircraft/aircraft_for_bench_GwGm.csv --optimizer IPOPT --max_iter 1' \
Expand Down
14 changes: 9 additions & 5 deletions aviary/subsystems/mass/gasp_based/design_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def setup(self):

if self.options[Aircraft.Design.PART25_STRUCTURAL_CATEGORY] < 3:

add_aviary_input(self, Aircraft.Wing.LOADING, val=128)
add_aviary_input(self, Aircraft.Wing.LOADING, val=128, units='lbf/ft**2')

self.add_output("max_airspeed", val=0, units="kn",
desc="VM0: maximum operating equivalent airspeed",
Expand Down Expand Up @@ -634,7 +634,9 @@ def setup(self):
add_aviary_input(self, Aircraft.Wing.SWEEP, val=0.436, units="rad")
add_aviary_input(self, Mission.Design.MACH, val=0.8)

add_aviary_output(self, Aircraft.Design.LIFT_CURVE_SLOPE, val=7.1765)
add_aviary_output(
self, Aircraft.Design.LIFT_CURVE_SLOPE, val=7.1765, units='1/rad'
)

self.declare_partials(Aircraft.Design.LIFT_CURVE_SLOPE, "*")

Expand Down Expand Up @@ -673,7 +675,7 @@ def initialize(self):

def setup(self):

add_aviary_input(self, Aircraft.Wing.LOADING, val=128)
add_aviary_input(self, Aircraft.Wing.LOADING, val=128, units='lbf/ft**2')

self.add_input(
"density_ratio",
Expand All @@ -695,8 +697,10 @@ def setup(self):
desc="EMLF: maximum maneuver load factor, units are in g`s",
)

add_aviary_input(self, Aircraft.Wing.AVERAGE_CHORD, val=12.6131)
add_aviary_input(self, Aircraft.Design.LIFT_CURVE_SLOPE, val=7.1765)
add_aviary_input(self, Aircraft.Wing.AVERAGE_CHORD, val=12.6131, units='ft')
add_aviary_input(
self, Aircraft.Design.LIFT_CURVE_SLOPE, val=7.1765, units='1/rad'
)

add_aviary_output(self, Aircraft.Wing.ULTIMATE_LOAD_FACTOR, val=3.5)

Expand Down
3 changes: 3 additions & 0 deletions aviary/utils/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,9 @@ def get_path(path: Union[str, Path], verbose: bool = False) -> Path:
return path


top_dir = Path(get_aviary_resource_path(''))


def wrapped_convert_units(val_unit_tuple, new_units):
"""
Wrapper for OpenMDAO's convert_units function.
Expand Down
7 changes: 7 additions & 0 deletions aviary/utils/test/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from aviary.variable_info.options import get_option_defaults
from aviary.variable_info.variables import Aircraft, Mission
from aviary.utils.functions import add_opts2vals, create_opts2vals, get_path
from aviary.api import top_dir


class TestOpts2Vals(unittest.TestCase):
Expand Down Expand Up @@ -104,5 +105,11 @@ def test_non_existent_path(self):
get_path('nonexistentfile.txt')


class TestTopDir(unittest.TestCase):
def test_top_dir(self):
result = Path(__file__).parent.parent.parent
self.assertEqual(result, top_dir)


if __name__ == "__main__":
unittest.main()
74 changes: 63 additions & 11 deletions aviary/variable_info/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def add_aviary_input(comp, varname, val=None, units=None, desc=None, shape_by_co
val: float or ndarray
Default value for variable.
units: str
(Optional) when speficying val, units should also be specified.
(Optional) when specifying val, units should also be specified.
desc: str
(Optional) description text for the variable.
shape_by_conn: bool
Expand All @@ -47,13 +47,16 @@ def add_aviary_input(comp, varname, val=None, units=None, desc=None, shape_by_co
(Optional) shape for this input.
"""
meta = meta_data[varname]
# units of None are overwritten with defaults. Overwriting units with None is
# unnecessary as it will cause errors down the line if the default is not already
# None
default_units = meta['units']

if units:
input_units = units
else:
# units of None are overwritten with defaults. Overwriting units with None is
# unecessary as it will cause errors down the line if the default is not already
# None
input_units = meta['units']
input_units = default_units

if desc:
input_desc = desc
else:
Expand All @@ -69,6 +72,18 @@ def add_aviary_input(comp, varname, val=None, units=None, desc=None, shape_by_co
val = np.zeros(shape)
else:
val = np.ones(shape) * val

# val was not provided but different units were
if input_units != default_units:
try:
# convert the default units to requested units
val = convert_units(val, default_units, input_units)
except ValueError:
raise ValueError(
f'The requested units {units} for input {varname} in component '
f'{comp.name} are invalid.'
)

comp.add_input(varname, val=val, units=input_units,
desc=input_desc, shape_by_conn=shape_by_conn, shape=shape)

Expand Down Expand Up @@ -104,13 +119,16 @@ def add_aviary_output(comp, varname, val=None, units=None, desc=None, shape_by_c
(Optional) shape for this input.
"""
meta = meta_data[varname]
# units of None are overwritten with defaults. Overwriting units with None is
# unnecessary as it will cause errors down the line if the default is not already
# None
default_units = meta['units']

if units:
output_units = units
else:
# units of None are overwritten with defaults. Overwriting units with None is
# unecessary as it will cause errors down the line if the default is not already
# None
output_units = meta['units']
output_units = default_units

if desc:
output_desc = desc
else:
Expand All @@ -126,6 +144,18 @@ def add_aviary_output(comp, varname, val=None, units=None, desc=None, shape_by_c
val = np.zeros(shape)
else:
val = np.ones(shape) * val

# val was not provided but different units were
if output_units != default_units:
try:
# convert the default units to requested units
val = convert_units(val, default_units, output_units)
except ValueError:
raise ValueError(
f'The requested units {units} for output {varname} in component '
f'{comp.name} are invalid.'
)

comp.add_output(varname, val=val, units=output_units,
desc=output_desc, shape_by_conn=shape_by_conn)

Expand Down Expand Up @@ -226,10 +256,18 @@ def add_aviary_option(comp, name, val=_unspecified, units=None, desc=None, meta_
be used.
"""
meta = meta_data[name]
# units of None are overwritten with defaults. Overwriting units with None is
# unnecessary as it will cause errors down the line if the default is not already
# None
default_units = meta['units']

if units:
option_units = units
else:
option_units = default_units

if not desc:
desc = meta['desc']
if val is _unspecified:
val = meta['default_value']

types = meta['types']
if meta['multivalue']:
Expand All @@ -238,6 +276,20 @@ def add_aviary_option(comp, name, val=_unspecified, units=None, desc=None, meta_
else:
types = (list, types)

if val is _unspecified:
val = meta['default_value']

# val was not provided but different units were
if option_units != default_units:
try:
# convert the default units to requested units
val = convert_units(val, default_units, option_units)
except ValueError:
raise ValueError(
f'The requested units {units} for output {name} in component '
f'{comp.name} are invalid.'
)

if units not in [None, 'unitless']:
types = tuple
comp.options.declare(name, default=(val, units),
Expand Down
Loading

0 comments on commit 9fc63b0

Please sign in to comment.