def make_problem(self, transcription=GaussLobatto, optimizer='SLSQP', numseg=30): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.declare_coloring() p.driver.options['optimizer'] = optimizer if optimizer == 'SNOPT': p.driver.declare_coloring() p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 elif optimizer == 'IPOPT': p.driver.opt_settings['hessian_approximation'] = 'limited-memory' # p.driver.opt_settings['nlp_scaling_method'] = 'user-scaling' p.driver.opt_settings['print_level'] = 5 p.driver.opt_settings['linear_solver'] = 'mumps' p.driver.declare_coloring() else: p.driver.declare_coloring() traj = p.model.add_subsystem('traj', Trajectory()) phase0 = traj.add_phase( 'phase0', Phase(ode_class=HyperSensitiveODE, transcription=transcription(num_segments=numseg, order=3))) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.add_state('x', fix_initial=True, fix_final=False, rate_source='x_dot', targets=['x']) phase0.add_state('xL', fix_initial=True, fix_final=False, rate_source='L', targets=['xL']) phase0.add_control('u', opt=True, targets=['u']) phase0.add_boundary_constraint('x', loc='final', equals=1) phase0.add_objective('xL', loc='final') phase0.set_refine_options(refine=True, tol=1e-6, max_order=14) p.setup(check=True) p.set_val('traj.phase0.states:x', phase0.interpolate(ys=[1.5, 1], nodes='state_input')) p.set_val('traj.phase0.states:xL', phase0.interpolate(ys=[0, 1], nodes='state_input')) p.set_val('traj.phase0.t_initial', 0) p.set_val('traj.phase0.t_duration', tf) p.set_val('traj.phase0.controls:u', phase0.interpolate(ys=[-0.6, 2.4], nodes='control_input')) return p
def make_problem(self, transcription=Radau, optimizer='SLSQP', numseg=30): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.declare_coloring(tol=1.0E-12) OPT, OPTIMIZER = set_pyoptsparse_opt(optimizer, fallback=False) p.driver.options['optimizer'] = OPTIMIZER if OPTIMIZER == 'SNOPT': p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Verify level'] = 3 elif OPTIMIZER == 'IPOPT': p.driver.opt_settings['max_iter'] = 500 p.driver.opt_settings['print_level'] = 4 p.driver.opt_settings['tol'] = 1.0E-6 p.driver.opt_settings['acceptable_tol'] = 1.0E-5 traj = p.model.add_subsystem('traj', Trajectory()) phase = traj.add_phase('phase', Phase(ode_class=RobotArmODE, transcription=transcription(num_segments=numseg, order=3))) phase.set_time_options(fix_initial=True, fix_duration=False) phase.add_state('x0', fix_initial=True, fix_final=True, rate_source='x0_dot', units='m') phase.add_state('x1', fix_initial=True, fix_final=True, rate_source='x1_dot', units='rad') phase.add_state('x2', fix_initial=True, fix_final=True, rate_source='x2_dot', units='rad') phase.add_state('x3', fix_initial=True, fix_final=True, rate_source='x3_dot', units='m/s') phase.add_state('x4', fix_initial=True, fix_final=True, rate_source='x4_dot', units='rad/s') phase.add_state('x5', fix_initial=True, fix_final=True, rate_source='x5_dot', units='rad/s') phase.add_control('u0', opt=True, lower=-1, upper=1, scaler=0.1, units='m**2/s**2', continuity=False, rate_continuity=False) phase.add_control('u1', opt=True, lower=-1, upper=1, scaler=0.1, units='m**3*rad/s**2', continuity=False, rate_continuity=False) phase.add_control('u2', opt=True, lower=-1, upper=1, scaler=0.1, units='m**3*rad/s**2', continuity=False, rate_continuity=False) phase.add_path_constraint('u0', lower=-1, upper=1, scaler=0.1) phase.add_path_constraint('u1', lower=-1, upper=1, scaler=0.1) phase.add_path_constraint('u2', lower=-1, upper=1, scaler=0.1) phase.add_objective('time', ref=0.1) phase.set_refine_options(refine=True, tol=1e-5, smoothness_factor=1.2) p.setup(check=True, force_alloc_complex=False, mode='auto') p.set_val('traj.phase.t_initial', 0) p.set_val('traj.phase.t_duration', 10) p.set_val('traj.phase.states:x0', phase.interpolate(ys=[4.5, 4.5], nodes='state_input')) p.set_val('traj.phase.states:x1', phase.interpolate(ys=[0.0, 2 * np.pi / 3], nodes='state_input')) p.set_val('traj.phase.states:x2', phase.interpolate(ys=[np.pi / 4, np.pi / 4], nodes='state_input')) p.set_val('traj.phase.states:x3', phase.interpolate(ys=[0.0, 0.0], nodes='state_input')) p.set_val('traj.phase.states:x4', phase.interpolate(ys=[0.0, 0.0], nodes='state_input')) p.set_val('traj.phase.states:x5', phase.interpolate(ys=[0.0, 0.0], nodes='state_input')) return p
def __init__(self, body, sc, method, nb_seg, order, solver, snopt_opts=None, rec_file=None): """Initializes NLP class. """ # input parameters self.body = body self.sc = sc self.method = method self.nb_seg = nb_seg self.order = order self.solver = solver if self.solver == 'SNOPT': self.snopt_opts = snopt_opts else: self.snopt_opts = None self.rec_file = rec_file # Problem object self.p = Problem(model=Group()) # Problem Driver self.p.driver = pyOptSparseDriver() self.p.driver.options['optimizer'] = self.solver self.p.driver.options['print_results'] = False self.p.driver.options['dynamic_derivs_sparsity'] = True if self.snopt_opts is not None: for k in self.snopt_opts.keys(): self.p.driver.opt_settings[k] = self.snopt_opts[k] self.p.driver.declare_coloring(show_summary=True, show_sparsity=False) # Problem Recorder if rec_file is not None: recorder = SqliteRecorder(rec_file) opts = ['record_objectives', 'record_constraints', 'record_desvars'] self.p.add_recorder(recorder) for opt in opts: self.p.recording_options[opt] = False self.p.recording_options['excludes'] = rec_excludes self.rec_file = rec_file # Trajectory object self.trajectory = self.p.model.add_subsystem('traj', Trajectory()) # Problem object for explicit simulation self.p_exp = None
def test_solver_defects_reverse_propagation(self): prob = Problem() 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, solve_segments=True) # 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, solve_segments=True) 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_rel_error(self, soc1[-1], 1.0, 1e-6)
def make_problem(self, transcription=GaussLobatto, optimizer='SLSQP', numseg=30): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.declare_coloring() OPT, OPTIMIZER = set_pyoptsparse_opt(optimizer, fallback=False) p.driver.options['optimizer'] = OPTIMIZER traj = p.model.add_subsystem('traj', Trajectory()) phase0 = traj.add_phase( 'phase0', Phase(ode_class=HyperSensitiveODE, transcription=transcription(num_segments=numseg, order=3))) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.add_state('x', fix_initial=True, fix_final=False, rate_source='x_dot', targets=['x']) phase0.add_state('xL', fix_initial=True, fix_final=False, rate_source='L', targets=['xL']) phase0.add_control('u', opt=True, targets=['u']) phase0.add_boundary_constraint('x', loc='final', equals=1) phase0.add_objective('xL', loc='final') p.setup(check=True) p.set_val('traj.phase0.states:x', phase0.interpolate(ys=[1.5, 1], nodes='state_input')) p.set_val('traj.phase0.states:xL', phase0.interpolate(ys=[0, 1], nodes='state_input')) p.set_val('traj.phase0.t_initial', 0) p.set_val('traj.phase0.t_duration', tf) p.set_val('traj.phase0.controls:u', phase0.interpolate(ys=[-0.6, 2.4], nodes='control_input')) return p
def make_problem(transcription=GaussLobatto, num_segments=10, order=3, compressed=True): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring() traj = p.model.add_subsystem('traj', Trajectory()) phase = traj.add_phase('phase', Phase(ode_class=crtbp_ode, transcription=transcription(num_segments=num_segments, order=order, compressed=compressed))) phase.set_time_options(fix_initial=True, fix_duration=True) phase.add_state('x', rate_source='vx', ) phase.add_state('y', rate_source='vz', fix_initial=True) phase.add_state('z', rate_source='vz') phase.add_state('x_dot', rate_source='vx_dot', fix_initial=True, units=None) phase.add_state('y_dot', rate_source='vy_dot', units=None) phase.add_state('z_dot', rate_source='vz_dot', fix_initial=True, units=None) p.model.add_subsystem('x_periodic_bc', om.ExecComp('bc_defect=final-initial')) p.model.connect('traj.phase.timeseries.states:x', 'x_periodic_bc.initial', src_indices=0) p.model.connect('traj.phase.timeseries.states:x', 'x_periodic_bc.final', src_indices=-1) p.model.add_constraint('x_periodic_bc.bc_defect', equals=0) p.model.add_subsystem('z_periodic_bc', om.ExecComp('bc_defect=final-initial')) p.model.connect('traj.phase.timeseries.states:z', 'z_periodic_bc.initial', src_indices=0) p.model.connect('traj.phase.timeseries.states:z', 'z_periodic_bc.final', src_indices=-1) p.model.add_constraint('z_periodic_bc.bc_defect', equals=0) p.model.add_subsystem('vy_periodic_bc', om.ExecComp('bc_defect=final-initial')) p.model.connect('traj.phase.timeseries.states:y_dot', 'vy_periodic_bc.initial', src_indices=0) p.model.connect('traj.phase.timeseries.states:y_dot', 'vy_periodic_bc.final', src_indices=-1) p.model.add_constraint('vy_periodic_bc.bc_defect', equals=0) phase.add_objective('time', loc='final') p.setup(check=True) return p
def test_reentry_mixed_controls(self): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring(tol=1.0E-12) p.driver.options['optimizer'] = 'IPOPT' p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' p.driver.opt_settings['print_level'] = 5 p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based' p.driver.opt_settings['mu_strategy'] = 'monotone' traj = p.model.add_subsystem('traj', Trajectory()) phase0 = traj.add_phase( 'phase0', Phase(ode_class=ShuttleODE, transcription=Radau(num_segments=30, order=3))) phase0.set_time_options(fix_initial=True, units='s', duration_ref=200) phase0.add_state('h', fix_initial=True, fix_final=True, units='ft', rate_source='hdot', targets=['h'], lower=0, ref0=75000, ref=300000, defect_ref=1000) phase0.add_state('gamma', fix_initial=True, fix_final=True, units='rad', rate_source='gammadot', targets=['gamma'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('phi', fix_initial=True, fix_final=False, units='rad', rate_source='phidot', lower=0, upper=89. * np.pi / 180) phase0.add_state('psi', fix_initial=True, fix_final=False, units='rad', rate_source='psidot', targets=['psi'], lower=0, upper=90. * np.pi / 180) phase0.add_state('theta', fix_initial=True, fix_final=False, units='rad', rate_source='thetadot', targets=['theta'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('v', fix_initial=True, fix_final=True, units='ft/s', rate_source='vdot', targets=['v'], lower=500, ref0=2500, ref=25000) phase0.add_control('alpha', units='rad', opt=True, lower=-np.pi / 2, upper=np.pi / 2) phase0.add_polynomial_control('beta', order=9, units='rad', opt=True, lower=-89 * np.pi / 180, upper=1 * np.pi / 180) phase0.add_objective('theta', loc='final', ref=-0.01) phase0.add_path_constraint('q', lower=0, upper=70, ref=70) p.setup(check=True, force_alloc_complex=True) p.set_val('traj.phase0.states:h', phase0.interp('h', [260000, 80000]), units='ft') p.set_val('traj.phase0.states:gamma', phase0.interp('gamma', [-1 * np.pi / 180, -5 * np.pi / 180]), units='rad') p.set_val('traj.phase0.states:phi', phase0.interp('phi', [0, 75 * np.pi / 180]), units='rad') p.set_val('traj.phase0.states:psi', phase0.interp('psi', [90 * np.pi / 180, 10 * np.pi / 180]), units='rad') p.set_val('traj.phase0.states:theta', phase0.interp('theta', [0, 25 * np.pi / 180]), units='rad') p.set_val('traj.phase0.states:v', phase0.interp('v', [25600, 2500]), units='ft/s') p.set_val('traj.phase0.t_initial', 0, units='s') p.set_val('traj.phase0.t_duration', 2000, units='s') p.set_val('traj.phase0.controls:alpha', phase0.interp('alpha', [17.4, 17.4]), units='deg') p.set_val('traj.phase0.polynomial_controls:beta', phase0.interp('beta', [-20, 0]), units='deg') run_problem(p, simulate=True) sol = om.CaseReader('dymos_solution.db').get_case('final') sim = om.CaseReader('dymos_simulation.db').get_case('final') from scipy.interpolate import interp1d t_sol = sol.get_val('traj.phase0.timeseries.time') beta_sol = sol.get_val( 'traj.phase0.timeseries.polynomial_controls:beta', units='deg') t_sim = sim.get_val('traj.phase0.timeseries.time') beta_sim = sim.get_val( 'traj.phase0.timeseries.polynomial_controls:beta', units='deg') sol_interp = interp1d(t_sol.ravel(), beta_sol.ravel()) sim_interp = interp1d(t_sim.ravel(), beta_sim.ravel()) t = np.linspace(0, t_sol.ravel()[-1], 1000) assert_near_equal(sim_interp(t), sol_interp(t), tolerance=0.01) assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1], expected_results['constrained']['time'], tolerance=1e-2) assert_near_equal(p.get_val('traj.phase0.timeseries.states:theta', units='deg')[-1], expected_results['constrained']['theta'], tolerance=1e-2)
import numpy as np import matplotlib.pyplot as plt from openmdao.api import Problem, Group, ScipyOptimizeDriver, SqliteRecorder, CaseReader, IndepVarComp from dymos import Trajectory, GaussLobatto, Phase, Radau from shuttle_ode import ShuttleODE prob = Problem(model=Group()) traj = prob.model.add_subsystem("traj", Trajectory()) phase0 = Phase(ode_class=ShuttleODE, transcription=Radau(num_segments=20, order=3)) traj.add_phase(name="phase0", phase=phase0) phase0.set_time_options(fix_initial=True, units="s", duration_ref=200)#, duration_ref=2000, duration_bounds=(50, 3000) phase0.set_state_options("h", fix_initial=True, fix_final=True, units="ft", rate_source="hdot", targets=["h"], lower=0)#, ref=260000, defect_ref=260000, ref0=80000 phase0.set_state_options("gamma", fix_initial=True, fix_final=True, units="rad", rate_source="gammadot", targets=["gamma"], lower=-89.*np.pi/180, upper=89.*np.pi/180) phase0.set_state_options("phi", fix_initial=True, fix_final=False, units="rad", rate_source="phidot", lower=0, upper=89.*np.pi/180) phase0.set_state_options("psi", fix_initial=True, fix_final=False, units="rad", rate_source="psidot", targets=["psi"], lower=0, upper=90.*np.pi/180) phase0.set_state_options("theta", fix_initial=True, fix_final=False, units="rad", rate_source="thetadot", targets=["theta"], lower=-89.*np.pi/180, upper=89.*np.pi/180) phase0.set_state_options("v", fix_initial=True, fix_final=True, units="ft/s", rate_source="vdot", targets=["v"], lower=0)#, ref=25600, defect_ref=25600, ref0=2500 phase0.add_control("alpha", units="rad", opt=True, lower=-np.pi/2, upper=np.pi/2, targets=["alpha"]) phase0.add_control("beta", units="rad", opt=True, lower=-89*np.pi/180, upper=1*np.pi/180, targets=["beta"]) phase0.add_path_constraint("q", lower=0, upper=70, units="Btu/ft**2/s", ref=70)# phase0.add_objective("theta", loc="final", ref=-1) prob.driver = ScipyOptimizeDriver() prob.driver.declare_coloring()
def two_burn_orbit_raise_problem(transcription='gauss-lobatto', optimizer='SNOPT', transcription_order=3, compressed=True, show_plots=False): traj = Trajectory() p = Problem(model=traj) if optimizer == 'SNOPT': p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = True p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings['iSumm'] = 6 else: p.driver = pyOptSparseDriver() p.driver.options['dynamic_simul_derivs'] = True traj.add_design_parameter('c', opt=False, val=1.5, units='DU/TU') # First Phase (burn) burn1 = Phase(transcription, ode_class=FiniteBurnODE, num_segments=10, transcription_order=transcription_order, compressed=compressed) burn1 = traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) burn1.set_state_options('r', fix_initial=True, fix_final=False, defect_scaler=100.0) burn1.set_state_options('theta', fix_initial=True, fix_final=False, defect_scaler=100.0) burn1.set_state_options('vr', fix_initial=True, fix_final=False, defect_scaler=100.0) burn1.set_state_options('vt', fix_initial=True, fix_final=False, defect_scaler=100.0) burn1.set_state_options('accel', fix_initial=True, fix_final=False) burn1.set_state_options('deltav', fix_initial=True, fix_final=False) burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, rate_continuity_scaler=0.001, rate2_continuity_scaler=0.001, lower=-30, upper=30) # Second Phase (Coast) coast = Phase(transcription, ode_class=FiniteBurnODE, num_segments=10, transcription_order=transcription_order, compressed=compressed) traj.add_phase('coast', coast) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), duration_ref=10) coast.set_state_options('r', fix_initial=False, fix_final=False, defect_scaler=100.0) coast.set_state_options('theta', fix_initial=False, fix_final=False, defect_scaler=100.0) coast.set_state_options('vr', fix_initial=False, fix_final=False, defect_scaler=100.0) coast.set_state_options('vt', fix_initial=False, fix_final=False, defect_scaler=100.0) coast.set_state_options('accel', fix_initial=True, fix_final=True) coast.set_state_options('deltav', fix_initial=False, fix_final=False) coast.add_control('u1', opt=False, val=0.0, units='deg') # Third Phase (burn) burn2 = Phase(transcription, ode_class=FiniteBurnODE, num_segments=10, transcription_order=transcription_order, compressed=compressed) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), initial_ref=10) burn2.set_state_options('r', fix_initial=False, fix_final=True, defect_scaler=100.0) burn2.set_state_options('theta', fix_initial=False, fix_final=False, defect_scaler=100.0) burn2.set_state_options('vr', fix_initial=False, fix_final=True, defect_scaler=100.0) burn2.set_state_options('vt', fix_initial=False, fix_final=True, defect_scaler=100.0) burn2.set_state_options('accel', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, rate_continuity_scaler=0.001, rate2_continuity_scaler=0.001, lower=-10, upper=10) burn2.add_objective('deltav', loc='final', scaler=100.0) # Link Phases traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) # Finish Problem Setup p.model.options['assembled_jac_type'] = 'csc' p.model.linear_solver = DirectSolver(assemble_jac=True) p.driver.add_recorder(SqliteRecorder('two_burn_orbit_raise_example.db')) p.setup(check=True) # Set Initial Guesses p.set_val('design_parameters:c', value=1.5) p.set_val('burn1.t_initial', value=0.0) p.set_val('burn1.t_duration', value=2.25) p.set_val('burn1.states:r', value=burn1.interpolate(ys=[1, 1.5], nodes='state_input')) p.set_val('burn1.states:theta', value=burn1.interpolate(ys=[0, 1.7], nodes='state_input')) p.set_val('burn1.states:vr', value=burn1.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('burn1.states:vt', value=burn1.interpolate(ys=[1, 1], nodes='state_input')) p.set_val('burn1.states:accel', value=burn1.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val( 'burn1.states:deltav', value=burn1.interpolate(ys=[0, 0.1], nodes='state_input'), ) p.set_val('burn1.controls:u1', value=burn1.interpolate(ys=[-3.5, 13.0], nodes='control_input')) p.set_val('coast.t_initial', value=2.25) p.set_val('coast.t_duration', value=3.0) p.set_val('coast.states:r', value=coast.interpolate(ys=[1.3, 1.5], nodes='state_input')) p.set_val('coast.states:theta', value=coast.interpolate(ys=[2.1767, 1.7], nodes='state_input')) p.set_val('coast.states:vr', value=coast.interpolate(ys=[0.3285, 0], nodes='state_input')) p.set_val('coast.states:vt', value=coast.interpolate(ys=[0.97, 1], nodes='state_input')) p.set_val('coast.states:accel', value=coast.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('coast.controls:u1', value=coast.interpolate(ys=[0, 0], nodes='control_input')) p.set_val('burn2.t_initial', value=5.25) p.set_val('burn2.t_duration', value=1.75) p.set_val('burn2.states:r', value=burn2.interpolate(ys=[1, 3], nodes='state_input')) p.set_val('burn2.states:theta', value=burn2.interpolate(ys=[0, 4.0], nodes='state_input')) p.set_val('burn2.states:vr', value=burn2.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('burn2.states:vt', value=burn2.interpolate(ys=[1, np.sqrt(1 / 3)], nodes='state_input')) p.set_val('burn2.states:accel', value=burn2.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('burn2.states:deltav', value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input')) p.set_val('burn2.controls:u1', value=burn2.interpolate(ys=[1, 1], nodes='control_input')) p.run_driver() # Plot results exp_out = traj.simulate(times=50, num_procs=3) fig = plt.figure(figsize=(8, 4)) fig.suptitle('Two Burn Orbit Raise Solution') ax_u1 = plt.subplot2grid((2, 2), (0, 0)) ax_deltav = plt.subplot2grid((2, 2), (1, 0)) ax_xy = plt.subplot2grid((2, 2), (0, 1), rowspan=2) span = np.linspace(0, 2 * np.pi, 100) ax_xy.plot(np.cos(span), np.sin(span), 'k--', lw=1) ax_xy.plot(3 * np.cos(span), 3 * np.sin(span), 'k--', lw=1) ax_xy.set_xlim(-4.5, 4.5) ax_xy.set_ylim(-4.5, 4.5) ax_xy.set_xlabel('x ($R_e$)') ax_xy.set_ylabel('y ($R_e$)') ax_u1.set_xlabel('time ($TU$)') ax_u1.set_ylabel('$u_1$ ($deg$)') ax_u1.grid(True) ax_deltav.set_xlabel('time ($TU$)') ax_deltav.set_ylabel('${\Delta}v$ ($DU/TU$)') ax_deltav.grid(True) t_sol = traj.get_values('time', flat=True) x_sol = traj.get_values('pos_x', flat=True) y_sol = traj.get_values('pos_y', flat=True) dv_sol = traj.get_values('deltav', flat=True) u1_sol = traj.get_values('u1', units='deg', flat=True) t_exp = exp_out.get_values('time', flat=True) x_exp = exp_out.get_values('pos_x', flat=True) y_exp = exp_out.get_values('pos_y', flat=True) dv_exp = exp_out.get_values('deltav', flat=True) u1_exp = exp_out.get_values('u1', units='deg', flat=True) ax_u1.plot(t_sol, u1_sol, 'ro', ms=3) ax_u1.plot(t_exp, u1_exp, 'b-') ax_deltav.plot(t_sol, dv_sol, 'ro', ms=3) ax_deltav.plot(t_exp, dv_exp, 'b-') ax_xy.plot(x_sol, y_sol, 'ro', ms=3, label='implicit') ax_xy.plot(x_exp, y_exp, 'b-', label='explicit') if show_plots: plt.show() return p
def test_two_phase_cannonball_for_docs(self): from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, SqliteRecorder, \ pyOptSparseDriver from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase, Trajectory, Radau, GaussLobatto from dymos.examples.cannonball.cannonball_ode import CannonballODE from dymos.examples.cannonball.size_comp import CannonballSizeComp p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.options['dynamic_simul_derivs'] = True external_params = p.model.add_subsystem('external_params', IndepVarComp()) external_params.add_output('radius', val=0.10, units='m') external_params.add_output('dens', val=7.87, units='g/cm**3') external_params.add_design_var('radius', lower=0.01, upper=0.10, ref0=0.01, ref=0.10) p.model.add_subsystem('size_comp', CannonballSizeComp()) traj = p.model.add_subsystem('traj', Trajectory()) transcription = Radau(num_segments=5, order=3, compressed=True) ascent = Phase(ode_class=CannonballODE, transcription=transcription) ascent = traj.add_phase('ascent', ascent) # All initial states except flight path angle are fixed # Final flight path angle is fixed (we will set it to zero so that the phase ends at apogee) ascent.set_time_options(fix_initial=True, duration_bounds=(1, 100), duration_ref=100, units='s') ascent.set_state_options('r', fix_initial=True, fix_final=False) ascent.set_state_options('h', fix_initial=True, fix_final=False) ascent.set_state_options('gam', fix_initial=False, fix_final=True) ascent.set_state_options('v', fix_initial=False, fix_final=False) # Limit the muzzle energy ascent.add_boundary_constraint('kinetic_energy.ke', loc='initial', units='J', upper=400000, lower=0, ref=100000, shape=(1,)) # Second Phase (descent) transcription = GaussLobatto(num_segments=5, order=3, compressed=True) descent = Phase(ode_class=CannonballODE, transcription=transcription) traj.add_phase('descent', descent) # All initial states and time are free (they will be linked to the final states of ascent. # Final altitude is fixed (we will set it to zero so that the phase ends at ground impact) descent.set_time_options(initial_bounds=(.5, 100), duration_bounds=(.5, 100), duration_ref=100) descent.set_state_options('r', fix_initial=False, fix_final=False) descent.set_state_options('h', fix_initial=False, fix_final=True) descent.set_state_options('gam', fix_initial=False, fix_final=False) descent.set_state_options('v', fix_initial=False, fix_final=False) descent.add_objective('r', loc='final', scaler=-1.0) # Add internally-managed design parameters to the trajectory. traj.add_design_parameter('CD', val=0.5, units=None, opt=False) traj.add_design_parameter('CL', val=0.0, units=None, opt=False) traj.add_design_parameter('T', val=0.0, units='N', opt=False) traj.add_design_parameter('alpha', val=0.0, units='deg', opt=False) # Add externally-provided design parameters to the trajectory. traj.add_input_parameter('mass', target_params={'ascent': 'm', 'descent': 'm'}, val=1.0) traj.add_input_parameter('S', val=0.005) # Link Phases (link time and all state variables) traj.link_phases(phases=['ascent', 'descent'], vars=['*']) # Issue Connections p.model.connect('external_params.radius', 'size_comp.radius') p.model.connect('external_params.dens', 'size_comp.dens') p.model.connect('size_comp.mass', 'traj.input_parameters:mass') p.model.connect('size_comp.S', 'traj.input_parameters:S') # Finish Problem Setup p.model.linear_solver = DirectSolver() p.driver.add_recorder(SqliteRecorder('ex_two_phase_cannonball.db')) p.setup(check=True) # Set Initial Guesses p.set_val('external_params.radius', 0.05, units='m') p.set_val('external_params.dens', 7.87, units='g/cm**3') p.set_val('traj.design_parameters:CD', 0.5) p.set_val('traj.design_parameters:CL', 0.0) p.set_val('traj.design_parameters:T', 0.0) p.set_val('traj.ascent.t_initial', 0.0) p.set_val('traj.ascent.t_duration', 10.0) p.set_val('traj.ascent.states:r', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:h', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:v', ascent.interpolate(ys=[200, 150], nodes='state_input')) p.set_val('traj.ascent.states:gam', ascent.interpolate(ys=[25, 0], nodes='state_input'), units='deg') p.set_val('traj.descent.t_initial', 10.0) p.set_val('traj.descent.t_duration', 10.0) p.set_val('traj.descent.states:r', descent.interpolate(ys=[100, 200], nodes='state_input')) p.set_val('traj.descent.states:h', descent.interpolate(ys=[100, 0], nodes='state_input')) p.set_val('traj.descent.states:v', descent.interpolate(ys=[150, 200], nodes='state_input')) p.set_val('traj.descent.states:gam', descent.interpolate(ys=[0, -45], nodes='state_input'), units='deg') p.run_driver() assert_rel_error(self, p.get_val('traj.descent.states:r')[-1], 3183.25, tolerance=1.0E-2) exp_out = traj.simulate() print('optimal radius: {0:6.4f} m '.format(p.get_val('external_params.radius', units='m')[0])) print('cannonball mass: {0:6.4f} kg '.format(p.get_val('size_comp.mass', units='kg')[0])) print('launch angle: {0:6.4f} ' 'deg '.format(p.get_val('traj.ascent.timeseries.states:gam', units='deg')[0, 0])) print('maximum range: {0:6.4f} ' 'm '.format(p.get_val('traj.descent.timeseries.states:r')[-1, 0])) fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(10, 6)) time_imp = {'ascent': p.get_val('traj.ascent.timeseries.time'), 'descent': p.get_val('traj.descent.timeseries.time')} time_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.time'), 'descent': exp_out.get_val('traj.descent.timeseries.time')} r_imp = {'ascent': p.get_val('traj.ascent.timeseries.states:r'), 'descent': p.get_val('traj.descent.timeseries.states:r')} r_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.states:r'), 'descent': exp_out.get_val('traj.descent.timeseries.states:r')} h_imp = {'ascent': p.get_val('traj.ascent.timeseries.states:h'), 'descent': p.get_val('traj.descent.timeseries.states:h')} h_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.states:h'), 'descent': exp_out.get_val('traj.descent.timeseries.states:h')} axes.plot(r_imp['ascent'], h_imp['ascent'], 'bo') axes.plot(r_imp['descent'], h_imp['descent'], 'ro') axes.plot(r_exp['ascent'], h_exp['ascent'], 'b--') axes.plot(r_exp['descent'], h_exp['descent'], 'r--') axes.set_xlabel('range (m)') axes.set_ylabel('altitude (m)') fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(10, 6)) states = ['r', 'h', 'v', 'gam'] for i, state in enumerate(states): x_imp = {'ascent': p.get_val('traj.ascent.timeseries.states:{0}'.format(state)), 'descent': p.get_val('traj.descent.timeseries.states:{0}'.format(state))} x_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.states:{0}'.format(state)), 'descent': exp_out.get_val('traj.descent.timeseries.states:{0}'.format(state))} axes[i].set_ylabel(state) axes[i].plot(time_imp['ascent'], x_imp['ascent'], 'bo') axes[i].plot(time_imp['descent'], x_imp['descent'], 'ro') axes[i].plot(time_exp['ascent'], x_exp['ascent'], 'b--') axes[i].plot(time_exp['descent'], x_exp['descent'], 'r--') params = ['CL', 'CD', 'T', 'alpha', 'm', 'S'] fig, axes = plt.subplots(nrows=6, ncols=1, figsize=(12, 6)) for i, param in enumerate(params): p_imp = { 'ascent': p.get_val('traj.ascent.timeseries.traj_parameters:{0}'.format(param)), 'descent': p.get_val('traj.descent.timeseries.traj_parameters:{0}'.format(param))} p_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.' 'traj_parameters:{0}'.format(param)), 'descent': exp_out.get_val('traj.descent.timeseries.' 'traj_parameters:{0}'.format(param))} axes[i].set_ylabel(param) axes[i].plot(time_imp['ascent'], p_imp['ascent'], 'bo') axes[i].plot(time_imp['descent'], p_imp['descent'], 'ro') axes[i].plot(time_exp['ascent'], p_exp['ascent'], 'b--') axes[i].plot(time_exp['descent'], p_exp['descent'], 'r--') plt.show()
def test_basic(self): import matplotlib.pyplot as plt from openmdao.api import Problem, ScipyOptimizeDriver, DirectSolver from openmdao.utils.assert_utils import assert_rel_error from dymos import Trajectory, Phase, Radau from dymos.examples.battery_multibranch.battery_multibranch_ode import BatteryODE from dymos.utils.lgl import lgl prob = Problem() opt = prob.driver = ScipyOptimizeDriver() opt.options['dynamic_simul_derivs'] = True opt.options['optimizer'] = 'SLSQP' num_seg = 5 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', Trajectory()) # First phase: normal operation. transcription = Radau(num_segments=num_seg, order=5, segment_ends=seg_ends, compressed=False) 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']) 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 = 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. print('State of Charge after 1 hour') assert_rel_error(self, soc0[-1], 0.63464982, 1e-6) print('State of Charge after 2 hours') assert_rel_error(self, soc1[-1], 0.23794217, 1e-6) print('State of Charge after 2 hours, battery fails at 1 hour') assert_rel_error(self, soc1b[-1], 0.0281523, 1e-6) print('State of Charge after 2 hours, motor fails at 1 hour') assert_rel_error(self, 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 instantiate_problem(self, idx): traj = Trajectory() p = Problem(model=traj) # First Phase (burn) burn1 = Phase('gauss-lobatto', ode_class=FiniteBurnODE, num_segments=4, transcription_order=3, compressed=True) traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) burn1.set_state_options('r', fix_initial=True, fix_final=False) burn1.set_state_options('theta', fix_initial=True, fix_final=False) burn1.set_state_options('vr', fix_initial=True, fix_final=False, defect_scaler=0.1) burn1.set_state_options('vt', fix_initial=True, fix_final=False, defect_scaler=0.1) burn1.set_state_options('accel', fix_initial=True, fix_final=False) burn1.set_state_options('deltav', fix_initial=True, fix_final=False) burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg') burn1.add_design_parameter('c', opt=False, val=1.5) # Second Phase (Coast) coast = Phase('gauss-lobatto', ode_class=FiniteBurnODE, num_segments=10, transcription_order=3, compressed=True) traj.add_phase('coast', coast) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10)) coast.set_state_options('r', fix_initial=False, fix_final=False) coast.set_state_options('theta', fix_initial=False, fix_final=False) coast.set_state_options('vr', fix_initial=False, fix_final=False) coast.set_state_options('vt', fix_initial=False, fix_final=False) coast.set_state_options('accel', fix_initial=True, fix_final=True) coast.set_state_options('deltav', fix_initial=False, fix_final=False) coast.add_control('u1', opt=False, val=0.0, units='deg') coast.add_design_parameter('c', opt=False, val=1.5) # Third Phase (burn) burn2 = Phase('gauss-lobatto', ode_class=FiniteBurnODE, num_segments=3, transcription_order=3, compressed=True) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10)) burn2.set_state_options('r', fix_initial=False, fix_final=True, defect_scaler=1.0) burn2.set_state_options('theta', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('vr', fix_initial=False, fix_final=True, defect_scaler=0.1) burn2.set_state_options('vt', fix_initial=False, fix_final=True, defect_scaler=0.1) burn2.set_state_options('accel', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', ref0=0, ref=10) burn2.add_design_parameter('c', opt=False, val=1.5) burn2.add_objective('deltav', loc='final') # Link Phases traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) # Finish Problem Setup p.model.options['assembled_jac_type'] = 'csc' p.model.linear_solver = DirectSolver(assemble_jac=True) rec_file = 'two_burn_orbit_raise_example_{0}.db'.format(idx) p.driver.add_recorder(SqliteRecorder(rec_file)) p.setup(check=True) # Set Initial Guesses p.set_val('burn1.t_initial', value=0.0) p.set_val('burn1.t_duration', value=2.25) p.set_val('burn1.states:r', value=burn1.interpolate(ys=[1, 1.5], nodes='state_input')) p.set_val('burn1.states:theta', value=burn1.interpolate(ys=[0, 1.7], nodes='state_input')) p.set_val('burn1.states:vr', value=burn1.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('burn1.states:vt', value=burn1.interpolate(ys=[1, 1], nodes='state_input')) p.set_val('burn1.states:accel', value=burn1.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('burn1.states:deltav', value=burn1.interpolate(ys=[0, 0.1], nodes='state_input')) p.set_val('burn1.controls:u1', value=burn1.interpolate(ys=[-3.5, 13.0], nodes='control_input')) p.set_val('burn1.design_parameters:c', value=1.5) p.set_val('coast.t_initial', value=2.25) p.set_val('coast.t_duration', value=3.0) p.set_val('coast.states:r', value=coast.interpolate(ys=[1.3, 1.5], nodes='state_input')) p.set_val('coast.states:theta', value=coast.interpolate(ys=[2.1767, 1.7], nodes='state_input')) p.set_val('coast.states:vr', value=coast.interpolate(ys=[0.3285, 0], nodes='state_input')) p.set_val('coast.states:vt', value=coast.interpolate(ys=[0.97, 1], nodes='state_input')) p.set_val('coast.states:accel', value=coast.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('coast.controls:u1', value=coast.interpolate(ys=[0, 0], nodes='control_input')) p.set_val('coast.design_parameters:c', value=1.5) p.set_val('burn2.t_initial', value=5.25) p.set_val('burn2.t_duration', value=1.75) p.set_val('burn2.states:r', value=burn2.interpolate(ys=[1, 3], nodes='state_input')) p.set_val('burn2.states:theta', value=burn2.interpolate(ys=[0, 4.0], nodes='state_input')) p.set_val('burn2.states:vr', value=burn2.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('burn2.states:vt', value=burn2.interpolate(ys=[1, np.sqrt(1 / 3)], nodes='state_input')) p.set_val('burn2.states:accel', value=burn2.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('burn2.states:deltav', value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input')) p.set_val('burn2.controls:u1', value=burn2.interpolate(ys=[1, 1], nodes='control_input')) p.set_val('burn2.design_parameters:c', value=1.5) p.run_model() # Plot results sim_rec_file = 'traj_sim_{0}.db'.format(idx) exp_out = traj.simulate(times=50, record_file=sim_rec_file) loaded_exp_out = load_simulation_results(sim_rec_file) return exp_out, loaded_exp_out, rec_file, sim_rec_file
def test_reentry_mixed_controls(self): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring() OPT, OPTIMIZER = set_pyoptsparse_opt('IPOPT', fallback=False) p.driver.options['optimizer'] = OPTIMIZER traj = p.model.add_subsystem('traj', Trajectory()) phase0 = traj.add_phase( 'phase0', Phase(ode_class=ShuttleODE, transcription=GaussLobatto(num_segments=20, order=3))) phase0.set_time_options(fix_initial=True, units='s', duration_ref=200) phase0.add_state('h', fix_initial=True, fix_final=True, units='ft', rate_source='hdot', targets=['h'], lower=0, ref0=75000, ref=300000, defect_ref=1000) phase0.add_state('gamma', fix_initial=True, fix_final=True, units='rad', rate_source='gammadot', targets=['gamma'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('phi', fix_initial=True, fix_final=False, units='rad', rate_source='phidot', lower=0, upper=89. * np.pi / 180) phase0.add_state('psi', fix_initial=True, fix_final=False, units='rad', rate_source='psidot', targets=['psi'], lower=0, upper=90. * np.pi / 180) phase0.add_state('theta', fix_initial=True, fix_final=False, units='rad', rate_source='thetadot', targets=['theta'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('v', fix_initial=True, fix_final=True, units='ft/s', rate_source='vdot', targets=['v'], lower=500, ref0=2500, ref=25000) phase0.add_control('alpha', units='rad', opt=True, lower=-np.pi / 2, upper=np.pi / 2) phase0.add_polynomial_control('beta', order=5, units='rad', opt=True, lower=-89 * np.pi / 180, upper=1 * np.pi / 180) phase0.add_objective('theta', loc='final', ref=-0.01) p.setup(check=True, force_alloc_complex=True) p.set_val('traj.phase0.states:h', phase0.interpolate(ys=[260000, 80000], nodes='state_input'), units='ft') p.set_val('traj.phase0.states:gamma', phase0.interpolate(ys=[-1 * np.pi / 180, -5 * np.pi / 180], nodes='state_input'), units='rad') p.set_val('traj.phase0.states:phi', phase0.interpolate(ys=[0, 75 * np.pi / 180], nodes='state_input'), units='rad') p.set_val('traj.phase0.states:psi', phase0.interpolate(ys=[90 * np.pi / 180, 10 * np.pi / 180], nodes='state_input'), units='rad') p.set_val('traj.phase0.states:theta', phase0.interpolate(ys=[0, 25 * np.pi / 180], nodes='state_input'), units='rad') p.set_val('traj.phase0.states:v', phase0.interpolate(ys=[25600, 2500], nodes='state_input'), units='ft/s') p.set_val('traj.phase0.t_initial', 0, units='s') p.set_val('traj.phase0.t_duration', 2000, units='s') p.set_val('traj.phase0.controls:alpha', phase0.interpolate( ys=[17.4 * np.pi / 180, 17.4 * np.pi / 180], nodes='control_input'), units='rad') p.set_val('traj.phase0.polynomial_controls:beta', np.radians(-75)) p.run_driver() exp_out = traj.simulate() from scipy.interpolate import interp1d t_sol = p.get_val('traj.phase0.timeseries.time') beta_sol = p.get_val('traj.phase0.timeseries.polynomial_controls:beta') t_sim = exp_out.get_val('traj.phase0.timeseries.time') beta_sim = exp_out.get_val( 'traj.phase0.timeseries.polynomial_controls:beta') sol_interp = interp1d(t_sol.ravel(), beta_sol.ravel()) sim_interp = interp1d(t_sim.ravel(), beta_sim.ravel()) t = np.linspace(0, t_sol.ravel()[-1], 100) assert_near_equal(sim_interp(t), sol_interp(t), tolerance=1.0E-3)
def test_reentry_gauss_lobatto_dymos(self): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.declare_coloring() traj = p.model.add_subsystem("traj", Trajectory()) phase0 = traj.add_phase( "phase0", Phase(ode_class=ShuttleODE, transcription=GaussLobatto(num_segments=50, order=3))) phase0.set_time_options(fix_initial=True, units="s", duration_ref=200) phase0.set_state_options("h", fix_initial=True, fix_final=True, units="ft", rate_source="hdot", targets=["h"], lower=0, ref0=75000, ref=300000, defect_ref=1000) phase0.set_state_options("gamma", fix_initial=True, fix_final=True, units="rad", rate_source="gammadot", targets=["gamma"], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.set_state_options("phi", fix_initial=True, fix_final=False, units="rad", rate_source="phidot", lower=0, upper=89. * np.pi / 180) phase0.set_state_options("psi", fix_initial=True, fix_final=False, units="rad", rate_source="psidot", targets=["psi"], lower=0, upper=90. * np.pi / 180) phase0.set_state_options("theta", fix_initial=True, fix_final=False, units="rad", rate_source="thetadot", targets=["theta"], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.set_state_options("v", fix_initial=True, fix_final=True, units="ft/s", rate_source="vdot", targets=["v"], lower=0, ref0=2500, ref=25000) phase0.add_control("alpha", units="rad", opt=True, lower=-np.pi / 2, upper=np.pi / 2, targets=["alpha"]) phase0.add_control("beta", units="rad", opt=True, lower=-89 * np.pi / 180, upper=1 * np.pi / 180, targets=["beta"]) phase0.add_path_constraint("q", lower=0, upper=70, units="Btu/ft**2/s", ref=70) phase0.add_objective("theta", loc="final", ref=-0.01) p.driver.options["optimizer"] = 'SNOPT' p.driver.opt_settings["iSumm"] = 6 p.setup(check=True) p.set_val("traj.phase0.states:h", phase0.interpolate(ys=[260000, 80000], nodes="state_input"), units="ft") p.set_val("traj.phase0.states:gamma", phase0.interpolate(ys=[-1 * np.pi / 180, -5 * np.pi / 180], nodes="state_input"), units="rad") p.set_val("traj.phase0.states:phi", phase0.interpolate(ys=[0, 75 * np.pi / 180], nodes="state_input"), units="rad") p.set_val("traj.phase0.states:psi", phase0.interpolate(ys=[90 * np.pi / 180, 10 * np.pi / 180], nodes="state_input"), units="rad") p.set_val("traj.phase0.states:theta", phase0.interpolate(ys=[0, 25 * np.pi / 180], nodes="state_input"), units="rad") p.set_val("traj.phase0.states:v", phase0.interpolate(ys=[25600, 2500], nodes="state_input"), units="ft/s") p.set_val("traj.phase0.t_initial", 0, units="s") p.set_val("traj.phase0.t_duration", 2000, units="s") p.set_val("traj.phase0.controls:alpha", phase0.interpolate( ys=[17.4 * np.pi / 180, 17.4 * np.pi / 180], nodes="control_input"), units="rad") p.set_val("traj.phase0.controls:beta", phase0.interpolate(ys=[-75 * np.pi / 180, 0 * np.pi / 180], nodes="control_input"), units="rad") p.run_driver() print(p.get_val("traj.phase0.timeseries.time")[-1]) print(p.get_val("traj.phase0.timeseries.states:theta")[-1]) assert_rel_error(self, p.get_val("traj.phase0.timeseries.time")[-1], 2181.88191719, tolerance=1e-3) assert_rel_error(self, p.get_val("traj.phase0.timeseries.states:theta")[-1], .53440955, tolerance=1e-3)
def setUpClass(cls): cls.traj = Trajectory() p = Problem(model=cls.traj) # Since we're only testing features like get_values that don't rely on a converged # solution, no driver is attached. We'll just invoke run_model. # First Phase (burn) burn1 = Phase('gauss-lobatto', ode_class=FiniteBurnODE, num_segments=4, transcription_order=3, compressed=True) cls.traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) burn1.set_state_options('r', fix_initial=True, fix_final=False) burn1.set_state_options('theta', fix_initial=True, fix_final=False) burn1.set_state_options('vr', fix_initial=True, fix_final=False, defect_scaler=0.1) burn1.set_state_options('vt', fix_initial=True, fix_final=False, defect_scaler=0.1) burn1.set_state_options('accel', fix_initial=True, fix_final=False) burn1.set_state_options('deltav', fix_initial=True, fix_final=False) burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg') burn1.add_design_parameter('c', opt=False, val=1.5) # Second Phase (Coast) coast = Phase('gauss-lobatto', ode_class=FiniteBurnODE, num_segments=10, transcription_order=3, compressed=True) cls.traj.add_phase('coast', coast) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10)) coast.set_state_options('r', fix_initial=False, fix_final=False) coast.set_state_options('theta', fix_initial=False, fix_final=False) coast.set_state_options('vr', fix_initial=False, fix_final=False) coast.set_state_options('vt', fix_initial=False, fix_final=False) coast.set_state_options('accel', fix_initial=True, fix_final=True) coast.set_state_options('deltav', fix_initial=False, fix_final=False) coast.add_control('u1', opt=False, val=0.0, units='deg') coast.add_design_parameter('c', opt=False, val=1.5) # Third Phase (burn) burn2 = Phase('gauss-lobatto', ode_class=FiniteBurnODE, num_segments=3, transcription_order=3, compressed=True) cls.traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10)) burn2.set_state_options('r', fix_initial=False, fix_final=True, defect_scaler=1.0) burn2.set_state_options('theta', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('vr', fix_initial=False, fix_final=True, defect_scaler=0.1) burn2.set_state_options('vt', fix_initial=False, fix_final=True, defect_scaler=0.1) burn2.set_state_options('accel', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', ref0=0, ref=10) burn2.add_design_parameter('c', opt=False, val=1.5) burn2.add_objective('deltav', loc='final') # Link Phases cls.traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) cls.traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) # Finish Problem Setup p.model.options['assembled_jac_type'] = 'csc' p.model.linear_solver = DirectSolver(assemble_jac=True) p.model.add_recorder(SqliteRecorder('test_trajectory_rec.db')) p.setup(check=True) # Set Initial Guesses p.set_val('burn1.t_initial', value=0.0) p.set_val('burn1.t_duration', value=2.25) p.set_val('burn1.states:r', value=burn1.interpolate(ys=[1, 1.5], nodes='state_input')) p.set_val('burn1.states:theta', value=burn1.interpolate(ys=[0, 1.7], nodes='state_input')) p.set_val('burn1.states:vr', value=burn1.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('burn1.states:vt', value=burn1.interpolate(ys=[1, 1], nodes='state_input')) p.set_val('burn1.states:accel', value=burn1.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('burn1.states:deltav', value=burn1.interpolate(ys=[0, 0.1], nodes='state_input')) p.set_val('burn1.controls:u1', value=burn1.interpolate(ys=[-3.5, 13.0], nodes='control_input')) p.set_val('burn1.design_parameters:c', value=1.5) p.set_val('coast.t_initial', value=2.25) p.set_val('coast.t_duration', value=3.0) p.set_val('coast.states:r', value=coast.interpolate(ys=[1.3, 1.5], nodes='state_input')) p.set_val('coast.states:theta', value=coast.interpolate(ys=[2.1767, 1.7], nodes='state_input')) p.set_val('coast.states:vr', value=coast.interpolate(ys=[0.3285, 0], nodes='state_input')) p.set_val('coast.states:vt', value=coast.interpolate(ys=[0.97, 1], nodes='state_input')) p.set_val('coast.states:accel', value=coast.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('coast.controls:u1', value=coast.interpolate(ys=[0, 0], nodes='control_input')) p.set_val('coast.design_parameters:c', value=1.5) p.set_val('burn2.t_initial', value=5.25) p.set_val('burn2.t_duration', value=1.75) p.set_val('burn2.states:r', value=burn2.interpolate(ys=[1, 3], nodes='state_input')) p.set_val('burn2.states:theta', value=burn2.interpolate(ys=[0, 4.0], nodes='state_input')) p.set_val('burn2.states:vr', value=burn2.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('burn2.states:vt', value=burn2.interpolate(ys=[1, np.sqrt(1 / 3)], nodes='state_input')) p.set_val('burn2.states:accel', value=burn2.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('burn2.states:deltav', value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input')) p.set_val('burn2.controls:u1', value=burn2.interpolate(ys=[1, 1], nodes='control_input')) p.set_val('burn2.design_parameters:c', value=1.5) p.run_model()
def test_two_burn_orbit_raise_for_docs(self): import numpy as np import matplotlib.pyplot as plt from openmdao.api import Problem, pyOptSparseDriver, DirectSolver, SqliteRecorder from openmdao.utils.assert_utils import assert_rel_error from openmdao.utils.general_utils import set_pyoptsparse_opt from dymos import Phase, Trajectory from dymos.examples.finite_burn_orbit_raise.finite_burn_eom import FiniteBurnODE traj = Trajectory() p = Problem(model=traj) p.driver = pyOptSparseDriver() _, optimizer = set_pyoptsparse_opt('SNOPT', fallback=False) p.driver.options['optimizer'] = 'SNOPT' p.driver.options['dynamic_simul_derivs'] = True traj.add_design_parameter('c', opt=False, val=1.5) # First Phase (burn) burn1 = Phase('gauss-lobatto', ode_class=FiniteBurnODE, num_segments=10, transcription_order=3, compressed=True) burn1 = traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) burn1.set_state_options('r', fix_initial=True, fix_final=False, defect_scaler=100.0) burn1.set_state_options('theta', fix_initial=True, fix_final=False, defect_scaler=100.0) burn1.set_state_options('vr', fix_initial=True, fix_final=False, defect_scaler=100.0) burn1.set_state_options('vt', fix_initial=True, fix_final=False, defect_scaler=100.0) burn1.set_state_options('accel', fix_initial=True, fix_final=False) burn1.set_state_options('deltav', fix_initial=True, fix_final=False) burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, rate_continuity_scaler=0.001, rate2_continuity_scaler=0.001, lower=-30, upper=30) # Second Phase (Coast) coast = Phase('gauss-lobatto', ode_class=FiniteBurnODE, num_segments=10, transcription_order=3, compressed=True) traj.add_phase('coast', coast) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), duration_ref=10) coast.set_state_options('r', fix_initial=False, fix_final=False, defect_scaler=100.0) coast.set_state_options('theta', fix_initial=False, fix_final=False, defect_scaler=100.0) coast.set_state_options('vr', fix_initial=False, fix_final=False, defect_scaler=100.0) coast.set_state_options('vt', fix_initial=False, fix_final=False, defect_scaler=100.0) coast.set_state_options('accel', fix_initial=True, fix_final=True) coast.set_state_options('deltav', fix_initial=False, fix_final=False) coast.add_control('u1', opt=False, val=0.0, units='deg') # Third Phase (burn) burn2 = Phase('gauss-lobatto', ode_class=FiniteBurnODE, num_segments=10, transcription_order=3, compressed=True) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), initial_ref=10) burn2.set_state_options('r', fix_initial=False, fix_final=True, defect_scaler=100.0) burn2.set_state_options('theta', fix_initial=False, fix_final=False, defect_scaler=100.0) burn2.set_state_options('vr', fix_initial=False, fix_final=True, defect_scaler=100.0) burn2.set_state_options('vt', fix_initial=False, fix_final=True, defect_scaler=100.0) burn2.set_state_options('accel', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, rate_continuity_scaler=0.001, rate2_continuity_scaler=0.001, lower=-30, upper=30) burn2.add_objective('deltav', loc='final', scaler=1.0) # Link Phases traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) # Finish Problem Setup p.model.options['assembled_jac_type'] = 'csc' p.model.linear_solver = DirectSolver(assemble_jac=True) p.driver.add_recorder( SqliteRecorder('two_burn_orbit_raise_example_for_docs.db')) p.setup(check=True) # Set Initial Guesses p.set_val('design_parameters:c', value=1.5) p.set_val('burn1.t_initial', value=0.0) p.set_val('burn1.t_duration', value=2.25) p.set_val('burn1.states:r', value=burn1.interpolate(ys=[1, 1.5], nodes='state_input')) p.set_val('burn1.states:theta', value=burn1.interpolate(ys=[0, 1.7], nodes='state_input')) p.set_val('burn1.states:vr', value=burn1.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('burn1.states:vt', value=burn1.interpolate(ys=[1, 1], nodes='state_input')) p.set_val('burn1.states:accel', value=burn1.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val( 'burn1.states:deltav', value=burn1.interpolate(ys=[0, 0.1], nodes='state_input'), ) p.set_val('burn1.controls:u1', value=burn1.interpolate(ys=[-3.5, 13.0], nodes='control_input')) p.set_val('coast.t_initial', value=2.25) p.set_val('coast.t_duration', value=3.0) p.set_val('coast.states:r', value=coast.interpolate(ys=[1.3, 1.5], nodes='state_input')) p.set_val('coast.states:theta', value=coast.interpolate(ys=[2.1767, 1.7], nodes='state_input')) p.set_val('coast.states:vr', value=coast.interpolate(ys=[0.3285, 0], nodes='state_input')) p.set_val('coast.states:vt', value=coast.interpolate(ys=[0.97, 1], nodes='state_input')) p.set_val('coast.states:accel', value=coast.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('coast.controls:u1', value=coast.interpolate(ys=[0, 0], nodes='control_input')) p.set_val('burn2.t_initial', value=5.25) p.set_val('burn2.t_duration', value=1.75) p.set_val('burn2.states:r', value=burn2.interpolate(ys=[1, 3], nodes='state_input')) p.set_val('burn2.states:theta', value=burn2.interpolate(ys=[0, 4.0], nodes='state_input')) p.set_val('burn2.states:vr', value=burn2.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('burn2.states:vt', value=burn2.interpolate(ys=[1, np.sqrt(1 / 3)], nodes='state_input')) p.set_val('burn2.states:accel', value=burn2.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('burn2.states:deltav', value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input')) p.set_val('burn2.controls:u1', value=burn2.interpolate(ys=[1, 1], nodes='control_input')) p.run_driver() assert_rel_error(self, traj.get_values('deltav', flat=True)[-1], 0.3995, tolerance=2.0E-3) # Plot results exp_out = traj.simulate(times=50, num_procs=3) fig = plt.figure(figsize=(8, 4)) fig.suptitle('Two Burn Orbit Raise Solution') ax_u1 = plt.subplot2grid((2, 2), (0, 0)) ax_deltav = plt.subplot2grid((2, 2), (1, 0)) ax_xy = plt.subplot2grid((2, 2), (0, 1), rowspan=2) span = np.linspace(0, 2 * np.pi, 100) ax_xy.plot(np.cos(span), np.sin(span), 'k--', lw=1) ax_xy.plot(3 * np.cos(span), 3 * np.sin(span), 'k--', lw=1) ax_xy.set_xlim(-4.5, 4.5) ax_xy.set_ylim(-4.5, 4.5) ax_xy.set_xlabel('x ($R_e$)') ax_xy.set_ylabel('y ($R_e$)') ax_u1.set_xlabel('time ($TU$)') ax_u1.set_ylabel('$u_1$ ($deg$)') ax_u1.grid(True) ax_deltav.set_xlabel('time ($TU$)') ax_deltav.set_ylabel('${\Delta}v$ ($DU/TU$)') ax_deltav.grid(True) t_sol = traj.get_values('time') x_sol = traj.get_values('pos_x') y_sol = traj.get_values('pos_y') dv_sol = traj.get_values('deltav') u1_sol = traj.get_values('u1', units='deg') t_exp = exp_out.get_values('time') x_exp = exp_out.get_values('pos_x') y_exp = exp_out.get_values('pos_y') dv_exp = exp_out.get_values('deltav') u1_exp = exp_out.get_values('u1', units='deg') for phase_name in ['burn1', 'coast', 'burn2']: ax_u1.plot(t_sol[phase_name], u1_sol[phase_name], 'ro', ms=3) ax_u1.plot(t_exp[phase_name], u1_exp[phase_name], 'b-') ax_deltav.plot(t_sol[phase_name], dv_sol[phase_name], 'ro', ms=3) ax_deltav.plot(t_exp[phase_name], dv_exp[phase_name], 'b-') ax_xy.plot(x_sol[phase_name], y_sol[phase_name], 'ro', ms=3, label='implicit' if phase_name == 'burn1' else None) ax_xy.plot(x_exp[phase_name], y_exp[phase_name], 'b-', label='explicit' if phase_name == 'burn1' else None) plt.show()
def test_invalid_linkage_phase(self): p = Problem(model=Group()) traj = Trajectory() p.model.add_subsystem('traj', subsys=traj) # Since we're only testing features like get_values that don't rely on a converged # solution, no driver is attached. We'll just invoke run_model. # First Phase (burn) burn1 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=4, order=3)) traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) burn1.set_state_options('r', fix_initial=True, fix_final=False) burn1.set_state_options('theta', fix_initial=True, fix_final=False) burn1.set_state_options('vr', fix_initial=True, fix_final=False, defect_scaler=0.1) burn1.set_state_options('vt', fix_initial=True, fix_final=False, defect_scaler=0.1) burn1.set_state_options('accel', fix_initial=True, fix_final=False) burn1.set_state_options('deltav', fix_initial=True, fix_final=False) burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg') burn1.add_design_parameter('c', opt=False, val=1.5) # Second Phase (Coast) coast = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=10, order=3)) traj.add_phase('coast', coast) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10)) coast.set_state_options('r', fix_initial=False, fix_final=False) coast.set_state_options('theta', fix_initial=False, fix_final=False) coast.set_state_options('vr', fix_initial=False, fix_final=False) coast.set_state_options('vt', fix_initial=False, fix_final=False) coast.set_state_options('accel', fix_initial=True, fix_final=True) coast.set_state_options('deltav', fix_initial=False, fix_final=False) coast.add_control('u1', opt=False, val=0.0, units='deg') coast.add_design_parameter('c', opt=False, val=1.5) # Third Phase (burn) burn2 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=3, order=3)) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10)) burn2.set_state_options('r', fix_initial=False, fix_final=True, defect_scaler=1.0) burn2.set_state_options('theta', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('vr', fix_initial=False, fix_final=True, defect_scaler=0.1) burn2.set_state_options('vt', fix_initial=False, fix_final=True, defect_scaler=0.1) burn2.set_state_options('accel', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', ref0=0, ref=10) burn2.add_design_parameter('c', opt=False, val=1.5) burn2.add_objective('deltav', loc='final') # Link Phases traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'foo'], vars=['u1', 'u1']) # Finish Problem Setup p.model.linear_solver = DirectSolver() p.model.add_recorder(SqliteRecorder('test_trajectory_rec.db')) with self.assertRaises(ValueError) as e: p.setup(check=True) self.assertEqual(str(e.exception), 'Invalid linkage. Phase \'foo\' does not exist in ' 'trajectory \'traj\'.')
def test_connected_linkages_rk(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 = 20 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', Trajectory()) # First phase: normal operation. transcription = RungeKutta(num_segments=num_seg) 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, 5e-5) assert_rel_error(self, soc1[-1], 0.23794217, 5e-5) assert_rel_error(self, soc1b[-1], 0.0281523, 5e-5) assert_rel_error(self, soc1m[-1], 0.18625395, 5e-5)
def test_solver_defects(self): prob = Problem() 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, solve_segments=True) # 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, solve_segments=True) 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, solve_segments=True) # 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, solve_segments=True) 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_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 make_problem(self, constrained=True, transcription=GaussLobatto, optimizer='SLSQP', numseg=50): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver(optimizer=optimizer) p.driver.declare_coloring() if optimizer == 'IPOPT': p.driver.opt_settings['max_iter'] = 500 p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' p.driver.opt_settings['print_level'] = 5 p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based' p.driver.opt_settings['tol'] = 1.0E-7 p.driver.opt_settings['mu_strategy'] = 'monotone' traj = p.model.add_subsystem('traj', Trajectory()) phase0 = traj.add_phase( 'phase0', Phase(ode_class=ShuttleODE, transcription=transcription(num_segments=numseg, order=3))) phase0.set_time_options(fix_initial=True, units='s', duration_ref=200) phase0.add_state('h', fix_initial=True, fix_final=True, units='ft', rate_source='hdot', targets=['h'], lower=0, ref0=75000, ref=300000, defect_ref=1000) phase0.add_state('gamma', fix_initial=True, fix_final=True, units='rad', rate_source='gammadot', targets=['gamma'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('phi', fix_initial=True, fix_final=False, units='rad', rate_source='phidot', lower=0, upper=89. * np.pi / 180) phase0.add_state('psi', fix_initial=True, fix_final=False, units='rad', rate_source='psidot', targets=['psi'], lower=0, upper=90. * np.pi / 180) phase0.add_state('theta', fix_initial=True, fix_final=False, units='rad', rate_source='thetadot', targets=['theta'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('v', fix_initial=True, fix_final=True, units='ft/s', rate_source='vdot', targets=['v'], lower=500, ref0=2500, ref=25000) phase0.add_control('alpha', units='rad', opt=True, lower=-np.pi / 2, upper=np.pi / 2, targets=['alpha']) phase0.add_control('beta', units='rad', opt=True, lower=-89 * np.pi / 180, upper=1 * np.pi / 180, targets=['beta']) if constrained: phase0.add_path_constraint('q', lower=0, upper=70, ref=70) phase0.add_objective('theta', loc='final', ref=-0.01) p.setup(check=True, force_alloc_complex=True) p.set_val('traj.phase0.states:h', phase0.interp('h', [260000, 80000]), units='ft') p.set_val('traj.phase0.states:gamma', phase0.interp('gamma', [-1 * np.pi / 180, -5 * np.pi / 180]), units='rad') p.set_val('traj.phase0.states:phi', phase0.interp('phi', [0, 75 * np.pi / 180]), units='rad') p.set_val('traj.phase0.states:psi', phase0.interp('psi', [90 * np.pi / 180, 10 * np.pi / 180]), units='rad') p.set_val('traj.phase0.states:theta', phase0.interp('theta', [0, 25 * np.pi / 180]), units='rad') p.set_val('traj.phase0.states:v', phase0.interp('v', [25600, 2500]), units='ft/s') p.set_val('traj.phase0.t_initial', 0, units='s') p.set_val('traj.phase0.t_duration', 2000, units='s') p.set_val('traj.phase0.controls:alpha', phase0.interp('alpha', [17.4 * np.pi / 180, 17.4 * np.pi / 180]), units='rad') p.set_val('traj.phase0.controls:beta', phase0.interp('beta', [-75 * np.pi / 180, 0 * np.pi / 180]), units='rad') return p
def test_two_phase_cannonball_for_docs(self): from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, SqliteRecorder, \ pyOptSparseDriver from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase, Trajectory, load_simulation_results from dymos.examples.cannonball.cannonball_ode import CannonballODE from dymos.examples.cannonball.size_comp import CannonballSizeComp p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.options['dynamic_simul_derivs'] = True external_params = p.model.add_subsystem('external_params', IndepVarComp()) external_params.add_output('radius', val=0.10, units='m') external_params.add_output('dens', val=7.87, units='g/cm**3') external_params.add_design_var('radius', lower=0.01, upper=0.10, ref0=0.01, ref=0.10) p.model.add_subsystem('size_comp', CannonballSizeComp()) traj = p.model.add_subsystem('traj', Trajectory()) # First Phase (ascent) ascent = Phase('radau-ps', ode_class=CannonballODE, num_segments=5, transcription_order=3, compressed=True) ascent = traj.add_phase('ascent', ascent) # All initial states except flight path angle are fixed # Final flight path angle is fixed (we will set it to zero so that the phase ends at apogee) ascent.set_time_options(fix_initial=True, duration_bounds=(1, 100), duration_ref=100) ascent.set_state_options('r', fix_initial=True, fix_final=False) ascent.set_state_options('h', fix_initial=True, fix_final=False) ascent.set_state_options('gam', fix_initial=False, fix_final=True) ascent.set_state_options('v', fix_initial=False, fix_final=False) # Limit the muzzle energy ascent.add_boundary_constraint('kinetic_energy.ke', loc='initial', units='J', upper=400000, lower=0, ref=100000) # Second Phase (descent) descent = Phase('gauss-lobatto', ode_class=CannonballODE, num_segments=5, transcription_order=3, compressed=True) traj.add_phase('descent', descent) # All initial states and time are free (they will be linked to the final states of ascent. # Final altitude is fixed (we will set it to zero so that the phase ends at ground impact) descent.set_time_options(initial_bounds=(.5, 100), duration_bounds=(.5, 100), duration_ref=100) descent.set_state_options('r', fix_initial=False, fix_final=False) descent.set_state_options('h', fix_initial=False, fix_final=True) descent.set_state_options('gam', fix_initial=False, fix_final=False) descent.set_state_options('v', fix_initial=False, fix_final=False) descent.add_objective('r', loc='final', scaler=-1.0) # Add internally-managed design parameters to the trajectory. traj.add_design_parameter('CD', val=0.5, units=None, opt=False) traj.add_design_parameter('CL', val=0.0, units=None, opt=False) traj.add_design_parameter('T', val=0.0, units='N', opt=False) traj.add_design_parameter('alpha', val=0.0, units='deg', opt=False) # Add externally-provided design parameters to the trajectory. traj.add_input_parameter('mass', targets={ 'ascent': 'm', 'descent': 'm' }, val=1.0, units='kg') traj.add_input_parameter('S', val=0.005, units='m**2') # Link Phases (link time and all state variables) traj.link_phases(phases=['ascent', 'descent'], vars=['*']) # Issue Connections p.model.connect('external_params.radius', 'size_comp.radius') p.model.connect('external_params.dens', 'size_comp.dens') p.model.connect('size_comp.mass', 'traj.input_parameters:mass') p.model.connect('size_comp.S', 'traj.input_parameters:S') # Finish Problem Setup p.model.options['assembled_jac_type'] = 'csc' p.model.linear_solver = DirectSolver(assemble_jac=True) p.driver.add_recorder(SqliteRecorder('ex_two_phase_cannonball.db')) p.setup(check=True) # Set Initial Guesses p.set_val('external_params.radius', 0.05, units='m') p.set_val('external_params.dens', 7.87, units='g/cm**3') p.set_val('traj.design_parameters:CD', 0.5) p.set_val('traj.design_parameters:CL', 0.0) p.set_val('traj.design_parameters:T', 0.0) p.set_val('traj.ascent.t_initial', 0.0) p.set_val('traj.ascent.t_duration', 10.0) p.set_val('traj.ascent.states:r', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:h', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:v', ascent.interpolate(ys=[200, 150], nodes='state_input')) p.set_val('traj.ascent.states:gam', ascent.interpolate(ys=[25, 0], nodes='state_input'), units='deg') p.set_val('traj.descent.t_initial', 10.0) p.set_val('traj.descent.t_duration', 10.0) p.set_val('traj.descent.states:r', descent.interpolate(ys=[100, 200], nodes='state_input')) p.set_val('traj.descent.states:h', descent.interpolate(ys=[100, 0], nodes='state_input')) p.set_val('traj.descent.states:v', descent.interpolate(ys=[150, 200], nodes='state_input')) p.set_val('traj.descent.states:gam', descent.interpolate(ys=[0, -45], nodes='state_input'), units='deg') p.run_driver() assert_rel_error(self, traj.get_values('r')['descent'][-1], 3191.83945861, tolerance=1.0E-2) exp_out = traj.simulate(times=100, record_file='ex_two_phase_cannonball_sim.db') # exp_out_loaded = load_simulation_results('ex_two_phase_cannonball_sim.db') print('optimal radius: {0:6.4f} m '.format( p.get_val('external_params.radius', units='m')[0])) print('cannonball mass: {0:6.4f} kg '.format( p.get_val('size_comp.mass', units='kg')[0])) fig, axes = plt.subplots(nrows=3, ncols=1, figsize=(8, 6)) axes[0].plot( traj.get_values('r')['ascent'], traj.get_values('h')['ascent'], 'bo') axes[0].plot( traj.get_values('r')['descent'], traj.get_values('h')['descent'], 'ro') axes[0].plot( exp_out.get_values('r')['ascent'], exp_out.get_values('h')['ascent'], 'b--') axes[0].plot( exp_out.get_values('r')['descent'], exp_out.get_values('h')['descent'], 'r--') axes[0].set_xlabel('range (m)') axes[0].set_ylabel('altitude (m)') # plt.suptitle('Kinetic Energy vs Time') axes[1].plot( traj.get_values('time')['ascent'], traj.get_values('kinetic_energy.ke')['ascent'], 'bo') axes[1].plot( traj.get_values('time')['descent'], traj.get_values('kinetic_energy.ke')['descent'], 'ro') axes[1].plot( exp_out.get_values('time')['ascent'], exp_out.get_values('kinetic_energy.ke')['ascent'], 'b--') axes[1].plot( exp_out.get_values('time')['descent'], exp_out.get_values('kinetic_energy.ke')['descent'], 'r--') # axes[1].plot(exp_out_loaded.get_values('time')['ascent'], # exp_out_loaded.get_values('kinetic_energy.ke')['ascent'], # 'b--') # # axes[1].plot(exp_out_loaded.get_values('time')['descent'], # exp_out_loaded.get_values('kinetic_energy.ke')['descent'], # 'r--') axes[1].set_xlabel('time (s)') axes[1].set_ylabel(r'kinetic energy (J)') # plt.figure() axes[2].plot( traj.get_values('time')['ascent'], traj.get_values('gam', units='deg')['ascent'], 'bo') axes[2].plot( traj.get_values('time')['descent'], traj.get_values('gam', units='deg')['descent'], 'ro') axes[2].plot( exp_out.get_values('time')['ascent'], exp_out.get_values('gam', units='deg')['ascent'], 'b--') axes[2].plot( exp_out.get_values('time')['descent'], exp_out.get_values('gam', units='deg')['descent'], 'r--') axes[2].set_xlabel('time (s)') axes[2].set_ylabel(r'flight path angle (deg)') plt.show()
def test_two_burn_orbit_raise_gl_rk_gl_constrained(self): import numpy as np import matplotlib.pyplot as plt from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver from openmdao.utils.assert_utils import assert_rel_error from openmdao.utils.general_utils import set_pyoptsparse_opt from dymos import Phase, GaussLobatto, RungeKutta, Trajectory from dymos.examples.finite_burn_orbit_raise.finite_burn_eom import FiniteBurnODE traj = Trajectory() p = Problem(model=Group()) p.model.add_subsystem('traj', traj) p.driver = pyOptSparseDriver() _, optimizer = set_pyoptsparse_opt('SNOPT', fallback=True) p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = True traj.add_design_parameter('c', opt=False, val=1.5, units='DU/TU') # First Phase (burn) burn1 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=10, order=3, compressed=True)) burn1 = traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) burn1.set_state_options('r', fix_initial=True, fix_final=False) burn1.set_state_options('theta', fix_initial=True, fix_final=False) burn1.set_state_options('vr', fix_initial=True, fix_final=False) burn1.set_state_options('vt', fix_initial=True, fix_final=False) burn1.set_state_options('accel', fix_initial=True, fix_final=False) burn1.set_state_options('deltav', fix_initial=True, fix_final=False) burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, lower=-30, upper=30) # Second Phase (Coast) coast = Phase(ode_class=FiniteBurnODE, transcription=RungeKutta(num_segments=20, compressed=True)) traj.add_phase('coast', coast) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), duration_ref=10) coast.set_state_options('r', fix_initial=False, fix_final=False) coast.set_state_options('theta', fix_initial=False, fix_final=False) coast.set_state_options('vr', fix_initial=False, fix_final=False) coast.set_state_options('vt', fix_initial=False, fix_final=False) coast.set_state_options('accel', fix_initial=True, fix_final=False) coast.set_state_options('deltav', fix_initial=False, fix_final=False) coast.add_design_parameter('u1', opt=False, val=0.0) # Third Phase (burn) burn2 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=10, order=3, compressed=True)) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), initial_ref=10) burn2.set_state_options('r', fix_initial=False, fix_final=True) burn2.set_state_options('theta', fix_initial=False, fix_final=False) burn2.set_state_options('vr', fix_initial=False, fix_final=True) burn2.set_state_options('vt', fix_initial=False, fix_final=True) burn2.set_state_options('accel', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, lower=-30, upper=30) burn2.add_objective('deltav', loc='final', scaler=1.0) burn1.add_timeseries_output('pos_x', units='DU') coast.add_timeseries_output('pos_x', units='DU') burn2.add_timeseries_output('pos_x', units='DU') burn1.add_timeseries_output('pos_y', units='DU') coast.add_timeseries_output('pos_y', units='DU') burn2.add_timeseries_output('pos_y', units='DU') # Link Phases traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) # Finish Problem Setup p.model.linear_solver = DirectSolver() p.setup(check=True, force_alloc_complex=True) # Set Initial Guesses p.set_val('traj.design_parameters:c', value=1.5) p.set_val('traj.burn1.t_initial', value=0.0) p.set_val('traj.burn1.t_duration', value=2.25) p.set_val('traj.burn1.states:r', value=burn1.interpolate(ys=[1, 1.5], nodes='state_input')) p.set_val('traj.burn1.states:theta', value=burn1.interpolate(ys=[0, 1.7], nodes='state_input')) p.set_val('traj.burn1.states:vr', value=burn1.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('traj.burn1.states:vt', value=burn1.interpolate(ys=[1, 1], nodes='state_input')) p.set_val('traj.burn1.states:accel', value=burn1.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('traj.burn1.states:deltav', value=burn1.interpolate(ys=[0, 0.1], nodes='state_input'), ) p.set_val('traj.burn1.controls:u1', value=burn1.interpolate(ys=[-3.5, 13.0], nodes='control_input')) p.set_val('traj.coast.t_initial', value=2.25) p.set_val('traj.coast.t_duration', value=3.0) p.set_val('traj.coast.states:r', value=coast.interpolate(ys=[1.3, 1.5], nodes='state_input')) p.set_val('traj.coast.states:theta', value=coast.interpolate(ys=[2.1767, 1.7], nodes='state_input')) p.set_val('traj.coast.states:vr', value=coast.interpolate(ys=[0.3285, 0], nodes='state_input')) p.set_val('traj.coast.states:vt', value=coast.interpolate(ys=[0.97, 1], nodes='state_input')) p.set_val('traj.coast.states:accel', value=coast.interpolate(ys=[0, 0], nodes='state_input')) # p.set_val('traj.coast.controls:u1', # value=coast.interpolate(ys=[0, 0], nodes='control_input')) p.set_val('traj.burn2.t_initial', value=5.25) p.set_val('traj.burn2.t_duration', value=1.75) p.set_val('traj.burn2.states:r', value=burn2.interpolate(ys=[1.8, 3], nodes='state_input')) p.set_val('traj.burn2.states:theta', value=burn2.interpolate(ys=[3.2, 4.0], nodes='state_input')) p.set_val('traj.burn2.states:vr', value=burn2.interpolate(ys=[.5, 0], nodes='state_input')) p.set_val('traj.burn2.states:vt', value=burn2.interpolate(ys=[1, np.sqrt(1 / 3)], nodes='state_input')) p.set_val('traj.burn2.states:accel', value=burn2.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('traj.burn2.states:deltav', value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input')) p.set_val('traj.burn2.controls:u1', value=burn2.interpolate(ys=[1, 1], nodes='control_input')) p.run_driver() assert_rel_error(self, p.get_val('traj.burn2.timeseries.states:deltav')[-1], 0.3995, tolerance=2.0E-3) # Plot results exp_out = traj.simulate() fig = plt.figure(figsize=(8, 4)) fig.suptitle('Two Burn Orbit Raise Solution') ax_u1 = plt.subplot2grid((2, 2), (0, 0)) ax_deltav = plt.subplot2grid((2, 2), (1, 0)) ax_xy = plt.subplot2grid((2, 2), (0, 1), rowspan=2) span = np.linspace(0, 2 * np.pi, 100) ax_xy.plot(np.cos(span), np.sin(span), 'k--', lw=1) ax_xy.plot(3 * np.cos(span), 3 * np.sin(span), 'k--', lw=1) ax_xy.set_xlim(-4.5, 4.5) ax_xy.set_ylim(-4.5, 4.5) ax_xy.set_xlabel('x ($R_e$)') ax_xy.set_ylabel('y ($R_e$)') ax_u1.set_xlabel('time ($TU$)') ax_u1.set_ylabel('$u_1$ ($deg$)') ax_u1.grid(True) ax_deltav.set_xlabel('time ($TU$)') ax_deltav.set_ylabel('${\Delta}v$ ($DU/TU$)') ax_deltav.grid(True) t_sol = dict((phs, p.get_val('traj.{0}.timeseries.time'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) x_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_x'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) y_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_y'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) dv_sol = dict((phs, p.get_val('traj.{0}.timeseries.states:deltav'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) u1_sol = dict((phs, p.get_val('traj.{0}.timeseries.controls:u1'.format(phs), units='deg')) for phs in ['burn1', 'burn2']) t_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.time'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) x_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.pos_x'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) y_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.pos_y'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) dv_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.states:deltav'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) u1_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.controls:u1'.format(phs), units='deg')) for phs in ['burn1', 'burn2']) for phs in ['burn1', 'coast', 'burn2']: try: ax_u1.plot(t_sol[phs], u1_sol[phs], 'ro', ms=3) ax_u1.plot(t_exp[phs], u1_exp[phs], 'b-') except KeyError: pass ax_deltav.plot(t_sol[phs], dv_sol[phs], 'ro', ms=3) ax_deltav.plot(t_exp[phs], dv_exp[phs], 'b-') ax_xy.plot(x_sol[phs], y_sol[phs], 'ro', ms=3, label='implicit') ax_xy.plot(x_exp[phs], y_exp[phs], 'b-', label='explicit') plt.show()
def test_dynamic_input_params(self): prob = Problem(model=Group()) traj = prob.model.add_subsystem('traj', Trajectory()) # First phase: normal operation. # NOTE: using RK4 integration here P_DEMAND = 2.0 phase0 = Phase(ode_class=BatteryODE, transcription=RungeKutta(num_segments=200)) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.set_state_options('state_of_charge', fix_initial=True, fix_final=False) phase0.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') phase0.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V') phase0.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A') phase0.add_input_parameter('P_demand', val=P_DEMAND, units='W') traj.add_phase('phase0', phase0) # Second phase: normal operation. transcription = Radau(num_segments=5, order=5, compressed=True) phase1 = Phase(ode_class=BatteryODE, transcription=transcription) phase1.set_time_options(fix_initial=False, fix_duration=True) phase1.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) phase1.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') phase1.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V') phase1.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A') phase1.add_input_parameter('P_demand', val=P_DEMAND, units='W') traj.add_phase('phase1', phase1) # Second phase, but with battery failure. phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) phase1_bfail.set_time_options(fix_initial=False, fix_duration=True) phase1_bfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) phase1_bfail.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') phase1_bfail.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V') phase1_bfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A') phase1_bfail.add_input_parameter('P_demand', val=P_DEMAND, units='W') traj.add_phase('phase1_bfail', phase1_bfail) # Second phase, but with motor failure. phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) phase1_mfail.set_time_options(fix_initial=False, fix_duration=True) phase1_mfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) phase1_mfail.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') phase1_mfail.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V') phase1_mfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A') phase1_mfail.add_input_parameter('P_demand', val=P_DEMAND, units='W') traj.add_phase('phase1_mfail', phase1_mfail) 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.linear_solver = DirectSolver(assemble_jac=True) prob.setup() prob.final_setup() prob['traj.phases.phase0.time_extents.t_initial'] = 0 prob['traj.phases.phase0.time_extents.t_duration'] = 1.0*3600 # prob['traj.phases.phase1.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1.time_extents.t_duration'] = 1.0*3600 # prob['traj.phases.phase1_bfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_bfail.time_extents.t_duration'] = 1.0*3600 # prob['traj.phases.phase1_mfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_mfail.time_extents.t_duration'] = 1.0*3600 prob.set_solver_print(level=0) prob.run_model() plot = True if plot: import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt t0 = prob['traj.phase0.timeseries.time'] t1 = prob['traj.phase1.timeseries.time'] t1b = prob['traj.phase1_bfail.timeseries.time'] t1m = prob['traj.phase1_mfail.timeseries.time'] soc0 = prob['traj.phase0.timeseries.states:state_of_charge'] soc1 = prob['traj.phase1.timeseries.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.timeseries.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.timeseries.states:state_of_charge'] plt.subplot(2, 2, 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)') V_oc0 = prob['traj.phase0.timeseries.V_oc'] V_oc1 = prob['traj.phase1.timeseries.V_oc'] V_oc1b = prob['traj.phase1_bfail.timeseries.V_oc'] V_oc1m = prob['traj.phase1_mfail.timeseries.V_oc'] plt.subplot(2, 2, 2) plt.plot(t0, V_oc0, 'b') plt.plot(t1, V_oc1, 'b') plt.plot(t1b, V_oc1b, 'r') plt.plot(t1m, V_oc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Open Circuit Voltage (V)') V_pack0 = prob['traj.phase0.timeseries.V_pack'] V_pack1 = prob['traj.phase1.timeseries.V_pack'] V_pack1b = prob['traj.phase1_bfail.timeseries.V_pack'] V_pack1m = prob['traj.phase1_mfail.timeseries.V_pack'] plt.subplot(2, 2, 3) plt.plot(t0, V_pack0, 'b') plt.plot(t1, V_pack1, 'b') plt.plot(t1b, V_pack1b, 'r') plt.plot(t1m, V_pack1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Terminal Voltage (V)') I_Li0 = prob['traj.phase0.timeseries.I_Li'] I_Li1 = prob['traj.phase1.timeseries.I_Li'] I_Li1b = prob['traj.phase1_bfail.timeseries.I_Li'] I_Li1m = prob['traj.phase1_mfail.timeseries.I_Li'] plt.subplot(2, 2, 4) 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.show()
def make_problem(self, constrained=True, transcription=GaussLobatto, optimizer='SLSQP', numseg=30): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring() OPT, OPTIMIZER = set_pyoptsparse_opt(optimizer, fallback=False) p.driver.options['optimizer'] = OPTIMIZER traj = p.model.add_subsystem('traj', Trajectory()) phase0 = traj.add_phase( 'phase0', Phase(ode_class=ShuttleODE, transcription=transcription(num_segments=numseg, order=3))) phase0.set_time_options(fix_initial=True, units='s', duration_ref=200) phase0.add_state('h', fix_initial=True, fix_final=True, units='ft', rate_source='hdot', targets=['h'], lower=0, ref0=75000, ref=300000, defect_ref=1000) phase0.add_state('gamma', fix_initial=True, fix_final=True, units='rad', rate_source='gammadot', targets=['gamma'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('phi', fix_initial=True, fix_final=False, units='rad', rate_source='phidot', lower=0, upper=89. * np.pi / 180) phase0.add_state('psi', fix_initial=True, fix_final=False, units='rad', rate_source='psidot', targets=['psi'], lower=0, upper=90. * np.pi / 180) phase0.add_state('theta', fix_initial=True, fix_final=False, units='rad', rate_source='thetadot', targets=['theta'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('v', fix_initial=True, fix_final=True, units='ft/s', rate_source='vdot', targets=['v'], lower=500, ref0=2500, ref=25000) phase0.add_control('alpha', units='rad', opt=True, lower=-np.pi / 2, upper=np.pi / 2, targets=['alpha']) phase0.add_control('beta', units='rad', opt=True, lower=-89 * np.pi / 180, upper=1 * np.pi / 180, targets=['beta']) if constrained: phase0.add_path_constraint('q', lower=0, upper=70, ref=70) phase0.add_objective('theta', loc='final', ref=-0.01) p.setup(check=True, force_alloc_complex=True) p.set_val('traj.phase0.states:h', phase0.interpolate(ys=[260000, 80000], nodes='state_input'), units='ft') p.set_val('traj.phase0.states:gamma', phase0.interpolate(ys=[-1 * np.pi / 180, -5 * np.pi / 180], nodes='state_input'), units='rad') p.set_val('traj.phase0.states:phi', phase0.interpolate(ys=[0, 75 * np.pi / 180], nodes='state_input'), units='rad') p.set_val('traj.phase0.states:psi', phase0.interpolate(ys=[90 * np.pi / 180, 10 * np.pi / 180], nodes='state_input'), units='rad') p.set_val('traj.phase0.states:theta', phase0.interpolate(ys=[0, 25 * np.pi / 180], nodes='state_input'), units='rad') p.set_val('traj.phase0.states:v', phase0.interpolate(ys=[25600, 2500], nodes='state_input'), units='ft/s') p.set_val('traj.phase0.t_initial', 0, units='s') p.set_val('traj.phase0.t_duration', 2000, units='s') p.set_val('traj.phase0.controls:alpha', phase0.interpolate( ys=[17.4 * np.pi / 180, 17.4 * np.pi / 180], nodes='control_input'), units='rad') p.set_val('traj.phase0.controls:beta', phase0.interpolate(ys=[-75 * np.pi / 180, 0 * np.pi / 180], nodes='control_input'), units='rad') return p
def thermal_mission_trajectory(num_seg=5, transcription_order=3, meeting_altitude=20000., Q_env=0., Q_sink=0., Q_out=0., m_recirculated=0., opt_m_recirculated=False, opt_m_burn=False, opt_throttle=True, engine_heat_coeff=0., pump_heat_coeff=0., T=None, T_o=None, opt_m=False, m_initial=20.e3, transcription='gauss-lobatto'): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SNOPT' p.driver.opt_settings['Major iterations limit'] = 50 #00 p.driver.opt_settings['Iterations limit'] = 5000000000000000 p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-8 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-8 p.driver.opt_settings['Verify level'] = -1 p.driver.opt_settings['Linesearch tolerance'] = .1 p.driver.opt_settings['Major step limit'] = .05 p.driver.options['dynamic_simul_derivs'] = True traj = p.model.add_subsystem('traj', Trajectory()) ascent = Phase(transcription, ode_class=ThermalMissionODE, ode_init_kwargs={ 'engine_heat_coeff': engine_heat_coeff, 'pump_heat_coeff': pump_heat_coeff }, num_segments=num_seg, transcription_order=transcription_order) ascent = traj.add_phase('ascent', ascent) ascent.set_time_options(opt_initial=False, duration_bounds=(50, 400), duration_ref=100.0) ascent.set_state_options('r', fix_initial=True, lower=0, upper=1.0E6, scaler=1.0E-3, defect_scaler=1.0E-2, units='m') ascent.set_state_options('h', fix_initial=True, lower=0, upper=20000.0, scaler=1.0E-3, defect_scaler=1.0E-3, units='m') ascent.set_state_options('v', fix_initial=True, lower=10.0, scaler=1.0E-2, defect_scaler=5.0E-0, units='m/s') ascent.set_state_options('gam', fix_initial=True, lower=-1.5, upper=1.5, ref=1.0, defect_scaler=1.0, units='rad') ascent.set_state_options('m', fix_initial=not opt_m, lower=15.e3, upper=80e3, scaler=1.0E-3, defect_scaler=1.0E-3, units='kg') ascent.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=True) ascent.add_design_parameter('S', val=1., units='m**2', opt=False) if opt_throttle: ascent.add_control('throttle', val=1.0, lower=0.0, upper=1.0, opt=True, rate_continuity=True) else: ascent.add_design_parameter('throttle', val=1.0, opt=False) ascent.add_design_parameter('W0', val=10.5e3, opt=False, units='kg') ascent.add_boundary_constraint('h', loc='final', equals=meeting_altitude, scaler=1.0E-3, units='m') ascent.add_boundary_constraint('aero.mach', loc='final', equals=1., units=None) ascent.add_boundary_constraint('gam', loc='final', equals=0.0, units='rad') ascent.add_path_constraint(name='h', lower=100.0, upper=20000, ref=20000) ascent.add_path_constraint(name='aero.mach', lower=0.1, upper=1.8) # ascent.add_path_constraint(name='time', upper=110.) # Minimize time at the end of the ascent ascent.add_objective('time', loc='final', ref=100.0) # ascent.add_objective('energy', loc='final', ref=100.0) # ascent.add_objective('m', loc='final', ref=-10000.0) # Set the state options for mass, temperature, and energy. ascent.set_state_options('T', fix_initial=True, ref=300, defect_scaler=1e-2) ascent.set_state_options('energy', fix_initial=True, ref=10e3, defect_scaler=1e-4) # Allow the optimizer to vary the fuel flow if opt_m_recirculated: ascent.add_control('m_recirculated', val=m_recirculated, lower=0., opt=True, rate_continuity=True, ref=20.) else: ascent.add_control('m_recirculated', val=m_recirculated, opt=False) ascent.add_design_parameter('Q_env', val=Q_env, opt=False) ascent.add_design_parameter('Q_sink', val=Q_sink, opt=False) ascent.add_design_parameter('Q_out', val=Q_out, opt=False) # Constrain the temperature, 2nd derivative of fuel mass in the tank, and make # sure that the amount recirculated is at least 0, otherwise we'd burn # more fuel than we pumped. if opt_m_recirculated: ascent.add_path_constraint('m_flow', lower=0., upper=50., units='kg/s', ref=10.) if T is not None: ascent.add_path_constraint('T', upper=T, units='K') if T_o is not None: ascent.add_path_constraint('T_o', upper=T_o, units='K', ref=300.) cruise = Phase(transcription, ode_class=ThermalMissionODE, ode_init_kwargs={ 'engine_heat_coeff': engine_heat_coeff, 'pump_heat_coeff': pump_heat_coeff }, num_segments=num_seg, transcription_order=transcription_order) cruise = traj.add_phase('cruise', cruise) cruise.set_time_options(opt_initial=False, duration_bounds=(50, 1e4), duration_ref=100.0) cruise.set_state_options('r', lower=0, upper=1.0E6, scaler=1.0E-3, defect_scaler=1.0E-2, units='m') cruise.set_state_options('h', lower=0, upper=20000.0, scaler=1.0E-3, defect_scaler=1.0E-3, units='m') cruise.set_state_options('v', lower=10.0, scaler=1.0E-2, defect_scaler=5.0E-0, units='m/s') cruise.set_state_options('gam', lower=-1.5, upper=1.5, ref=1.0, defect_scaler=1.0, units='rad') cruise.set_state_options('m', lower=15.e3, upper=80e3, scaler=1.0E-3, defect_scaler=1.0E-3, units='kg') cruise.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=True) cruise.add_design_parameter('S', val=1., units='m**2', opt=False) if opt_throttle: cruise.add_control('throttle', val=1.0, lower=0.0, upper=1.0, opt=True, rate_continuity=True) else: cruise.add_design_parameter('throttle', val=1.0, opt=False) cruise.add_design_parameter('W0', val=10.5e3, opt=False, units='kg') # Set the state options for mass, temperature, and energy. cruise.set_state_options('T', fix_initial=True, ref=300, defect_scaler=1e-2) cruise.set_state_options('energy', fix_initial=True, ref=10e3, defect_scaler=1e-4) # Allow the optimizer to vary the fuel flow if opt_m_recirculated: cruise.add_control('m_recirculated', val=m_recirculated, lower=0., opt=True, rate_continuity=True, ref=20.) else: cruise.add_control('m_recirculated', val=m_recirculated, opt=False) cruise.add_design_parameter('Q_env', val=Q_env, opt=False) cruise.add_design_parameter('Q_sink', val=Q_sink, opt=False) cruise.add_design_parameter('Q_out', val=Q_out, opt=False) cruise.add_path_constraint(name='h', lower=100.0, upper=20000, ref=20000) cruise.add_path_constraint(name='aero.mach', lower=0.1, upper=1.8) # Link Phases (link time and all state variables) traj.link_phases(phases=['ascent', 'cruise'], vars=['*']) p.setup(mode='fwd', check=True) p['traj.ascent.t_initial'] = 0.0 p['traj.ascent.t_duration'] = 200. p['traj.ascent.states:r'] = ascent.interpolate(ys=[0.0, 111319.54], nodes='state_input') p['traj.ascent.states:h'] = ascent.interpolate( ys=[100.0, meeting_altitude], nodes='state_input') # p['traj.ascent.states:h'][:] = 10000. p['traj.ascent.states:v'] = ascent.interpolate(ys=[135.964, 283.159], nodes='state_input') # p['traj.ascent.states:v'][:] = 200. p['traj.ascent.states:gam'] = ascent.interpolate(ys=[0.0, 0.0], nodes='state_input') p['traj.ascent.states:m'] = ascent.interpolate(ys=[m_initial, 20.e3], nodes='state_input') p['traj.ascent.controls:alpha'] = ascent.interpolate(ys=[1., 1.], nodes='control_input') # Give initial values for the ascent states, controls, and time p['traj.ascent.states:T'] = 310. p['traj.cruise.t_initial'] = 200 p['traj.cruise.t_duration'] = 1000. p['traj.cruise.states:r'] = cruise.interpolate(ys=[111319.54, 2e6], nodes='state_input') p['traj.cruise.states:h'] = cruise.interpolate( ys=[meeting_altitude, meeting_altitude], nodes='state_input') # p['traj.cruise.states:h'][:] = 10000. p['traj.cruise.states:v'] = cruise.interpolate(ys=[283.159, 283.159], nodes='state_input') # p['traj.cruise.states:v'][:] = 200. p['traj.cruise.states:gam'] = cruise.interpolate(ys=[0.0, 0.0], nodes='state_input') p['traj.cruise.states:m'] = cruise.interpolate(ys=[14e3, 12.e3], nodes='state_input') p['traj.cruise.controls:alpha'] = cruise.interpolate(ys=[1., 1.], nodes='control_input') # Give initial values for the cruise states, controls, and time p['traj.cruise.states:T'] = 310. return p