From 5d9ed03bc892ba451f6f7b4f4bad5e5468414f74 Mon Sep 17 00:00:00 2001 From: Owen Shepherd Date: Thu, 5 Feb 2026 07:36:12 -0800 Subject: [PATCH 1/5] Adding unit tests to test new report dir naming. Essentially, if your problem is named test, the baseline report dir will be 'test_out' and if you run multiple problems of a specific type, i.e. 'fallout', subsequent runs of the same problem will increment the directory: - test_fallout_out - test_fallout_2_out - test_fallout_3_out - and so on. --- aviary/interface/test/test_reports.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/aviary/interface/test/test_reports.py b/aviary/interface/test/test_reports.py index c5eb2963d..bc1e14c6c 100644 --- a/aviary/interface/test/test_reports.py +++ b/aviary/interface/test/test_reports.py @@ -1,4 +1,5 @@ import csv +import os import unittest from copy import deepcopy from pathlib import Path @@ -135,6 +136,27 @@ def build_pre_mission(self, aviary_inputs): # no need to run this model, just generate the report. prob.final_setup() + def test_report_directory_naming(self): + problem_name = "test_problem" + phase_info['post_mission']['target_range'] = (2500.0, 'nmi') + prob = AviaryProblem(name=problem_name) + prob.load_inputs( + 'models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv', phase_info + ) + prob.check_and_preprocess_inputs() + prob.build_model() + prob.add_driver('SLSQP', max_iter=50) + prob.add_design_variables() + prob.add_objective() + prob.setup() + prob.run_aviary_problem() + self.assertTrue(os.path.exists(f"{problem_name}_out")) + _ = prob.run_off_design_mission(problem_type='fallout', mission_gross_mass=115000) + self.assertTrue(os.path.exists(f"{problem_name}_fallout_out")) + _ = prob.run_off_design_mission(problem_type='fallout', mission_gross_mass=115000) + self.assertTrue(os.path.exists(f"{problem_name}_fallout_2_out")) + _ = prob.run_off_design_mission(problem_type='fallout', mission_gross_mass=115000) + self.assertTrue(os.path.exists(f"{problem_name}_fallout_3_out")) if __name__ == '__main__': unittest.main() From e803f6c70fecde35e7cfab6e723ec9a3570bb885 Mon Sep 17 00:00:00 2001 From: Owen Shepherd Date: Thu, 5 Feb 2026 07:41:08 -0800 Subject: [PATCH 2/5] Creates logic to pass test_report_directory_naming This adds some logic to update the naming of the output directories in line with the aforementioned unit test. --- aviary/interface/methods_for_level2.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 097d476d4..666f58fa6 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1366,7 +1366,14 @@ def run_off_design_mission( ) if name is None: - name = name = self._name + '_off_design' + suggestion = self._name + "_" + str(problem_type.value) + # For while loop / numbering names + suggestion_update = suggestion + counter = 2 + while os.path.exists(os.path.join(".", suggestion_update + "_out")): + suggestion_update = suggestion + "_" + str(counter) + counter += 1 + name = suggestion_update off_design_prob = AviaryProblem(name=name) # Set up problem for mission, such as equations of motion, configurators, etc. From db564f576648d97921b07b81ed2fcd9807a0893e Mon Sep 17 00:00:00 2001 From: Owen Shepherd Date: Thu, 5 Feb 2026 08:01:40 -0800 Subject: [PATCH 3/5] ruff / cleanup --- aviary/interface/methods_for_level2.py | 8 ++++---- aviary/interface/test/test_reports.py | 11 ++++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 666f58fa6..12a90b38f 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1366,12 +1366,12 @@ def run_off_design_mission( ) if name is None: - suggestion = self._name + "_" + str(problem_type.value) - # For while loop / numbering names + # Numbering problem names. + suggestion = self._name + '_' + str(problem_type.value) suggestion_update = suggestion counter = 2 - while os.path.exists(os.path.join(".", suggestion_update + "_out")): - suggestion_update = suggestion + "_" + str(counter) + while os.path.exists(suggestion_update + '_out'): + suggestion_update = suggestion + '_' + str(counter) counter += 1 name = suggestion_update off_design_prob = AviaryProblem(name=name) diff --git a/aviary/interface/test/test_reports.py b/aviary/interface/test/test_reports.py index bc1e14c6c..ccd11abd3 100644 --- a/aviary/interface/test/test_reports.py +++ b/aviary/interface/test/test_reports.py @@ -137,7 +137,7 @@ def build_pre_mission(self, aviary_inputs): prob.final_setup() def test_report_directory_naming(self): - problem_name = "test_problem" + problem_name = 'test_problem' phase_info['post_mission']['target_range'] = (2500.0, 'nmi') prob = AviaryProblem(name=problem_name) prob.load_inputs( @@ -150,13 +150,14 @@ def test_report_directory_naming(self): prob.add_objective() prob.setup() prob.run_aviary_problem() - self.assertTrue(os.path.exists(f"{problem_name}_out")) + self.assertTrue(os.path.exists(f'{problem_name}_out')) _ = prob.run_off_design_mission(problem_type='fallout', mission_gross_mass=115000) - self.assertTrue(os.path.exists(f"{problem_name}_fallout_out")) + self.assertTrue(os.path.exists(f'{problem_name}_fallout_out')) _ = prob.run_off_design_mission(problem_type='fallout', mission_gross_mass=115000) - self.assertTrue(os.path.exists(f"{problem_name}_fallout_2_out")) + self.assertTrue(os.path.exists(f'{problem_name}_fallout_2_out')) _ = prob.run_off_design_mission(problem_type='fallout', mission_gross_mass=115000) - self.assertTrue(os.path.exists(f"{problem_name}_fallout_3_out")) + self.assertTrue(os.path.exists(f'{problem_name}_fallout_3_out')) + if __name__ == '__main__': unittest.main() From a5d5f80d805b5a80a9cada6294f13f1ed844a4c4 Mon Sep 17 00:00:00 2001 From: Owen Shepherd Date: Thu, 5 Feb 2026 23:22:46 -0800 Subject: [PATCH 4/5] Changing output dir naming logic. Use the current datetime instead of numbering output directories. --- aviary/interface/methods_for_level2.py | 11 +++-------- aviary/interface/test/test_reports.py | 23 ---------------------- aviary/interface/test/test_save_results.py | 15 ++++++++++++++ 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 12a90b38f..08a19d4ea 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1366,14 +1366,9 @@ def run_off_design_mission( ) if name is None: - # Numbering problem names. - suggestion = self._name + '_' + str(problem_type.value) - suggestion_update = suggestion - counter = 2 - while os.path.exists(suggestion_update + '_out'): - suggestion_update = suggestion + '_' + str(counter) - counter += 1 - name = suggestion_update + name = self._name + '_' + str(problem_type.value) + curr_time = datetime.now().strftime("%m%d%y%H%M%S") + name += '_' + curr_time off_design_prob = AviaryProblem(name=name) # Set up problem for mission, such as equations of motion, configurators, etc. diff --git a/aviary/interface/test/test_reports.py b/aviary/interface/test/test_reports.py index ccd11abd3..c5eb2963d 100644 --- a/aviary/interface/test/test_reports.py +++ b/aviary/interface/test/test_reports.py @@ -1,5 +1,4 @@ import csv -import os import unittest from copy import deepcopy from pathlib import Path @@ -136,28 +135,6 @@ def build_pre_mission(self, aviary_inputs): # no need to run this model, just generate the report. prob.final_setup() - def test_report_directory_naming(self): - problem_name = 'test_problem' - phase_info['post_mission']['target_range'] = (2500.0, 'nmi') - prob = AviaryProblem(name=problem_name) - prob.load_inputs( - 'models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv', phase_info - ) - prob.check_and_preprocess_inputs() - prob.build_model() - prob.add_driver('SLSQP', max_iter=50) - prob.add_design_variables() - prob.add_objective() - prob.setup() - prob.run_aviary_problem() - self.assertTrue(os.path.exists(f'{problem_name}_out')) - _ = prob.run_off_design_mission(problem_type='fallout', mission_gross_mass=115000) - self.assertTrue(os.path.exists(f'{problem_name}_fallout_out')) - _ = prob.run_off_design_mission(problem_type='fallout', mission_gross_mass=115000) - self.assertTrue(os.path.exists(f'{problem_name}_fallout_2_out')) - _ = prob.run_off_design_mission(problem_type='fallout', mission_gross_mass=115000) - self.assertTrue(os.path.exists(f'{problem_name}_fallout_3_out')) - if __name__ == '__main__': unittest.main() diff --git a/aviary/interface/test/test_save_results.py b/aviary/interface/test/test_save_results.py index d15e24d86..c79e92b97 100644 --- a/aviary/interface/test/test_save_results.py +++ b/aviary/interface/test/test_save_results.py @@ -1,5 +1,8 @@ import unittest +from unittest.mock import patch, Mock from copy import deepcopy +from datetime import datetime +import re from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs @@ -66,6 +69,18 @@ def test_fallout(self): prob = reload_aviary_problem('interface/test/sizing_results_for_test.json') prob.run_off_design_mission(problem_type='fallout', phase_info=local_phase_info) + @require_pyoptsparse(optimizer='IPOPT') + @patch('aviary.interface.methods_for_level2.datetime') + def test_output_naming(self, mock_datetime): + fixed_now = datetime(2026, 2, 5, 12, 1, 1) + mock_datetime.now.return_value = fixed_now + + local_phase_info = deepcopy(phase_info) + + prob = reload_aviary_problem('interface/test/sizing_results_for_test.json') + prob = prob.run_off_design_mission(problem_type='fallout', phase_info=local_phase_info) + self.assertTrue('fallout_020526120101' in prob._name) + def compare_files(self, test_file, validation_file): """ Compares the specified file with a validation file. From 86fea6698f033cb910ca40acdd97eb3249e0736f Mon Sep 17 00:00:00 2001 From: Owen Shepherd Date: Fri, 6 Feb 2026 00:11:18 -0800 Subject: [PATCH 5/5] ruff --- aviary/interface/methods_for_level2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 08a19d4ea..04aa7a971 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1367,7 +1367,7 @@ def run_off_design_mission( if name is None: name = self._name + '_' + str(problem_type.value) - curr_time = datetime.now().strftime("%m%d%y%H%M%S") + curr_time = datetime.now().strftime('%m%d%y%H%M%S') name += '_' + curr_time off_design_prob = AviaryProblem(name=name)