Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to variable tests + minor cleanup #194

Merged
merged 15 commits into from
Mar 27, 2024
Merged
2 changes: 1 addition & 1 deletion aviary/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
from aviary.interface.methods_for_level2 import AviaryProblem
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.fortran_to_aviary import create_aviary_deck
from aviary.utils.functions import 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
Expand Down
2 changes: 1 addition & 1 deletion aviary/interface/cmd_entry_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import aviary
from aviary.interface.methods_for_level1 import _exec_level1, _setup_level1_parser
from aviary.utils.Fortran_to_Aviary import _exec_F2A, _setup_F2A_parser
from aviary.utils.fortran_to_aviary import _exec_F2A, _setup_F2A_parser
from aviary.utils.engine_deck_conversion import _exec_EDC, _setup_EDC_parser, EDC_description
from aviary.visualization.dashboard import _dashboard_setup_parser, _dashboard_cmd
from aviary.interface.graphical_input import _exec_flight_profile, _setup_flight_profile_parser
Expand Down
15 changes: 12 additions & 3 deletions aviary/utils/engine_deck_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import itertools
from datetime import datetime
from enum import Enum
from pathlib import Path

import numpy as np
import openmdao.api as om
Expand All @@ -25,6 +24,9 @@ class EngineDeckType(Enum):
GASP = 'GASP'
GASP_TP = 'GASP_TP'

def __str__(self):
return self.value


MACH = EngineModelVariables.MACH
ALTITUDE = EngineModelVariables.ALTITUDE
Expand Down Expand Up @@ -98,8 +100,15 @@ def EngineDeckConverter(input_file, output_file, data_format: EngineDeckType):
data_file = get_path(input_file)

comments.append(f'# created {timestamp} by {user}')
legacy_code = data_format.value
engine_type = 'engine'
if legacy_code == 'GASP_TP':
engine_type = 'turboshaft engine'
legacy_code = 'GASP'

comments.append(
f'# {data_format.value}-derived engine deck converted from {data_file.name}')
f'# {legacy_code}-derived {engine_type} deck converted from {data_file.name}')

if data_format == EngineDeckType.FLOPS:
header = {key: default_units[key] for key in flops_keys}
data = {key: np.array([]) for key in flops_keys}
Expand Down Expand Up @@ -771,7 +780,7 @@ def _setup_EDC_parser(parser):
help='path to engine deck file to be converted')
parser.add_argument('output_file', type=str,
help='path to file where new converted data will be written')
parser.add_argument('data_format', type=EngineDeckType, choices=list(EngineDeckType),
parser.add_argument('-f', '--data_format', type=EngineDeckType, choices=list(EngineDeckType),
help='data format used by input_file')


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@

import csv
import re
from enum import Enum
from pathlib import Path
import getpass

from datetime import datetime
from pathlib import Path
from openmdao.utils.units import valid_units

from aviary.utils.functions import convert_strings_to_data
Expand Down Expand Up @@ -54,6 +55,14 @@ def create_aviary_deck(fortran_deck: str, legacy_code=None, defaults_deck=None,

fortran_deck: Path = get_path(fortran_deck, verbose=False)

timestamp = datetime.now().strftime('%m/%d/%y at %H:%M')
user = getpass.getuser()
comments = []

comments.append(f'# created {timestamp} by {user}')
comments.append(
f'# {legacy_code.value}-derived aircraft input deck converted from {fortran_deck.name}')

if out_file:
out_file = Path(out_file)
else:
Expand Down Expand Up @@ -88,15 +97,16 @@ def create_aviary_deck(fortran_deck: str, legacy_code=None, defaults_deck=None,
out_file = fortran_deck.parent / out_file

if out_file.is_file():
if force:
if force and verbosity.value >= 1:
Copy link
Contributor

@crecine crecine Mar 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

won't this cause an error (the else path) if verbosity is quiet, even if force is True?

print(f'Overwriting existing file: {out_file.name}')
else:
raise RuntimeError(f'{out_file} already exists. Choose a new name or enable '
'--force')
else:
# create any directories defined by the new filename if they don't already exist
out_file.parent.mkdir(parents=True, exist_ok=True)
print('Writing to:', out_file)
if verbosity.value >= 2:
print('Writing to:', out_file)

# open the file in write mode
with open(out_file, 'w', newline='') as f:
Expand Down Expand Up @@ -603,16 +613,18 @@ def _setup_F2A_parser(parser):
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Enable verbose print statements",
)
parser.add_argument(
"-vv",
"--very_verbose",
action="store_true",
help="Enable debug print statements",
"--verbosity",
type=Verbosity,
choices=list(Verbosity),
default=1,
help="Set level of print statements",
)
# parser.add_argument(
# "-vv",
# "--very_verbose",
# action="store_true",
# help="Enable debug print statements",
# )


def _exec_F2A(args, user_args):
Expand All @@ -621,12 +633,8 @@ def _exec_F2A(args, user_args):
args.input_deck = args.input_deck[0]
filepath = args.input_deck

if args.very_verbose is True:
verbosity = Verbosity.DEBUG
elif args.verbose is True:
verbosity = Verbosity.VERBOSE
else:
verbosity = Verbosity.BRIEF
# convert verbosity from number to enum
verbosity = Verbosity(args.verbosity)

create_aviary_deck(filepath, args.legacy_code, args.defaults_deck,
args.out_file, args.force, verbosity)
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from aviary.utils.functions import get_path
from openmdao.utils.testing_utils import use_tempdirs

from aviary.utils.Fortran_to_Aviary import LegacyCode, _exec_F2A
from aviary.utils.fortran_to_aviary import LegacyCode, _exec_F2A


class DummyArgs(object):
Expand All @@ -14,8 +14,7 @@ def __init__(self):
self.legacy_code = None
self.defaults_deck = False
self.force = False
self.verbose = False
self.very_verbose = False
self.verbosity = 1


@use_tempdirs
Expand Down
2 changes: 1 addition & 1 deletion aviary/utils/test/test_process_input_decks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from aviary.utils.functions import get_path


# @use_tempdirs
@use_tempdirs
class TestCreateVehicle(unittest.TestCase):

def test_load_aircraft_csv(self):
Expand Down
16 changes: 11 additions & 5 deletions aviary/utils/test_utils/variable_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,17 @@ def get_names_from_hierarchy(hierarchy):
keys = list(filter(filter_underscore, list(keys)))

for key in keys:
subclass_vars = vars(
getattr(hierarchy, key)
) # grab dictionary of variables for the subclass
# filter out keys that aren't for relevant variables
subclass_keys = list(filter(filter_underscore, list(subclass_vars.keys())))
try:
# If there are multiple hierarchy levels, dig down one more
subclass_vars = vars(
getattr(hierarchy, key)
) # grab dictionary of variables for the subclass
# filter out keys that aren't for relevant variables
subclass_keys = list(filter(filter_underscore, list(subclass_vars.keys())))
except TypeError:
# Only one hierarchy level
subclass_vars = vars(hierarchy)
subclass_keys = [key]

for var_name in subclass_keys:
names.append(
Expand Down
3 changes: 3 additions & 0 deletions aviary/variable_info/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,6 @@ class Verbosity(Enum):
BRIEF = 1
VERBOSE = 2
DEBUG = 3

def __str__(self):
return str(self.value)
37 changes: 34 additions & 3 deletions aviary/variable_info/test/test_var_structure.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import unittest

from copy import deepcopy

from aviary.utils.test_utils.variable_test import (
DuplicateHierarchy, assert_metadata_alphabetization, assert_no_duplicates,
assert_structure_alphabetization, get_names_from_hierarchy)
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, Dynamic, Settings


class MetaDataTest(unittest.TestCase):
Expand All @@ -26,12 +28,41 @@ def test_alphabetization(self):

assert_metadata_alphabetization(metadata_var_names)

def test_missing_names(self):
"""
Test that all variables inside the metadata exist in the hierarchy, and vice-versa
"""
# NOTE: This is messy due to the fact we are dealing with attributes inside nested classes
var_names = \
[(var_name, var) for cat_name, cat in Aircraft.__dict__.items() if not cat_name.startswith('__')
for var_name, var in cat.__dict__.items() if not var_name.startswith('__')]\
+ [(var_name, var) for cat_name, cat in Mission.__dict__.items() if not cat_name.startswith('__')
for var_name, var in cat.__dict__.items() if not var_name.startswith('__')]\
+ [(var_name, var) for cat_name, cat in Dynamic.__dict__.items() if not cat_name.startswith('__')
for var_name, var in cat.__dict__.items() if not var_name.startswith('__')]\
+ [(var_name, var) for var_name, var in Settings.__dict__.items()
if not var_name.startswith('__')]

metadata_dict = deepcopy(_MetaData)
for var in var_names:
try:
metadata_dict.pop(var[1])
except (TypeError, KeyError):
raise Exception(f"Variable {var[0]} ('{var[1]}') is present in variables.py but is not "
'defined in metadata')
if metadata_dict:
# This will only happen if a variable in the metadata wasn't using the hierarchy
raise Exception(f'Variables {[*metadata_dict.keys()]} are present in metadata, but are'
' not defined in variables.py')


class VariableStructureTest(unittest.TestCase):
def test_duplicate_names_Aviary(self):

aviary_names = get_names_from_hierarchy(
Aircraft) + get_names_from_hierarchy(Mission)
aviary_names = get_names_from_hierarchy(Aircraft)\
+ get_names_from_hierarchy(Mission)\
+ get_names_from_hierarchy(Dynamic)\
+ get_names_from_hierarchy(Settings)

assert_no_duplicates(aviary_names)

Expand Down
38 changes: 37 additions & 1 deletion aviary/variable_info/variable_meta_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6125,6 +6125,17 @@
desc='Current Mach number of the vehicle'
)

add_meta_data(
Dynamic.Mission.MACH_RATE,
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'
)

add_meta_data(
Dynamic.Mission.MASS,
meta_data=_MetaData,
Expand Down Expand Up @@ -6182,6 +6193,18 @@
default_value=500.0,
)

add_meta_data(
Dynamic.Mission.SPECIFIC_ENERGY,
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'
)

add_meta_data(
Dynamic.Mission.SPECIFIC_ENERGY_RATE,
meta_data=_MetaData,
Expand Down Expand Up @@ -6423,6 +6446,19 @@
'tolerance)',
)

add_meta_data(
Mission.Constraints.RANGE_RESIDUAL_RESERVE,
meta_data=_MetaData,
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)',
)

# _____ _
# | __ \ (_)
# | | | | ___ ___ _ __ _ _ __
Expand Down Expand Up @@ -7476,7 +7512,7 @@
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 avaliable informating is output, in human-readable format'
'2. VERBOSE: All avaliable information is output, in human-readable format'
'3. DEBUG: Intermediate status and calculation outputs, no formatting requirement',
option=True,
types=Verbosity,
Expand Down
3 changes: 2 additions & 1 deletion aviary/variable_info/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,8 @@ class Wing:
AVERAGE_CHORD = 'aircraft:wing:average_chord'
BENDING_FACTOR = 'aircraft:wing:bending_factor'
BENDING_MASS = 'aircraft:wing:bending_mass'
BENDING_MASS_NO_INERTIA = 'aircraft:wing:bending_mass_no_inertia'
# Not defined in metadata!
# BENDING_MASS_NO_INERTIA = 'aircraft:wing:bending_mass_no_inertia'
BENDING_MASS_SCALER = 'aircraft:wing:bending_mass_scaler'
BWB_AFTBODY_MASS = 'aircraft:wing:bwb_aft_body_mass'
BWB_AFTBODY_MASS_SCALER = 'aircraft:wing:bwb_aft_body_mass_scaler'
Expand Down
Loading