def gauss_lobatto_subsets_and_nodes(n, seg_idx, compressed=False): """ Returns the subset dictionary corresponding to the Gauss-Lobatto transcription. Parameters ---------- n : int The total number of nodes in the Gauss-Lobatto segment. Must be an odd number. seg_idx : int The index of this segment within its phase. compressed : bool True if the subset requested is for a phase with compressed transcription. Returns ------- dict A dictionary with the following keys: 'disc' gives the indices of the state discretization nodes (deprecated) 'state_disc' gives the indices of the state discretization nodes 'state_input' gives the indices of the state input nodes 'control_disc' gives the indices of the control discretization nodes 'control_input' gives the indices of the control input nodes 'segment_ends' gives the indices of the nodes at the start (even) and end (odd) of a segment 'col' gives the indices of the collocation nodes 'all' gives all node indices. Notes ----- Subset 'state_input' is the same as subset 'state_disc' if `compressed == False` or `first_seg == True`. The same is true of subsets 'control_input' and 'control_disc'. """ if n % 2 == 0: raise ValueError( 'A Gauss-Lobatto scheme must use an odd number of points') subsets = { 'disc': np.arange(0, n, 2, dtype=int), 'state_disc': np.arange(0, n, 2, dtype=int), 'state_input': np.arange(0, n, 2, dtype=int) if not compressed or seg_idx == 0 else np.arange(2, n, 2, dtype=int), 'control_disc': np.arange(n, dtype=int), 'control_input': np.arange(n, dtype=int) if not compressed or seg_idx == 0 else np.arange(1, n, dtype=int), 'segment_ends': np.array([0, n - 1], dtype=int), 'col': np.arange(1, n, 2, dtype=int), 'all': np.arange(n, dtype=int), 'solution': np.arange(n, dtype=int), } return subsets, lgl(n)[0]
def test_single_phase_reverse_propagation_rk(self): prob = om.Problem() num_seg = 10 seg_ends, _ = lgl(num_seg + 1) # First phase: normal operation. transcription = dm.RungeKutta(num_segments=num_seg) phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = prob.model.add_subsystem('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.add_state('state_of_charge', fix_initial=True, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') prob.setup() prob['phase0.t_initial'] = 0 prob['phase0.t_duration'] = -1.0 * 3600 prob['phase0.states:state_of_charge'][:] = 0.63464982 prob.set_solver_print(level=0) prob.run_model() soc0 = prob['phase0.states:state_of_charge'] assert_near_equal(soc0[-1], 1.0, 1e-6)
def test_solver_defects_single_phase_reverse_propagation(self): prob = Problem() num_seg = 5 seg_ends, _ = lgl(num_seg + 1) # First phase: normal operation. transcription = Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) phase0 = Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = prob.model.add_subsystem('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.set_state_options('state_of_charge', fix_initial=True, fix_final=False, solve_segments=True) prob.setup() prob['phase0.t_initial'] = 0 prob['phase0.t_duration'] = -1.0 * 3600 prob['phase0.states:state_of_charge'][:] = 0.63464982 prob.set_solver_print(level=0) prob.run_model() soc0 = prob['phase0.states:state_of_charge'] assert_rel_error(self, soc0[-1], 1.0, 1e-6)
def test_static_input_parameter_connections_gl(self): class TrajectoryODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] self.add_subsystem('sum', om.ExecComp('m_tot = sum(m)', m={'value': np.zeros((2, 2)), 'units': 'kg'}, m_tot={'value': np.zeros(nn), 'units': 'kg'})) self.add_subsystem('eom', FlightPathEOM2D(num_nodes=nn)) self.connect('sum.m_tot', 'eom.m') optimizer = 'SLSQP' num_segments = 1 transcription_order = 5 p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.declare_coloring() seg_ends, _ = lgl(num_segments + 1) phase = dm.Phase(ode_class=TrajectoryODE, transcription=dm.GaussLobatto(num_segments=num_segments, order=transcription_order, segment_ends=seg_ends)) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0.0, 100.0), duration_bounds=(0., 100.), units='s') phase.add_state('h', fix_initial=True, fix_final=True, lower=0.0, units='m', rate_source='eom.h_dot') phase.add_state('v', fix_initial=True, fix_final=False, units='m/s', rate_source='eom.v_dot') phase.add_input_parameter('m', val=[[1, 2], [3, 4]], units='kg', targets='sum.m', dynamic=False) p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 100.0 p['phase0.states:h'] = phase.interpolate(ys=[20, 0], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, -5], nodes='state_input') p.run_model() expected = np.array([[1, 2], [3, 4]]) assert_rel_error(self, p.get_val('phase0.rhs_disc.sum.m'), expected) assert_rel_error(self, p.get_val('phase0.rhs_col.sum.m'), expected)
def test_solver_defects_reverse_propagation(self): prob = om.Problem() num_seg = 5 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. transcription = dm.Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.add_state('state_of_charge', fix_initial=True, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') # Second phase: normal operation. phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) traj_p1.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') traj_p1.add_objective('time', loc='final') traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) prob.setup() prob['traj.phase0.t_initial'] = 0 prob['traj.phase0.t_duration'] = -1.0 * 3600 prob['traj.phase0.states:state_of_charge'][:] = 0.23794217 prob['traj.phase1.t_initial'] = 0 prob['traj.phase1.t_duration'] = -1.0 * 3600 prob.set_solver_print(level=0) prob.run_model() soc1 = prob['traj.phase1.states:state_of_charge'] assert_near_equal(soc1[-1], 1.0, 1e-6)
def explicit_subsets_and_nodes(n, seg_idx, compressed=False, shooting='single'): """ Returns the subset dictionary corresponding to the Runge-Kutta transcription. Parameters ---------- n : int The total number of control discretization nodes in the Runge-Kutta segment. seg_idx : int The index of this segment within its phase. compressed : bool True if the subset requested is for a phase with compressed transcription. shooting : str One of the shooting method types for explicit phases ('single', 'hybrid', or 'multiple') Returns ------- subsets : dict of {str: np.ndarray} 'state_disc' gives the indices of the state discretization nodes 'state_input' gives the indices of the state input nodes 'control_disc' gives the indices of the control discretization nodes 'control_input' gives the indices of the control input nodes 'segment_ends' gives the indices of the nodes at the start (even) and end (odd) of a segment 'step' gives the indices of the nodes at step boundaries 'all' gives all node indices nodes : np.ndarray The location of all nodes on the interval -1, 1. Notes ----- (subsets, nodes) Subset 'state_input' is the same as subset 'state_disc'. """ subsets = { 'disc': np.arange(0, n, 2, dtype=int), 'state_disc': np.zeros((1,), dtype=int) if seg_idx == 0 or shooting == 'multiple' else np.empty((0,), dtype=int), 'state_input': np.zeros((1,), dtype=int) if seg_idx == 0 or shooting == 'multiple' else np.empty((0,), dtype=int), 'control_disc': np.arange(n, dtype=int), 'control_input': np.arange(n, dtype=int) if not compressed or seg_idx == 0 else np.arange(1, n, dtype=int), 'segment_ends': np.array([0, n-1], dtype=int), 'col': np.arange(1, n, 2, dtype=int), 'all': np.arange(n, dtype=int), 'solution': np.arange(n, dtype=int), } return subsets, lgl(n)[0]
def test_polynomial_control(self): tx = dm.GaussLobatto(num_segments=8, order=5, compressed=True) phase = dm.Phase(ode_class=BrachistochroneODE, transcription=tx) phase.add_polynomial_control('u', fix_initial=True, fix_final=True, order=3) xs = np.linspace(-10, 10, 100) ys = xs**3 input_nodes, _ = lgl(4) expected = np.atleast_2d((10 * input_nodes)**3).T assert_near_equal(phase.interp('u', ys=ys, xs=xs, kind='cubic'), expected)
def test_basic(self): import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.battery_multibranch.battery_multibranch_ode import BatteryODE from dymos.utils.lgl import lgl prob = om.Problem() opt = prob.driver = om.ScipyOptimizeDriver() opt.declare_coloring() opt.options['optimizer'] = 'SLSQP' num_seg = 5 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. transcription = dm.Radau(num_segments=num_seg, order=5, segment_ends=seg_ends, compressed=False) phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.add_state('state_of_charge', fix_initial=True, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') # Second phase: normal operation. phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) traj_p1.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') traj_p1.add_objective('time', loc='final') # Second phase, but with battery failure. phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_bfail.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') # Second phase, but with motor failure. phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_mfail.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time']) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time']) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time']) prob.model.options['assembled_jac_type'] = 'csc' prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() prob['traj.phase0.t_initial'] = 0 prob['traj.phase0.t_duration'] = 1.0 * 3600 prob['traj.phase1.t_initial'] = 1.0 * 3600 prob['traj.phase1.t_duration'] = 1.0 * 3600 prob['traj.phase1_bfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_bfail.t_duration'] = 1.0 * 3600 prob['traj.phase1_mfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_mfail.t_duration'] = 1.0 * 3600 prob.set_solver_print(level=0) dm.run_problem(prob) soc0 = prob['traj.phase0.states:state_of_charge'] soc1 = prob['traj.phase1.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.states:state_of_charge'] # Final value for State of Chrage in each segment should be a good test. print('State of Charge after 1 hour') assert_near_equal(soc0[-1], 0.63464982, 1e-6) print('State of Charge after 2 hours') assert_near_equal(soc1[-1], 0.23794217, 1e-6) print('State of Charge after 2 hours, battery fails at 1 hour') assert_near_equal(soc1b[-1], 0.0281523, 1e-6) print('State of Charge after 2 hours, motor fails at 1 hour') assert_near_equal(soc1m[-1], 0.18625395, 1e-6) # Plot Results t0 = prob['traj.phases.phase0.time.time'] / 3600 t1 = prob['traj.phases.phase1.time.time'] / 3600 t1b = prob['traj.phases.phase1_bfail.time.time'] / 3600 t1m = prob['traj.phases.phase1_mfail.time.time'] / 3600 plt.subplot(2, 1, 1) plt.plot(t0, soc0, 'b') plt.plot(t1, soc1, 'b') plt.plot(t1b, soc1b, 'r') plt.plot(t1m, soc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('State of Charge (percent)') I_Li0 = prob['traj.phases.phase0.rhs_all.pwr_balance.I_Li'] I_Li1 = prob['traj.phases.phase1.rhs_all.pwr_balance.I_Li'] I_Li1b = prob['traj.phases.phase1_bfail.rhs_all.pwr_balance.I_Li'] I_Li1m = prob['traj.phases.phase1_mfail.rhs_all.pwr_balance.I_Li'] plt.subplot(2, 1, 2) plt.plot(t0, I_Li0, 'b') plt.plot(t1, I_Li1, 'b') plt.plot(t1b, I_Li1b, 'r') plt.plot(t1m, I_Li1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Line Current (A)') plt.legend([ 'Phase 1', 'Phase 2', 'Phase 2 Battery Fail', 'Phase 2 Motor Fail' ], loc=2) plt.show()
def test_steady_aircraft_for_docs(self): import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.aircraft_steady_flight.aircraft_ode import AircraftODE from dymos.examples.plotting import plot_results from dymos.utils.lgl import lgl p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() num_seg = 15 seg_ends, _ = lgl(num_seg + 1) traj = p.model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=AircraftODE, transcription=dm.Radau(num_segments=num_seg, segment_ends=seg_ends, order=3, compressed=False))) # Pass Reference Area from an external source assumptions = p.model.add_subsystem('assumptions', om.IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') phase.set_time_options(fix_initial=True, duration_bounds=(300, 10000), duration_ref=5600) phase.add_state('range', units='NM', rate_source='range_rate_comp.dXdt:range', fix_initial=True, fix_final=False, ref=1e-3, defect_ref=1e-3, lower=0, upper=2000) phase.add_state('mass_fuel', units='lbm', rate_source='propulsion.dXdt:mass_fuel', fix_initial=True, fix_final=True, upper=1.5E5, lower=0.0, ref=1e2, defect_ref=1e2) phase.add_state('alt', units='kft', rate_source='climb_rate', fix_initial=True, fix_final=True, lower=0.0, upper=60, ref=1e-3, defect_ref=1e-3) phase.add_control('climb_rate', units='ft/min', opt=True, lower=-3000, upper=3000, targets=['gam_comp.climb_rate'], rate_continuity=True, rate2_continuity=False) phase.add_control('mach', targets=['tas_comp.mach', 'aero.mach'], units=None, opt=False) phase.add_parameter( 'S', targets=['aero.S', 'flight_equilibrium.S', 'propulsion.S'], units='m**2') phase.add_parameter('mass_empty', targets=['mass_comp.mass_empty'], units='kg') phase.add_parameter('mass_payload', targets=['mass_comp.mass_payload'], units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=2.0, shape=(1, )) p.model.connect('assumptions.S', 'traj.phase0.parameters:S') p.model.connect('assumptions.mass_empty', 'traj.phase0.parameters:mass_empty') p.model.connect('assumptions.mass_payload', 'traj.phase0.parameters:mass_payload') phase.add_objective('range', loc='final', ref=-1.0e-4) phase.add_timeseries_output('aero.CL') phase.add_timeseries_output('aero.CD') p.setup() p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 3600.0 p['traj.phase0.states:range'][:] = phase.interpolate( ys=(0, 724.0), nodes='state_input') p['traj.phase0.states:mass_fuel'][:] = phase.interpolate( ys=(30000, 1e-3), nodes='state_input') p['traj.phase0.states:alt'][:] = 10.0 p['traj.phase0.controls:mach'][:] = 0.8 p['assumptions.S'] = 427.8 p['assumptions.mass_empty'] = 0.15E6 p['assumptions.mass_payload'] = 84.02869 * 400 dm.run_problem(p) assert_near_equal(p.get_val('traj.phase0.timeseries.states:range', units='NM')[-1], 726.85, tolerance=1.0E-2) exp_out = traj.simulate() assert_near_equal(p.get_val('traj.phase0.timeseries.CL')[0], exp_out.get_val('traj.phase0.timeseries.CL')[0], tolerance=1.0E-9) assert_near_equal(p.get_val('traj.phase0.timeseries.CD')[0], exp_out.get_val('traj.phase0.timeseries.CD')[0], tolerance=1.0E-9) plot_results( [('traj.phase0.timeseries.states:range', 'traj.phase0.timeseries.states:alt', 'range (NM)', 'altitude (kft)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:mass_fuel', 'time (s)', 'fuel mass (lbm)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.CL', 'time (s)', 'lift coefficient'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.CD', 'time (s)', 'drag coefficient')], title='Commercial Aircraft Optimization', p_sol=p, p_sim=exp_out) plt.show()
def test_optimizer_segments_direct_connections(self): prob = Problem() if optimizer == 'SNOPT': opt = prob.driver = pyOptSparseDriver() opt.options['optimizer'] = optimizer opt.options['dynamic_simul_derivs'] = True opt.opt_settings['Major iterations limit'] = 1000 opt.opt_settings['Major feasibility tolerance'] = 1.0E-6 opt.opt_settings['Major optimality tolerance'] = 1.0E-6 opt.opt_settings["Linesearch tolerance"] = 0.10 opt.opt_settings['iSumm'] = 6 else: opt = prob.driver = ScipyOptimizeDriver() opt.options['dynamic_simul_derivs'] = True num_seg = 5 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', Trajectory()) # First phase: normal operation. transcription = Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) phase0 = Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.set_state_options('state_of_charge', fix_initial=True, fix_final=False) # Second phase: normal operation. phase1 = Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) traj_p1.set_state_options('state_of_charge', fix_initial=False, fix_final=False) traj_p1.add_objective('time', loc='final') # Second phase, but with battery failure. phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_bfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False) # Second phase, but with motor failure. phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_mfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False) traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) prob.model.options['assembled_jac_type'] = 'csc' prob.model.linear_solver = DirectSolver(assemble_jac=True) prob.setup() prob['traj.phase0.t_initial'] = 0 prob['traj.phase0.t_duration'] = 1.0 * 3600 prob['traj.phase1.t_initial'] = 1.0 * 3600 prob['traj.phase1.t_duration'] = 1.0 * 3600 prob['traj.phase1_bfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_bfail.t_duration'] = 1.0 * 3600 prob['traj.phase1_mfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_mfail.t_duration'] = 1.0 * 3600 prob.set_solver_print(level=0) prob.run_driver() soc0 = prob['traj.phase0.states:state_of_charge'] soc1 = prob['traj.phase1.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.states:state_of_charge'] # Final value for State of Chrage in each segment should be a good test. assert_rel_error(self, soc0[-1], 0.63464982, 1e-6) assert_rel_error(self, soc1[-1], 0.23794217, 1e-6) assert_rel_error(self, soc1b[-1], 0.0281523, 1e-6) assert_rel_error(self, soc1m[-1], 0.18625395, 1e-6)
def test_connected_linkages_rk(self): prob = om.Problem() if optimizer == 'SNOPT': opt = prob.driver = om.pyOptSparseDriver() opt.options['optimizer'] = optimizer opt.declare_coloring() opt.opt_settings['Major iterations limit'] = 1000 opt.opt_settings['Major feasibility tolerance'] = 1.0E-6 opt.opt_settings['Major optimality tolerance'] = 1.0E-6 opt.opt_settings["Linesearch tolerance"] = 0.10 opt.opt_settings['iSumm'] = 6 else: opt = prob.driver = om.ScipyOptimizeDriver() opt.declare_coloring() num_seg = 20 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. transcription = dm.RungeKutta(num_segments=num_seg) phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.add_state('state_of_charge', fix_initial=True, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') # Second phase: normal operation. phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) traj_p1.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') traj_p1.add_objective('time', loc='final') # Second phase, but with battery failure. phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_bfail.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') # Second phase, but with motor failure. phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_mfail.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) prob.model.options['assembled_jac_type'] = 'csc' prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() prob['traj.phase0.t_initial'] = 0 prob['traj.phase0.t_duration'] = 1.0 * 3600 prob['traj.phase1.t_initial'] = 1.0 * 3600 prob['traj.phase1.t_duration'] = 1.0 * 3600 prob['traj.phase1_bfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_bfail.t_duration'] = 1.0 * 3600 prob['traj.phase1_mfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_mfail.t_duration'] = 1.0 * 3600 prob.set_solver_print(level=0) dm.run_problem(prob) soc0 = prob['traj.phase0.states:state_of_charge'] soc1 = prob['traj.phase1.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.states:state_of_charge'] # Final value for State of Chrage in each segment should be a good test. assert_near_equal(soc0[-1], 0.63464982, 5e-5) assert_near_equal(soc1[-1], 0.23794217, 5e-5) assert_near_equal(soc1b[-1], 0.0281523, 5e-5) assert_near_equal(soc1m[-1], 0.18625395, 5e-5)
def test_solver_defects(self): prob = om.Problem() num_seg = 5 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. transcription = dm.Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.add_state('state_of_charge', fix_initial=True, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') # Second phase: normal operation. phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) traj_p1.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') traj_p1.add_objective('time', loc='final') # Second phase, but with battery failure. phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_bfail.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') # Second phase, but with motor failure. phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_mfail.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) prob.setup() prob['traj.phase0.t_initial'] = 0 prob['traj.phase0.t_duration'] = 1.0 * 3600 prob['traj.phase1.t_initial'] = 1.0 * 3600 prob['traj.phase1.t_duration'] = 1.0 * 3600 prob['traj.phase1_bfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_bfail.t_duration'] = 1.0 * 3600 prob['traj.phase1_mfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_mfail.t_duration'] = 1.0 * 3600 prob['traj.phase0.states:state_of_charge'][:] = 1.0 prob.set_solver_print(level=0) prob.run_model() soc0 = prob['traj.phase0.states:state_of_charge'] soc1 = prob['traj.phase1.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.states:state_of_charge'] # Final value for State of Charge in each segment should be a good test. assert_near_equal(soc0[-1], 0.63464982, 1e-6) assert_near_equal(soc1[-1], 0.23794217, 1e-6) assert_near_equal(soc1b[-1], 0.0281523, 1e-6) assert_near_equal(soc1m[-1], 0.18625395, 1e-6)
scale=.25) if i == 0: plt.savefig('lgl_animation_1.png') # Plot the interpolating polynomials t_dense = np.linspace(time[0], time[-1], 100) A_i, B_i, A_d, B_d = hermite_matrices(time[state_disc_idxs], t_dense) y_dense = (A_i.dot(y[state_disc_idxs]) + B_i.dot(ydot[state_disc_idxs])) vy_dense = A_i.dot(vy[state_disc_idxs]) + B_i.dot(vydot[state_disc_idxs]) axes[0].plot(t_dense, y_dense, ms=None, ls=':') axes[1].plot(t_dense, vy_dense, ms=None, ls=':') # Plot the values and rates at the collocation nodes tau_s, _ = lgl(3) tau_disc = tau_s[0::2] tau_col = tau_s[1::2] A_i, B_i, A_d, B_d = hermite_matrices(tau_disc, tau_col) y_col = B_i.dot(ydot[state_disc_idxs]) * dt_dstau[col_idxs] + A_i.dot( y[state_disc_idxs]) vy_col = B_i.dot(vydot[state_disc_idxs]) * dt_dstau[col_idxs] + A_i.dot( vy[state_disc_idxs]) yprime_col = A_d.dot(y[state_disc_idxs]) / dt_dstau + B_d.dot( ydot[state_disc_idxs]) vyprime_col = A_d.dot(vy[state_disc_idxs]) / dt_dstau + B_d.dot( vydot[state_disc_idxs]) axes[0].plot(time[col_idxs], y_col, marker=(3, 0, 0), ms=8)
def test_nodes_and_weights_2(self): x_2, w_2 = lgl(2) assert_almost_equal(x_2, x_i[2], decimal=6) assert_almost_equal(w_2, w_i[2], decimal=6)
def ex_aircraft_steady_flight(optimizer='SLSQP', transcription='gauss-lobatto'): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = True if optimizer == 'SNOPT': p.driver.opt_settings['Major iterations limit'] = 1000 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings["Linesearch tolerance"] = 0.10 p.driver.opt_settings['iSumm'] = 6 num_seg = 15 seg_ends, _ = lgl(num_seg + 1) phase = Phase(transcription, ode_class=AircraftODE, num_segments=num_seg, segment_ends=seg_ends, transcription_order=5, compressed=False) # Pass Reference Area from an external source assumptions = p.model.add_subsystem('assumptions', IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(300, 10000), duration_ref=3600) phase.set_state_options('range', units='NM', fix_initial=True, fix_final=False, scaler=0.001, defect_scaler=1.0E-2) phase.set_state_options('mass_fuel', units='lbm', fix_initial=True, fix_final=True, upper=1.5E5, lower=0.0, scaler=1.0E-5, defect_scaler=1.0E-1) phase.add_control('alt', units='kft', opt=True, lower=0.0, upper=50.0, rate_param='climb_rate', rate_continuity=True, rate_continuity_scaler=1.0, rate2_continuity=True, rate2_continuity_scaler=1.0, ref=1.0, fix_initial=True, fix_final=True) phase.add_control('mach', units=None, opt=False) phase.add_input_parameter('S', units='m**2') phase.add_input_parameter('mass_empty', units='kg') phase.add_input_parameter('mass_payload', units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=1.0) phase.add_path_constraint('alt_rate', units='ft/min', lower=-3000, upper=3000, ref=3000) p.model.connect('assumptions.S', 'phase0.input_parameters:S') p.model.connect('assumptions.mass_empty', 'phase0.input_parameters:mass_empty') p.model.connect('assumptions.mass_payload', 'phase0.input_parameters:mass_payload') phase.add_objective('range', loc='final', ref=-1.0) p.model.linear_solver = DirectSolver(assemble_jac=True) p.setup() p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 3600.0 p['phase0.states:range'] = phase.interpolate(ys=(0, 1000.0), nodes='state_input') p['phase0.states:mass_fuel'] = phase.interpolate(ys=(30000, 0), nodes='state_input') p['phase0.controls:mach'][:] = 0.8 p['phase0.controls:alt'][:] = 10.0 p['assumptions.S'] = 427.8 p['assumptions.mass_empty'] = 0.15E6 p['assumptions.mass_payload'] = 84.02869 * 400 p.run_driver() exp_out = phase.simulate( times=np.linspace(0, p['phase0.t_duration'], 500), record=True, record_file='test_ex_aircraft_steady_flight_rec.db') plt.plot(phase.get_values('time', nodes='all'), phase.get_values('alt', nodes='all'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('alt'), 'b-') plt.suptitle('altitude vs time') plt.figure() plt.plot(phase.get_values('time', nodes='all'), phase.get_values('alt_rate', nodes='all', units='ft/min'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('alt_rate', units='ft/min'), 'b-') plt.suptitle('altitude rate vs time') plt.figure() plt.plot(phase.get_values('time', nodes='all'), phase.get_values('mass_fuel', nodes='all'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('mass_fuel'), 'b-') plt.suptitle('fuel mass vs time') plt.figure() plt.plot(phase.get_values('time', nodes='all'), phase.get_values('propulsion.dXdt:mass_fuel', nodes='all'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('propulsion.dXdt:mass_fuel'), 'b-') plt.suptitle('fuel mass flow rate vs time') plt.figure() plt.plot(phase.get_values('time', nodes='all'), phase.get_values('mach', nodes='all'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('mach'), 'b-') plt.suptitle('mach vs time') plt.figure() plt.plot(phase.get_values('time', nodes='all'), phase.get_values('mach_rate', nodes='all'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('mach_rate'), 'b-') plt.suptitle('mach rate vs time') print('time') print(phase.get_values('time', nodes='all').T) print('alt') print(phase.get_values('alt', nodes='all').T) print('alt_rate') print(phase.get_values('alt_rate', nodes='all').T) print('alt_rate2') print(phase.get_values('alt_rate2', nodes='all').T) print('range') print(phase.get_values('range', nodes='all').T) print('flight path angle') print(phase.get_values('gam_comp.gam').T) print('true airspeed') print(phase.get_values('tas_comp.TAS', units='m/s').T) print('coef of lift') print(phase.get_values('aero.CL').T) print('coef of drag') print(phase.get_values('aero.CD').T) print('atmos density') print(phase.get_values('atmos.rho').T) print('alpha') print(phase.get_values('flight_equilibrium.alpha', units='rad').T) print('coef of thrust') print(phase.get_values('flight_equilibrium.CT').T) print('fuel flow rate') print(phase.get_values('propulsion.dXdt:mass_fuel').T) print('max_thrust') print(phase.get_values('propulsion.max_thrust', units='N').T) print('tau') print(phase.get_values('propulsion.tau').T) print('dynamic pressure') print(phase.get_values('q_comp.q', units='Pa').T) print('S') print(phase.get_values('S', units='m**2').T) plt.show() return p
def test_polynomial_control_group_scalar_gl(self): transcription = 'gauss-lobatto' compressed = True segends = np.array([0.0, 3.0, 10.0]) gd = GridData(num_segments=2, transcription_order=5, segment_ends=segends, transcription=transcription, compressed=compressed) p = om.Problem(model=om.Group()) controls = { 'a': PolynomialControlOptionsDictionary(), 'b': PolynomialControlOptionsDictionary() } controls['a']['units'] = 'm' controls['a']['order'] = 3 controls['a']['shape'] = (1, ) controls['a']['opt'] = True controls['b']['units'] = 'm' controls['b']['order'] = 3 controls['b']['shape'] = (1, ) controls['b']['opt'] = True ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') ivc.add_output('t_duration', val=10.0, units='s') p.model.add_subsystem('time_comp', subsys=TimeComp( num_nodes=gd.num_nodes, node_ptau=gd.node_ptau, node_dptau_dstau=gd.node_dptau_dstau, units='s'), promotes_inputs=['t_initial', 't_duration'], promotes_outputs=['time', 'dt_dstau']) polynomial_control_group = PolynomialControlGroup( grid_data=gd, polynomial_control_options=controls, time_units='s') p.model.add_subsystem('polynomial_control_group', subsys=polynomial_control_group, promotes_inputs=['*'], promotes_outputs=['*']) p.setup(force_alloc_complex=True) p['t_initial'] = 0.0 p['t_duration'] = 3.0 p.run_model() control_nodes_ptau, _ = lgl(controls['a']['order'] + 1) t_control_input = p['t_initial'] + 0.5 * (control_nodes_ptau + 1) * p['t_duration'] t_all = p['time'] p['polynomial_controls:a'][:, 0] = f_a(t_control_input) p['polynomial_controls:b'][:, 0] = f_b(t_control_input) p.run_model() a_value_expected = f_a(t_all) b_value_expected = f_b(t_all) a_rate_expected = f1_a(t_all) b_rate_expected = f1_b(t_all) a_rate2_expected = f2_a(t_all) b_rate2_expected = f2_b(t_all) assert_almost_equal(p['polynomial_control_values:a'], np.atleast_2d(a_value_expected).T) assert_almost_equal(p['polynomial_control_values:b'], np.atleast_2d(b_value_expected).T) assert_almost_equal(p['polynomial_control_rates:a_rate'], np.atleast_2d(a_rate_expected).T) assert_almost_equal(p['polynomial_control_rates:b_rate'], np.atleast_2d(b_rate_expected).T) assert_almost_equal(p['polynomial_control_rates:a_rate2'], np.atleast_2d(a_rate2_expected).T) assert_almost_equal(p['polynomial_control_rates:b_rate2'], np.atleast_2d(b_rate2_expected).T) np.set_printoptions(linewidth=1024) cpd = p.check_partials(compact_print=False, out_stream=None, method='cs') assert_check_partials(cpd)
def test_nodes_and_weights_3(self): x_3, w_3 = lgl(3) assert_almost_equal(x_3, x_i[3], decimal=6) assert_almost_equal(w_3, w_i[3], decimal=6)
def test_polynomial_control_group_matrix_rungekutta(self): transcription = 'runge-kutta' compressed = True segends = np.array([0.0, 3.0, 10.0]) gd = GridData(num_segments=2, transcription_order='RK4', segment_ends=segends, transcription=transcription, compressed=compressed) p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary()} controls['a']['units'] = 'm' controls['a']['order'] = 3 controls['a']['opt'] = True controls['a']['shape'] = (3, 1) ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') ivc.add_output('t_duration', val=10.0, units='s') p.model.add_subsystem('time_comp', subsys=TimeComp(num_nodes=gd.num_nodes, node_ptau=gd.node_ptau, node_dptau_dstau=gd.node_dptau_dstau, units='s'), promotes_inputs=['t_initial', 't_duration'], promotes_outputs=['time', 'dt_dstau']) polynomial_control_group = PolynomialControlGroup(grid_data=gd, polynomial_control_options=controls, time_units='s') p.model.add_subsystem('polynomial_control_group', subsys=polynomial_control_group, promotes_inputs=['*'], promotes_outputs=['*']) # p.model.connect('dt_dstau', 'control_interp_comp.dt_dstau') p.setup(force_alloc_complex=True) p['t_initial'] = 0.0 p['t_duration'] = 3.0 p.run_model() control_nodes_ptau, _ = lgl(controls['a']['order'] + 1) t_control_input = p['t_initial'] + 0.5 * (control_nodes_ptau + 1) * p['t_duration'] t_all = p['time'] p['polynomial_controls:a'][:, 0, 0] = f_a(t_control_input) p['polynomial_controls:a'][:, 1, 0] = f_b(t_control_input) p['polynomial_controls:a'][:, 2, 0] = f_c(t_control_input) p.run_model() a0_value_expected = f_a(t_all) a1_value_expected = f_b(t_all) a2_value_expected = f_c(t_all) a0_rate_expected = f1_a(t_all) a1_rate_expected = f1_b(t_all) a2_rate_expected = f1_c(t_all) a0_rate2_expected = f2_a(t_all) a1_rate2_expected = f2_b(t_all) a2_rate2_expected = f2_c(t_all) assert_almost_equal(p['polynomial_control_values:a'][:, 0, 0], a0_value_expected) assert_almost_equal(p['polynomial_control_values:a'][:, 1, 0], a1_value_expected) assert_almost_equal(p['polynomial_control_values:a'][:, 2, 0], a2_value_expected) assert_almost_equal(p['polynomial_control_rates:a_rate'][:, 0, 0], a0_rate_expected) assert_almost_equal(p['polynomial_control_rates:a_rate'][:, 1, 0], a1_rate_expected) assert_almost_equal(p['polynomial_control_rates:a_rate'][:, 2, 0], a2_rate_expected) assert_almost_equal(p['polynomial_control_rates:a_rate2'][:, 0, 0], a0_rate2_expected) assert_almost_equal(p['polynomial_control_rates:a_rate2'][:, 1, 0], a1_rate2_expected) assert_almost_equal(p['polynomial_control_rates:a_rate2'][:, 2, 0], a2_rate2_expected) np.set_printoptions(linewidth=1024) cpd = p.check_partials(method='cs', out_stream=None) assert_check_partials(cpd)
def main(): prob = om.Problem() model = prob.model num_seg = 15 seg_ends, _ = lgl(num_seg + 1) traj = model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase('phase0', dm.Phase(ode_class=AircraftODE, transcription=dm.Radau(num_segments=num_seg, segment_ends=seg_ends, order=3, compressed=False))) assumptions = model.add_subsystem('assumptions', om.IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') prob.driver = om.pyOptSparseDriver() prob.driver.options['optimizer'] = 'SNOPT' phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(300, 10000)) phase.set_state_options('range', units='NM', fix_initial=True, fix_final=False, lower=0, upper=2000) phase.set_state_options('mass_fuel', units='lbm', fix_initial=True, fix_final=True, upper=1.5E5, lower=0.0) phase.set_state_options('alt', units='kft', fix_initial=True, fix_final=True, lower=0.0, upper=60) phase.add_control('climb_rate', units='ft/min', opt=True, lower=-3000, upper=3000, rate_continuity=True, rate2_continuity=False) phase.add_control('mach', units=None, opt=False) phase.add_input_parameter('S', units='m**2') phase.add_input_parameter('mass_empty', units='kg') phase.add_input_parameter('mass_payload', units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=2.0, shape=(1,)) model.connect('assumptions.S', 'traj.phase0.input_parameters:S') model.connect('assumptions.mass_empty', 'traj.phase0.input_parameters:mass_empty') model.connect('assumptions.mass_payload', 'traj.phase0.input_parameters:mass_payload') phase.add_objective('range', loc='final') prob.setup() prob['traj.phase0.t_initial'] = 0.0 prob['traj.phase0.t_duration'] = 3600.0 prob['traj.phase0.states:range'][:] = phase.interpolate(ys=(0, 724.0), nodes='state_input') prob['traj.phase0.states:mass_fuel'][:] = phase.interpolate( ys=(30000, 1e-3), nodes='state_input') prob['traj.phase0.states:alt'][:] = 10.0 prob['traj.phase0.controls:mach'][:] = 0.8 prob['assumptions.S'] = 427.8 prob['assumptions.mass_empty'] = 0.15E6 prob['assumptions.mass_payload'] = 84.02869 * 400 with open('total_jac_info.pickle', 'rb') as file: jac = pickle.load(file) with open('lower_bounds_info.pickle', 'rb') as file: lbs = pickle.load(file) with open('upper_bounds_info.pickle', 'rb') as file: ubs = pickle.load(file) # sc = None # sc = IsoScaler(jac, lbs, ubs) sc = PJRNScaler(jac, lbs, ubs) autoscale(prob, autoscaler=sc) prob.run_driver() return prob
def test_nodes_and_weights_6(self): x_6, w_6 = lgl(6) assert_almost_equal(x_6, x_i[6], decimal=6) assert_almost_equal(w_6, w_i[6], decimal=6)
def test_nodes_and_weights_5(self): x_5, w_5 = lgl(5) assert_almost_equal(x_5, x_i[5], decimal=6) assert_almost_equal(w_5, w_i[5], decimal=6)
def test_nodes_and_weights_4(self): x_4, w_4 = lgl(4) assert_almost_equal(x_4, x_i[4], decimal=6) assert_almost_equal(w_4, w_i[4], decimal=6)
def test_overlapping_phases_make_plot(self): prob = om.Problem() opt = prob.driver = om.ScipyOptimizeDriver() opt.declare_coloring() opt.options['optimizer'] = 'SLSQP' num_seg = 5 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. transcription = dm.Radau(num_segments=num_seg, order=5, segment_ends=seg_ends, compressed=False) phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.add_state('state_of_charge', fix_initial=True, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') # Second phase: normal operation. phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) traj_p1.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') traj_p1.add_objective('time', loc='final') # Second phase, but with battery failure. phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_bfail.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') # Second phase, but with motor failure. phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_mfail.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time']) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time']) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time']) prob.model.options['assembled_jac_type'] = 'csc' prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() prob['traj.phase0.t_initial'] = 0 prob['traj.phase0.t_duration'] = 1.0*3600 prob['traj.phase1.t_initial'] = 1.0*3600 prob['traj.phase1.t_duration'] = 1.0*3600 prob['traj.phase1_bfail.t_initial'] = 1.0*3600 prob['traj.phase1_bfail.t_duration'] = 1.0*3600 prob['traj.phase1_mfail.t_initial'] = 1.0*3600 prob['traj.phase1_mfail.t_duration'] = 1.0*3600 prob.set_solver_print(level=0) dm.run_problem(prob, simulate=True, make_plots=False, simulation_record_file='simulation_record_file.db') timeseries_plots('dymos_solution.db', simulation_record_file='simulation_record_file.db') self.assertTrue(os.path.exists('plots/time_phase.png')) self.assertTrue(os.path.exists('plots/states_state_of_charge.png')) self.assertTrue(os.path.exists('plots/state_rates_state_of_charge.png'))
0.0, 0.0, 0.0, 0.0, 457.0, 1744.0, 1744.0, 457.0, 457.0, 457.0, 457.0, 457.0 ]) h_seg += 690.0 # add ground level # Create the problem prob = om.Problem() opt = prob.driver = om.ScipyOptimizeDriver() opt.declare_coloring() opt.options['optimizer'] = 'SLSQP' # Set up the segments based on the type of mission num_seg = 11 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', dm.Trajectory()) ''' Set the values of the design parameters ''' # Geometric parameters # -------------------- traj.add_design_parameter('x', val=10e-3, lower=1e-3, upper=80e-3, units='m', opt=True, dynamic=False) # targets={'traj_p1':'x', 'traj_p2':'x', 'traj_p3':'x', # 'traj_p4':'x', 'traj_p5':'x', 'traj_p6':'x',
def ex_aircraft_steady_flight(optimizer='SLSQP', solve_segments=False, use_boundary_constraints=False, compressed=False): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.declare_coloring() if optimizer == 'SNOPT': p.driver.opt_settings['Major iterations limit'] = 20 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings["Linesearch tolerance"] = 0.10 p.driver.opt_settings['iSumm'] = 6 if optimizer == 'SLSQP': p.driver.opt_settings['MAXIT'] = 50 num_seg = 15 seg_ends, _ = lgl(num_seg + 1) phase = dm.Phase(ode_class=AircraftODE, transcription=dm.Radau(num_segments=num_seg, segment_ends=seg_ends, order=3, compressed=compressed, solve_segments=solve_segments)) # Pass Reference Area from an external source assumptions = p.model.add_subsystem('assumptions', om.IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(300, 10000), duration_ref=5600) fix_final = True if use_boundary_constraints: fix_final = False phase.add_boundary_constraint('mass_fuel', loc='final', equals=1e-3, linear=False) phase.add_boundary_constraint('alt', loc='final', equals=10.0, linear=False) phase.add_state('range', units='NM', rate_source='range_rate_comp.dXdt:range', fix_initial=True, fix_final=False, ref=1e-3, defect_ref=1e-3, lower=0, upper=2000) phase.add_state('mass_fuel', units='lbm', rate_source='propulsion.dXdt:mass_fuel', fix_initial=True, fix_final=fix_final, upper=1.5E5, lower=0.0, ref=1e2, defect_ref=1e2) phase.add_state('alt', units='kft', rate_source='climb_rate', fix_initial=True, fix_final=fix_final, lower=0.0, upper=60, ref=1e-3, defect_ref=1e-3) phase.add_control('climb_rate', units='ft/min', opt=True, lower=-3000, upper=3000, targets=['gam_comp.climb_rate'], rate_continuity=True, rate2_continuity=False) phase.add_control('mach', targets=['tas_comp.mach', 'aero.mach'], opt=False) phase.add_parameter( 'S', targets=['aero.S', 'flight_equilibrium.S', 'propulsion.S'], units='m**2') phase.add_parameter('mass_empty', targets=['mass_comp.mass_empty'], units='kg') phase.add_parameter('mass_payload', targets=['mass_comp.mass_payload'], units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=2.0) p.model.connect('assumptions.S', 'phase0.parameters:S') p.model.connect('assumptions.mass_empty', 'phase0.parameters:mass_empty') p.model.connect('assumptions.mass_payload', 'phase0.parameters:mass_payload') phase.add_objective('range', loc='final', ref=-1.0e-4) p.setup() p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 3600.0 p['phase0.states:range'] = phase.interp('range', (0, 724.0)) p['phase0.states:mass_fuel'] = phase.interp('mass_fuel', (30000, 1e-3)) p['phase0.states:alt'][:] = 10.0 p['phase0.controls:mach'][:] = 0.8 p['assumptions.S'] = 427.8 p['assumptions.mass_empty'] = 0.15E6 p['assumptions.mass_payload'] = 84.02869 * 400 dm.run_problem(p) return p
def test_steady_aircraft_for_docs(self): import numpy as np import matplotlib.pyplot as plt from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver, IndepVarComp from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase from dymos.examples.aircraft_steady_flight.aircraft_ode import AircraftODE from dymos.utils.lgl import lgl p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.options['dynamic_simul_derivs'] = True num_seg = 15 seg_ends, _ = lgl(num_seg + 1) phase = Phase('gauss-lobatto', ode_class=AircraftODE, num_segments=num_seg, segment_ends=seg_ends, transcription_order=5, compressed=False) # Pass design parameters in externally from an external source assumptions = p.model.add_subsystem('assumptions', IndepVarComp()) assumptions.add_output('mach', val=0.8, units=None) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(300, 10000), duration_ref=3600) phase.set_state_options('range', units='NM', fix_initial=True, fix_final=False, scaler=0.001, defect_scaler=1.0E-2) phase.set_state_options('mass_fuel', units='lbm', fix_initial=True, fix_final=True, upper=1.5E5, lower=0.0, scaler=1.0E-5, defect_scaler=1.0E-1) phase.add_control('alt', units='kft', opt=True, lower=0.0, upper=50.0, rate_param='climb_rate', rate_continuity=True, rate_continuity_scaler=1.0, rate2_continuity=True, rate2_continuity_scaler=1.0, ref=1.0, fix_initial=True, fix_final=True) phase.add_input_parameter('mach', units=None) phase.add_input_parameter('S', units='m**2') phase.add_input_parameter('mass_empty', units='kg') phase.add_input_parameter('mass_payload', units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=1.0) phase.add_path_constraint('alt_rate', units='ft/min', lower=-3000, upper=3000, ref=3000) p.model.connect('assumptions.mach', 'phase0.input_parameters:mach') p.model.connect('assumptions.S', 'phase0.input_parameters:S') p.model.connect('assumptions.mass_empty', 'phase0.input_parameters:mass_empty') p.model.connect('assumptions.mass_payload', 'phase0.input_parameters:mass_payload') phase.add_objective('range', loc='final', ref=-1.0) p.model.linear_solver = DirectSolver(assemble_jac=True) p.setup() p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 3600.0 p['phase0.states:range'] = phase.interpolate(ys=(0, 1000.0), nodes='state_input') p['phase0.states:mass_fuel'] = phase.interpolate(ys=(30000, 0), nodes='state_input') p['phase0.controls:alt'][:] = 10.0 p['assumptions.mach'][:] = 0.8 p['assumptions.S'] = 427.8 p['assumptions.mass_empty'] = 0.15E6 p['assumptions.mass_payload'] = 84.02869 * 400 p.run_driver() exp_out = phase.simulate(times=np.linspace(0, p['phase0.t_duration'], 500), record=True, record_file='test_doc_aircraft_steady_flight_rec.db') assert_rel_error(self, phase.get_values('range', units='NM')[-1], 726.7, tolerance=1.0E-2) plt.figure() plt.plot(phase.get_values('time', nodes='all'), phase.get_values('alt', nodes='all', units='ft'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('alt', units='ft'), 'b-') plt.suptitle('Altitude vs Time') plt.xlabel('Time (s)') plt.ylabel('Altitude (ft)') plt.figure() plt.plot(phase.get_values('time', nodes='all'), phase.get_values('alt_rate', nodes='all', units='ft/min'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('alt_rate', units='ft/min'), 'b-') plt.suptitle('Climb Rate vs Time') plt.xlabel('Time (s)') plt.ylabel('Climb Rate (ft/min)') plt.figure() plt.plot(phase.get_values('time', nodes='all'), phase.get_values('mass_fuel', nodes='all', units='lbm'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('mass_fuel', units='lbm'), 'b-') plt.suptitle('Fuel Mass vs Time') plt.xlabel('Time (s)') plt.ylabel('Fuel Mass (lbm)') plt.show()