Skip to content

Commit

Permalink
Merge pull request #94 from johnjasa/update_height_energy
Browse files Browse the repository at this point in the history
Improvements to height energy mission based on Ken's feedback
  • Loading branch information
crecine authored Jan 25, 2024
2 parents a2d8b44 + 51d8f29 commit b1505df
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 42 deletions.
96 changes: 56 additions & 40 deletions aviary/interface/methods_for_level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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=['*'],
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -2309,63 +2311,77 @@ 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'),
Cl_max_ldg=self.aviary_inputs.get_val(
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(
Expand Down
2 changes: 2 additions & 0 deletions aviary/models/N3CC/N3CC_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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
# ---------------------------
Expand Down
6 changes: 4 additions & 2 deletions aviary/validation_cases/benchmark_tests/test_0_iters.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)


Expand Down

0 comments on commit b1505df

Please sign in to comment.