Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to height energy mission based on Ken's feedback #94

Merged
merged 5 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 56 additions & 40 deletions aviary/interface/methods_for_level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,13 +416,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 @@ -435,7 +435,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 @@ -1180,11 +1180,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()
crecine marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -1750,7 +1753,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 @@ -2369,63 +2371,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].get('optimize_mach', False):
if self.phase_info[first_flight_phase_name].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])
# 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].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 @@ -49,6 +47,10 @@ class HEZeroItersTestCase(BaseProblemPhaseTestCase):
@require_pyoptsparse(optimizer="IPOPT")
def test_zero_iters_height_energy(self):
local_phase_info = deepcopy(height_energy_phase_info)
local_phase_info['pre_mission']['include_takeoff'] = True
crecine marked this conversation as resolved.
Show resolved Hide resolved
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(inputs, local_phase_info)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ def run_trajectory(sim=True):
promotes_outputs=['mission:*'])

traj.link_phases(["climb", "cruise", "descent"], [
"time", Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple)
"time", Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple)

traj = setup_trajectory_params(prob.model, traj, aviary_inputs)

Expand Down
Loading