diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 0a49eebe5..3deea8577 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -412,13 +412,13 @@ def add_pre_mission_systems(self): # Check for 2DOF mission method # NOTE should solved trigger this as well? if self.mission_method is TWO_DEGREES_OF_FREEDOM: - self._add_gasp_takeoff_systems() + self._add_two_dof_takeoff_systems() # Check for HE mission method elif self.mission_method is HEIGHT_ENERGY: - self._add_flops_takeoff_systems() + self._add_height_energy_takeoff_systems() - def _add_flops_takeoff_systems(self): + def _add_height_energy_takeoff_systems(self): # Initialize takeoff options takeoff_options = Takeoff( airport_altitude=0., # ft @@ -431,7 +431,7 @@ def _add_flops_takeoff_systems(self): 'takeoff', takeoff, promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['mission:*']) - def _add_gasp_takeoff_systems(self): + def _add_two_dof_takeoff_systems(self): # Create options to values OptionsToValues = create_opts2vals( [Aircraft.CrewPayload.NUM_PASSENGERS, @@ -1120,11 +1120,14 @@ def add_post_mission_systems(self, include_landing=True): A user can override this with their own postmission systems. """ + if self.pre_mission_info['include_takeoff'] and self.mission_method is HEIGHT_ENERGY: + self._add_post_mission_takeoff_systems() + if include_landing and self.post_mission_info['include_landing']: if self.mission_method is HEIGHT_ENERGY: - self._add_flops_landing_systems() + self._add_height_energy_landing_systems() elif self.mission_method is TWO_DEGREES_OF_FREEDOM: - self._add_gasp_landing_systems() + self._add_two_dof_landing_systems() self.model.add_subsystem('post_mission', self.post_mission, promotes_inputs=['*'], @@ -1690,7 +1693,6 @@ def add_objective(self, objective_type=None, ref=None): elif objective_type == "fuel": self.model.add_objective(Mission.Objectives.FUEL, ref=ref) - # If 'mission_method' is 'FLOPS', add a 'fuel_burned' objective elif self.mission_method is HEIGHT_ENERGY: ref = ref if ref is not None else default_ref_values.get("fuel_burned", 1) self.model.add_objective("fuel_burned", ref=ref) @@ -2309,7 +2311,7 @@ def _get_all_subsystems(self, external_subsystems=None): return all_subsystems - def _add_flops_landing_systems(self): + def _add_height_energy_landing_systems(self): landing_options = Landing( ref_wing_area=self.aviary_inputs.get_val( Aircraft.Wing.AREA, units='ft**2'), @@ -2317,55 +2319,69 @@ def _add_flops_landing_systems(self): Mission.Landing.LIFT_COEFFICIENT_MAX) # no units ) - landing = landing_options.build_phase( - False, - ) + landing = landing_options.build_phase(False) self.model.add_subsystem( 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['mission:*']) - connect_takeoff_to_climb = not self.phase_info['climb']['user_options'].get( + last_flight_phase_name = list(self.phase_info.keys())[-1] + if self.phase_info[last_flight_phase_name]['user_options'].get('use_polynomial_control', True): + control_type_string = 'polynomial_control_values' + else: + control_type_string = 'control_values' + + self.model.connect(f'traj.{last_flight_phase_name}.states:mass', + Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) + self.model.connect(f'traj.{last_flight_phase_name}.{control_type_string}:altitude', Mission.Landing.INITIAL_ALTITUDE, + src_indices=[0]) + + def _add_post_mission_takeoff_systems(self): + first_flight_phase_name = list(self.phase_info.keys())[0] + connect_takeoff_to_climb = not self.phase_info[first_flight_phase_name]['user_options'].get( 'add_initial_mass_constraint', True) if connect_takeoff_to_climb: self.model.connect(Mission.Takeoff.FINAL_MASS, - 'traj.climb.initial_states:mass') + f'traj.{first_flight_phase_name}.initial_states:mass') self.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:distance') + f'traj.{first_flight_phase_name}.initial_states:distance') - # Create an ExecComp to compute the difference in mach - mach_diff_comp = om.ExecComp( - 'mach_resid_for_connecting_takeoff = final_mach - initial_mach') - self.model.add_subsystem('mach_diff_comp', mach_diff_comp) + if self.phase_info[first_flight_phase_name]['user_options'].get('use_polynomial_control', True): + control_type_string = 'polynomial_control_values' + else: + control_type_string = 'control_values' - # Connect the inputs to the mach difference component - self.model.connect(Mission.Takeoff.FINAL_MACH, 'mach_diff_comp.final_mach') - self.model.connect('traj.climb.control_values:mach', - 'mach_diff_comp.initial_mach', src_indices=[0]) + if self.phase_info[first_flight_phase_name]['user_options'].get('optimize_mach', False): + # Create an ExecComp to compute the difference in mach + mach_diff_comp = om.ExecComp( + 'mach_resid_for_connecting_takeoff = final_mach - initial_mach') + self.model.add_subsystem('mach_diff_comp', mach_diff_comp) - # Add constraint for mach difference - self.model.add_constraint( - 'mach_diff_comp.mach_resid_for_connecting_takeoff', equals=0.0) + # Connect the inputs to the mach difference component + self.model.connect(Mission.Takeoff.FINAL_MACH, + 'mach_diff_comp.final_mach') + self.model.connect(f'traj.{first_flight_phase_name}.{control_type_string}:mach', + 'mach_diff_comp.initial_mach', src_indices=[0]) - # Similar steps for altitude difference - alt_diff_comp = om.ExecComp( - 'altitude_resid_for_connecting_takeoff = final_altitude - initial_altitude', units='ft') - self.model.add_subsystem('alt_diff_comp', alt_diff_comp) + # Add constraint for mach difference + self.model.add_constraint( + 'mach_diff_comp.mach_resid_for_connecting_takeoff', equals=0.0) - self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - 'alt_diff_comp.final_altitude') - self.model.connect('traj.climb.control_values:altitude', - 'alt_diff_comp.initial_altitude', src_indices=[0]) + if self.phase_info[first_flight_phase_name]['user_options'].get('optimize_altitude', False): + # Similar steps for altitude difference + alt_diff_comp = om.ExecComp( + 'altitude_resid_for_connecting_takeoff = final_altitude - initial_altitude', units='ft') + self.model.add_subsystem('alt_diff_comp', alt_diff_comp) - self.model.add_constraint( - 'alt_diff_comp.altitude_resid_for_connecting_takeoff', equals=0.0) + self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, + 'alt_diff_comp.final_altitude') + self.model.connect(f'traj.{first_flight_phase_name}.{control_type_string}:altitude', + 'alt_diff_comp.initial_altitude', src_indices=[0]) - self.model.connect('traj.descent.states:mass', - Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) - self.model.connect('traj.descent.control_values:altitude', Mission.Landing.INITIAL_ALTITUDE, - src_indices=[0]) + self.model.add_constraint( + 'alt_diff_comp.altitude_resid_for_connecting_takeoff', equals=0.0) - def _add_gasp_landing_systems(self): + def _add_two_dof_landing_systems(self): self.model.add_subsystem( "landing", LandingSegment( diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index d84fa3d2e..b73505170 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -291,6 +291,7 @@ inputs.set_val(Mission.Design.RANGE, 3500, 'NM') inputs.set_val(Mission.Constraints.MAX_MACH, 0.785) inputs.set_val(Mission.Landing.DRAG_COEFFICIENT, 0.045, 'unitless') +inputs.set_val(Mission.Landing.LIFT_COEFFICIENT_MAX, 2.0, 'unitless') inputs.set_val(Mission.Takeoff.AIRPORT_ALTITUDE, 0., 'ft') inputs.set_val(Mission.Takeoff.DRAG_COEFFICIENT_MIN, 0.05, 'unitless') inputs.set_val(Mission.Takeoff.LIFT_COEFFICIENT_MAX, 2.0, 'unitless') @@ -308,6 +309,7 @@ inputs.set_val(Mission.Landing.SPOILER_DRAG_COEFFICIENT, 0.085000) inputs.set_val(Mission.Landing.SPOILER_LIFT_COEFFICIENT, -0.810000) inputs.set_val(Mission.Takeoff.THRUST_INCIDENCE, 0., 'deg') +inputs.set_val(Mission.Takeoff.FUEL_SIMPLE, 577., 'lbm') # Settings # --------------------------- diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 023c7e92a..3686ca5c8 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -8,8 +8,6 @@ from aviary.interface.default_phase_info.height_energy import phase_info as height_energy_phase_info from aviary.interface.default_phase_info.solved import phase_info as solved_phase_info from aviary.models.N3CC.N3CC_data import inputs -from aviary.variable_info.variables import Settings -from aviary.variable_info.enums import EquationsOfMotion class BaseProblemPhaseTestCase(unittest.TestCase): @@ -50,6 +48,10 @@ class HEZeroItersTestCase(BaseProblemPhaseTestCase): def test_zero_iters_height_energy(self): local_phase_info = deepcopy(height_energy_phase_info) local_inputs = deepcopy(inputs) + local_phase_info['pre_mission']['include_takeoff'] = True + local_phase_info['post_mission']['include_landing'] = True + local_phase_info['climb']['user_options']['fix_initial'] = False + local_phase_info['climb']['user_options']['input_initial'] = True self.build_and_run_problem(local_inputs, local_phase_info)