From d557225799a8a28bffc8a1063871dd3f37df6a90 Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:46:45 -0700 Subject: [PATCH 01/26] refactor: add legacy variable-name compatibility map --- aviary/variable_info/legacy_aliases.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 aviary/variable_info/legacy_aliases.py diff --git a/aviary/variable_info/legacy_aliases.py b/aviary/variable_info/legacy_aliases.py new file mode 100644 index 0000000000..9d45a1f5fc --- /dev/null +++ b/aviary/variable_info/legacy_aliases.py @@ -0,0 +1,15 @@ +"""Compatibility aliases for renamed Aviary variable keys. + +New code and generated data should always use canonical names. This map is +only for reading or accessing values that were written with an older Aviary +variable name. +""" + +LEGACY_VARIABLE_NAME_MAP = { + 'mission:constraints:max_mach': 'aircraft:design:max_mach', +} + + +def resolve_legacy_variable_name(name): + """Return the canonical name for a supported legacy Aviary variable.""" + return LEGACY_VARIABLE_NAME_MAP.get(name, name) From ee9f8c96807cbe700f62e49d87b12a2ea72209e3 Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:46:58 -0700 Subject: [PATCH 02/26] test: define MAX_MACH namespace migration contract --- .../test/test_max_mach_namespace.py | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 aviary/variable_info/test/test_max_mach_namespace.py diff --git a/aviary/variable_info/test/test_max_mach_namespace.py b/aviary/variable_info/test/test_max_mach_namespace.py new file mode 100644 index 0000000000..713f6039cd --- /dev/null +++ b/aviary/variable_info/test/test_max_mach_namespace.py @@ -0,0 +1,66 @@ +import tempfile +import unittest +from pathlib import Path + +from aviary.utils.aviary_values import AviaryValues +from aviary.utils.csv_data_file import read_data_file +from aviary.variable_info.legacy_aliases import LEGACY_VARIABLE_NAME_MAP, resolve_legacy_variable_name +from aviary.variable_info.variable_meta_data import CoreMetaData +from aviary.variable_info.variables import Aircraft, Mission + + +class MaxMachNamespaceTest(unittest.TestCase): + def test_canonical_namespace(self): + self.assertEqual(Aircraft.Design.MAX_MACH, 'aircraft:design:max_mach') + self.assertEqual(Mission.Constraints.MAX_MACH, Aircraft.Design.MAX_MACH) + self.assertIn(Aircraft.Design.MAX_MACH, CoreMetaData) + self.assertNotIn('mission:constraints:max_mach', CoreMetaData) + + def test_legacy_values_access_canonical_storage(self): + legacy = 'mission:constraints:max_mach' + self.assertEqual(resolve_legacy_variable_name(legacy), Aircraft.Design.MAX_MACH) + values = AviaryValues() + values.set_val(legacy, 0.86) + self.assertIn(legacy, values) + self.assertIn(Aircraft.Design.MAX_MACH, values) + self.assertEqual(values.get_val(legacy), 0.86) + self.assertEqual(values.get_val(Aircraft.Design.MAX_MACH), 0.86) + self.assertEqual(list(values.keys()), [Aircraft.Design.MAX_MACH]) + + def test_legacy_csv_header_is_normalized(self): + legacy = next(iter(LEGACY_VARIABLE_NAME_MAP)) + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / 'legacy.csv' + path.write_text(f'{legacy}\n0.84\n', encoding='utf-8') + data, _, _ = read_data_file(path, metadata=CoreMetaData) + self.assertIn(Aircraft.Design.MAX_MACH, data) + self.assertNotIn(legacy, data) + self.assertEqual(data.get_val(Aircraft.Design.MAX_MACH), 0.84) + + def test_no_unapproved_legacy_references(self): + root = Path(__file__).resolve().parents[3] + allowed = { + Path('aviary/variable_info/legacy_aliases.py'), + Path('aviary/variable_info/test/test_max_mach_namespace.py'), + Path('aviary/variable_info/migrations/max_mach_namespace_manifest.json'), + Path('tools/migrate_max_mach_namespace.py'), + } + suffixes = {'.py', '.csv', '.json', '.ipynb', '.md', '.rst', '.txt', '.toml', '.yaml', '.yml'} + failures = [] + for path in root.rglob('*'): + if not path.is_file() or path.suffix.lower() not in suffixes: + continue + rel = path.relative_to(root) + if rel in allowed or '.git' in rel.parts: + continue + try: + text = path.read_text(encoding='utf-8') + except UnicodeDecodeError: + continue + if 'Mission.Constraints.MAX_MACH' in text or 'mission:constraints:max_mach' in text: + failures.append(str(rel)) + self.assertEqual(failures, [], 'Legacy MAX_MACH references remain: ' + ', '.join(failures)) + + +if __name__ == '__main__': + unittest.main() From 3e7216324e86154373f92296146ea4b38b59f49b Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:47:25 -0700 Subject: [PATCH 03/26] tools: add deterministic MAX_MACH migration engine --- tools/migrate_max_mach_namespace.py | 208 ++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 tools/migrate_max_mach_namespace.py diff --git a/tools/migrate_max_mach_namespace.py b/tools/migrate_max_mach_namespace.py new file mode 100644 index 0000000000..997d23e17f --- /dev/null +++ b/tools/migrate_max_mach_namespace.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python3 +"""Apply and audit the repository-wide MAX_MACH namespace migration (#1046).""" + +import argparse +import json +import re +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +OLD_SYMBOL = 'Mission.Constraints.MAX_MACH' +NEW_SYMBOL = 'Aircraft.Design.MAX_MACH' +OLD_KEY = 'mission:constraints:max_mach' +NEW_KEY = 'aircraft:design:max_mach' +SUFFIXES = {'.py', '.csv', '.json', '.ipynb', '.md', '.rst', '.txt', '.toml', '.yaml', '.yml'} +SKIP = {'.git', '.venv', 'venv', 'build', 'dist', '__pycache__', '.pytest_cache'} +ALLOW = { + Path('tools/migrate_max_mach_namespace.py'), + Path('aviary/variable_info/legacy_aliases.py'), + Path('aviary/variable_info/test/test_max_mach_namespace.py'), + Path('aviary/variable_info/migrations/max_mach_namespace_manifest.json'), +} + + +def files(): + for path in ROOT.rglob('*'): + if path.is_file() and path.suffix.lower() in SUFFIXES: + rel = path.relative_to(ROOT) + if not any(part in SKIP for part in rel.parts): + yield rel + + +def patch_variables(text): + old = " MAX_MACH = 'mission:constraints:max_mach'\n" + alias = ( + ' # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH.\n' + ' MAX_MACH = Aircraft.Design.MAX_MACH\n' + ) + if old in text: + text = text.replace(old, alias, 1) + elif 'MAX_MACH = Aircraft.Design.MAX_MACH' not in text: + raise RuntimeError('Mission.Constraints.MAX_MACH definition not found') + + anchor = " MACH = 'aircraft:design:mach'\n" + canonical = " MAX_MACH = 'aircraft:design:max_mach'\n" + if canonical not in text: + if anchor not in text: + raise RuntimeError('Aircraft.Design.MACH anchor not found') + text = text.replace(anchor, anchor + canonical, 1) + return text + + +def patch_metadata(text): + start = text.find('add_meta_data(\n Aircraft.Design.MAX_MACH,') + if start < 0: + raise RuntimeError('MAX_MACH metadata block not found') + end = text.find('\n)\n', start) + if end < 0: + raise RuntimeError('MAX_MACH metadata block end not found') + block = text[start:end + 3] + desc = ( + " desc=(\n" + " 'Maximum aircraft design Mach number. Used by FLOPS-based air-conditioning, '\n" + " 'fuel-system, hydraulics, instruments, passenger-service, starter, and surface-'\n" + " 'control mass correlations, and by FLOPS pre-mission aerodynamics when computing '\n" + " 'the design lift coefficient.'\n" + " ),\n" + ) + pattern = re.compile(r" desc=.*?(?= [a-zA-Z_]+\s*=|\)\n)", re.S) + match = pattern.search(block) + if match: + block = block[:match.start()] + desc + block[match.end():] + else: + close = block.rfind(')\n') + block = block[:close] + desc + block[close:] + return text[:start] + block + text[end + 3:] + + +def patch_values(text): + marker = 'from aviary.variable_info.variable_meta_data import CoreMetaData\n' + imp = 'from aviary.variable_info.legacy_aliases import resolve_legacy_variable_name\n' + if imp not in text: + text = text.replace(marker, imp + marker, 1) + + marker = ' if key in meta_data:\n' + normalize = ' key = resolve_legacy_variable_name(key)\n\n' + if normalize + marker not in text: + text = text.replace(marker, normalize + marker, 1) + + marker = ' def _check_units_compatibility(self, key, val, units, meta_data=CoreMetaData):\n' + methods = ''' def get_item(self, key): + return super().get_item(resolve_legacy_variable_name(key)) + + def get_val(self, key, units='unitless'): + return super().get_val(resolve_legacy_variable_name(key), units) + + def delete(self, key): + return super().delete(resolve_legacy_variable_name(key)) + + def __contains__(self, key): + return super().__contains__(resolve_legacy_variable_name(key)) + +''' + if 'def get_item(self, key):' not in text: + if marker not in text: + raise RuntimeError('AviaryValues insertion point not found') + text = text.replace(marker, methods + marker, 1) + return text + + +def patch_csv(text): + marker = 'from aviary.variable_info.enums import Verbosity\n' + imp = 'from aviary.variable_info.legacy_aliases import resolve_legacy_variable_name\n' + if imp not in text: + text = text.replace(marker, marker + imp, 1) + marker = " name = re.sub('\\\\s', '_', item[0])\n" + add = marker + ' name = resolve_legacy_variable_name(name)\n' + if 'name = resolve_legacy_variable_name(name)' not in text: + if marker not in text: + raise RuntimeError('CSV header normalization point not found') + text = text.replace(marker, add, 1) + return text + + +def rewrite(rel, text): + if rel == Path('aviary/variable_info/variables.py'): + text = patch_variables(text) + if rel not in ALLOW: + text = text.replace(OLD_SYMBOL, NEW_SYMBOL).replace(OLD_KEY, NEW_KEY) + if rel == Path('aviary/variable_info/variable_meta_data.py'): + text = patch_metadata(text) + elif rel == Path('aviary/utils/aviary_values.py'): + text = patch_values(text) + elif rel == Path('aviary/utils/csv_data_file.py'): + text = patch_csv(text) + return text + + +def apply(): + changed = [] + counts = {'python_symbol': 0, 'serialized_key': 0} + for rel in list(files()): + path = ROOT / rel + try: + before = path.read_text(encoding='utf-8') + except UnicodeDecodeError: + continue + after = rewrite(rel, before) + if before != after: + counts['python_symbol'] += before.count(OLD_SYMBOL) + counts['serialized_key'] += before.count(OLD_KEY) + path.write_text(after, encoding='utf-8') + changed.append(str(rel)) + + manifest = { + 'issue': 'OpenMDAO/Aviary#1046', + 'canonical_symbol': NEW_SYMBOL, + 'canonical_key': NEW_KEY, + 'legacy_symbol': OLD_SYMBOL, + 'legacy_key': OLD_KEY, + 'changed_file_count': len(changed), + 'changed_files': sorted(changed), + 'replacement_counts': counts, + 'compatibility': { + 'python_symbol': 'Mission.Constraints.MAX_MACH aliases Aircraft.Design.MAX_MACH', + 'serialized_inputs': 'legacy raw names normalize before metadata validation/storage', + }, + } + out = ROOT / 'aviary/variable_info/migrations/max_mach_namespace_manifest.json' + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text(json.dumps(manifest, indent=2) + '\n', encoding='utf-8') + return changed, counts + + +def leftovers(): + found = [] + for rel in files(): + if rel in ALLOW: + continue + try: + text = (ROOT / rel).read_text(encoding='utf-8') + except UnicodeDecodeError: + continue + if OLD_SYMBOL in text or OLD_KEY in text: + found.append(str(rel)) + return found + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--write', action='store_true') + parser.add_argument('--check', action='store_true') + args = parser.parse_args() + if args.write: + changed, counts = apply() + print(f'Migrated {len(changed)} files: {counts}') + if args.check: + remain = leftovers() + if remain: + print('Legacy references remain:') + print('\n'.join(remain)) + raise SystemExit(1) + print('MAX_MACH namespace audit passed') + if not args.write and not args.check: + raise SystemExit('use --write and/or --check') + + +if __name__ == '__main__': + main() From c59aceca04f0448246678c90b9b8abec0ca38d6c Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:47:40 -0700 Subject: [PATCH 04/26] ci: apply repo-wide MAX_MACH migration --- .github/workflows/max-mach-migration.yml | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/max-mach-migration.yml diff --git a/.github/workflows/max-mach-migration.yml b/.github/workflows/max-mach-migration.yml new file mode 100644 index 0000000000..4e7b87eb5d --- /dev/null +++ b/.github/workflows/max-mach-migration.yml @@ -0,0 +1,40 @@ +name: Apply MAX_MACH namespace migration + +on: + push: + branches: + - refactor/aircraft-design-max-mach + +permissions: + contents: write + +jobs: + migrate: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: refactor/aircraft-design-max-mach + fetch-depth: 0 + + - name: Apply deterministic repository migration + run: | + python tools/migrate_max_mach_namespace.py --write --check + + - name: Static validation + run: | + python -m compileall -q aviary tools/migrate_max_mach_namespace.py + git diff --check + + - name: Commit generated migration + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + if git diff --cached --quiet; then + echo "Migration already applied" + else + git commit -m "refactor: migrate MAX_MACH to aircraft design namespace" + git push origin HEAD:refactor/aircraft-design-max-mach + fi From bed9411cb434fa290aeba5e425b93ceccdfde710 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 22 Aug 2026 01:47:53 +0000 Subject: [PATCH 05/26] refactor: migrate MAX_MACH to aircraft design namespace --- .../examples_unreviewed/modified_aircraft.csv | 2 +- .../fundamentals/aircraft_definition.ipynb | 4 +- .../test/sizing_results_for_test.json | 2 +- .../advanced_single_aisle_FLOPS.csv | 2 +- .../bwb300_baseline_FLOPS.csv | 2 +- .../blended_wing_body/bwb_detailed_FLOPS.csv | 2 +- .../blended_wing_body/bwb_simple_FLOPS.csv | 2 +- .../large_single_aisle_1_FLOPS.csv | 2 +- .../large_single_aisle_2_FLOPS.csv | 2 +- .../large_single_aisle_2_altwt_FLOPS.csv | 2 +- .../large_single_aisle_2_detailwing_FLOPS.csv | 2 +- .../minimum_single_aisle_FLOPS.csv | 2 +- .../flops_based/premission_aero.py | 6 +- .../flops_based/test/test_premission_aero.py | 8 +-- .../mass/flops_based/air_conditioning.py | 6 +- .../mass/flops_based/fuel_system.py | 6 +- .../subsystems/mass/flops_based/hydraulics.py | 6 +- .../mass/flops_based/instruments.py | 6 +- .../mass/flops_based/passenger_service.py | 6 +- aviary/subsystems/mass/flops_based/starter.py | 6 +- .../mass/flops_based/surface_controls.py | 6 +- .../mass/flops_based/test/test_fuel_system.py | 4 +- .../mass/flops_based/test/test_hydraulics.py | 6 +- .../mass/flops_based/test/test_instruments.py | 4 +- .../mass/flops_based/test/test_starter.py | 6 +- aviary/utils/aviary_values.py | 15 ++++ aviary/utils/csv_data_file.py | 2 + .../converter_test_BWB_detailed_FLOPS.csv | 2 +- .../data/converter_test_BWB_simple_FLOPS.csv | 2 +- ...erter_test_advanced_single_aisle_FLOPS.csv | 2 +- .../test_data/V3_bug_fixed_IO.py | 2 +- .../test_data/advanced_single_aisle_data.py | 2 +- .../test_data/bwb300_baseline_FLOPS_data.py | 2 +- .../test_data/bwb_detailed_FLOPS_data.py | 2 +- .../test_data/bwb_simple_FLOPS_data.py | 2 +- .../large_single_aisle_1_FLOPS_data.py | 2 +- .../large_single_aisle_2_FLOPS_data.py | 2 +- .../large_single_aisle_2_altwt_FLOPS_data.py | 2 +- ...ge_single_aisle_2_detailwing_FLOPS_data.py | 2 +- .../multi_engine_single_aisle_data.py | 2 +- .../test_models/aircraft_for_bench_FwFm.csv | 2 +- .../aircraft_for_bench_FwFm_with_electric.csv | 2 +- .../test_models/aircraft_for_bench_FwGm.csv | 2 +- .../test_models/aircraft_for_bench_GwFm.csv | 2 +- .../aircraft_for_bench_solved2dof.csv | 2 +- .../test_models/bwb_root_chord1.csv | 2 +- .../test_models/bwb_root_chord2.csv | 2 +- .../test_models/high_wing_single_aisle.csv | 2 +- .../max_mach_namespace_manifest.json | 68 +++++++++++++++++++ aviary/variable_info/variable_meta_data.py | 10 ++- aviary/variable_info/variables.py | 4 +- 51 files changed, 167 insertions(+), 76 deletions(-) create mode 100644 aviary/variable_info/migrations/max_mach_namespace_manifest.json diff --git a/aviary/docs/examples_unreviewed/modified_aircraft.csv b/aviary/docs/examples_unreviewed/modified_aircraft.csv index 6b01de0d7f..2666aac543 100644 --- a/aviary/docs/examples_unreviewed/modified_aircraft.csv +++ b/aviary/docs/examples_unreviewed/modified_aircraft.csv @@ -141,7 +141,7 @@ 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 +aircraft:design:max_mach,0.785,unitless aircraft:design:cruise_altitude,35000,ft aircraft:design:gross_mass,175400.0,lbm aircraft:design:range,3500,NM diff --git a/aviary/docs/user_guide/fundamentals/aircraft_definition.ipynb b/aviary/docs/user_guide/fundamentals/aircraft_definition.ipynb index bc62a003d0..14fbd81264 100644 --- a/aviary/docs/user_guide/fundamentals/aircraft_definition.ipynb +++ b/aviary/docs/user_guide/fundamentals/aircraft_definition.ipynb @@ -22,7 +22,7 @@ "glue_variable(get_variable_name(Aircraft.Fuselage.LENGTH), md_code=True)\n", "glue_variable(get_variable_name(Aircraft.Wing.AREA), md_code=True)\n", "\n", - "glue_variable(get_variable_name(Mission.Constraints.MAX_MACH), md_code=True)\n", + "glue_variable(get_variable_name(Aircraft.Design.MAX_MACH), md_code=True)\n", "glue_variable(get_variable_name(Aircraft.Design.GROSS_MASS), md_code=True)\n", "glue_variable(get_variable_name(Aircraft.Design.RANGE), md_code=True)\n", "\n", @@ -65,7 +65,7 @@ "```\n", "...\n", "```text\n", - "{glue:md}mission:constraints:max_mach, 0.785, unitless\n", + "{glue:md}aircraft:design:max_mach, 0.785, unitless\n", "{glue:md}aircraft:design:gross_mass, 130000, lbm\n", "{glue:md}aircraft:design:range, 1906, NM\n", "```\n", diff --git a/aviary/interface/test/sizing_results_for_test.json b/aviary/interface/test/sizing_results_for_test.json index 4b0b834dff..593d56791d 100644 --- a/aviary/interface/test/sizing_results_for_test.json +++ b/aviary/interface/test/sizing_results_for_test.json @@ -975,7 +975,7 @@ "" ], [ - "mission:constraints:max_mach", + "aircraft:design:max_mach", 0.785, "unitless", "" diff --git a/aviary/models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv b/aviary/models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv index 4d455ce6aa..8d44e53820 100644 --- a/aviary/models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv +++ b/aviary/models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv @@ -167,7 +167,7 @@ aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0,unitless aircraft:wing:wetted_area,2210.280228,ft**2 aircraft:wing:wetted_area_scaler,1,unitless -mission:constraints:max_mach,0.785,unitless +aircraft:design:max_mach,0.785,unitless aircraft:design:gross_mass,130000,lbm aircraft:design:range,3500,NM mission:landing:airport_altitude,0,ft diff --git a/aviary/models/aircraft/blended_wing_body/bwb300_baseline_FLOPS.csv b/aviary/models/aircraft/blended_wing_body/bwb300_baseline_FLOPS.csv index eca36bf7c9..3ae1cd72d6 100644 --- a/aviary/models/aircraft/blended_wing_body/bwb300_baseline_FLOPS.csv +++ b/aviary/models/aircraft/blended_wing_body/bwb300_baseline_FLOPS.csv @@ -174,7 +174,7 @@ aircraft:wing:thickness_to_chord_reference,0.0,unitless aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.0,unitless aircraft:wing:wetted_area_scaler,0.61,unitless -mission:constraints:max_mach,0.9,unitless +aircraft:design:max_mach,0.9,unitless aircraft:design:gross_mass,600000.0,lbm aircraft:design:range,7500.0,NM mission:landing:drag_coefficient_min,0.0,unitless diff --git a/aviary/models/aircraft/blended_wing_body/bwb_detailed_FLOPS.csv b/aviary/models/aircraft/blended_wing_body/bwb_detailed_FLOPS.csv index d699545e35..3351bc43a8 100644 --- a/aviary/models/aircraft/blended_wing_body/bwb_detailed_FLOPS.csv +++ b/aviary/models/aircraft/blended_wing_body/bwb_detailed_FLOPS.csv @@ -156,7 +156,7 @@ aircraft:wing:thickness_to_chord_distribution,0.15,0.1132,0.0928,0.0822,0.0764,0 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 -mission:constraints:max_mach,0.85,unitless +aircraft:design:max_mach,0.85,unitless aircraft:design:gross_mass,874099,lbm aircraft:design:range,7750,NM mission:landing:initial_velocity,140,ft/s diff --git a/aviary/models/aircraft/blended_wing_body/bwb_simple_FLOPS.csv b/aviary/models/aircraft/blended_wing_body/bwb_simple_FLOPS.csv index 4a4468839d..a788fea1cc 100644 --- a/aviary/models/aircraft/blended_wing_body/bwb_simple_FLOPS.csv +++ b/aviary/models/aircraft/blended_wing_body/bwb_simple_FLOPS.csv @@ -156,7 +156,7 @@ aircraft:wing:thickness_to_chord_reference,0.11,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 -mission:constraints:max_mach,0.85,unitless +aircraft:design:max_mach,0.85,unitless aircraft:design:gross_mass,874099,lbm aircraft:design:range,7750,NM mission:landing:initial_velocity,140,ft/s diff --git a/aviary/models/aircraft/large_single_aisle_1/large_single_aisle_1_FLOPS.csv b/aviary/models/aircraft/large_single_aisle_1/large_single_aisle_1_FLOPS.csv index f20015090b..76fbf800dd 100644 --- a/aviary/models/aircraft/large_single_aisle_1/large_single_aisle_1_FLOPS.csv +++ b/aviary/models/aircraft/large_single_aisle_1/large_single_aisle_1_FLOPS.csv @@ -152,7 +152,7 @@ aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.0,unitless aircraft:wing:wetted_area,2396.56,ft**2 aircraft:wing:wetted_area_scaler,1.0,unitless -mission:constraints:max_mach,0.785,unitless +aircraft:design:max_mach,0.785,unitless mission:landing:lift_coefficient_max,3.0,unitless mission:takeoff:fuel_mass,577.0,lbm mission:takeoff:lift_coefficient_max,2.0,unitless diff --git a/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_FLOPS.csv b/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_FLOPS.csv index deb7e2509b..7a8ed2ed91 100644 --- a/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_FLOPS.csv +++ b/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_FLOPS.csv @@ -148,7 +148,7 @@ aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.0,unitless aircraft:wing:wetted_area,2423.02,ft**2 aircraft:wing:wetted_area_scaler,1.0,unitless -mission:constraints:max_mach,0.82,unitless +aircraft:design:max_mach,0.82,unitless mission:landing:lift_coefficient_max,3.0,unitless mission:takeoff:fuel_mass,659.0,lbm mission:takeoff:lift_coefficient_max,2.0,unitless diff --git a/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS.csv b/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS.csv index cd3b6277fc..c160e6a05e 100644 --- a/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS.csv +++ b/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS.csv @@ -146,7 +146,7 @@ aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.0,unitless aircraft:wing:wetted_area,2423.02,ft**2 aircraft:wing:wetted_area_scaler,1.0,unitless -mission:constraints:max_mach,0.82,unitless +aircraft:design:max_mach,0.82,unitless mission:landing:lift_coefficient_max,3.0,unitless mission:takeoff:fuel_mass,659.0,lbm mission:takeoff:lift_coefficient_max,2.0,unitless diff --git a/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS.csv b/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS.csv index 9dd350909d..bad5a003b7 100644 --- a/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS.csv +++ b/aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS.csv @@ -148,7 +148,7 @@ aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.0,unitless aircraft:wing:wetted_area,2423.02,ft**2 aircraft:wing:wetted_area_scaler,1.0,unitless -mission:constraints:max_mach,0.82,unitless +aircraft:design:max_mach,0.82,unitless mission:landing:lift_coefficient_max,3.0,unitless mission:takeoff:fuel_mass,577.0,lbm mission:takeoff:lift_coefficient_max,2.0,unitless diff --git a/aviary/models/aircraft/minimum_single_aisle/minimum_single_aisle_FLOPS.csv b/aviary/models/aircraft/minimum_single_aisle/minimum_single_aisle_FLOPS.csv index f102ec1ca0..c6787a9d1a 100644 --- a/aviary/models/aircraft/minimum_single_aisle/minimum_single_aisle_FLOPS.csv +++ b/aviary/models/aircraft/minimum_single_aisle/minimum_single_aisle_FLOPS.csv @@ -49,7 +49,7 @@ aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:hydraulics:system_pressure,5000,psi # Design mission -mission:constraints:max_mach,0.785,unitless +aircraft:design:max_mach,0.785,unitless aircraft:design:gross_mass,130000,lbm aircraft:design:range,1906,NM aircraft:design:cruise_mach,0.72,unitless diff --git a/aviary/subsystems/aerodynamics/flops_based/premission_aero.py b/aviary/subsystems/aerodynamics/flops_based/premission_aero.py index 9cefa7a0d8..1d87ae02ce 100644 --- a/aviary/subsystems/aerodynamics/flops_based/premission_aero.py +++ b/aviary/subsystems/aerodynamics/flops_based/premission_aero.py @@ -27,7 +27,7 @@ def __init__(self, **kwargs): def initialize(self): add_aviary_option(self, Aircraft.Wing.AIRFOIL_TECHNOLOGY) - add_aviary_option(self, Mission.Constraints.MAX_MACH) + add_aviary_option(self, Aircraft.Design.MAX_MACH) def setup(self): # Aircraft design inputs @@ -45,7 +45,7 @@ def setup_partials(self): def compute(self, inputs, outputs): AITEK = self.options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] - VMAX = self.options[Mission.Constraints.MAX_MACH] + VMAX = self.options[Aircraft.Design.MAX_MACH] AR, CAM, SW25, TC = inputs.values() @@ -87,7 +87,7 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, partials): AITEK = self.options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] - VMAX = self.options[Mission.Constraints.MAX_MACH] + VMAX = self.options[Aircraft.Design.MAX_MACH] AR, CAM, SW25, TC = inputs.values() diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_premission_aero.py b/aviary/subsystems/aerodynamics/flops_based/test/test_premission_aero.py index c85d98dd04..687ed2c4c2 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_premission_aero.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_premission_aero.py @@ -18,7 +18,7 @@ def test_derivs_supersonic1(self): options = {} options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = 1.0 - options[Mission.Constraints.MAX_MACH] = 1.2 + options[Aircraft.Design.MAX_MACH] = 1.2 model.add_subsystem( 'design', @@ -49,7 +49,7 @@ def test_derivs_subsonic1(self): options = {} options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = 1.0 - options[Mission.Constraints.MAX_MACH] = 0.9 + options[Aircraft.Design.MAX_MACH] = 0.9 model.add_subsystem( 'design', @@ -80,7 +80,7 @@ def test_derivs_supersonic2(self): options = {} options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = 1.0 - options[Mission.Constraints.MAX_MACH] = 1.2 + options[Aircraft.Design.MAX_MACH] = 1.2 model.add_subsystem( 'design', @@ -111,7 +111,7 @@ def test_derivs_subsonic2(self): options = {} options[Aircraft.Wing.AIRFOIL_TECHNOLOGY] = 1.0 - options[Mission.Constraints.MAX_MACH] = 0.9 + options[Aircraft.Design.MAX_MACH] = 0.9 model.add_subsystem( 'design', diff --git a/aviary/subsystems/mass/flops_based/air_conditioning.py b/aviary/subsystems/mass/flops_based/air_conditioning.py index c394edbec0..7340a2c410 100644 --- a/aviary/subsystems/mass/flops_based/air_conditioning.py +++ b/aviary/subsystems/mass/flops_based/air_conditioning.py @@ -14,7 +14,7 @@ class TransportAirCondMass(om.ExplicitComponent): def initialize(self): add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) - add_aviary_option(self, Mission.Constraints.MAX_MACH) + add_aviary_option(self, Aircraft.Design.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.AirConditioning.MASS_SCALER, units='unitless') @@ -34,7 +34,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): avionics_wt = inputs[Aircraft.Avionics.MASS] * GRAV_ENGLISH_LBM height = inputs[Aircraft.Fuselage.MAX_HEIGHT] planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] outputs[Aircraft.AirConditioning.MASS] = ( ((3.2 * (planform * height) ** 0.6 + 9 * pax**0.83) * max_mach + 0.075 * avionics_wt) @@ -49,7 +49,7 @@ def compute_partials(self, inputs, J): avionics_wt = inputs[Aircraft.Avionics.MASS] * GRAV_ENGLISH_LBM height = inputs[Aircraft.Fuselage.MAX_HEIGHT] planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] planform_exp = planform**0.6 height_exp = height**0.6 diff --git a/aviary/subsystems/mass/flops_based/fuel_system.py b/aviary/subsystems/mass/flops_based/fuel_system.py index 5e37d5b559..8dccb43b5d 100644 --- a/aviary/subsystems/mass/flops_based/fuel_system.py +++ b/aviary/subsystems/mass/flops_based/fuel_system.py @@ -15,7 +15,7 @@ class TransportFuelSystemMass(om.ExplicitComponent): def initialize(self): add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_ENGINES) - add_aviary_option(self, Mission.Constraints.MAX_MACH) + add_aviary_option(self, Aircraft.Design.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, units='unitless') @@ -31,7 +31,7 @@ def compute(self, inputs, outputs): capacity = inputs[Aircraft.Fuel.MAX_CAPACITY_MASS] num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_eng_fact = distributed_engine_count_factor(num_eng) - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] outputs[Aircraft.Fuel.FUEL_SYSTEM_MASS] = ( 1.07 * capacity**0.58 * num_eng_fact**0.43 * max_mach**0.34 * scaler @@ -42,7 +42,7 @@ def compute_partials(self, inputs, J): capacity = inputs[Aircraft.Fuel.MAX_CAPACITY_MASS] num_eng = self.options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] num_eng_fact = distributed_engine_count_factor(num_eng) - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.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 diff --git a/aviary/subsystems/mass/flops_based/hydraulics.py b/aviary/subsystems/mass/flops_based/hydraulics.py index 2b312ee93f..bbd6eac1a8 100644 --- a/aviary/subsystems/mass/flops_based/hydraulics.py +++ b/aviary/subsystems/mass/flops_based/hydraulics.py @@ -18,7 +18,7 @@ class TransportHydraulicsGroupMass(om.ExplicitComponent): def initialize(self): 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) + add_aviary_option(self, Aircraft.Design.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.Fuselage.PLANFORM_AREA, units='ft**2') @@ -43,7 +43,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 = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] if sys_press <= 0: # No hydraulic system (e.g. small electric UAVs): nothing to size. @@ -72,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 = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] term1 = planform + 0.27 * area term2 = 1.0 + 0.03 * num_wing_eng_fact + 0.05 * num_fuse_eng_fact diff --git a/aviary/subsystems/mass/flops_based/instruments.py b/aviary/subsystems/mass/flops_based/instruments.py index 874e46870d..0b5d920214 100644 --- a/aviary/subsystems/mass/flops_based/instruments.py +++ b/aviary/subsystems/mass/flops_based/instruments.py @@ -19,7 +19,7 @@ def initialize(self): 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) + add_aviary_option(self, Aircraft.Design.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.Fuselage.PLANFORM_AREA, units='ft**2') @@ -37,7 +37,7 @@ def compute(self, inputs, outputs): num_fuse_eng_fact = distributed_engine_count_factor(num_fuse_eng) fuse_area = inputs[Aircraft.Fuselage.PLANFORM_AREA] - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] mass_scaler = inputs[Aircraft.Instruments.MASS_SCALER] instrument_weight = ( @@ -57,7 +57,7 @@ def compute_partials(self, inputs, J): num_fuse_eng_fact = distributed_engine_count_factor(num_fuse_eng) fuse_area = inputs[Aircraft.Fuselage.PLANFORM_AREA] - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.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/passenger_service.py b/aviary/subsystems/mass/flops_based/passenger_service.py index ec6da58967..5b0b65416d 100644 --- a/aviary/subsystems/mass/flops_based/passenger_service.py +++ b/aviary/subsystems/mass/flops_based/passenger_service.py @@ -21,7 +21,7 @@ def initialize(self): 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_ECONOMY_CLASS) - add_aviary_option(self, Mission.Constraints.MAX_MACH) + add_aviary_option(self, Aircraft.Design.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER, units='unitless') @@ -38,7 +38,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): economy_class_count = self.options[Aircraft.CrewPayload.Design.NUM_ECONOMY_CLASS] design_range = inputs[Aircraft.Design.RANGE] - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] passenger_service_mass_scaler = inputs[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER] @@ -57,7 +57,7 @@ def compute_partials(self, inputs, J, discrete_inputs=None): economy_class_count = self.options[Aircraft.CrewPayload.Design.NUM_ECONOMY_CLASS] design_range = inputs[Aircraft.Design.RANGE] - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] passenger_service_mass_scaler = inputs[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER] diff --git a/aviary/subsystems/mass/flops_based/starter.py b/aviary/subsystems/mass/flops_based/starter.py index 7def8a54de..8824d17807 100644 --- a/aviary/subsystems/mass/flops_based/starter.py +++ b/aviary/subsystems/mass/flops_based/starter.py @@ -21,7 +21,7 @@ class TransportStarterMass(om.ExplicitComponent): def initialize(self): 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) + add_aviary_option(self, Aircraft.Design.MAX_MACH) def setup(self): num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) @@ -39,7 +39,7 @@ def setup_partials(self): def compute(self, inputs, outputs): 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] + max_mach = self.options[Aircraft.Design.MAX_MACH] d_nacelle = inputs[Aircraft.Nacelle.AVG_DIAMETER] num_engines_factor = distributed_engine_count_factor(total_engines) @@ -57,7 +57,7 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): 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] + max_mach = self.options[Aircraft.Design.MAX_MACH] d_nacelle = inputs[Aircraft.Nacelle.AVG_DIAMETER] eng_count_factor = distributed_engine_count_factor(total_engines) diff --git a/aviary/subsystems/mass/flops_based/surface_controls.py b/aviary/subsystems/mass/flops_based/surface_controls.py index d6d0f7acbf..8471b224e9 100644 --- a/aviary/subsystems/mass/flops_based/surface_controls.py +++ b/aviary/subsystems/mass/flops_based/surface_controls.py @@ -12,7 +12,7 @@ class SurfaceControlMass(om.ExplicitComponent): """ def initialize(self): - add_aviary_option(self, Mission.Constraints.MAX_MACH) + add_aviary_option(self, Aircraft.Design.MAX_MACH) def setup(self): add_aviary_input(self, Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, units='unitless') @@ -31,7 +31,7 @@ def setup(self): def compute(self, inputs, outputs): scaler = inputs[Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER] - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] gross_weight = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM flap_ratio = inputs[Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO] wing_area = inputs[Aircraft.Wing.AREA] @@ -48,7 +48,7 @@ def compute(self, inputs, outputs): def compute_partials(self, inputs, J): scaler = inputs[Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER] - max_mach = self.options[Mission.Constraints.MAX_MACH] + max_mach = self.options[Aircraft.Design.MAX_MACH] gross_weight = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM flap_ratio = inputs[Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO] wing_area = inputs[Aircraft.Wing.AREA] 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 15cf34f1ad..8ffa34f052 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fuel_system.py +++ b/aviary/subsystems/mass/flops_based/test/test_fuel_system.py @@ -107,7 +107,7 @@ def test_case(self, case_name): Aircraft.Propulsion.TOTAL_NUM_ENGINES: inputs.get_val( Aircraft.Propulsion.TOTAL_NUM_ENGINES ), - Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + Aircraft.Design.MAX_MACH: inputs.get_val(Aircraft.Design.MAX_MACH), } prob.model.add_subsystem( @@ -155,7 +155,7 @@ def test_case(self): Aircraft.Propulsion.TOTAL_NUM_ENGINES: inputs.get_val( Aircraft.Propulsion.TOTAL_NUM_ENGINES ), - Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + Aircraft.Design.MAX_MACH: inputs.get_val(Aircraft.Design.MAX_MACH), } prob.model.add_subsystem( diff --git a/aviary/subsystems/mass/flops_based/test/test_hydraulics.py b/aviary/subsystems/mass/flops_based/test/test_hydraulics.py index 3c1f25239f..7411140825 100644 --- a/aviary/subsystems/mass/flops_based/test/test_hydraulics.py +++ b/aviary/subsystems/mass/flops_based/test/test_hydraulics.py @@ -42,7 +42,7 @@ def test_case(self, case_name): 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), + Aircraft.Design.MAX_MACH: inputs.get_val(Aircraft.Design.MAX_MACH), } prob.model.add_subsystem( @@ -99,7 +99,7 @@ def test_case(self): 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), + Aircraft.Design.MAX_MACH: inputs.get_val(Aircraft.Design.MAX_MACH), } prob.model.add_subsystem( @@ -201,7 +201,7 @@ def testsdg_case(self, case_name): 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), + Aircraft.Design.MAX_MACH: inputs.get_val(Aircraft.Design.MAX_MACH), } prob.model.add_subsystem( diff --git a/aviary/subsystems/mass/flops_based/test/test_instruments.py b/aviary/subsystems/mass/flops_based/test/test_instruments.py index 4304bb0ff5..bc2d12df24 100644 --- a/aviary/subsystems/mass/flops_based/test/test_instruments.py +++ b/aviary/subsystems/mass/flops_based/test/test_instruments.py @@ -38,7 +38,7 @@ def test_case(self, case_name): 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), + Aircraft.Design.MAX_MACH: inputs.get_val(Aircraft.Design.MAX_MACH), } prob.model.add_subsystem( @@ -94,7 +94,7 @@ def test_case(self): 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), + Aircraft.Design.MAX_MACH: inputs.get_val(Aircraft.Design.MAX_MACH), } prob.model.add_subsystem( diff --git a/aviary/subsystems/mass/flops_based/test/test_starter.py b/aviary/subsystems/mass/flops_based/test/test_starter.py index 03965d3393..bba89eaa90 100644 --- a/aviary/subsystems/mass/flops_based/test/test_starter.py +++ b/aviary/subsystems/mass/flops_based/test/test_starter.py @@ -57,7 +57,7 @@ def test_case_2(self): options = { Aircraft.Engine.NUM_ENGINES: np.array([5]), Aircraft.Propulsion.TOTAL_NUM_ENGINES: 5, - Mission.Constraints.MAX_MACH: 0.785, + Aircraft.Design.MAX_MACH: 0.785, } prob.model.add_subsystem( @@ -105,7 +105,7 @@ def test_case_2(self): options = { Aircraft.Engine.NUM_ENGINES: np.array([5]), Aircraft.Propulsion.TOTAL_NUM_ENGINES: 5, - Mission.Constraints.MAX_MACH: 0.785, + Aircraft.Design.MAX_MACH: 0.785, } prob.model.add_subsystem( @@ -118,7 +118,7 @@ def test_case_2(self): prob.model_options['*'] = get_flops_options('AdvancedSingleAisle', preprocess=True) prob.model_options[Aircraft.Engine.NUM_ENGINES] = np.array([5]) prob.model_options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] = 5 - prob.model_options[Mission.Constraints.MAX_MACH] = 0.875 + prob.model_options[Aircraft.Design.MAX_MACH] = 0.875 prob.setup(check=False, force_alloc_complex=True) prob.set_val(Aircraft.Nacelle.AVG_DIAMETER, np.array([7.94]), 'ft') diff --git a/aviary/utils/aviary_values.py b/aviary/utils/aviary_values.py index 67d3d005b9..f315555231 100644 --- a/aviary/utils/aviary_values.py +++ b/aviary/utils/aviary_values.py @@ -21,6 +21,7 @@ class AviaryValues from aviary.utils.named_values import NamedValues from aviary.utils.utils import cast_type, check_type +from aviary.variable_info.legacy_aliases import resolve_legacy_variable_name from aviary.variable_info.variable_meta_data import CoreMetaData @@ -47,6 +48,8 @@ def set_val(self, key, val, units='unitless', meta_data=CoreMetaData): TypeError if units of `None` were specified or units of any type other than `str` """ + key = resolve_legacy_variable_name(key) + if key in meta_data: val = cast_type(key, val, meta_data) check_type(key, val, meta_data) @@ -55,6 +58,18 @@ def set_val(self, key, val, units='unitless', meta_data=CoreMetaData): super().set_val(key=key, val=val, units=units) + def get_item(self, key): + return super().get_item(resolve_legacy_variable_name(key)) + + def get_val(self, key, units='unitless'): + return super().get_val(resolve_legacy_variable_name(key), units) + + def delete(self, key): + return super().delete(resolve_legacy_variable_name(key)) + + def __contains__(self, key): + return super().__contains__(resolve_legacy_variable_name(key)) + def _check_units_compatibility(self, key, val, units, meta_data=CoreMetaData): """ Check that the two provided units are compatible - we don't actually want to convert here, diff --git a/aviary/utils/csv_data_file.py b/aviary/utils/csv_data_file.py index 4498bbe26c..abcbbf6b02 100644 --- a/aviary/utils/csv_data_file.py +++ b/aviary/utils/csv_data_file.py @@ -10,6 +10,7 @@ from aviary.utils.functions import get_path from aviary.utils.named_values import NamedValues from aviary.variable_info.enums import Verbosity +from aviary.variable_info.legacy_aliases import resolve_legacy_variable_name # multiple type annotation uses "typeA | typeB" syntax, but requires Python 3.10+ @@ -109,6 +110,7 @@ def read_data_file( item = [item[i].strip(') ') for i in range(len(item))] # OpenMDAO vars can't have spaces, convert to underscores name = re.sub('\\s', '_', item[0]) + name = resolve_legacy_variable_name(name) if aliases: # "reverse" lookup name in alias dict for key in aliases: diff --git a/aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv b/aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv index a5d032e461..21ea0cc808 100644 --- a/aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv +++ b/aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv @@ -89,7 +89,7 @@ aircraft:wing:thickness_to_chord,0.11,unitless aircraft:wing:thickness_to_chord_distribution,-1.0,0.15,0.1132,0.0928,0.0822,0.0764,0.0742,0.0746,0.0758,0.0758,0.0756,0.0756,0.0758,0.076,0.076,unitless aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0,unitless -mission:constraints:max_mach,0.85,unitless +aircraft:design:max_mach,0.85,unitless mission:landing:lift_coefficient_max,3.0,unitless mission:takeoff:braking_friction_coefficient,0.3,unitless mission:takeoff:rolling_friction_coefficient,0.025,unitless diff --git a/aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv b/aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv index 5da1a02068..9dbb7ae955 100644 --- a/aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv +++ b/aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv @@ -88,7 +88,7 @@ aircraft:wing:taper_ratio,0.311,unitless aircraft:wing:thickness_to_chord,0.11,unitless aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0,unitless -mission:constraints:max_mach,0.85,unitless +aircraft:design:max_mach,0.85,unitless mission:landing:lift_coefficient_max,3.0,unitless mission:takeoff:braking_friction_coefficient,0.3,unitless mission:takeoff:rolling_friction_coefficient,0.025,unitless diff --git a/aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv b/aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv index 9bb9ab3995..3931a6ef1d 100644 --- a/aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv +++ b/aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv @@ -152,7 +152,7 @@ aircraft:wing:thickness_to_chord_reference,0.116565,unitless aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.0,unitless aircraft:wing:wetted_area,2210.280228,ft**2 -mission:constraints:max_mach,0.785,unitless +aircraft:design:max_mach,0.785,unitless mission:landing:drag_coefficient_min,0.045,unitless mission:landing:flare_rate,2.2,deg/s mission:landing:lift_coefficient_max,2.5,unitless diff --git a/aviary/validation_cases/validation_data/test_data/V3_bug_fixed_IO.py b/aviary/validation_cases/validation_data/test_data/V3_bug_fixed_IO.py index a93696124f..8ac1787d04 100644 --- a/aviary/validation_cases/validation_data/test_data/V3_bug_fixed_IO.py +++ b/aviary/validation_cases/validation_data/test_data/V3_bug_fixed_IO.py @@ -106,7 +106,7 @@ def local_get_option_defaults() -> AviaryValues: option_defaults.set_val(Aircraft.Wing.NUM_FLAP_SEGMENTS, 2, units='unitless') option_defaults.set_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS, 50, units='unitless') option_defaults.set_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, False, units='unitless') - option_defaults.set_val(Mission.Constraints.MAX_MACH, 0.0, units='unitless') + option_defaults.set_val(Aircraft.Design.MAX_MACH, 0.0, units='unitless') option_defaults.set_val(Mission.GRAVITY, 9.80665, units='m/s**2') option_defaults.set_val(Mission.RESERVE_FUEL_MARGIN, 0.0, units='unitless') option_defaults.set_val(Mission.RESERVE_FUEL_MASS_ADDITIONAL, 0.0, units='lbm') diff --git a/aviary/validation_cases/validation_data/test_data/advanced_single_aisle_data.py b/aviary/validation_cases/validation_data/test_data/advanced_single_aisle_data.py index 2c7f688332..741c698b93 100644 --- a/aviary/validation_cases/validation_data/test_data/advanced_single_aisle_data.py +++ b/aviary/validation_cases/validation_data/test_data/advanced_single_aisle_data.py @@ -295,7 +295,7 @@ # --------------------------- inputs.set_val(Aircraft.Design.CRUISE_MACH, 0.785) inputs.set_val(Aircraft.Design.RANGE, 3500, 'NM') -inputs.set_val(Mission.Constraints.MAX_MACH, 0.785) +inputs.set_val(Aircraft.Design.MAX_MACH, 0.785) inputs.set_val(Mission.Landing.DRAG_COEFFICIENT_MIN, 0.045, 'unitless') inputs.set_val(Mission.Landing.LIFT_COEFFICIENT_MAX, 2.0, 'unitless') inputs.set_val(Mission.Takeoff.AIRPORT_ALTITUDE, 0.0, 'ft') diff --git a/aviary/validation_cases/validation_data/test_data/bwb300_baseline_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/bwb300_baseline_FLOPS_data.py index 3ecc60c156..296c4e47e5 100644 --- a/aviary/validation_cases/validation_data/test_data/bwb300_baseline_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/bwb300_baseline_FLOPS_data.py @@ -266,7 +266,7 @@ # --------------------------- inputs.set_val(Aircraft.Design.CRUISE_MACH, 0.85) # VCMN inputs.set_val(Aircraft.Design.RANGE, 7500.0, 'NM') # DESRNG -inputs.set_val(Mission.Constraints.MAX_MACH, 0.9) # VMMO +inputs.set_val(Aircraft.Design.MAX_MACH, 0.9) # VMMO inputs.set_val(Mission.Landing.LIFT_COEFFICIENT_MAX, 3.0) # CLLDM inputs.set_val(Mission.Takeoff.LIFT_COEFFICIENT_MAX, 1.3) # CLTOM diff --git a/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py index c8c16f9180..93f79b66b4 100644 --- a/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py @@ -273,7 +273,7 @@ # --------------------------- inputs.set_val(Aircraft.Design.CRUISE_MACH, 0.85) # VCMN inputs.set_val(Aircraft.Design.RANGE, 7750.0, 'NM') # DESRNG -inputs.set_val(Mission.Constraints.MAX_MACH, 0.85) # VMMO +inputs.set_val(Aircraft.Design.MAX_MACH, 0.85) # VMMO # inputs.set_val(Mission.Takeoff.FUEL, 577, 'lbm') # FTKOFL inputs.set_val(Mission.Landing.LIFT_COEFFICIENT_MAX, 3.0) # CLLDM diff --git a/aviary/validation_cases/validation_data/test_data/bwb_simple_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/bwb_simple_FLOPS_data.py index 8f0b71a6c2..e0431349fa 100644 --- a/aviary/validation_cases/validation_data/test_data/bwb_simple_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/bwb_simple_FLOPS_data.py @@ -225,7 +225,7 @@ # --------------------------- inputs.set_val(Aircraft.Design.CRUISE_MACH, 0.85) # VCMN inputs.set_val(Aircraft.Design.RANGE, 7750.0, 'NM') # DESRNG -inputs.set_val(Mission.Constraints.MAX_MACH, 0.85) # VMMO +inputs.set_val(Aircraft.Design.MAX_MACH, 0.85) # VMMO # inputs.set_val(Mission.Takeoff.FUEL, 577, 'lbm') # FTKOFL inputs.set_val(Mission.Landing.LIFT_COEFFICIENT_MAX, 3.0) # CLLDM diff --git a/aviary/validation_cases/validation_data/test_data/large_single_aisle_1_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/large_single_aisle_1_FLOPS_data.py index 9b8de67707..86e6d370a9 100644 --- a/aviary/validation_cases/validation_data/test_data/large_single_aisle_1_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/large_single_aisle_1_FLOPS_data.py @@ -229,7 +229,7 @@ # --------------------------- inputs.set_val(Aircraft.Design.CRUISE_MACH, 0.785) inputs.set_val(Aircraft.Design.RANGE, 3500, 'NM') -inputs.set_val(Mission.Constraints.MAX_MACH, 0.785) +inputs.set_val(Aircraft.Design.MAX_MACH, 0.785) # TODO investigate the origin of these values (taken from benchmark tests) # TODO: where should this get connected from? inputs.set_val(Mission.Takeoff.FUEL_MASS, 577, 'lbm') diff --git a/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_FLOPS_data.py index 44ca8ce8c8..bed99c85a7 100644 --- a/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_FLOPS_data.py @@ -230,7 +230,7 @@ # --------------------------- inputs.set_val(Aircraft.Design.CRUISE_MACH, 0.785) inputs.set_val(Aircraft.Design.RANGE, 2960.0, 'NM') -inputs.set_val(Mission.Constraints.MAX_MACH, 0.82) +inputs.set_val(Aircraft.Design.MAX_MACH, 0.82) # TODO investigate the origin of these values (taken from benchmark tests) # TODO: where should this get connected from? inputs.set_val(Mission.Takeoff.FUEL_MASS, 659, 'lbm') diff --git a/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_altwt_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_altwt_FLOPS_data.py index 22f39893fe..b49978ce73 100644 --- a/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_altwt_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_altwt_FLOPS_data.py @@ -230,7 +230,7 @@ # --------------------------- inputs.set_val(Aircraft.Design.CRUISE_MACH, 0.785) inputs.set_val(Aircraft.Design.RANGE, 2960.0, 'NM') -inputs.set_val(Mission.Constraints.MAX_MACH, 0.82) +inputs.set_val(Aircraft.Design.MAX_MACH, 0.82) # TODO investigate the origin of these values (taken from benchmark tests) # TODO: where should this get connected from? inputs.set_val(Mission.Takeoff.FUEL_MASS, 659, 'lbm') diff --git a/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_detailwing_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_detailwing_FLOPS_data.py index 7cb2f1f50c..f92173b07e 100644 --- a/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_detailwing_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/large_single_aisle_2_detailwing_FLOPS_data.py @@ -225,7 +225,7 @@ # --------------------------- inputs.set_val(Aircraft.Design.CRUISE_MACH, 0.785) # was 0.82 inputs.set_val(Aircraft.Design.RANGE, 2960.0, 'NM') -inputs.set_val(Mission.Constraints.MAX_MACH, 0.82) +inputs.set_val(Aircraft.Design.MAX_MACH, 0.82) # TODO investigate the origin of these values (taken from benchmark tests) # TODO: where should this get connected from? inputs.set_val(Mission.Takeoff.FUEL_MASS, 577, 'lbm') diff --git a/aviary/validation_cases/validation_data/test_data/multi_engine_single_aisle_data.py b/aviary/validation_cases/validation_data/test_data/multi_engine_single_aisle_data.py index 2829336bf3..80b79c09a4 100644 --- a/aviary/validation_cases/validation_data/test_data/multi_engine_single_aisle_data.py +++ b/aviary/validation_cases/validation_data/test_data/multi_engine_single_aisle_data.py @@ -260,7 +260,7 @@ # --------------------------- inputs.set_val(Aircraft.Design.CRUISE_MACH, 0.785) # was 0.82 inputs.set_val(Aircraft.Design.RANGE, 2960.0, 'NM') -inputs.set_val(Mission.Constraints.MAX_MACH, 0.82) +inputs.set_val(Aircraft.Design.MAX_MACH, 0.82) # TODO investigate the origin of these values (taken from benchmark tests) # TODO: where should this get connected from? inputs.set_val(Mission.Takeoff.FUEL_MASS, 577, 'lbm') diff --git a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm.csv b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm.csv index b482febfd9..16993860c8 100644 --- a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm.csv +++ b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm.csv @@ -141,7 +141,7 @@ 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 +aircraft:design:max_mach,0.785,unitless aircraft:design:cruise_altitude,35000,ft aircraft:design:gross_mass,175400.0,lbm aircraft:design:range,3500,NM diff --git a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm_with_electric.csv b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm_with_electric.csv index 19a17a36d3..b321eba451 100644 --- a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm_with_electric.csv +++ b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm_with_electric.csv @@ -140,7 +140,7 @@ 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 +aircraft:design:max_mach,0.785,unitless aircraft:design:cruise_altitude,35000,ft aircraft:design:gross_mass,175400.0,lbm aircraft:design:range,3500,NM diff --git a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwGm.csv b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwGm.csv index e07bad7f34..5ea8d06410 100644 --- a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwGm.csv +++ b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwGm.csv @@ -235,7 +235,7 @@ aircraft:wing:thickness_to_chord_distribution,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 -mission:constraints:max_mach,0.8,unitless +aircraft:design:max_mach,0.8,unitless mission:landing:braking_friction_coefficient,0.4,unitless mission:landing:lift_coefficient_max,2.0,unitless aircraft:design:cruise_mach,0.8,unitless diff --git a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_GwFm.csv b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_GwFm.csv index 26a08427b7..fbf4d4b1f5 100644 --- a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_GwFm.csv +++ b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_GwFm.csv @@ -140,7 +140,7 @@ aircraft:wing:taper_ratio,0.33,unitless aircraft:wing:thickness_to_chord_root,0.15,unitless aircraft:wing:thickness_to_chord_tip,0.12,unitless aircraft:wing:zero_lift_angle,-1.2,deg -mission:constraints:max_mach,0.785,unitless +aircraft:design:max_mach,0.785,unitless aircraft:design:cruise_altitude,37500,ft # double check against phase_info aircraft:design:gross_mass,175400.0,lbm aircraft:design:lift_coefficient_max_flaps_up,1.2596,unitless diff --git a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_solved2dof.csv b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_solved2dof.csv index 9dac74d748..0761ddd143 100644 --- a/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_solved2dof.csv +++ b/aviary/validation_cases/validation_data/test_models/aircraft_for_bench_solved2dof.csv @@ -141,7 +141,7 @@ 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 +aircraft:design:max_mach,0.785,unitless aircraft:design:cruise_altitude,35000,ft aircraft:design:gross_mass,175400.0,lbm mission:gross_mass,175400.0,lbm diff --git a/aviary/validation_cases/validation_data/test_models/bwb_root_chord1.csv b/aviary/validation_cases/validation_data/test_models/bwb_root_chord1.csv index 4b7c1ac82e..882aad50a3 100644 --- a/aviary/validation_cases/validation_data/test_models/bwb_root_chord1.csv +++ b/aviary/validation_cases/validation_data/test_models/bwb_root_chord1.csv @@ -164,7 +164,7 @@ aircraft:wing:thickness_to_chord_reference,0.0,unitless aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.0,unitless aircraft:wing:wetted_area,9111.14415,ft**2 -mission:constraints:max_mach,0.85,unitless +aircraft:design:max_mach,0.85,unitless mission:landing:lift_coefficient_max,0.8,unitless mission:takeoff:braking_friction_coefficient,0.3,unitless mission:takeoff:fuel_mass,0.0,lbm diff --git a/aviary/validation_cases/validation_data/test_models/bwb_root_chord2.csv b/aviary/validation_cases/validation_data/test_models/bwb_root_chord2.csv index 2f5c95a591..266a3be708 100644 --- a/aviary/validation_cases/validation_data/test_models/bwb_root_chord2.csv +++ b/aviary/validation_cases/validation_data/test_models/bwb_root_chord2.csv @@ -164,7 +164,7 @@ aircraft:wing:thickness_to_chord_reference,0.0,unitless aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.0,unitless aircraft:wing:wetted_area,9111.14415,ft**2 -mission:constraints:max_mach,0.85,unitless +aircraft:design:max_mach,0.85,unitless mission:landing:lift_coefficient_max,0.8,unitless mission:takeoff:braking_friction_coefficient,0.3,unitless mission:takeoff:fuel_mass,0.0,lbm diff --git a/aviary/validation_cases/validation_data/test_models/high_wing_single_aisle.csv b/aviary/validation_cases/validation_data/test_models/high_wing_single_aisle.csv index 0d91f5091d..1803e67673 100644 --- a/aviary/validation_cases/validation_data/test_models/high_wing_single_aisle.csv +++ b/aviary/validation_cases/validation_data/test_models/high_wing_single_aisle.csv @@ -125,7 +125,7 @@ aircraft:wing:thickness_to_chord_distribution,0.1,0.1,0.1,unitless aircraft:wing:thickness_to_chord_reference,0.01,unitless #check aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.01,unitless #check -mission:constraints:max_mach,0.85,unitless +aircraft:design:max_mach,0.85,unitless aircraft:design:cruise_altitude,38000,ft aircraft:design:gross_mass,150000.0,lbm aircraft:design:range,3500,NM diff --git a/aviary/variable_info/migrations/max_mach_namespace_manifest.json b/aviary/variable_info/migrations/max_mach_namespace_manifest.json new file mode 100644 index 0000000000..7c4b475c1b --- /dev/null +++ b/aviary/variable_info/migrations/max_mach_namespace_manifest.json @@ -0,0 +1,68 @@ +{ + "issue": "OpenMDAO/Aviary#1046", + "canonical_symbol": "Aircraft.Design.MAX_MACH", + "canonical_key": "aircraft:design:max_mach", + "legacy_symbol": "Mission.Constraints.MAX_MACH", + "legacy_key": "mission:constraints:max_mach", + "changed_file_count": 50, + "changed_files": [ + "aviary/docs/examples_unreviewed/modified_aircraft.csv", + "aviary/docs/user_guide/fundamentals/aircraft_definition.ipynb", + "aviary/interface/test/sizing_results_for_test.json", + "aviary/models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv", + "aviary/models/aircraft/blended_wing_body/bwb300_baseline_FLOPS.csv", + "aviary/models/aircraft/blended_wing_body/bwb_detailed_FLOPS.csv", + "aviary/models/aircraft/blended_wing_body/bwb_simple_FLOPS.csv", + "aviary/models/aircraft/large_single_aisle_1/large_single_aisle_1_FLOPS.csv", + "aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_FLOPS.csv", + "aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS.csv", + "aviary/models/aircraft/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS.csv", + "aviary/models/aircraft/minimum_single_aisle/minimum_single_aisle_FLOPS.csv", + "aviary/subsystems/aerodynamics/flops_based/premission_aero.py", + "aviary/subsystems/aerodynamics/flops_based/test/test_premission_aero.py", + "aviary/subsystems/mass/flops_based/air_conditioning.py", + "aviary/subsystems/mass/flops_based/fuel_system.py", + "aviary/subsystems/mass/flops_based/hydraulics.py", + "aviary/subsystems/mass/flops_based/instruments.py", + "aviary/subsystems/mass/flops_based/passenger_service.py", + "aviary/subsystems/mass/flops_based/starter.py", + "aviary/subsystems/mass/flops_based/surface_controls.py", + "aviary/subsystems/mass/flops_based/test/test_fuel_system.py", + "aviary/subsystems/mass/flops_based/test/test_hydraulics.py", + "aviary/subsystems/mass/flops_based/test/test_instruments.py", + "aviary/subsystems/mass/flops_based/test/test_starter.py", + "aviary/utils/aviary_values.py", + "aviary/utils/csv_data_file.py", + "aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv", + "aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv", + "aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv", + "aviary/validation_cases/validation_data/test_data/V3_bug_fixed_IO.py", + "aviary/validation_cases/validation_data/test_data/advanced_single_aisle_data.py", + "aviary/validation_cases/validation_data/test_data/bwb300_baseline_FLOPS_data.py", + "aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py", + "aviary/validation_cases/validation_data/test_data/bwb_simple_FLOPS_data.py", + "aviary/validation_cases/validation_data/test_data/large_single_aisle_1_FLOPS_data.py", + "aviary/validation_cases/validation_data/test_data/large_single_aisle_2_FLOPS_data.py", + "aviary/validation_cases/validation_data/test_data/large_single_aisle_2_altwt_FLOPS_data.py", + "aviary/validation_cases/validation_data/test_data/large_single_aisle_2_detailwing_FLOPS_data.py", + "aviary/validation_cases/validation_data/test_data/multi_engine_single_aisle_data.py", + "aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm.csv", + "aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwFm_with_electric.csv", + "aviary/validation_cases/validation_data/test_models/aircraft_for_bench_FwGm.csv", + "aviary/validation_cases/validation_data/test_models/aircraft_for_bench_GwFm.csv", + "aviary/validation_cases/validation_data/test_models/aircraft_for_bench_solved2dof.csv", + "aviary/validation_cases/validation_data/test_models/bwb_root_chord1.csv", + "aviary/validation_cases/validation_data/test_models/bwb_root_chord2.csv", + "aviary/validation_cases/validation_data/test_models/high_wing_single_aisle.csv", + "aviary/variable_info/variable_meta_data.py", + "aviary/variable_info/variables.py" + ], + "replacement_counts": { + "python_symbol": 57, + "serialized_key": 24 + }, + "compatibility": { + "python_symbol": "Mission.Constraints.MAX_MACH aliases Aircraft.Design.MAX_MACH", + "serialized_inputs": "legacy raw names normalize before metadata validation/storage" + } +} diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index a170848188..55206cbe91 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -7074,7 +7074,7 @@ ) add_meta_data( - Mission.Constraints.MAX_MACH, + Aircraft.Design.MAX_MACH, meta_data=_MetaData, historical_name={ 'GASP': None, @@ -7086,8 +7086,12 @@ # ], }, units='unitless', - desc='aircraft cruise Mach number', - # TODO: derived default value: Aircraft.Design.CRUISE_MACH ??? + desc=( + 'Maximum aircraft design Mach number. Used by FLOPS-based air-conditioning, ' + 'fuel-system, hydraulics, instruments, passenger-service, starter, and surface-' + 'control mass correlations, and by FLOPS pre-mission aerodynamics when computing ' + 'the design lift coefficient.' + ), default_value=0.0, option=True, ) diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index afebc56fd2..740dbadf27 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -166,6 +166,7 @@ class Design: LIFT_INDEPENDENT_DRAG_POLAR = 'aircraft:design:lift_independent_drag_polar' LIFT_POLAR = 'aircraft:design:lift_polar' MACH = 'aircraft:design:mach' + MAX_MACH = 'aircraft:design:max_mach' MAX_FUSELAGE_PITCH_ANGLE = 'aircraft:design:max_fuselage_pitch_angle' MAX_STRUCTURAL_SPEED = 'aircraft:design:max_structural_speed' PART25_STRUCTURAL_CATEGORY = 'aircraft:design:part25_structural_category' @@ -699,7 +700,8 @@ class Constraints: EXCESS_FUEL_MASS_CAPACITY = 'mission:constraints:excess_fuel_mass_capacity' GEARBOX_SHAFT_POWER_RESIDUAL = 'mission:constraints:gearbox_shaft_power_residual' MASS_RESIDUAL = 'mission:constraints:mass_residual' - MAX_MACH = 'mission:constraints:max_mach' + # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH. + MAX_MACH = Aircraft.Design.MAX_MACH RANGE_RESIDUAL = 'mission:constraints:range_residual' RANGE_RESIDUAL_RESERVE = 'mission:constraints:range_residual_reserve' From d2a1c1353aebc9606545355c358bd6e23facb80b Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:48:39 -0700 Subject: [PATCH 06/26] ci: remove one-shot MAX_MACH migration workflow --- .github/workflows/max-mach-migration.yml | 40 ------------------------ 1 file changed, 40 deletions(-) delete mode 100644 .github/workflows/max-mach-migration.yml diff --git a/.github/workflows/max-mach-migration.yml b/.github/workflows/max-mach-migration.yml deleted file mode 100644 index 4e7b87eb5d..0000000000 --- a/.github/workflows/max-mach-migration.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Apply MAX_MACH namespace migration - -on: - push: - branches: - - refactor/aircraft-design-max-mach - -permissions: - contents: write - -jobs: - migrate: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: refactor/aircraft-design-max-mach - fetch-depth: 0 - - - name: Apply deterministic repository migration - run: | - python tools/migrate_max_mach_namespace.py --write --check - - - name: Static validation - run: | - python -m compileall -q aviary tools/migrate_max_mach_namespace.py - git diff --check - - - name: Commit generated migration - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - if git diff --cached --quiet; then - echo "Migration already applied" - else - git commit -m "refactor: migrate MAX_MACH to aircraft design namespace" - git push origin HEAD:refactor/aircraft-design-max-mach - fi From 191bd0d671287f3da46061f134719ad5766271f5 Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:49:49 -0700 Subject: [PATCH 07/26] ci: stage MAX_MACH metadata relocation --- .../reposition-max-mach-metadata.yml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/reposition-max-mach-metadata.yml diff --git a/.github/workflows/reposition-max-mach-metadata.yml b/.github/workflows/reposition-max-mach-metadata.yml new file mode 100644 index 0000000000..9d71317aa1 --- /dev/null +++ b/.github/workflows/reposition-max-mach-metadata.yml @@ -0,0 +1,48 @@ +name: Reposition MAX_MACH metadata + +on: + push: + branches: + - refactor/aircraft-design-max-mach + +permissions: + contents: write + +jobs: + reposition: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: refactor/aircraft-design-max-mach + - name: Move metadata beside Aircraft.Design.MACH + run: | + python - <<'PY' + from pathlib import Path + + path = Path('aviary/variable_info/variable_meta_data.py') + text = path.read_text(encoding='utf-8') + target = text.find('add_meta_data(\n Aircraft.Design.MAX_MACH,') + if target < 0: + raise SystemExit('MAX_MACH metadata block not found') + target_end = text.find('\n)\n', target) + 3 + block = text[target:target_end] + text = text[:target] + text[target_end:] + + mach = text.find(' Aircraft.Design.MACH,') + if mach < 0: + raise SystemExit('Aircraft.Design.MACH metadata block not found') + mach_start = text.rfind('add_meta_data(\n', 0, mach) + mach_end = text.find('\n)\n', mach) + 3 + text = text[:mach_end] + '\n' + block + text[mach_end:] + path.write_text(text, encoding='utf-8') + PY + git diff --check + - name: Commit source organization fix + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add aviary/variable_info/variable_meta_data.py + git commit -m "refactor: colocate MAX_MACH aircraft design metadata" + git push origin HEAD:refactor/aircraft-design-max-mach From af62777803a00ce665864db8e9f8610f1c3befa5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 22 Aug 2026 01:49:58 +0000 Subject: [PATCH 08/26] refactor: colocate MAX_MACH aircraft design metadata --- aviary/variable_info/variable_meta_data.py | 45 +++++++++++----------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 55206cbe91..30bde7551c 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -1588,6 +1588,29 @@ default_value=0.0, ) +add_meta_data( + Aircraft.Design.MAX_MACH, + meta_data=_MetaData, + historical_name={ + 'GASP': None, + 'FLOPS': 'WTIN.VMMO', + # [ # inputs + # '&DEFINE.WTIN.VMMO', 'VLIMIT.VMMO', + # # outputs + # 'VLIMIT.VMAX', + # ], + }, + units='unitless', + desc=( + 'Maximum aircraft design Mach number. Used by FLOPS-based air-conditioning, ' + 'fuel-system, hydraulics, instruments, passenger-service, starter, and surface-' + 'control mass correlations, and by FLOPS pre-mission aerodynamics when computing ' + 'the design lift coefficient.' + ), + default_value=0.0, + option=True, +) + add_meta_data( Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE, meta_data=_MetaData, @@ -7073,28 +7096,6 @@ '(within acceptable tolerance)', ) -add_meta_data( - Aircraft.Design.MAX_MACH, - meta_data=_MetaData, - historical_name={ - 'GASP': None, - 'FLOPS': 'WTIN.VMMO', - # [ # inputs - # '&DEFINE.WTIN.VMMO', 'VLIMIT.VMMO', - # # outputs - # 'VLIMIT.VMAX', - # ], - }, - units='unitless', - desc=( - 'Maximum aircraft design Mach number. Used by FLOPS-based air-conditioning, ' - 'fuel-system, hydraulics, instruments, passenger-service, starter, and surface-' - 'control mass correlations, and by FLOPS pre-mission aerodynamics when computing ' - 'the design lift coefficient.' - ), - default_value=0.0, - option=True, -) add_meta_data( Mission.Constraints.RANGE_RESIDUAL, From 288a51f418bb12146ba100e132a7bf178917cd1d Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:50:03 -0700 Subject: [PATCH 09/26] ci: remove one-shot metadata relocation workflow --- .../reposition-max-mach-metadata.yml | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 .github/workflows/reposition-max-mach-metadata.yml diff --git a/.github/workflows/reposition-max-mach-metadata.yml b/.github/workflows/reposition-max-mach-metadata.yml deleted file mode 100644 index 9d71317aa1..0000000000 --- a/.github/workflows/reposition-max-mach-metadata.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Reposition MAX_MACH metadata - -on: - push: - branches: - - refactor/aircraft-design-max-mach - -permissions: - contents: write - -jobs: - reposition: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: refactor/aircraft-design-max-mach - - name: Move metadata beside Aircraft.Design.MACH - run: | - python - <<'PY' - from pathlib import Path - - path = Path('aviary/variable_info/variable_meta_data.py') - text = path.read_text(encoding='utf-8') - target = text.find('add_meta_data(\n Aircraft.Design.MAX_MACH,') - if target < 0: - raise SystemExit('MAX_MACH metadata block not found') - target_end = text.find('\n)\n', target) + 3 - block = text[target:target_end] - text = text[:target] + text[target_end:] - - mach = text.find(' Aircraft.Design.MACH,') - if mach < 0: - raise SystemExit('Aircraft.Design.MACH metadata block not found') - mach_start = text.rfind('add_meta_data(\n', 0, mach) - mach_end = text.find('\n)\n', mach) + 3 - text = text[:mach_end] + '\n' + block + text[mach_end:] - path.write_text(text, encoding='utf-8') - PY - git diff --check - - name: Commit source organization fix - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add aviary/variable_info/variable_meta_data.py - git commit -m "refactor: colocate MAX_MACH aircraft design metadata" - git push origin HEAD:refactor/aircraft-design-max-mach From c4e61739b996de7095d3be63ee54730a10de4094 Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:50:32 -0700 Subject: [PATCH 10/26] tools: make MAX_MACH migration reproducible and idempotent --- tools/migrate_max_mach_namespace.py | 65 +++++++++++++++++------------ 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/tools/migrate_max_mach_namespace.py b/tools/migrate_max_mach_namespace.py index 997d23e17f..6d85255d8d 100644 --- a/tools/migrate_max_mach_namespace.py +++ b/tools/migrate_max_mach_namespace.py @@ -13,11 +13,12 @@ NEW_KEY = 'aircraft:design:max_mach' SUFFIXES = {'.py', '.csv', '.json', '.ipynb', '.md', '.rst', '.txt', '.toml', '.yaml', '.yml'} SKIP = {'.git', '.venv', 'venv', 'build', 'dist', '__pycache__', '.pytest_cache'} +MANIFEST = Path('aviary/variable_info/migrations/max_mach_namespace_manifest.json') ALLOW = { Path('tools/migrate_max_mach_namespace.py'), Path('aviary/variable_info/legacy_aliases.py'), Path('aviary/variable_info/test/test_max_mach_namespace.py'), - Path('aviary/variable_info/migrations/max_mach_namespace_manifest.json'), + MANIFEST, } @@ -49,14 +50,20 @@ def patch_variables(text): return text +def metadata_block(text, symbol): + pos = text.find(symbol) + if pos < 0: + raise RuntimeError(f'{symbol} metadata block not found') + start = text.rfind('add_meta_data(\n', 0, pos) + end = text.find('\n)\n', pos) + if start < 0 or end < 0: + raise RuntimeError(f'{symbol} metadata block boundaries not found') + return start, end + 3 + + def patch_metadata(text): - start = text.find('add_meta_data(\n Aircraft.Design.MAX_MACH,') - if start < 0: - raise RuntimeError('MAX_MACH metadata block not found') - end = text.find('\n)\n', start) - if end < 0: - raise RuntimeError('MAX_MACH metadata block end not found') - block = text[start:end + 3] + start, end = metadata_block(text, ' Aircraft.Design.MAX_MACH,') + block = text[start:end] desc = ( " desc=(\n" " 'Maximum aircraft design Mach number. Used by FLOPS-based air-conditioning, '\n" @@ -72,7 +79,12 @@ def patch_metadata(text): else: close = block.rfind(')\n') block = block[:close] + desc + block[close:] - return text[:start] + block + text[end + 3:] + + # Remove the block first, then insert it immediately after Aircraft.Design.MACH. + text = text[:start] + text[end:] + _, mach_end = metadata_block(text, ' Aircraft.Design.MACH,') + text = text[:mach_end] + '\n' + block + text[mach_end:] + return text def patch_values(text): @@ -151,23 +163,24 @@ def apply(): path.write_text(after, encoding='utf-8') changed.append(str(rel)) - manifest = { - 'issue': 'OpenMDAO/Aviary#1046', - 'canonical_symbol': NEW_SYMBOL, - 'canonical_key': NEW_KEY, - 'legacy_symbol': OLD_SYMBOL, - 'legacy_key': OLD_KEY, - 'changed_file_count': len(changed), - 'changed_files': sorted(changed), - 'replacement_counts': counts, - 'compatibility': { - 'python_symbol': 'Mission.Constraints.MAX_MACH aliases Aircraft.Design.MAX_MACH', - 'serialized_inputs': 'legacy raw names normalize before metadata validation/storage', - }, - } - out = ROOT / 'aviary/variable_info/migrations/max_mach_namespace_manifest.json' - out.parent.mkdir(parents=True, exist_ok=True) - out.write_text(json.dumps(manifest, indent=2) + '\n', encoding='utf-8') + out = ROOT / MANIFEST + if changed or not out.exists(): + manifest = { + 'issue': 'OpenMDAO/Aviary#1046', + 'canonical_symbol': NEW_SYMBOL, + 'canonical_key': NEW_KEY, + 'legacy_symbol': OLD_SYMBOL, + 'legacy_key': OLD_KEY, + 'changed_file_count': len(changed), + 'changed_files': sorted(changed), + 'replacement_counts': counts, + 'compatibility': { + 'python_symbol': 'Mission.Constraints.MAX_MACH aliases Aircraft.Design.MAX_MACH', + 'serialized_inputs': 'legacy raw names normalize before metadata validation/storage', + }, + } + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text(json.dumps(manifest, indent=2) + '\n', encoding='utf-8') return changed, counts From 9e83699d5d48d49c2ea6593a57f6edd834cebf11 Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:50:47 -0700 Subject: [PATCH 11/26] ci: verify MAX_MACH migration idempotence --- .../workflows/verify-max-mach-migration.yml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/verify-max-mach-migration.yml diff --git a/.github/workflows/verify-max-mach-migration.yml b/.github/workflows/verify-max-mach-migration.yml new file mode 100644 index 0000000000..570f265316 --- /dev/null +++ b/.github/workflows/verify-max-mach-migration.yml @@ -0,0 +1,21 @@ +name: Verify MAX_MACH migration idempotence + +on: + push: + branches: + - refactor/aircraft-design-max-mach + +permissions: + contents: read + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Re-run migration and audit + run: | + python tools/migrate_max_mach_namespace.py --write --check + git diff --exit-code + - name: Verify Python syntax + run: python -m compileall -q aviary tools/migrate_max_mach_namespace.py From f7e6341576665895f5b21c465dc034a55aab4c98 Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:51:57 -0700 Subject: [PATCH 12/26] style: format MAX_MACH migration contract test --- .../test/test_max_mach_namespace.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/aviary/variable_info/test/test_max_mach_namespace.py b/aviary/variable_info/test/test_max_mach_namespace.py index 713f6039cd..2a87bb1021 100644 --- a/aviary/variable_info/test/test_max_mach_namespace.py +++ b/aviary/variable_info/test/test_max_mach_namespace.py @@ -4,7 +4,10 @@ from aviary.utils.aviary_values import AviaryValues from aviary.utils.csv_data_file import read_data_file -from aviary.variable_info.legacy_aliases import LEGACY_VARIABLE_NAME_MAP, resolve_legacy_variable_name +from aviary.variable_info.legacy_aliases import ( + LEGACY_VARIABLE_NAME_MAP, + resolve_legacy_variable_name, +) from aviary.variable_info.variable_meta_data import CoreMetaData from aviary.variable_info.variables import Aircraft, Mission @@ -45,7 +48,18 @@ def test_no_unapproved_legacy_references(self): Path('aviary/variable_info/migrations/max_mach_namespace_manifest.json'), Path('tools/migrate_max_mach_namespace.py'), } - suffixes = {'.py', '.csv', '.json', '.ipynb', '.md', '.rst', '.txt', '.toml', '.yaml', '.yml'} + suffixes = { + '.py', + '.csv', + '.json', + '.ipynb', + '.md', + '.rst', + '.txt', + '.toml', + '.yaml', + '.yml', + } failures = [] for path in root.rglob('*'): if not path.is_file() or path.suffix.lower() not in suffixes: From 0186e43bd707153af7e7eadea44e7138348cf534 Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:52:25 -0700 Subject: [PATCH 13/26] style: format MAX_MACH migration tool --- tools/migrate_max_mach_namespace.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/migrate_max_mach_namespace.py b/tools/migrate_max_mach_namespace.py index 6d85255d8d..12a6601b5b 100644 --- a/tools/migrate_max_mach_namespace.py +++ b/tools/migrate_max_mach_namespace.py @@ -65,17 +65,17 @@ def patch_metadata(text): start, end = metadata_block(text, ' Aircraft.Design.MAX_MACH,') block = text[start:end] desc = ( - " desc=(\n" + ' desc=(\n' " 'Maximum aircraft design Mach number. Used by FLOPS-based air-conditioning, '\n" " 'fuel-system, hydraulics, instruments, passenger-service, starter, and surface-'\n" " 'control mass correlations, and by FLOPS pre-mission aerodynamics when computing '\n" " 'the design lift coefficient.'\n" - " ),\n" + ' ),\n' ) - pattern = re.compile(r" desc=.*?(?= [a-zA-Z_]+\s*=|\)\n)", re.S) + pattern = re.compile(r' desc=.*?(?= [a-zA-Z_]+\s*=|\)\n)', re.S) match = pattern.search(block) if match: - block = block[:match.start()] + desc + block[match.end():] + block = block[: match.start()] + desc + block[match.end() :] else: close = block.rfind(')\n') block = block[:close] + desc + block[close:] @@ -99,7 +99,7 @@ def patch_values(text): text = text.replace(marker, normalize + marker, 1) marker = ' def _check_units_compatibility(self, key, val, units, meta_data=CoreMetaData):\n' - methods = ''' def get_item(self, key): + methods = """ def get_item(self, key): return super().get_item(resolve_legacy_variable_name(key)) def get_val(self, key, units='unitless'): @@ -111,7 +111,7 @@ def delete(self, key): def __contains__(self, key): return super().__contains__(resolve_legacy_variable_name(key)) -''' +""" if 'def get_item(self, key):' not in text: if marker not in text: raise RuntimeError('AviaryValues insertion point not found') From 5d2335f4af7e5beb14b3c3638bfd8212d9466b02 Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:10:44 -0700 Subject: [PATCH 14/26] ci: apply MAX_MACH migration corrections --- .github/workflows/fix-max-mach-ci.yml | 130 ++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 .github/workflows/fix-max-mach-ci.yml diff --git a/.github/workflows/fix-max-mach-ci.yml b/.github/workflows/fix-max-mach-ci.yml new file mode 100644 index 0000000000..e5fc7ba5d8 --- /dev/null +++ b/.github/workflows/fix-max-mach-ci.yml @@ -0,0 +1,130 @@ +name: Apply MAX_MACH CI corrections + +on: + push: + branches: + - refactor/aircraft-design-max-mach + +permissions: + contents: write + +jobs: + fix: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: refactor/aircraft-design-max-mach + - name: Correct hierarchy, metadata, fixtures, and migration contract + run: | + python - <<'PY' + import json + from pathlib import Path + + def block_bounds(text, symbol): + pos = text.find(symbol) + if pos < 0: + raise RuntimeError(f'missing metadata symbol: {symbol}') + start = text.rfind('add_meta_data(\n', 0, pos) + end = text.find('\n)\n', pos) + if start < 0 or end < 0: + raise RuntimeError(f'bad metadata block: {symbol}') + return start, end + 3 + + # Variable hierarchy: remove the duplicate Mission symbol and place the + # canonical aircraft variable in alphabetical order. + p = Path('aviary/variable_info/variables.py') + text = p.read_text(encoding='utf-8') + text = text.replace( + ' # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH.\n' + ' MAX_MACH = Aircraft.Design.MAX_MACH\n', + '', + ) + canonical = " MAX_MACH = 'aircraft:design:max_mach'\n" + text = text.replace(canonical, '') + anchor = " MAX_FUSELAGE_PITCH_ANGLE = 'aircraft:design:max_fuselage_pitch_angle'\n" + if anchor not in text: + raise RuntimeError('MAX_FUSELAGE_PITCH_ANGLE variable anchor missing') + text = text.replace(anchor, anchor + canonical, 1) + p.write_text(text, encoding='utf-8') + + # Metadata hierarchy: MAX_FUSELAGE_PITCH_ANGLE < MAX_MACH < MAX_STRUCTURAL_SPEED. + p = Path('aviary/variable_info/variable_meta_data.py') + text = p.read_text(encoding='utf-8') + start, end = block_bounds(text, ' Aircraft.Design.MAX_MACH,') + block = text[start:end] + text = text[:start] + text[end:] + _, anchor_end = block_bounds(text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,') + text = text[:anchor_end] + '\n' + block + text[anchor_end:] + p.write_text(text, encoding='utf-8') + + # Fortran converter validation is line-order sensitive. The renamed key + # must move from the old Mission section into the sorted Aircraft.Design section. + fixtures = [ + 'aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv', + 'aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv', + 'aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv', + ] + for name in fixtures: + p = Path(name) + lines = p.read_text(encoding='utf-8').splitlines() + max_lines = [line for line in lines if line.startswith('aircraft:design:max_mach,')] + if len(max_lines) != 1: + raise RuntimeError(f'{name}: expected one MAX_MACH line, got {len(max_lines)}') + max_line = max_lines[0] + lines = [line for line in lines if not line.startswith('aircraft:design:max_mach,')] + idx = next(i for i, line in enumerate(lines) if line.startswith('aircraft:design:mach,')) + lines.insert(idx + 1, max_line) + p.write_text('\n'.join(lines) + '\n', encoding='utf-8') + + # Contract now verifies that the old Python symbol is gone; serialized + # legacy input compatibility is handled by the string-key resolver. + p = Path('aviary/variable_info/test/test_max_mach_namespace.py') + text = p.read_text(encoding='utf-8') + text = text.replace( + ' self.assertEqual(Mission.Constraints.MAX_MACH, Aircraft.Design.MAX_MACH)\n', + " self.assertFalse(hasattr(Mission.Constraints, 'MAX_MACH'))\n", + ) + p.write_text(text, encoding='utf-8') + + # Keep the deterministic migration tool consistent with the corrected end state. + p = Path('tools/migrate_max_mach_namespace.py') + text = p.read_text(encoding='utf-8') + old_chunk = ''' old = " MAX_MACH = 'mission:constraints:max_mach'\\n"\n alias = (\n ' # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH.\\n'\n ' MAX_MACH = Aircraft.Design.MAX_MACH\\n'\n )\n if old in text:\n text = text.replace(old, alias, 1)\n elif 'MAX_MACH = Aircraft.Design.MAX_MACH' not in text:\n raise RuntimeError('Mission.Constraints.MAX_MACH definition not found')\n\n anchor = " MACH = 'aircraft:design:mach'\\n"\n canonical = " MAX_MACH = 'aircraft:design:max_mach'\\n"\n if canonical not in text:\n if anchor not in text:\n raise RuntimeError('Aircraft.Design.MACH anchor not found')\n text = text.replace(anchor, anchor + canonical, 1)\n''' + new_chunk = ''' old = " MAX_MACH = 'mission:constraints:max_mach'\\n"\n alias = (\n ' # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH.\\n'\n ' MAX_MACH = Aircraft.Design.MAX_MACH\\n'\n )\n text = text.replace(old, '', 1).replace(alias, '', 1)\n\n canonical = " MAX_MACH = 'aircraft:design:max_mach'\\n"\n text = text.replace(canonical, '')\n anchor = (\n " MAX_FUSELAGE_PITCH_ANGLE = "\n "'aircraft:design:max_fuselage_pitch_angle'\\n"\n )\n if anchor not in text:\n raise RuntimeError('Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE anchor not found')\n text = text.replace(anchor, anchor + canonical, 1)\n''' + if old_chunk not in text: + raise RuntimeError('patch_variables implementation did not match expected source') + text = text.replace(old_chunk, new_chunk, 1) + text = text.replace( + " _, mach_end = metadata_block(text, ' Aircraft.Design.MACH,')\n" + " text = text[:mach_end] + '\\n' + block + text[mach_end:]\n", + " _, anchor_end = metadata_block(\n" + " text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,'\n" + " )\n" + " text = text[:anchor_end] + '\\n' + block + text[anchor_end:]\n", + ) + text = text.replace( + "'python_symbol': 'Mission.Constraints.MAX_MACH aliases Aircraft.Design.MAX_MACH',", + "'python_symbol': 'legacy Python symbol removed; serialized legacy key remains supported',", + ) + p.write_text(text, encoding='utf-8') + + # Preserve the original migration audit while correcting its compatibility statement. + p = Path('aviary/variable_info/migrations/max_mach_namespace_manifest.json') + data = json.loads(p.read_text(encoding='utf-8')) + data['compatibility']['python_symbol'] = ( + 'legacy Python symbol removed; serialized legacy key remains supported' + ) + p.write_text(json.dumps(data, indent=2) + '\n', encoding='utf-8') + PY + python tools/migrate_max_mach_namespace.py --write --check + python -m compileall -q aviary tools/migrate_max_mach_namespace.py + git diff --check + - name: Commit corrections + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git commit -m "fix: preserve MAX_MACH hierarchy invariants" + git push origin HEAD:refactor/aircraft-design-max-mach From 867ad653d89e6c9d6240b038c5d375470d90c59a Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:16:01 -0700 Subject: [PATCH 15/26] ci: run MAX_MACH repair on pull request updates --- .github/workflows/fix-max-mach-ci.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/fix-max-mach-ci.yml b/.github/workflows/fix-max-mach-ci.yml index e5fc7ba5d8..b0692361d9 100644 --- a/.github/workflows/fix-max-mach-ci.yml +++ b/.github/workflows/fix-max-mach-ci.yml @@ -1,16 +1,17 @@ name: Apply MAX_MACH CI corrections on: - push: + pull_request: branches: - - refactor/aircraft-design-max-mach + - main + types: [opened, synchronize, reopened] permissions: contents: write jobs: fix: - if: github.actor != 'github-actions[bot]' + if: github.actor != 'github-actions[bot]' && github.head_ref == 'refactor/aircraft-design-max-mach' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -32,8 +33,6 @@ jobs: raise RuntimeError(f'bad metadata block: {symbol}') return start, end + 3 - # Variable hierarchy: remove the duplicate Mission symbol and place the - # canonical aircraft variable in alphabetical order. p = Path('aviary/variable_info/variables.py') text = p.read_text(encoding='utf-8') text = text.replace( @@ -49,7 +48,6 @@ jobs: text = text.replace(anchor, anchor + canonical, 1) p.write_text(text, encoding='utf-8') - # Metadata hierarchy: MAX_FUSELAGE_PITCH_ANGLE < MAX_MACH < MAX_STRUCTURAL_SPEED. p = Path('aviary/variable_info/variable_meta_data.py') text = p.read_text(encoding='utf-8') start, end = block_bounds(text, ' Aircraft.Design.MAX_MACH,') @@ -59,8 +57,6 @@ jobs: text = text[:anchor_end] + '\n' + block + text[anchor_end:] p.write_text(text, encoding='utf-8') - # Fortran converter validation is line-order sensitive. The renamed key - # must move from the old Mission section into the sorted Aircraft.Design section. fixtures = [ 'aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv', 'aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv', @@ -78,8 +74,6 @@ jobs: lines.insert(idx + 1, max_line) p.write_text('\n'.join(lines) + '\n', encoding='utf-8') - # Contract now verifies that the old Python symbol is gone; serialized - # legacy input compatibility is handled by the string-key resolver. p = Path('aviary/variable_info/test/test_max_mach_namespace.py') text = p.read_text(encoding='utf-8') text = text.replace( @@ -88,7 +82,6 @@ jobs: ) p.write_text(text, encoding='utf-8') - # Keep the deterministic migration tool consistent with the corrected end state. p = Path('tools/migrate_max_mach_namespace.py') text = p.read_text(encoding='utf-8') old_chunk = ''' old = " MAX_MACH = 'mission:constraints:max_mach'\\n"\n alias = (\n ' # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH.\\n'\n ' MAX_MACH = Aircraft.Design.MAX_MACH\\n'\n )\n if old in text:\n text = text.replace(old, alias, 1)\n elif 'MAX_MACH = Aircraft.Design.MAX_MACH' not in text:\n raise RuntimeError('Mission.Constraints.MAX_MACH definition not found')\n\n anchor = " MACH = 'aircraft:design:mach'\\n"\n canonical = " MAX_MACH = 'aircraft:design:max_mach'\\n"\n if canonical not in text:\n if anchor not in text:\n raise RuntimeError('Aircraft.Design.MACH anchor not found')\n text = text.replace(anchor, anchor + canonical, 1)\n''' @@ -110,7 +103,6 @@ jobs: ) p.write_text(text, encoding='utf-8') - # Preserve the original migration audit while correcting its compatibility statement. p = Path('aviary/variable_info/migrations/max_mach_namespace_manifest.json') data = json.loads(p.read_text(encoding='utf-8')) data['compatibility']['python_symbol'] = ( From e95be8589841f60cfc0488df8d0646624116e01b Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:19:54 -0700 Subject: [PATCH 16/26] ci: make MAX_MACH fixture repair order-aware --- .github/workflows/fix-max-mach-ci.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/fix-max-mach-ci.yml b/.github/workflows/fix-max-mach-ci.yml index b0692361d9..92e98b0ab0 100644 --- a/.github/workflows/fix-max-mach-ci.yml +++ b/.github/workflows/fix-max-mach-ci.yml @@ -62,16 +62,24 @@ jobs: 'aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv', 'aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv', ] + target_key = 'aircraft:design:max_mach' for name in fixtures: p = Path(name) lines = p.read_text(encoding='utf-8').splitlines() - max_lines = [line for line in lines if line.startswith('aircraft:design:max_mach,')] + max_lines = [line for line in lines if line.startswith(target_key + ',')] if len(max_lines) != 1: raise RuntimeError(f'{name}: expected one MAX_MACH line, got {len(max_lines)}') max_line = max_lines[0] - lines = [line for line in lines if not line.startswith('aircraft:design:max_mach,')] - idx = next(i for i, line in enumerate(lines) if line.startswith('aircraft:design:mach,')) - lines.insert(idx + 1, max_line) + lines = [line for line in lines if not line.startswith(target_key + ',')] + insert_at = len(lines) + for idx, line in enumerate(lines): + if not line or line.startswith('#') or ',' not in line: + continue + key = line.split(',', 1)[0] + if key > target_key: + insert_at = idx + break + lines.insert(insert_at, max_line) p.write_text('\n'.join(lines) + '\n', encoding='utf-8') p = Path('aviary/variable_info/test/test_max_mach_namespace.py') From dd8419b751d3c585100dee50d4e0e28e5917e1d3 Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:21:09 -0700 Subject: [PATCH 17/26] ci: keep MAX_MACH repair commit workflow-free --- .github/workflows/fix-max-mach-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/fix-max-mach-ci.yml b/.github/workflows/fix-max-mach-ci.yml index 92e98b0ab0..a4bee6549a 100644 --- a/.github/workflows/fix-max-mach-ci.yml +++ b/.github/workflows/fix-max-mach-ci.yml @@ -118,7 +118,6 @@ jobs: ) p.write_text(json.dumps(data, indent=2) + '\n', encoding='utf-8') PY - python tools/migrate_max_mach_namespace.py --write --check python -m compileall -q aviary tools/migrate_max_mach_namespace.py git diff --check - name: Commit corrections From 24b362064774b0a933c01fd52bc884eaee856605 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 22 Aug 2026 02:21:27 +0000 Subject: [PATCH 18/26] fix: preserve MAX_MACH hierarchy invariants --- .../converter_test_BWB_detailed_FLOPS.csv | 2 +- .../data/converter_test_BWB_simple_FLOPS.csv | 2 +- ...erter_test_advanced_single_aisle_FLOPS.csv | 2 +- .../max_mach_namespace_manifest.json | 2 +- .../test/test_max_mach_namespace.py | 2 +- aviary/variable_info/variable_meta_data.py | 19 +++++++------- aviary/variable_info/variables.py | 4 +-- tools/migrate_max_mach_namespace.py | 26 ++++++++++--------- 8 files changed, 30 insertions(+), 29 deletions(-) diff --git a/aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv b/aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv index 21ea0cc808..82b2c6d3ee 100644 --- a/aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv +++ b/aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv @@ -20,6 +20,7 @@ aircraft:design:cruise_mach,0.85,unitless aircraft:design:gross_mass,874099,lbm aircraft:design:landing_to_takeoff_mass_ratio,0.8,unitless aircraft:design:lift_dependent_drag_coeff_factor,1,unitless +aircraft:design:max_mach,0.85,unitless aircraft:design:range,7750,NM aircraft:design:type,BWB,unitless aircraft:design:use_alt_mass,False,unitless @@ -89,7 +90,6 @@ aircraft:wing:thickness_to_chord,0.11,unitless aircraft:wing:thickness_to_chord_distribution,-1.0,0.15,0.1132,0.0928,0.0822,0.0764,0.0742,0.0746,0.0758,0.0758,0.0756,0.0756,0.0758,0.076,0.076,unitless aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0,unitless -aircraft:design:max_mach,0.85,unitless mission:landing:lift_coefficient_max,3.0,unitless mission:takeoff:braking_friction_coefficient,0.3,unitless mission:takeoff:rolling_friction_coefficient,0.025,unitless diff --git a/aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv b/aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv index 9dbb7ae955..d3f01f62e5 100644 --- a/aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv +++ b/aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv @@ -20,6 +20,7 @@ aircraft:design:cruise_mach,0.85,unitless aircraft:design:gross_mass,874099,lbm aircraft:design:landing_to_takeoff_mass_ratio,0.8,unitless aircraft:design:lift_dependent_drag_coeff_factor,1,unitless +aircraft:design:max_mach,0.85,unitless aircraft:design:range,7750,NM aircraft:design:type,BWB,unitless aircraft:design:use_alt_mass,False,unitless @@ -88,7 +89,6 @@ aircraft:wing:taper_ratio,0.311,unitless aircraft:wing:thickness_to_chord,0.11,unitless aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0,unitless -aircraft:design:max_mach,0.85,unitless mission:landing:lift_coefficient_max,3.0,unitless mission:takeoff:braking_friction_coefficient,0.3,unitless mission:takeoff:rolling_friction_coefficient,0.025,unitless diff --git a/aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv b/aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv index 3931a6ef1d..a460ba61ef 100644 --- a/aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv +++ b/aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv @@ -29,6 +29,7 @@ aircraft:design:landing_to_takeoff_mass_ratio,0.84,unitless aircraft:design:lift_coefficient,-1.0,unitless aircraft:design:lift_dependent_drag_coeff_factor,0.93,unitless aircraft:design:mach,-1.0,unitless +aircraft:design:max_mach,0.785,unitless aircraft:design:range,3500.0,NM aircraft:design:subsonic_drag_coeff_factor,0.95,unitless aircraft:design:supersonic_drag_coeff_factor,1.0,unitless @@ -152,7 +153,6 @@ aircraft:wing:thickness_to_chord_reference,0.116565,unitless aircraft:wing:ultimate_load_factor,3.75,unitless aircraft:wing:var_sweep_mass_penalty,0.0,unitless aircraft:wing:wetted_area,2210.280228,ft**2 -aircraft:design:max_mach,0.785,unitless mission:landing:drag_coefficient_min,0.045,unitless mission:landing:flare_rate,2.2,deg/s mission:landing:lift_coefficient_max,2.5,unitless diff --git a/aviary/variable_info/migrations/max_mach_namespace_manifest.json b/aviary/variable_info/migrations/max_mach_namespace_manifest.json index 7c4b475c1b..f7d293de0b 100644 --- a/aviary/variable_info/migrations/max_mach_namespace_manifest.json +++ b/aviary/variable_info/migrations/max_mach_namespace_manifest.json @@ -62,7 +62,7 @@ "serialized_key": 24 }, "compatibility": { - "python_symbol": "Mission.Constraints.MAX_MACH aliases Aircraft.Design.MAX_MACH", + "python_symbol": "legacy Python symbol removed; serialized legacy key remains supported", "serialized_inputs": "legacy raw names normalize before metadata validation/storage" } } diff --git a/aviary/variable_info/test/test_max_mach_namespace.py b/aviary/variable_info/test/test_max_mach_namespace.py index 2a87bb1021..e7b3e1fc6f 100644 --- a/aviary/variable_info/test/test_max_mach_namespace.py +++ b/aviary/variable_info/test/test_max_mach_namespace.py @@ -15,7 +15,7 @@ class MaxMachNamespaceTest(unittest.TestCase): def test_canonical_namespace(self): self.assertEqual(Aircraft.Design.MAX_MACH, 'aircraft:design:max_mach') - self.assertEqual(Mission.Constraints.MAX_MACH, Aircraft.Design.MAX_MACH) + self.assertFalse(hasattr(Mission.Constraints, 'MAX_MACH')) self.assertIn(Aircraft.Design.MAX_MACH, CoreMetaData) self.assertNotIn('mission:constraints:max_mach', CoreMetaData) diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 30bde7551c..201dbf1d69 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -1588,6 +1588,16 @@ default_value=0.0, ) + +add_meta_data( + Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE, + meta_data=_MetaData, + historical_name={'GASP': 'INGASP.THEMAX', 'FLOPS': None}, + units='deg', + desc='maximum fuselage pitch allowed', + default_value=15, +) + add_meta_data( Aircraft.Design.MAX_MACH, meta_data=_MetaData, @@ -1611,15 +1621,6 @@ option=True, ) -add_meta_data( - Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE, - meta_data=_MetaData, - historical_name={'GASP': 'INGASP.THEMAX', 'FLOPS': None}, - units='deg', - desc='maximum fuselage pitch allowed', - default_value=15, -) - add_meta_data( Aircraft.Design.MAX_STRUCTURAL_SPEED, meta_data=_MetaData, diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index 740dbadf27..1f5d8a8814 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -166,8 +166,8 @@ class Design: LIFT_INDEPENDENT_DRAG_POLAR = 'aircraft:design:lift_independent_drag_polar' LIFT_POLAR = 'aircraft:design:lift_polar' MACH = 'aircraft:design:mach' - MAX_MACH = 'aircraft:design:max_mach' MAX_FUSELAGE_PITCH_ANGLE = 'aircraft:design:max_fuselage_pitch_angle' + MAX_MACH = 'aircraft:design:max_mach' MAX_STRUCTURAL_SPEED = 'aircraft:design:max_structural_speed' PART25_STRUCTURAL_CATEGORY = 'aircraft:design:part25_structural_category' PERCENT_EXCRESCENCE_DRAG = 'aircraft:design:percent_excrescence_drag' @@ -700,8 +700,6 @@ class Constraints: EXCESS_FUEL_MASS_CAPACITY = 'mission:constraints:excess_fuel_mass_capacity' GEARBOX_SHAFT_POWER_RESIDUAL = 'mission:constraints:gearbox_shaft_power_residual' MASS_RESIDUAL = 'mission:constraints:mass_residual' - # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH. - MAX_MACH = Aircraft.Design.MAX_MACH RANGE_RESIDUAL = 'mission:constraints:range_residual' RANGE_RESIDUAL_RESERVE = 'mission:constraints:range_residual_reserve' diff --git a/tools/migrate_max_mach_namespace.py b/tools/migrate_max_mach_namespace.py index 12a6601b5b..f91b54437d 100644 --- a/tools/migrate_max_mach_namespace.py +++ b/tools/migrate_max_mach_namespace.py @@ -36,17 +36,17 @@ def patch_variables(text): ' # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH.\n' ' MAX_MACH = Aircraft.Design.MAX_MACH\n' ) - if old in text: - text = text.replace(old, alias, 1) - elif 'MAX_MACH = Aircraft.Design.MAX_MACH' not in text: - raise RuntimeError('Mission.Constraints.MAX_MACH definition not found') + text = text.replace(old, '', 1).replace(alias, '', 1) - anchor = " MACH = 'aircraft:design:mach'\n" canonical = " MAX_MACH = 'aircraft:design:max_mach'\n" - if canonical not in text: - if anchor not in text: - raise RuntimeError('Aircraft.Design.MACH anchor not found') - text = text.replace(anchor, anchor + canonical, 1) + text = text.replace(canonical, '') + anchor = ( + " MAX_FUSELAGE_PITCH_ANGLE = " + "'aircraft:design:max_fuselage_pitch_angle'\n" + ) + if anchor not in text: + raise RuntimeError('Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE anchor not found') + text = text.replace(anchor, anchor + canonical, 1) return text @@ -82,8 +82,10 @@ def patch_metadata(text): # Remove the block first, then insert it immediately after Aircraft.Design.MACH. text = text[:start] + text[end:] - _, mach_end = metadata_block(text, ' Aircraft.Design.MACH,') - text = text[:mach_end] + '\n' + block + text[mach_end:] + _, anchor_end = metadata_block( + text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,' + ) + text = text[:anchor_end] + '\n' + block + text[anchor_end:] return text @@ -175,7 +177,7 @@ def apply(): 'changed_files': sorted(changed), 'replacement_counts': counts, 'compatibility': { - 'python_symbol': 'Mission.Constraints.MAX_MACH aliases Aircraft.Design.MAX_MACH', + 'python_symbol': 'legacy Python symbol removed; serialized legacy key remains supported', 'serialized_inputs': 'legacy raw names normalize before metadata validation/storage', }, } From ce99ed9e01967c2e0a500dca032f792c206535bf Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:21:57 -0700 Subject: [PATCH 19/26] ci: remove completed MAX_MACH repair helper --- .github/workflows/fix-max-mach-ci.yml | 129 -------------------------- 1 file changed, 129 deletions(-) delete mode 100644 .github/workflows/fix-max-mach-ci.yml diff --git a/.github/workflows/fix-max-mach-ci.yml b/.github/workflows/fix-max-mach-ci.yml deleted file mode 100644 index a4bee6549a..0000000000 --- a/.github/workflows/fix-max-mach-ci.yml +++ /dev/null @@ -1,129 +0,0 @@ -name: Apply MAX_MACH CI corrections - -on: - pull_request: - branches: - - main - types: [opened, synchronize, reopened] - -permissions: - contents: write - -jobs: - fix: - if: github.actor != 'github-actions[bot]' && github.head_ref == 'refactor/aircraft-design-max-mach' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: refactor/aircraft-design-max-mach - - name: Correct hierarchy, metadata, fixtures, and migration contract - run: | - python - <<'PY' - import json - from pathlib import Path - - def block_bounds(text, symbol): - pos = text.find(symbol) - if pos < 0: - raise RuntimeError(f'missing metadata symbol: {symbol}') - start = text.rfind('add_meta_data(\n', 0, pos) - end = text.find('\n)\n', pos) - if start < 0 or end < 0: - raise RuntimeError(f'bad metadata block: {symbol}') - return start, end + 3 - - p = Path('aviary/variable_info/variables.py') - text = p.read_text(encoding='utf-8') - text = text.replace( - ' # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH.\n' - ' MAX_MACH = Aircraft.Design.MAX_MACH\n', - '', - ) - canonical = " MAX_MACH = 'aircraft:design:max_mach'\n" - text = text.replace(canonical, '') - anchor = " MAX_FUSELAGE_PITCH_ANGLE = 'aircraft:design:max_fuselage_pitch_angle'\n" - if anchor not in text: - raise RuntimeError('MAX_FUSELAGE_PITCH_ANGLE variable anchor missing') - text = text.replace(anchor, anchor + canonical, 1) - p.write_text(text, encoding='utf-8') - - p = Path('aviary/variable_info/variable_meta_data.py') - text = p.read_text(encoding='utf-8') - start, end = block_bounds(text, ' Aircraft.Design.MAX_MACH,') - block = text[start:end] - text = text[:start] + text[end:] - _, anchor_end = block_bounds(text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,') - text = text[:anchor_end] + '\n' + block + text[anchor_end:] - p.write_text(text, encoding='utf-8') - - fixtures = [ - 'aviary/utils/test/data/converter_test_advanced_single_aisle_FLOPS.csv', - 'aviary/utils/test/data/converter_test_BWB_detailed_FLOPS.csv', - 'aviary/utils/test/data/converter_test_BWB_simple_FLOPS.csv', - ] - target_key = 'aircraft:design:max_mach' - for name in fixtures: - p = Path(name) - lines = p.read_text(encoding='utf-8').splitlines() - max_lines = [line for line in lines if line.startswith(target_key + ',')] - if len(max_lines) != 1: - raise RuntimeError(f'{name}: expected one MAX_MACH line, got {len(max_lines)}') - max_line = max_lines[0] - lines = [line for line in lines if not line.startswith(target_key + ',')] - insert_at = len(lines) - for idx, line in enumerate(lines): - if not line or line.startswith('#') or ',' not in line: - continue - key = line.split(',', 1)[0] - if key > target_key: - insert_at = idx - break - lines.insert(insert_at, max_line) - p.write_text('\n'.join(lines) + '\n', encoding='utf-8') - - p = Path('aviary/variable_info/test/test_max_mach_namespace.py') - text = p.read_text(encoding='utf-8') - text = text.replace( - ' self.assertEqual(Mission.Constraints.MAX_MACH, Aircraft.Design.MAX_MACH)\n', - " self.assertFalse(hasattr(Mission.Constraints, 'MAX_MACH'))\n", - ) - p.write_text(text, encoding='utf-8') - - p = Path('tools/migrate_max_mach_namespace.py') - text = p.read_text(encoding='utf-8') - old_chunk = ''' old = " MAX_MACH = 'mission:constraints:max_mach'\\n"\n alias = (\n ' # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH.\\n'\n ' MAX_MACH = Aircraft.Design.MAX_MACH\\n'\n )\n if old in text:\n text = text.replace(old, alias, 1)\n elif 'MAX_MACH = Aircraft.Design.MAX_MACH' not in text:\n raise RuntimeError('Mission.Constraints.MAX_MACH definition not found')\n\n anchor = " MACH = 'aircraft:design:mach'\\n"\n canonical = " MAX_MACH = 'aircraft:design:max_mach'\\n"\n if canonical not in text:\n if anchor not in text:\n raise RuntimeError('Aircraft.Design.MACH anchor not found')\n text = text.replace(anchor, anchor + canonical, 1)\n''' - new_chunk = ''' old = " MAX_MACH = 'mission:constraints:max_mach'\\n"\n alias = (\n ' # Backward-compatible symbol alias; new code uses Aircraft.Design.MAX_MACH.\\n'\n ' MAX_MACH = Aircraft.Design.MAX_MACH\\n'\n )\n text = text.replace(old, '', 1).replace(alias, '', 1)\n\n canonical = " MAX_MACH = 'aircraft:design:max_mach'\\n"\n text = text.replace(canonical, '')\n anchor = (\n " MAX_FUSELAGE_PITCH_ANGLE = "\n "'aircraft:design:max_fuselage_pitch_angle'\\n"\n )\n if anchor not in text:\n raise RuntimeError('Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE anchor not found')\n text = text.replace(anchor, anchor + canonical, 1)\n''' - if old_chunk not in text: - raise RuntimeError('patch_variables implementation did not match expected source') - text = text.replace(old_chunk, new_chunk, 1) - text = text.replace( - " _, mach_end = metadata_block(text, ' Aircraft.Design.MACH,')\n" - " text = text[:mach_end] + '\\n' + block + text[mach_end:]\n", - " _, anchor_end = metadata_block(\n" - " text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,'\n" - " )\n" - " text = text[:anchor_end] + '\\n' + block + text[anchor_end:]\n", - ) - text = text.replace( - "'python_symbol': 'Mission.Constraints.MAX_MACH aliases Aircraft.Design.MAX_MACH',", - "'python_symbol': 'legacy Python symbol removed; serialized legacy key remains supported',", - ) - p.write_text(text, encoding='utf-8') - - p = Path('aviary/variable_info/migrations/max_mach_namespace_manifest.json') - data = json.loads(p.read_text(encoding='utf-8')) - data['compatibility']['python_symbol'] = ( - 'legacy Python symbol removed; serialized legacy key remains supported' - ) - p.write_text(json.dumps(data, indent=2) + '\n', encoding='utf-8') - PY - python -m compileall -q aviary tools/migrate_max_mach_namespace.py - git diff --check - - name: Commit corrections - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git commit -m "fix: preserve MAX_MACH hierarchy invariants" - git push origin HEAD:refactor/aircraft-design-max-mach From 8757817cc9a34871e3f01900c067a374ccf7d34e Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:25:50 -0700 Subject: [PATCH 20/26] style: format MAX_MACH migration tool --- tools/migrate_max_mach_namespace.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/migrate_max_mach_namespace.py b/tools/migrate_max_mach_namespace.py index f91b54437d..9cfa9455bf 100644 --- a/tools/migrate_max_mach_namespace.py +++ b/tools/migrate_max_mach_namespace.py @@ -40,10 +40,7 @@ def patch_variables(text): canonical = " MAX_MACH = 'aircraft:design:max_mach'\n" text = text.replace(canonical, '') - anchor = ( - " MAX_FUSELAGE_PITCH_ANGLE = " - "'aircraft:design:max_fuselage_pitch_angle'\n" - ) + anchor = " MAX_FUSELAGE_PITCH_ANGLE = 'aircraft:design:max_fuselage_pitch_angle'\n" if anchor not in text: raise RuntimeError('Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE anchor not found') text = text.replace(anchor, anchor + canonical, 1) @@ -82,9 +79,7 @@ def patch_metadata(text): # Remove the block first, then insert it immediately after Aircraft.Design.MACH. text = text[:start] + text[end:] - _, anchor_end = metadata_block( - text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,' - ) + _, anchor_end = metadata_block(text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,') text = text[:anchor_end] + '\n' + block + text[anchor_end:] return text From de83803dac3633241a1d0cc4052fd5f61e7e6cfc Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 22 Aug 2026 05:56:45 +0000 Subject: [PATCH 21/26] Fix MAX_MACH migration idempotence - Make patch_metadata() idempotent by checking if MAX_MACH is already correctly positioned after MAX_FUSELAGE_PITCH_ANGLE with the expected description before making any changes - Strip multiple blank lines when reinserting the MAX_MACH metadata block to ensure exactly one blank line separator is maintained - Only rewrite the manifest when there are actual content migrations (python_symbol or serialized_key replacements > 0) to preserve the historical 50-file migration record on idempotent re-runs This fixes the failing CI check that runs the migration tool twice and expects zero git diff on the second run. Co-authored-by: Suhas --- tools/migrate_max_mach_namespace.py | 41 ++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/tools/migrate_max_mach_namespace.py b/tools/migrate_max_mach_namespace.py index 9cfa9455bf..9419f47ad9 100644 --- a/tools/migrate_max_mach_namespace.py +++ b/tools/migrate_max_mach_namespace.py @@ -59,6 +59,34 @@ def metadata_block(text, symbol): def patch_metadata(text): + # Check if MAX_MACH is already correctly placed after MAX_FUSELAGE_PITCH_ANGLE + try: + anchor_start, anchor_end = metadata_block(text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,') + max_mach_start, max_mach_end = metadata_block(text, ' Aircraft.Design.MAX_MACH,') + except RuntimeError: + # If we can't find the blocks, let the original logic handle it + pass + else: + # If MAX_MACH immediately follows MAX_FUSELAGE_PITCH_ANGLE (with only one blank line), + # check if the description is correct + expected_gap = '\n' + gap = text[anchor_end:max_mach_start] + if gap == expected_gap: + # Check if description matches expected + block = text[max_mach_start:max_mach_end] + expected_desc = ( + ' desc=(\n' + " 'Maximum aircraft design Mach number. Used by FLOPS-based air-conditioning, '\n" + " 'fuel-system, hydraulics, instruments, passenger-service, starter, and surface-'\n" + " 'control mass correlations, and by FLOPS pre-mission aerodynamics when computing '\n" + " 'the design lift coefficient.'\n" + ' ),\n' + ) + if expected_desc in block: + # Already in correct position with correct description - no changes needed + return text + + # Need to move/fix the block start, end = metadata_block(text, ' Aircraft.Design.MAX_MACH,') block = text[start:end] desc = ( @@ -77,10 +105,14 @@ def patch_metadata(text): close = block.rfind(')\n') block = block[:close] + desc + block[close:] - # Remove the block first, then insert it immediately after Aircraft.Design.MACH. + # Remove the block first, then insert it immediately after MAX_FUSELAGE_PITCH_ANGLE. text = text[:start] + text[end:] _, anchor_end = metadata_block(text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,') - text = text[:anchor_end] + '\n' + block + text[anchor_end:] + # Check if there are already blank lines after anchor_end and trim them to single newline + insert_pos = anchor_end + while insert_pos < len(text) and text[insert_pos] == '\n': + insert_pos += 1 + text = text[:anchor_end] + '\n' + block + text[insert_pos:] return text @@ -161,7 +193,10 @@ def apply(): changed.append(str(rel)) out = ROOT / MANIFEST - if changed or not out.exists(): + # Only rewrite manifest if there were actual content migrations (symbol/key replacements) + # or if the manifest doesn't exist yet + has_real_migrations = counts['python_symbol'] > 0 or counts['serialized_key'] > 0 + if has_real_migrations or not out.exists(): manifest = { 'issue': 'OpenMDAO/Aviary#1046', 'canonical_symbol': NEW_SYMBOL, From 5b42a835f9bf9d5e63b1493d8e136cbdca0bd576 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 22 Aug 2026 05:59:10 +0000 Subject: [PATCH 22/26] Apply ruff formatting to migrate_max_mach_namespace.py - Split long metadata_block call lines for readability - Remove trailing whitespace from blank line Fixes pre_commit/ruff-format CI check. Co-authored-by: Suhas --- tools/migrate_max_mach_namespace.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/migrate_max_mach_namespace.py b/tools/migrate_max_mach_namespace.py index 9419f47ad9..ce5f8743be 100644 --- a/tools/migrate_max_mach_namespace.py +++ b/tools/migrate_max_mach_namespace.py @@ -61,8 +61,12 @@ def metadata_block(text, symbol): def patch_metadata(text): # Check if MAX_MACH is already correctly placed after MAX_FUSELAGE_PITCH_ANGLE try: - anchor_start, anchor_end = metadata_block(text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,') - max_mach_start, max_mach_end = metadata_block(text, ' Aircraft.Design.MAX_MACH,') + anchor_start, anchor_end = metadata_block( + text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,' + ) + max_mach_start, max_mach_end = metadata_block( + text, ' Aircraft.Design.MAX_MACH,' + ) except RuntimeError: # If we can't find the blocks, let the original logic handle it pass @@ -85,7 +89,7 @@ def patch_metadata(text): if expected_desc in block: # Already in correct position with correct description - no changes needed return text - + # Need to move/fix the block start, end = metadata_block(text, ' Aircraft.Design.MAX_MACH,') block = text[start:end] From 4be6d5b8e9869076d18beb3ae17c911f4512de85 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 22 Aug 2026 06:02:29 +0000 Subject: [PATCH 23/26] Fix ruff-format: keep short metadata_block call on one line Ruff prefers the shorter call to fit on a single line for readability. Co-authored-by: Suhas --- tools/migrate_max_mach_namespace.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/migrate_max_mach_namespace.py b/tools/migrate_max_mach_namespace.py index ce5f8743be..37e2e7ae89 100644 --- a/tools/migrate_max_mach_namespace.py +++ b/tools/migrate_max_mach_namespace.py @@ -64,9 +64,7 @@ def patch_metadata(text): anchor_start, anchor_end = metadata_block( text, ' Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE,' ) - max_mach_start, max_mach_end = metadata_block( - text, ' Aircraft.Design.MAX_MACH,' - ) + max_mach_start, max_mach_end = metadata_block(text, ' Aircraft.Design.MAX_MACH,') except RuntimeError: # If we can't find the blocks, let the original logic handle it pass From 3b7d30e791dd10db194f2fa66d9adaf0d4b6272d Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Sat, 22 Aug 2026 09:50:06 -0700 Subject: [PATCH 24/26] ci: empty retrigger for OpenMDAO/Aviary#1277 --- .ci-retrigger | 1 + 1 file changed, 1 insertion(+) create mode 100644 .ci-retrigger diff --git a/.ci-retrigger b/.ci-retrigger new file mode 100644 index 0000000000..915c5f7d5c --- /dev/null +++ b/.ci-retrigger @@ -0,0 +1 @@ +retrigger From ade8cac32bdfaa33e887546fca98d4012847d95f Mon Sep 17 00:00:00 2001 From: Suhas <139655090+suhaslord@users.noreply.github.com> Date: Sat, 22 Aug 2026 09:50:43 -0700 Subject: [PATCH 25/26] ci: remove retrigger marker --- .ci-retrigger | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .ci-retrigger diff --git a/.ci-retrigger b/.ci-retrigger deleted file mode 100644 index 915c5f7d5c..0000000000 --- a/.ci-retrigger +++ /dev/null @@ -1 +0,0 @@ -retrigger From fb0463e65532a20dd17723bef04a28f3e7777349 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 22 Aug 2026 19:17:03 +0000 Subject: [PATCH 26/26] test: increase max_iter for test_bench_Solved2DOF_landing to harden against flakes Bump IPOPT max_iter from 100 to 150 for test_bench_Solved2DOF_landing to address occasional convergence failures on latest-ubuntu py314. Other platforms pass consistently; this provides margin for solver variability without changing test logic or tolerances. --- .../validation_cases/benchmark_tests/test_bench_solved2dof.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_solved2dof.py b/aviary/validation_cases/benchmark_tests/test_bench_solved2dof.py index 1152bc4773..985f8029f8 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_solved2dof.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_solved2dof.py @@ -202,7 +202,7 @@ def test_bench_Solved2DOF_landing(self): ) prob.check_and_preprocess_inputs() prob.build_model() - prob.add_driver('IPOPT', max_iter=100) + prob.add_driver('IPOPT', max_iter=150) prob.add_design_variables() prob.add_objective('time', ref=1e2) prob.setup()