From 44f12e20f2887914b5f7b86b827e40d95a76d217 Mon Sep 17 00:00:00 2001 From: Kenneth-T-Moore Date: Tue, 12 Nov 2024 14:33:11 -0500 Subject: [PATCH 1/2] Fixed FLOPS tabular with training data. --- .../aerodynamics/aerodynamics_builder.py | 60 ++++++++++++- .../flops_based/tabular_aero_group.py | 17 +++- .../test/test_tabular_aero_group.py | 85 +++++++++++++++++-- aviary/variable_info/variable_meta_data.py | 22 +++++ aviary/variable_info/variables.py | 4 + 5 files changed, 179 insertions(+), 9 deletions(-) diff --git a/aviary/subsystems/aerodynamics/aerodynamics_builder.py b/aviary/subsystems/aerodynamics/aerodynamics_builder.py index f43e45930..7de423498 100644 --- a/aviary/subsystems/aerodynamics/aerodynamics_builder.py +++ b/aviary/subsystems/aerodynamics/aerodynamics_builder.py @@ -330,7 +330,8 @@ def get_parameters(self, aviary_inputs=None, phase_info=None): method = 'computed' if phase_info is not None: - # Only solved_alpha has connectable inputs. + + # Only some methods have connectable training inputs. if method == 'solved_alpha': aero_data = aero_opt['aero_data'] @@ -369,6 +370,63 @@ def get_parameters(self, aviary_inputs=None, phase_info=None): params[Aircraft.Design.LIFT_POLAR] = lift_opts params[Aircraft.Design.DRAG_POLAR] = drag_opts + elif method == 'tabular': + CD0_data = aero_opt['CD0_data'] + + if isinstance(CD0_data, NamedValues): + altitude = CD0_data.get_item('altitude')[0] + mach = CD0_data.get_item('mach')[0] + + n1 = altitude.size + n2 = mach.size + n1u = np.unique(altitude).size + + if n1 > n1u: + # Data is free-format instead of pre-formatted. + n1 = n1u + n2 = np.unique(mach).size + + shape = (n1, n2) + + if aviary_inputs is not None and Aircraft.Design.LIFT_INDEPENDENT_DRAG_POLAR in aviary_inputs: + opts = { + 'val': aviary_inputs.get_val(Aircraft.Design.LIFT_INDEPENDENT_DRAG_POLAR), + 'static_target': True + } + else: + opts = {'shape': shape, + 'static_target': True} + + params[Aircraft.Design.LIFT_INDEPENDENT_DRAG_POLAR] = opts + + CDI_data = aero_opt['CDI_data'] + + if isinstance(CDI_data, NamedValues): + mach = CDI_data.get_item('mach')[0] + cl = CDI_data.get_item('lift_coefficient')[0] + + n1 = mach.size + n2 = cl.size + n1u = np.unique(mach).size + + if n1 > n1u: + # Data is free-format instead of pre-formatted. + n1 = n1u + n2 = np.unique(cl).size + + shape = (n1, n2) + + if aviary_inputs is not None and Aircraft.Design.LIFT_DEPENDENT_DRAG_POLAR in aviary_inputs: + opts = { + 'val': aviary_inputs.get_val(Aircraft.Design.LIFT_DEPENDENT_DRAG_POLAR), + 'static_target': True + } + else: + opts = {'shape': shape, + 'static_target': True} + + params[Aircraft.Design.LIFT_DEPENDENT_DRAG_POLAR] = opts + if method == 'computed': for var in COMPUTED_CORE_INPUTS: diff --git a/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py index 936495c02..1423fdc27 100644 --- a/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py @@ -93,6 +93,7 @@ def setup(self): else: method = '2D-lagrange3' + CD0_interp = build_data_interpolator( nn, interpolator_data=CD0_table, @@ -123,12 +124,24 @@ def setup(self): Aircraft.Wing.AREA, Dynamic.Mission.DYNAMIC_PRESSURE], promotes_outputs=[('cl', 'lift_coefficient'), Dynamic.Mission.LIFT]) + if connect_training_data: + extra_promotes = [('zero_lift_drag_coefficient_train', + Aircraft.Design.LIFT_INDEPENDENT_DRAG_POLAR)] + else: + extra_promotes = [] + self.add_subsystem('CD0_interp', CD0_interp, - promotes_inputs=['*'], + promotes_inputs=['*'] + extra_promotes, promotes_outputs=['*']) + if connect_training_data: + extra_promotes = [('lift_dependent_drag_coefficient_train', + Aircraft.Design.LIFT_DEPENDENT_DRAG_POLAR)] + else: + extra_promotes = [] + self.add_subsystem('CDI_interp', CDI_interp, - promotes_inputs=['*'], + promotes_inputs=['*'] + extra_promotes, promotes_outputs=['*']) self.add_subsystem( diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py index e458dbb71..e85f923d4 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py @@ -134,15 +134,13 @@ def setUp(self): CDI_table = _default_CDI_data() CDI_values = CDI_table.get_val('lift_dependent_drag_coefficient') - # CDI_table.delete('lift_dependent_drag_coefficient') CD0_table = _default_CD0_data() CD0_values = CD0_table.get_val('zero_lift_drag_coefficient') - # CD0_table.delete('zero_lift_drag_coefficient') drag_data = om.ExecComp() - drag_data.add_output('zero_lift_drag_coefficient_train', + drag_data.add_output(Aircraft.Design.LIFT_INDEPENDENT_DRAG_POLAR, CD0_values, units='unitless') - drag_data.add_output('lift_dependent_drag_coefficient_train', + drag_data.add_output(Aircraft.Design.LIFT_DEPENDENT_DRAG_POLAR, CDI_values, units='unitless') self.prob.model.add_subsystem( @@ -151,8 +149,33 @@ def setUp(self): promotes_outputs=['*'] ) - kwargs = {'method': 'tabular', 'CDI_data': CDI_table, 'CD0_data': CD0_table, } - # 'training_data': True} + # Pass zero-arrays for the training data, so that this test won't pass unless + # we are passing the values from the drag_data component. + shape = CDI_table.get_item('lift_dependent_drag_coefficient')[0].shape + CDI_clean_table = _default_CDI_data() + CDI_clean_table.set_val( + 'lift_dependent_drag_coefficient', + np.zeros(shape) + ) + + shape = CD0_table.get_item('zero_lift_drag_coefficient')[0].shape + CD0_clean_table = _default_CD0_data() + CD0_clean_table.set_val( + 'zero_lift_drag_coefficient', + np.zeros(shape) + ) + + self.CDI_values = CDI_values + self.CD0_values = CD0_values + self.CDI_clean_table = CDI_clean_table + self.CD0_clean_table = CD0_clean_table + + kwargs = { + 'method': 'tabular', + 'CDI_data': CDI_clean_table, + 'CD0_data': CD0_clean_table, + 'connect_training_data': True + } aero_builder = CoreAerodynamicsBuilder(code_origin=FLOPS) @@ -199,6 +222,56 @@ def test_case(self): partial_data, atol=1e-9, rtol=1e-12 ) # check the partial derivatives + def test_parameters(self): + + local_phase_info = deepcopy(phase_info) + core_aero = local_phase_info['cruise']['subsystem_options']['core_aerodynamics'] + + core_aero['method'] = 'tabular' + core_aero['connect_training_data'] = True + core_aero['CDI_data'] = self.CDI_clean_table + core_aero['CD0_data'] = self.CD0_clean_table + local_phase_info.pop('climb') + local_phase_info.pop('descent') + + prob = AviaryProblem() + + prob.load_inputs( + "subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv", + local_phase_info + ) + + # Preprocess inputs + prob.check_and_preprocess_inputs() + + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + + prob.link_phases() + + # Connect or set. + prob.aviary_inputs.set_val( + Aircraft.Design.LIFT_INDEPENDENT_DRAG_POLAR, + self.CD0_values + ) + prob.aviary_inputs.set_val( + Aircraft.Design.LIFT_DEPENDENT_DRAG_POLAR, + self.CDI_values + ) + + prob.setup() + + prob.set_initial_guesses() + + prob.run_model() + + assert_near_equal( + prob.get_val("traj.cruise.rhs_all.drag", units='lbf')[0], + 9896.0, + 1.0e-3 + ) + data_sets = ['LargeSingleAisle1FLOPS', 'LargeSingleAisle2FLOPS', 'N3CC'] diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index ac028334e..06b2c52fb 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -1296,6 +1296,28 @@ desc='Scaling factor for lift-dependent drag coefficient' ) +add_meta_data( + Aircraft.Design.LIFT_DEPENDENT_DRAG_POLAR, + meta_data=_MetaData, + historical_name={"GASP": None, + "FLOPS": None, + "LEAPS1": None + }, + units='unitless', + desc='Lift dependent drag polar computed during Aviary pre-mission.', +) + +add_meta_data( + Aircraft.Design.LIFT_INDEPENDENT_DRAG_POLAR, + meta_data=_MetaData, + historical_name={"GASP": None, + "FLOPS": None, + "LEAPS1": None + }, + units='unitless', + desc='Lift independent drag polar computed during Aviary pre-mission.', +) + add_meta_data( Aircraft.Design.LIFT_POLAR, meta_data=_MetaData, diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index 9e576cd1a..b3488defb 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -163,6 +163,10 @@ class Design: LIFT_CURVE_SLOPE = 'aircraft:design:lift_curve_slope' LIFT_DEPENDENT_DRAG_COEFF_FACTOR = \ 'aircraft:design:lift_dependent_drag_coeff_factor' + + LIFT_DEPENDENT_DRAG_POLAR = 'aircraft:design:lift_dependent_drag_polar' + LIFT_INDEPENDENT_DRAG_POLAR = 'aircraft:design:lift_independent_drag_polar' + LIFT_POLAR = 'aircraft:design:lift_polar' MAX_FUSELAGE_PITCH_ANGLE = 'aircraft:design:max_fuselage_pitch_angle' From 63ba736583466f0f9d12fec4e8dbf8b268b11707 Mon Sep 17 00:00:00 2001 From: Kenneth-T-Moore Date: Tue, 12 Nov 2024 17:20:15 -0500 Subject: [PATCH 2/2] PEP --- aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py | 1 - 1 file changed, 1 deletion(-) diff --git a/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py index 1423fdc27..8d7bb012a 100644 --- a/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/tabular_aero_group.py @@ -93,7 +93,6 @@ def setup(self): else: method = '2D-lagrange3' - CD0_interp = build_data_interpolator( nn, interpolator_data=CD0_table,