def test_brachistochrone_for_docs_coloring_demo_solve_segments(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.plotting import plot_results from dymos.examples.brachistochrone import BrachistochroneODE # # Initialize the Problem and the optimization driver # p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver(optimizer='IPOPT') p.driver.opt_settings['print_level'] = 4 # p.driver.declare_coloring() # # Create a trajectory and add a phase to it # traj = p.model.add_subsystem('traj', dm.Trajectory()) # # In this case the phase has many segments to demonstrate the impact of coloring. # phase = traj.add_phase( 'phase0', dm.Phase(ode_class=BrachistochroneODE, transcription=dm.Radau(num_segments=100, solve_segments='forward'))) # # Set the variables # phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=True) phase.add_state('y', fix_initial=True) phase.add_state('v', fix_initial=True) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', units='m/s**2', val=9.80665) # # Replace state terminal bounds with nonlinear constraints # phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # # Minimize time at the end of the phase # phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() # # Setup the Problem # p.setup() # # Set the initial values # p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 2.0 p.set_val('traj.phase0.states:x', phase.interp('x', ys=[0, 10])) p.set_val('traj.phase0.states:y', phase.interp('y', ys=[10, 5])) p.set_val('traj.phase0.states:v', phase.interp('v', ys=[0, 9.9])) p.set_val('traj.phase0.controls:theta', phase.interp('theta', ys=[5, 100.5])) # # Solve for the optimal trajectory # dm.run_problem(p) # Test the results assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-3) # Generate the explicitly simulated trajectory exp_out = traj.simulate() plot_results( [('traj.phase0.timeseries.states:x', 'traj.phase0.timeseries.states:y', 'x (m)', 'y (m)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.controls:theta', 'time (s)', 'theta (deg)')], title='Brachistochrone Solution\nRadau Pseudospectral Method', p_sol=p, p_sim=exp_out) plt.show()
import openmdao.api as om import dymos as dm from donner_sub_ode import DonnerSubODE # Create the problem p = om.Problem(model=om.Group()) # Add the trajectory (optional for single phase problems) traj = dm.Trajectory() # Create the phase phase = dm.Phase(ode_class=DonnerSubODE, transcription=dm.GaussLobatto(num_segments=30, order=3, compressed=False)) # Add the phase to the trajectory, and the trajectory to the model traj.add_phase('phase0', phase=phase) p.model.add_subsystem('traj', traj) # # Configure the phase # phase.set_time_options(units=None, targets=['threat_comp.time'], fix_initial=True, duration_bounds=(0.1, 100)) phase.add_state('x', rate_source='eom_comp.dx_dt', targets=['nav_comp.x'],
def _test_integrate_polynomial_control_rate2(self, transcription): # # Define the OpenMDAO problem # p = om.Problem(model=om.Group()) # # Define a Trajectory object # traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # # Define a Dymos Phase object with GaussLobatto Transcription # phase = dm.Phase(ode_class=BrachistochroneODE, transcription=transcription(num_segments=20, order=3)) traj.add_phase(name='phase0', phase=phase) # # Set the time options # Time has no targets in our ODE. # We fix the initial time so that the it is not a design variable in the optimization. # The duration of the phase is allowed to be optimized, but is bounded on [0.5, 10]. # phase.set_time_options(fix_initial=True, duration_bounds=(1.0, 10.0), units='s') # # Set the time options # Initial values of positions and velocity are all fixed. # The final value of position are fixed, but the final velocity is a free variable. # The equations of motion are not functions of position, so 'x' and 'y' have no targets. # The rate source points to the output in the ODE which provides the time derivative of the # given state. phase.add_state('x', fix_initial=True, fix_final=True) phase.add_state('y', fix_initial=True, fix_final=True) phase.add_state('v', fix_initial=True) phase.add_state('int_theta_dot', fix_initial=False, rate_source='theta_rate2') phase.add_state('int_theta', fix_initial=False, rate_source='int_theta_dot', targets=['theta']) # Define theta as a control. phase.add_polynomial_control(name='theta', order=11, units='rad', shape=(1, ), targets=None) # Force the initial value of the theta polynomial control to equal the initial value of the theta state. traj.add_linkage_constraint(phase_a='phase0', phase_b='phase0', var_a='theta', var_b='int_theta', loc_a='initial', loc_b='initial') traj.add_linkage_constraint(phase_a='phase0', phase_b='phase0', var_a='int_theta_dot', var_b='theta_rate', loc_a='initial', loc_b='initial', units='rad/s') # Minimize final time. phase.add_objective('time', loc='final') # Set the driver. p.driver = om.pyOptSparseDriver(optimizer='SLSQP') # Allow OpenMDAO to automatically determine our sparsity pattern. # Doing so can significant speed up the execution of Dymos. p.driver.declare_coloring() # Setup the problem p.setup(check=True) # Now that the OpenMDAO problem is setup, we can set the values of the states. p.set_val('traj.phase0.t_initial', 0.0, units='s') p.set_val('traj.phase0.t_duration', 5.0, units='s') p.set_val('traj.phase0.states:x', phase.interp('x', [0, 10]), units='m') p.set_val('traj.phase0.states:y', phase.interp('y', [10, 5]), units='m') p.set_val('traj.phase0.states:v', phase.interp('v', [0, 5]), units='m/s') p.set_val('traj.phase0.states:int_theta', phase.interp('int_theta', [0.1, 45]), units='deg') p.set_val('traj.phase0.states:int_theta_dot', phase.interp('int_theta_dot', [0, 0]), units='deg/s') p.set_val('traj.phase0.polynomial_controls:theta', 45.0, units='deg') # Run the driver to solve the problem dm.run_problem(p, simulate=True, make_plots=True) sol = om.CaseReader('dymos_solution.db').get_case('final') sim = om.CaseReader('dymos_simulation.db').get_case('final') t_sol = sol.get_val('traj.phase0.timeseries.time') t_sim = sim.get_val('traj.phase0.timeseries.time') x_sol = sol.get_val('traj.phase0.timeseries.states:x') x_sim = sim.get_val('traj.phase0.timeseries.states:x') y_sol = sol.get_val('traj.phase0.timeseries.states:y') y_sim = sim.get_val('traj.phase0.timeseries.states:y') v_sol = sol.get_val('traj.phase0.timeseries.states:v') v_sim = sim.get_val('traj.phase0.timeseries.states:v') int_theta_sol = sol.get_val('traj.phase0.timeseries.states:int_theta') int_theta_sim = sim.get_val('traj.phase0.timeseries.states:int_theta') theta_sol = sol.get_val( 'traj.phase0.timeseries.polynomial_controls:theta') theta_sim = sim.get_val( 'traj.phase0.timeseries.polynomial_controls:theta') assert_timeseries_near_equal(t_sol, x_sol, t_sim, x_sim, tolerance=1.0E-2) assert_timeseries_near_equal(t_sol, y_sol, t_sim, y_sim, tolerance=1.0E-2) assert_timeseries_near_equal(t_sol, v_sol, t_sim, v_sim, tolerance=1.0E-2) assert_timeseries_near_equal(t_sol, int_theta_sol, t_sim, int_theta_sim, tolerance=1.0E-2)
def test_steady_aircraft_for_docs(self): import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.aircraft_steady_flight.aircraft_ode import AircraftODE from dymos.examples.plotting import plot_results from dymos.utils.lgl import lgl p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() num_seg = 15 seg_ends, _ = lgl(num_seg + 1) traj = p.model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=AircraftODE, transcription=dm.Radau(num_segments=num_seg, segment_ends=seg_ends, order=3, compressed=False))) # Pass Reference Area from an external source assumptions = p.model.add_subsystem('assumptions', om.IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(300, 10000), duration_ref=5600) phase.add_state('range', units='NM', rate_source='range_rate_comp.dXdt:range', fix_initial=True, fix_final=False, ref=1e-3, defect_ref=1e-3, lower=0, upper=2000) phase.add_state('mass_fuel', units='lbm', rate_source='propulsion.dXdt:mass_fuel', targets=['mass_comp.mass_fuel'], fix_initial=True, fix_final=True, upper=1.5E5, lower=0.0, ref=1e2, defect_ref=1e2) phase.add_state('alt', units='kft', rate_source='climb_rate', targets=['atmos.h', 'aero.alt', 'propulsion.alt'], fix_initial=True, fix_final=True, lower=0.0, upper=60, ref=1e-3, defect_ref=1e-3) phase.add_control('climb_rate', units='ft/min', opt=True, lower=-3000, upper=3000, targets=['gam_comp.climb_rate'], rate_continuity=True, rate2_continuity=False) phase.add_control('mach', targets=['tas_comp.mach', 'aero.mach'], units=None, opt=False) phase.add_input_parameter( 'S', targets=['aero.S', 'flight_equilibrium.S', 'propulsion.S'], units='m**2') phase.add_input_parameter('mass_empty', targets=['mass_comp.mass_empty'], units='kg') phase.add_input_parameter('mass_payload', targets=['mass_comp.mass_payload'], units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=2.0, shape=(1, )) p.model.connect('assumptions.S', 'traj.phase0.input_parameters:S') p.model.connect('assumptions.mass_empty', 'traj.phase0.input_parameters:mass_empty') p.model.connect('assumptions.mass_payload', 'traj.phase0.input_parameters:mass_payload') phase.add_objective('range', loc='final', ref=-1.0e-4) p.setup() p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 3600.0 p['traj.phase0.states:range'][:] = phase.interpolate( ys=(0, 724.0), nodes='state_input') p['traj.phase0.states:mass_fuel'][:] = phase.interpolate( ys=(30000, 1e-3), nodes='state_input') p['traj.phase0.states:alt'][:] = 10.0 p['traj.phase0.controls:mach'][:] = 0.8 p['assumptions.S'] = 427.8 p['assumptions.mass_empty'] = 0.15E6 p['assumptions.mass_payload'] = 84.02869 * 400 dm.run_problem(p) assert_rel_error(self, p.get_val('traj.phase0.timeseries.states:range', units='NM')[-1], 726.85, tolerance=1.0E-2) exp_out = traj.simulate() plot_results([('traj.phase0.timeseries.states:range', 'traj.phase0.timeseries.states:alt', 'range (NM)', 'altitude (kft)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:mass_fuel', 'time (s)', 'fuel mass (lbm)')], title='Commercial Aircraft Optimization', p_sol=p, p_sim=exp_out) plt.show()
def test_min_time_climb_for_docs_gauss_lobatto(self): import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.min_time_climb.min_time_climb_ode import MinTimeClimbODE # # Instantiate the problem and configure the optimization driver # p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # # Instantiate the trajectory and phase # traj = dm.Trajectory() phase = dm.Phase(ode_class=MinTimeClimbODE, transcription=dm.GaussLobatto(num_segments=15, compressed=False)) traj.add_phase('phase0', phase) p.model.add_subsystem('traj', traj) # # Set the options on the optimization variables # Note the use of explicit state units here since much of the ODE uses imperial units # and we prefer to solve this problem using metric units. # phase.set_time_options(fix_initial=True, duration_bounds=(50, 400), duration_ref=100.0) phase.add_state('r', fix_initial=True, lower=0, upper=1.0E6, units='m', ref=1.0E3, defect_ref=1.0E3, rate_source='flight_dynamics.r_dot') phase.add_state('h', fix_initial=True, lower=0, upper=20000.0, units='m', ref=1.0E2, defect_ref=1.0E2, rate_source='flight_dynamics.h_dot') phase.add_state('v', fix_initial=True, lower=10.0, units='m/s', ref=1.0E2, defect_ref=1.0E2, rate_source='flight_dynamics.v_dot') phase.add_state('gam', fix_initial=True, lower=-1.5, upper=1.5, units='rad', ref=1.0, defect_ref=1.0, rate_source='flight_dynamics.gam_dot') phase.add_state('m', fix_initial=True, lower=10.0, upper=1.0E5, units='kg', ref=1.0E3, defect_ref=1.0E3, rate_source='prop.m_dot') phase.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=True, rate_continuity_scaler=100.0, rate2_continuity=False) phase.add_parameter('S', val=49.2386, units='m**2', opt=False, targets=['S']) phase.add_parameter('Isp', val=1600.0, units='s', opt=False, targets=['Isp']) phase.add_parameter('throttle', val=1.0, opt=False, targets=['throttle']) # # Setup the boundary and path constraints # phase.add_boundary_constraint('h', loc='final', equals=20000, scaler=1.0E-3) phase.add_boundary_constraint('aero.mach', loc='final', equals=1.0) phase.add_boundary_constraint('gam', loc='final', equals=0.0) phase.add_path_constraint(name='h', lower=100.0, upper=20000, ref=20000) phase.add_path_constraint(name='aero.mach', lower=0.1, upper=1.8) # Minimize time at the end of the phase phase.add_objective('time', loc='final', ref=1.0) p.model.linear_solver = om.DirectSolver() # # Setup the problem and set the initial guess # p.setup(check=True) p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 500 p.set_val('traj.phase0.states:r', phase.interp('r', [0.0, 50000.0])) p.set_val('traj.phase0.states:h', phase.interp('h', [100.0, 20000.0])) p.set_val('traj.phase0.states:v', phase.interp('v', [135.964, 283.159])) p.set_val('traj.phase0.states:gam', phase.interp('gam', [0.0, 0.0])) p.set_val('traj.phase0.states:m', phase.interp('m', [19030.468, 10000.])) p.set_val('traj.phase0.controls:alpha', phase.interp('alpha', [0.0, 0.0])) # # Solve for the optimal trajectory # dm.run_problem(p, simulate=True) # # Test the results # assert_near_equal(p.get_val('traj.phase0.t_duration'), 321.0, tolerance=1.0E-1)
print() print(p['max_I'], np.max(p['I'])) raw = input("Continue with baseline sim run test? (y/n)") if raw != "y": quit() # test baseline model pop_total = 1.0 infected0 = 0.01 ns = 50 p = om.Problem(model=om.Group()) traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) phase = dm.Phase(ode_class=SIR, transcription=dm.GaussLobatto(num_segments=ns, order=3)) p.model.linear_solver = om.DirectSolver() phase.set_time_options(fix_initial=True, duration_bounds=(200.0, 301.0)) ds = 1e-2 phase.add_state('S', fix_initial=True, rate_source='Sdot', targets=['S'], lower=0.0, upper=pop_total, ref=pop_total/2, defect_scaler = ds) phase.add_state('I', fix_initial=True, rate_source='Idot', targets=['I'], lower=0.0, upper=pop_total, ref=pop_total/2, defect_scaler = ds) phase.add_state('R', fix_initial=True, rate_source='Rdot', targets=['R'], lower=0.0, upper=pop_total, ref=pop_total/2, defect_scaler = ds) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'IPOPT'
def test_ex_double_integrator_input_times_compressed(self): """ Tests that externally connected t_initial and t_duration function as expected. """ compressed = True p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring() times_ivc = p.model.add_subsystem('times_ivc', om.IndepVarComp(), promotes_outputs=['t0', 'tp']) times_ivc.add_output(name='t0', val=0.0, units='s') times_ivc.add_output(name='tp', val=1.0, units='s') transcription = dm.Radau(num_segments=20, order=3, compressed=compressed) phase = dm.Phase(ode_class=DoubleIntegratorODE, transcription=transcription) p.model.add_subsystem('phase0', phase) p.model.connect('t0', 'phase0.t_initial') p.model.connect('tp', 'phase0.t_duration') phase.set_time_options(input_initial=True, input_duration=True, units='s') phase.add_state('v', fix_initial=True, fix_final=True, rate_source='u', units='m/s') phase.add_state('x', fix_initial=True, rate_source='v', units='m') phase.add_control('u', units='m/s**2', scaler=0.01, continuity=False, rate_continuity=False, rate2_continuity=False, shape=(1, ), lower=-1.0, upper=1.0) # Maximize distance travelled in one second. phase.add_objective('x', loc='final', scaler=-1) p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['t0'] = 0.0 p['tp'] = 1.0 p['phase0.states:x'] = phase.interp('x', [0, 0.25]) p['phase0.states:v'] = phase.interp('v', [0, 0]) p['phase0.controls:u'] = phase.interp('u', [1, -1]) p.run_driver() assert_near_equal(p.get_val('phase0.timeseries.states:x')[-1, ...], [0.25], tolerance=1.0E-8)
help='Optimizer name from pyOptSparse') args = parser.parse_args() optimizer = args.optimizer algorithm = args.algorithm # Define the OpenMDAO problem p = om.Problem(model=om.Group()) # Define a Trajectory object traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # Define a Dymos Phase object with GaussLobatto Transcription phase = dm.Phase(ode_class=SimpleODE, transcription=dm.GaussLobatto(num_segments=10, order=3)) traj.add_phase(name='phase0', phase=phase) # Set the time options phase.set_time_options(fix_initial=True, fix_duration=True, duration_val=5.0, units='s') # Define state variables phase.add_state('x', fix_initial=True, fix_final=True, units='m', rate_source='xdot')
def make_traj(transcription='gauss-lobatto', transcription_order=3, compressed=False, connected=False): t = { 'gauss-lobatto': dm.GaussLobatto(num_segments=5, order=transcription_order, compressed=compressed), 'radau': dm.Radau(num_segments=20, order=transcription_order, compressed=compressed), 'runge-kutta': dm.RungeKutta(num_segments=5, compressed=compressed) } traj = dm.Trajectory() traj.add_design_parameter('c', opt=False, val=1.5, units='DU/TU') # First Phase (burn) burn1 = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription]) 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 = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription]) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 50), duration_ref=50) 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_design_parameter('u1', opt=False, val=0.0, units='deg') # Third Phase (burn) burn2 = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription]) if connected: traj.add_phase('burn2', burn2) traj.add_phase('coast', coast) burn2.set_time_options(initial_bounds=(1.0, 60), duration_bounds=(-10.0, -0.5), initial_ref=10) burn2.set_state_options('r', fix_initial=True, fix_final=False, 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=True, fix_final=False, defect_scaler=1000.0) burn2.set_state_options('vt', fix_initial=True, fix_final=False, defect_scaler=1000.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_objective('deltav', loc='initial', scaler=100.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, lower=-180, upper=180) else: traj.add_phase('coast', coast) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 50), 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=1000.0) burn2.set_state_options('vt', fix_initial=False, fix_final=True, defect_scaler=1000.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_objective('deltav', loc='final', scaler=100.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01) 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 if connected: traj.link_phases(phases=['burn1', 'coast'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav'], connected=True) # No direct connections to the end of a phase. traj.link_phases(phases=['burn2', 'coast'], vars=['r', 'theta', 'vr', 'vt', 'deltav'], locs=('++', '++')) traj.link_phases(phases=['burn2', 'coast'], vars=['time'], locs=('++', '++')) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel'], locs=('++', '++')) else: traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) return traj
def make_traj(transcription='gauss-lobatto', transcription_order=3, compressed=False, connected=False, param_mode='param_sequence'): t = {'gauss-lobatto': dm.GaussLobatto(num_segments=5, order=transcription_order, compressed=compressed), 'radau': dm.Radau(num_segments=20, order=transcription_order, compressed=compressed)} traj = dm.Trajectory() if param_mode == 'param_sequence': traj.add_parameter('c', opt=False, val=1.5, units='DU/TU', targets={'burn1': ['c'], 'coast': ['c'], 'burn2': ['c']}) elif param_mode == 'param_sequence_missing_phase': traj.add_parameter('c', opt=False, val=1.5, units='DU/TU', targets={'burn1': ['c'], 'burn2': ['c']}) elif param_mode == 'param_no_targets': traj.add_parameter('c', val=1.5, units='DU/TU') # First Phase (burn) burn1 = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription]) burn1 = traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10), units='TU') burn1.add_state('r', fix_initial=True, fix_final=False, defect_scaler=100.0, rate_source='r_dot', targets=['r'], units='DU') burn1.add_state('theta', fix_initial=True, fix_final=False, defect_scaler=100.0, rate_source='theta_dot', targets=['theta'], units='rad') burn1.add_state('vr', fix_initial=True, fix_final=False, defect_scaler=100.0, rate_source='vr_dot', targets=['vr'], units='DU/TU') burn1.add_state('vt', fix_initial=True, fix_final=False, defect_scaler=100.0, rate_source='vt_dot', targets=['vt'], units='DU/TU') burn1.add_state('accel', fix_initial=True, fix_final=False, rate_source='at_dot', targets=['accel'], units='DU/TU**2') burn1.add_state('deltav', fix_initial=True, fix_final=False, rate_source='deltav_dot', targets=None, units='DU/TU') 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, targets=['u1']) # Second Phase (Coast) coast = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription]) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 50), duration_ref=50, units='TU') coast.add_state('r', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='r_dot', targets=['r'], units='DU') coast.add_state('theta', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='theta_dot', targets=['theta'], units='rad') coast.add_state('vr', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='vr_dot', targets=['vr'], units='DU/TU') coast.add_state('vt', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='vt_dot', targets=['vt'], units='DU/TU') coast.add_state('accel', fix_initial=True, fix_final=True, rate_source='at_dot', targets=['accel'], units='DU/TU**2') coast.add_state('deltav', fix_initial=False, fix_final=False, rate_source='deltav_dot', units='DU/TU', targets=None) coast.add_parameter('u1', opt=False, val=0.0, units='deg', targets=['u1']) # Third Phase (burn) burn2 = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription]) traj.add_phase('coast', coast) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 50), duration_bounds=(.5, 10), initial_ref=10, units='TU') burn2.add_state('r', fix_initial=False, fix_final=True, defect_scaler=100.0, rate_source='r_dot', targets=['r'], units='DU') burn2.add_state('theta', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='theta_dot', targets=['theta'], units='rad') burn2.add_state('vr', fix_initial=False, fix_final=True, defect_scaler=1000.0, rate_source='vr_dot', targets=['vr'], units='DU/TU') burn2.add_state('vt', fix_initial=False, fix_final=True, defect_scaler=1000.0, rate_source='vt_dot', targets=['vt'], units='DU/TU') burn2.add_state('accel', fix_initial=False, fix_final=False, defect_scaler=1.0, rate_source='at_dot', targets=['accel'], units='DU/TU**2') burn2.add_state('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0, rate_source='deltav_dot', units='DU/TU', targets=None) burn2.add_objective('deltav', loc='final', scaler=100.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, lower=-180, upper=180, targets=['u1']) if 'sequence_missing_phase' in param_mode: coast.add_parameter('c', val=0.0, units='DU/TU', targets=['c']) elif 'no_targets' in param_mode: burn1.add_parameter('c', val=0.0, units='DU/TU', targets=['c']) coast.add_parameter('c', val=0.0, units='DU/TU', targets=['c']) burn2.add_parameter('c', val=0.0, units='DU/TU', targets=['c']) burn1.add_timeseries_output('pos_x') coast.add_timeseries_output('pos_x') burn2.add_timeseries_output('pos_x') burn1.add_timeseries_output('pos_y') coast.add_timeseries_output('pos_y') burn2.add_timeseries_output('pos_y') # Link Phases if connected: traj.link_phases(phases=['burn1', 'coast'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav'], connected=True) # No direct connections to the end of a phase. traj.link_phases(phases=['burn2', 'coast'], vars=['r', 'theta', 'vr', 'vt', 'deltav'], locs=('final', 'final')) traj.link_phases(phases=['burn2', 'coast'], vars=['time'], locs=('final', 'final')) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel'], locs=('final', 'final')) else: traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) return traj
def _make_problem(self, transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP', run_driver=True, force_alloc_complex=False, solve_segments=False): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.declare_coloring(tol=1.0E-12) if transcription == 'gauss-lobatto': t = dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'radau-ps': t = dm.Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) traj = dm.Trajectory() phase = dm.Phase(ode_class=self.ode, transcription=t) p.model.add_subsystem('traj0', traj) traj.add_phase('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=True, fix_final=False, solve_segments=solve_segments, rate_source='xdot') phase.add_state('y', fix_initial=True, fix_final=False, solve_segments=solve_segments, rate_source='ydot') # Note that by omitting the targets here Dymos will automatically attempt to connect # to a top-level input named 'v' in the ODE, and connect to nothing if it's not found. phase.add_state('v', fix_initial=True, fix_final=False, solve_segments=solve_segments, rate_source='vdot') phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', units='m/s**2', dynamic=False) phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) p.setup(check=['unconnected_inputs'], force_alloc_complex=force_alloc_complex) p['traj0.phase0.t_initial'] = 0.0 p['traj0.phase0.t_duration'] = 2.0 p['traj0.phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['traj0.phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['traj0.phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['traj0.phase0.controls:theta'] = phase.interpolate( ys=[5, 100], nodes='control_input') p['traj0.phase0.parameters:g'] = 9.80665 dm.run_problem(p, run_driver=run_driver, simulate=True) return p
def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP'): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.declare_coloring() if transcription == 'gauss-lobatto': t = dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'radau-ps': t = dm.Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'runge-kutta': t = dm.RungeKutta(num_segments=num_segments, order=transcription_order, compressed=compressed) phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', rate_source=BrachistochroneODE.states['x']['rate_source'], units=BrachistochroneODE.states['x']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state('y', rate_source=BrachistochroneODE.states['y']['rate_source'], units=BrachistochroneODE.states['y']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state('v', rate_source=BrachistochroneODE.states['v']['rate_source'], targets=BrachistochroneODE.states['v']['targets'], units=BrachistochroneODE.states['v']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_control( 'theta', targets=BrachistochroneODE.parameters['theta']['targets'], continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_input_parameter( 'g', targets=BrachistochroneODE.parameters['g']['targets'], units='m/s**2', val=9.80665) phase.add_timeseries('timeseries2', transcription=dm.Radau(num_segments=num_segments * 5, order=transcription_order, compressed=compressed), subset='control_input') phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=['unconnected_inputs']) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100], nodes='control_input') p['phase0.input_parameters:g'] = 9.80665 p.run_driver() # Plot results if SHOW_PLOTS: exp_out = phase.simulate() fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.states:x') y_imp = p.get_val('phase0.timeseries.states:y') x_exp = exp_out.get_val('phase0.timeseries.states:x') y_exp = exp_out.get_val('phase0.timeseries.states:y') ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('x (m)') ax.set_ylabel('y (m)') ax.grid(True) ax.legend(loc='upper right') fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.time_phase') y_imp = p.get_val('phase0.timeseries.controls:theta') x_exp = exp_out.get_val('phase0.timeseries.time_phase') y_exp = exp_out.get_val('phase0.timeseries.controls:theta') ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('time (s)') ax.set_ylabel('theta (rad)') ax.grid(True) ax.legend(loc='lower right') plt.show() return p
def test_ivp_solver(self): import openmdao.api as om import dymos as dm import matplotlib.pyplot as plt plt.switch_backend('Agg') # disable plotting to the screen from dymos.examples.oscillator.doc.oscillator_ode import OscillatorODE # Instantiate an OpenMDAO Problem instance. prob = om.Problem() # Instantiate a Dymos Trajectory and add it to the Problem model. traj = dm.Trajectory() prob.model.add_subsystem('traj', traj) # Instantiate a Phase and add it to the Trajectory. phase = dm.Phase(ode_class=OscillatorODE, transcription=dm.Radau(num_segments=4, solve_segments='forward')) traj.add_phase('phase0', phase) # Tell Dymos the states to be propagated using the given ODE. phase.add_state('x', fix_initial=True, rate_source='v', targets=['x'], units='m') phase.add_state('v', fix_initial=True, rate_source='v_dot', targets=['v'], units='m/s') # The spring constant, damping coefficient, and mass are inputs to the system that are # constant throughout the phase. phase.add_parameter('k', units='N/m', targets=['k']) phase.add_parameter('c', units='N*s/m', targets=['c']) phase.add_parameter('m', units='kg', targets=['m']) # Setup the OpenMDAO problem prob.setup() # Assign values to the times and states prob.set_val('traj.phase0.t_initial', 0.0) prob.set_val('traj.phase0.t_duration', 15.0) prob.set_val('traj.phase0.states:x', 10.0) prob.set_val('traj.phase0.states:v', 0.0) prob.set_val('traj.phase0.parameters:k', 1.0) prob.set_val('traj.phase0.parameters:c', 0.5) prob.set_val('traj.phase0.parameters:m', 1.0) # Now we're using the optimization driver to iteratively run the model and vary the # phase duration until the final y value is 0. prob.run_model() # Perform an explicit simulation of our ODE from the initial conditions. sim_out = traj.simulate(times_per_seg=50) # Plot the state values obtained from the phase timeseries objects in the simulation output. t_sol = prob.get_val('traj.phase0.timeseries.time') t_sim = sim_out.get_val('traj.phase0.timeseries.time') states = ['x', 'v'] fig, axes = plt.subplots(len(states), 1) for i, state in enumerate(states): sol = axes[i].plot( t_sol, prob.get_val(f'traj.phase0.timeseries.states:{state}'), 'o') sim = axes[i].plot( t_sim, sim_out.get_val(f'traj.phase0.timeseries.states:{state}'), '-') axes[i].set_ylabel(state) axes[-1].set_xlabel('time (s)') fig.legend((sol[0], sim[0]), ('solution', 'simulation'), 'lower right', ncol=2) plt.tight_layout() plt.show()
def test_brachistochrone_for_docs_gauss_lobatto(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.plotting import plot_results from dymos.examples.brachistochrone import BrachistochroneODE import matplotlib.pyplot as plt # # Initialize the Problem and the optimization driver # p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() # # Create a trajectory and add a phase to it # traj = p.model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=10))) # # Set the variables # phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=True, fix_final=True) phase.add_state('y', fix_initial=True, fix_final=True) phase.add_state('v', fix_initial=True, fix_final=False) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', units='m/s**2', val=9.80665) # # Minimize time at the end of the phase # phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() # # Setup the Problem # p.setup() # # Set the initial values # p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 2.0 p.set_val('traj.phase0.states:x', phase.interp('x', ys=[0, 10])) p.set_val('traj.phase0.states:y', phase.interp('y', ys=[10, 5])) p.set_val('traj.phase0.states:v', phase.interp('v', ys=[0, 9.9])) p.set_val('traj.phase0.controls:theta', phase.interp('theta', ys=[5, 100.5])) # # Solve for the optimal trajectory # dm.run_problem(p) # Test the results assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-3) # Generate the explicitly simulated trajectory exp_out = traj.simulate() plot_results( [('traj.phase0.timeseries.states:x', 'traj.phase0.timeseries.states:y', 'x (m)', 'y (m)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.controls:theta', 'time (s)', 'theta (deg)')], title='Brachistochrone Solution\nHigh-Order Gauss-Lobatto Method', p_sol=p, p_sim=exp_out) plt.show()
def test_radau(self): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() t = dm.Radau(num_segments=20, order=[3, 5] * 10, compressed=True) phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state( 'x', rate_source=BrachistochroneODE.states['x']['rate_source'], units=BrachistochroneODE.states['x']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'y', rate_source=BrachistochroneODE.states['y']['rate_source'], units=BrachistochroneODE.states['y']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'v', rate_source=BrachistochroneODE.states['v']['rate_source'], targets=BrachistochroneODE.states['v']['targets'], units=BrachistochroneODE.states['v']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_control( 'theta', targets=BrachistochroneODE.parameters['theta']['targets'], continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_input_parameter( 'g', targets=BrachistochroneODE.parameters['g']['targets'], units='m/s**2', val=9.80665) phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100], nodes='control_input') p['phase0.input_parameters:g'] = 9.80665 p.run_driver() exp_out = phase.simulate() t_initial = p.get_val('phase0.timeseries.time')[0] tf = p.get_val('phase0.timeseries.time')[-1] x0 = p.get_val('phase0.timeseries.states:x')[0] xf = p.get_val('phase0.timeseries.states:x')[-1] y0 = p.get_val('phase0.timeseries.states:y')[0] yf = p.get_val('phase0.timeseries.states:y')[-1] v0 = p.get_val('phase0.timeseries.states:v')[0] vf = p.get_val('phase0.timeseries.states:v')[-1] g = p.get_val('phase0.timeseries.input_parameters:g')[0] thetaf = exp_out.get_val('phase0.timeseries.controls:theta')[-1] assert_almost_equal(t_initial, 0.0) assert_almost_equal(x0, 0.0) assert_almost_equal(y0, 10.0) assert_almost_equal(v0, 0.0) assert_almost_equal(tf, 1.8016, decimal=3) assert_almost_equal(xf, 10.0, decimal=3) assert_almost_equal(yf, 5.0, decimal=3) assert_almost_equal(vf, 9.902, decimal=3) assert_almost_equal(g, 9.80665, decimal=3) assert_almost_equal(thetaf, 100.12, decimal=0)
def test_double_integrator_for_docs(self): import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.plotting import plot_results from dymos.examples.double_integrator.double_integrator_ode import DoubleIntegratorODE # Initialize the problem and assign the driver p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # Setup the trajectory and its phase traj = p.model.add_subsystem('traj', dm.Trajectory()) transcription = dm.Radau(num_segments=30, order=3, compressed=False) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=DoubleIntegratorODE, transcription=transcription)) # # Set the options for our variables. # phase.set_time_options(fix_initial=True, fix_duration=True, units='s') phase.add_state('v', fix_initial=True, fix_final=True, rate_source='u', units='m/s') phase.add_state('x', fix_initial=True, rate_source='v', units='m') phase.add_control('u', units='m/s**2', scaler=0.01, continuity=False, rate_continuity=False, rate2_continuity=False, shape=(1, ), lower=-1.0, upper=1.0) # # Maximize distance travelled. # phase.add_objective('x', loc='final', scaler=-1) p.model.linear_solver = om.DirectSolver() # # Setup the problem and set our initial values. # p.setup(check=True) p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 1.0 p['traj.phase0.states:x'] = phase.interpolate(ys=[0, 0.25], nodes='state_input') p['traj.phase0.states:v'] = phase.interpolate(ys=[0, 0], nodes='state_input') p['traj.phase0.controls:u'] = phase.interpolate(ys=[1, -1], nodes='control_input') # # Solve the problem. # dm.run_problem(p) # # Verify that the results are correct. # x = p.get_val('traj.phase0.timeseries.states:x') v = p.get_val('traj.phase0.timeseries.states:v') assert_near_equal(x[0], 0.0, tolerance=1.0E-4) assert_near_equal(x[-1], 0.25, tolerance=1.0E-4) assert_near_equal(v[0], 0.0, tolerance=1.0E-4) assert_near_equal(v[-1], 0.0, tolerance=1.0E-4) # # Simulate the explicit solution and plot the results. # exp_out = traj.simulate() plot_results( [('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:x', 'time (s)', 'x $(m)$'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:v', 'time (s)', 'v $(m/s)$'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.controls:u', 'time (s)', 'u $(m/s^2)$')], title='Double Integrator Solution\nRadau Pseudospectral Method', p_sol=p, p_sim=exp_out) plt.show()
def _make_problem(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP', force_alloc_complex=False, solve_segments=False, y_bounds=None): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() 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['mu_init'] = 1e-3 p.driver.opt_settings['max_iter'] = 500 p.driver.opt_settings['print_level'] = 5 p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based' # for faster convergence p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' p.driver.opt_settings['mu_strategy'] = 'monotone' p.driver.declare_coloring(tol=1.0E-12) if transcription == 'gauss-lobatto': t = dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'radau-ps': t = dm.Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) traj = dm.Trajectory() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) p.model.add_subsystem('traj0', traj) traj.add_phase('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=False, fix_final=False, solve_segments=solve_segments) phase.add_state('y', fix_initial=False, fix_final=False, solve_segments=solve_segments) if y_bounds is not None: phase.set_state_options('y', lower=y_bounds[0], upper=y_bounds[1]) # Note that by omitting the targets here Dymos will automatically attempt to connect # to a top-level input named 'v' in the ODE, and connect to nothing if it's not found. phase.add_state('v', fix_initial=False, fix_final=False, solve_segments=solve_segments) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', targets=['g'], units='m/s**2') phase.add_boundary_constraint('x', loc='initial', equals=0) phase.add_boundary_constraint('y', loc='initial', equals=10) phase.add_boundary_constraint('v', loc='initial', equals=0) phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) p.set_solver_print(0) p.setup(check=['unconnected_inputs'], force_alloc_complex=force_alloc_complex) p['traj0.phase0.t_initial'] = 0.0 p['traj0.phase0.t_duration'] = 1.5 p['traj0.phase0.states:x'] = phase.interp('x', [0, 10]) p['traj0.phase0.states:y'] = phase.interp('y', [10, 5]) p['traj0.phase0.states:v'] = phase.interp('v', [0, 9.9]) p['traj0.phase0.controls:theta'] = phase.interp('theta', [5, 100]) p['traj0.phase0.parameters:g'] = 9.80665 return p
def test_brachistochrone_simulate_units(self): # # Define the OpenMDAO problem # p = om.Problem(model=om.Group()) # # Define a Trajectory object # traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # # Define a Dymos Phase object with GaussLobatto Transcription # phase = dm.Phase(ode_class=BrachistochroneODE, ode_init_kwargs={'static_gravity': True}, transcription=dm.GaussLobatto(num_segments=7, order=3)) traj.add_phase(name='phase0', phase=phase) # # Set the time options # Time has no targets in our ODE. # We fix the initial time so that the it is not a design variable in the optimization. # The duration of the phase is allowed to be optimized, but is bounded on [0.5, 10]. # phase.set_time_options(fix_initial=True, duration_bounds=(0.5, 10.0), units='s') # # Set the time options # Initial values of positions and velocity are all fixed. # The final value of position are fixed, but the final velocity is a free variable. # The equations of motion are not functions of position, so 'x' and 'y' have no targets. # The rate source points to the output in the ODE which provides the time derivative of the # given state. phase.add_state('x', fix_initial=True, fix_final=True, rate_source='xdot') phase.add_state('y', fix_initial=True, fix_final=True, rate_source='ydot') phase.add_state('v', fix_initial=True, fix_final=False, rate_source='vdot') # Define theta as a control. phase.add_control(name='theta', units='rad', lower=0, upper=np.pi) phase.add_parameter(name='g', units='m/s**2', static_target=True, opt=False) # Minimize final time. phase.add_objective('time', loc='final') # Set the driver. p.driver = om.ScipyOptimizeDriver() # Allow OpenMDAO to automatically determine our sparsity pattern. # Doing so can significant speed up the execution of Dymos. p.driver.declare_coloring() p.model.set_input_defaults("traj.phase0.parameters:g", val=9.80665 / 0.3048, units="ft/s**2") # Setup the problem p.setup(check=True) # Now that the OpenMDAO problem is setup, we can set the values of the states. p.set_val('traj.phase0.states:x', phase.interp('x', [0, 10]), units='m') p.set_val('traj.phase0.states:y', phase.interp('y', [10, 5]), units='m') p.set_val('traj.phase0.states:v', phase.interp('v', [1.0E-6, 5]), units='m/s') p.set_val('traj.phase0.controls:theta', phase.interp('theta', [5, 100]), units='deg') p.set_val('traj.phase0.parameters:g', 9.80665, units='m/s**2') # Run the driver to solve the problem dm.run_problem(p, simulate=True) sol_case = om.CaseReader('dymos_solution.db').get_case('final') sim_case = om.CaseReader('dymos_simulation.db').get_case('final') assert_near_equal( sim_case.get_val('traj.phase0.timeseries.parameters:g', units='m/s**2')[0], sol_case.get_val('traj.phase0.timeseries.parameters:g', units='m/s**2')[0]) assert_near_equal(sol_case.get_val('traj.phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-4) assert_near_equal(sim_case.get_val('traj.phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-4)
def test_tandem_phases_for_docs(self): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # # First Phase: Standard Brachistochrone # num_segments = 10 transcription_order = 3 compressed = False tx0 = dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) tx1 = dm.Radau(num_segments=num_segments * 2, order=transcription_order * 3, compressed=compressed) phase0 = dm.Phase(ode_class=BrachistochroneODE, transcription=tx0) p.model.add_subsystem('phase0', phase0) phase0.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase0.add_state( 'x', rate_source=BrachistochroneODE.states['x']['rate_source'], units=BrachistochroneODE.states['x']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase0.add_state( 'y', rate_source=BrachistochroneODE.states['y']['rate_source'], units=BrachistochroneODE.states['y']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase0.add_state( 'v', rate_source=BrachistochroneODE.states['v']['rate_source'], targets=BrachistochroneODE.states['v']['targets'], units=BrachistochroneODE.states['v']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase0.add_control( 'theta', continuity=True, rate_continuity=True, targets=BrachistochroneODE.parameters['theta']['targets'], units='deg', lower=0.01, upper=179.9) phase0.add_input_parameter( 'g', targets=BrachistochroneODE.parameters['g']['targets'], units='m/s**2', val=9.80665) phase0.add_boundary_constraint('x', loc='final', equals=10) phase0.add_boundary_constraint('y', loc='final', equals=5) # Add alternative timeseries output to provide control inputs for the next phase phase0.add_timeseries('timeseries2', transcription=tx1, subset='control_input') # # Second Phase: Integration of ArcLength # phase1 = dm.Phase(ode_class=BrachistochroneArclengthODE, transcription=tx1) p.model.add_subsystem('phase1', phase1) phase1.set_time_options(fix_initial=True, input_duration=True) phase1.add_state('S', fix_initial=True, fix_final=False, rate_source='Sdot', units='m') phase1.add_control('theta', opt=False, units='deg', targets='theta') phase1.add_control('v', opt=False, units='m/s', targets='v') # # Connect the two phases # p.model.connect('phase0.t_duration', 'phase1.t_duration') p.model.connect('phase0.timeseries2.controls:theta', 'phase1.controls:theta') p.model.connect('phase0.timeseries2.states:v', 'phase1.controls:v') # Minimize time at the end of the phase # phase1.add_objective('time', loc='final', scaler=1) # phase1.add_boundary_constraint('S', loc='final', upper=12) phase1.add_objective('S', loc='final', ref=1) p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase0.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase0.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase0.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase0.interpolate(ys=[5, 100], nodes='control_input') p['phase0.input_parameters:g'] = 9.80665 p['phase1.states:S'] = 0.0 p.run_driver() expected = np.sqrt((10 - 0)**2 + (10 - 5)**2) assert_rel_error(self, p['phase1.timeseries.states:S'][-1], expected, tolerance=1.0E-3) fig, (ax0, ax1) = plt.subplots(2, 1) fig.tight_layout() ax0.plot(p.get_val('phase0.timeseries.states:x'), p.get_val('phase0.timeseries.states:y'), '.') ax0.set_xlabel('x (m)') ax0.set_ylabel('y (m)') ax1.plot(p.get_val('phase1.timeseries.time'), p.get_val('phase1.timeseries.states:S'), '+') ax1.set_xlabel('t (s)') ax1.set_ylabel('S (m)') plt.show()
def _run_racecar_problem(transcription, timeseries=False): # change track here and in curvature.py. Tracks are defined in tracks.py track = ovaltrack # generate nodes along the centerline for curvature calculation (different # than collocation nodes) points = get_track_points(track) # fit the centerline spline. finespline, gates, gatesd, curv, slope = get_spline(points, s=0.0) # by default 10000 points s_final = track.get_total_length() # Define the OpenMDAO problem p = om.Problem(model=om.Group()) # Define a Trajectory object traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # Define a Dymos Phase object with radau Transcription phase = dm.Phase(ode_class=CombinedODE, transcription=transcription(num_segments=50, order=3, compressed=True)) traj.add_phase(name='phase0', phase=phase) # Set the time options, in this problem we perform a change of variables. So 'time' is # actually 's' (distance along the track centerline) # This is done to fix the collocation nodes in space, which saves us the calculation of # the rate of change of curvature. # The state equations are written with respect to time, the variable change occurs in # timeODE.py phase.set_time_options(fix_initial=True, fix_duration=True, duration_val=s_final, targets=['curv.s'], units='m', duration_ref=s_final, duration_ref0=10) # Define states phase.add_state('t', fix_initial=True, fix_final=False, units='s', lower=0, rate_source='dt_ds', ref=100) # time phase.add_state( 'n', fix_initial=False, fix_final=False, units='m', upper=4.0, lower=-4.0, rate_source='dn_ds', targets=['n'], ref=4.0) # normal distance to centerline. The bounds on n define the # width of the track phase.add_state('V', fix_initial=False, fix_final=False, units='m/s', ref=40, ref0=5, rate_source='dV_ds', targets=['V']) # velocity phase.add_state( 'alpha', fix_initial=False, fix_final=False, units='rad', rate_source='dalpha_ds', targets=['alpha'], ref=0.15) # vehicle heading angle with respect to centerline phase.add_state( 'lambda', fix_initial=False, fix_final=False, units='rad', rate_source='dlambda_ds', targets=['lambda'], ref=0.01 ) # vehicle slip angle, or angle between the axis of the vehicle # and velocity vector (all cars drift a little) phase.add_state('omega', fix_initial=False, fix_final=False, units='rad/s', rate_source='domega_ds', targets=['omega'], ref=0.3) # yaw rate phase.add_state('ax', fix_initial=False, fix_final=False, units='m/s**2', rate_source='dax_ds', targets=['ax'], ref=8) # longitudinal acceleration phase.add_state('ay', fix_initial=False, fix_final=False, units='m/s**2', rate_source='day_ds', targets=['ay'], ref=8) # lateral acceleration # Define Controls phase.add_control(name='delta', units='rad', lower=None, upper=None, fix_initial=False, fix_final=False, targets=['delta'], ref=0.04) # steering angle phase.add_control( name='thrust', units=None, fix_initial=False, fix_final=False, targets=['thrust'] ) # the thrust controls the longitudinal force of the rear tires and is # positive while accelerating, negative while braking # Performance Constraints pmax = 960000 # W phase.add_path_constraint('power', upper=pmax, ref=100000) # engine power limit # The following four constraints are the tire friction limits, with 'rr' designating the # rear right wheel etc. This limit is computed in tireConstraintODE.py phase.add_path_constraint('c_rr', upper=1) phase.add_path_constraint('c_rl', upper=1) phase.add_path_constraint('c_fr', upper=1) phase.add_path_constraint('c_fl', upper=1) # Some of the vehicle design parameters are available to set here. Other parameters can # be found in their respective ODE files. phase.add_parameter( 'M', val=800.0, units='kg', opt=False, targets=['car.M', 'tire.M', 'tireconstraint.M', 'normal.M'], static_target=True) # vehicle mass phase.add_parameter('beta', val=0.62, units=None, opt=False, targets=['tire.beta'], static_target=True) # brake bias phase.add_parameter('CoP', val=1.6, units='m', opt=False, targets=['normal.CoP'], static_target=True) # center of pressure location phase.add_parameter('h', val=0.3, units='m', opt=False, targets=['normal.h'], static_target=True) # center of gravity height phase.add_parameter('chi', val=0.5, units=None, opt=False, targets=['normal.chi'], static_target=True) # roll stiffness phase.add_parameter('ClA', val=4.0, units='m**2', opt=False, targets=['normal.ClA'], static_target=True) # downforce coefficient*area phase.add_parameter('CdA', val=2.0, units='m**2', opt=False, targets=['car.CdA'], static_target=True) # drag coefficient*area # Minimize final time. # note that we use the 'state' time instead of Dymos 'time' phase.add_objective('t', loc='final') # Add output timeseries if timeseries: phase.add_timeseries_output('*') # Link the states at the start and end of the phase in order to ensure a continous lap traj.link_phases(phases=['phase0', 'phase0'], vars=['V', 'n', 'alpha', 'omega', 'lambda', 'ax', 'ay'], locs=('final', 'initial')) # Set the driver. IPOPT or SNOPT are recommended but SLSQP might work. p.driver = om.pyOptSparseDriver(optimizer='IPOPT') p.driver.opt_settings['mu_init'] = 1e-3 p.driver.opt_settings['max_iter'] = 500 p.driver.opt_settings['acceptable_tol'] = 1e-3 p.driver.opt_settings['constr_viol_tol'] = 1e-3 p.driver.opt_settings['compl_inf_tol'] = 1e-3 p.driver.opt_settings['acceptable_iter'] = 0 p.driver.opt_settings['tol'] = 1e-3 p.driver.opt_settings['print_level'] = 5 p.driver.opt_settings[ 'nlp_scaling_method'] = 'gradient-based' # for faster convergence p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' p.driver.opt_settings['mu_strategy'] = 'monotone' p.driver.opt_settings['bound_mult_init_method'] = 'mu-based' # Allow OpenMDAO to automatically determine our sparsity pattern. # Doing so can significant speed up the execution of Dymos. p.driver.declare_coloring() # Setup the problem p.setup(check=True) # force_alloc_complex=True # Now that the OpenMDAO problem is setup, we can set the values of the states. # States # non-zero velocity in order to protect against 1/0 errors. p.set_val('traj.phase0.states:V', phase.interp('V', [20, 20]), units='m/s') p.set_val('traj.phase0.states:lambda', phase.interp('lambda', [0.0, 0.0]), units='rad') # all other states start at 0 p.set_val('traj.phase0.states:omega', phase.interp('omega', [0.0, 0.0]), units='rad/s') p.set_val('traj.phase0.states:alpha', phase.interp('alpha', [0.0, 0.0]), units='rad') p.set_val('traj.phase0.states:ax', phase.interp('ax', [0.0, 0.0]), units='m/s**2') p.set_val('traj.phase0.states:ay', phase.interp('ay', [0.0, 0.0]), units='m/s**2') p.set_val('traj.phase0.states:n', phase.interp('n', [0.0, 0.0]), units='m') # initial guess for what the final time should be p.set_val('traj.phase0.states:t', phase.interp('t', [0.0, 100.0]), units='s') # Controls p.set_val('traj.phase0.controls:delta', phase.interp('delta', [0.0, 0.0]), units='rad') p.set_val('traj.phase0.controls:thrust', phase.interp('thrust', [0.1, 0.1]), units=None) # a small amount of thrust can speed up convergence dm.run_problem(p, run_driver=True, simulate=False, make_plots=False) print('Optimization finished') t = p.get_val('traj.phase0.timeseries.states:t') assert_near_equal(t[-1], 22.2657, tolerance=0.01)
def test_doc_ssto_linear_tangent_guidance(self): import numpy as np import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.plotting import plot_results g = 1.61544 # lunar gravity, m/s**2 class LaunchVehicle2DEOM(om.ExplicitComponent): """ Simple 2D Cartesian Equations of Motion for a launch vehicle subject to thrust and drag. """ def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] # Inputs self.add_input('vx', val=np.zeros(nn), desc='x velocity', units='m/s') self.add_input('vy', val=np.zeros(nn), desc='y velocity', units='m/s') self.add_input('m', val=np.zeros(nn), desc='mass', units='kg') self.add_input('theta', val=np.zeros(nn), desc='pitch angle', units='rad') self.add_input('thrust', val=2100000 * np.ones(nn), desc='thrust', units='N') self.add_input('Isp', val=265.2 * np.ones(nn), desc='specific impulse', units='s') # Outputs self.add_output('xdot', val=np.zeros(nn), desc='velocity component in x', units='m/s') self.add_output('ydot', val=np.zeros(nn), desc='velocity component in y', units='m/s') self.add_output('vxdot', val=np.zeros(nn), desc='x acceleration magnitude', units='m/s**2') self.add_output('vydot', val=np.zeros(nn), desc='y acceleration magnitude', units='m/s**2') self.add_output('mdot', val=np.zeros(nn), desc='mass rate of change', units='kg/s') # Setup partials ar = np.arange(self.options['num_nodes']) self.declare_partials(of='xdot', wrt='vx', rows=ar, cols=ar, val=1.0) self.declare_partials(of='ydot', wrt='vy', rows=ar, cols=ar, val=1.0) self.declare_partials(of='vxdot', wrt='vx', rows=ar, cols=ar) self.declare_partials(of='vxdot', wrt='m', rows=ar, cols=ar) self.declare_partials(of='vxdot', wrt='theta', rows=ar, cols=ar) self.declare_partials(of='vxdot', wrt='thrust', rows=ar, cols=ar) self.declare_partials(of='vydot', wrt='m', rows=ar, cols=ar) self.declare_partials(of='vydot', wrt='theta', rows=ar, cols=ar) self.declare_partials(of='vydot', wrt='vy', rows=ar, cols=ar) self.declare_partials(of='vydot', wrt='thrust', rows=ar, cols=ar) self.declare_partials(of='mdot', wrt='thrust', rows=ar, cols=ar) self.declare_partials(of='mdot', wrt='Isp', rows=ar, cols=ar) def compute(self, inputs, outputs): theta = inputs['theta'] cos_theta = np.cos(theta) sin_theta = np.sin(theta) vx = inputs['vx'] vy = inputs['vy'] m = inputs['m'] F_T = inputs['thrust'] Isp = inputs['Isp'] outputs['xdot'] = vx outputs['ydot'] = vy outputs['vxdot'] = F_T * cos_theta / m outputs['vydot'] = F_T * sin_theta / m - g outputs['mdot'] = -F_T / (g * Isp) def compute_partials(self, inputs, jacobian): theta = inputs['theta'] cos_theta = np.cos(theta) sin_theta = np.sin(theta) m = inputs['m'] F_T = inputs['thrust'] Isp = inputs['Isp'] # jacobian['vxdot', 'vx'] = -CDA * rho * vx / m jacobian['vxdot', 'm'] = -(F_T * cos_theta) / m**2 jacobian['vxdot', 'theta'] = -(F_T / m) * sin_theta jacobian['vxdot', 'thrust'] = cos_theta / m # jacobian['vydot', 'vy'] = -CDA * rho * vy / m jacobian['vydot', 'm'] = -(F_T * sin_theta) / m**2 jacobian['vydot', 'theta'] = (F_T / m) * cos_theta jacobian['vydot', 'thrust'] = sin_theta / m jacobian['mdot', 'thrust'] = -1.0 / (g * Isp) jacobian['mdot', 'Isp'] = F_T / (g * Isp**2) class LinearTangentGuidanceComp(om.ExplicitComponent): """ Compute pitch angle from static controls governing linear expression for pitch angle tangent as function of time. """ def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] self.add_input('a_ctrl', val=np.zeros(nn), desc='linear tangent slope', units='1/s') self.add_input('b_ctrl', val=np.zeros(nn), desc='tangent of theta at t=0', units=None) self.add_input('time_phase', val=np.zeros(nn), desc='time', units='s') self.add_output('theta', val=np.zeros(nn), desc='pitch angle', units='rad') # Setup partials arange = np.arange(self.options['num_nodes']) self.declare_partials(of='theta', wrt='a_ctrl', rows=arange, cols=arange, val=1.0) self.declare_partials(of='theta', wrt='b_ctrl', rows=arange, cols=arange, val=1.0) self.declare_partials(of='theta', wrt='time_phase', rows=arange, cols=arange, val=1.0) def compute(self, inputs, outputs): a = inputs['a_ctrl'] b = inputs['b_ctrl'] t = inputs['time_phase'] outputs['theta'] = np.arctan(a * t + b) def compute_partials(self, inputs, jacobian): a = inputs['a_ctrl'] b = inputs['b_ctrl'] t = inputs['time_phase'] x = a * t + b denom = x**2 + 1.0 jacobian['theta', 'a_ctrl'] = t / denom jacobian['theta', 'b_ctrl'] = 1.0 / denom jacobian['theta', 'time_phase'] = a / denom class LaunchVehicleLinearTangentODE(om.Group): """ The LaunchVehicleLinearTangentODE for this case consists of a guidance component and the EOM. Guidance is simply an OpenMDAO ExecComp which computes the arctangent of the tan_theta variable. """ def initialize(self): self.options.declare( 'num_nodes', types=int, desc='Number of nodes to be evaluated in the RHS') def setup(self): nn = self.options['num_nodes'] self.add_subsystem('guidance', LinearTangentGuidanceComp(num_nodes=nn)) self.add_subsystem('eom', LaunchVehicle2DEOM(num_nodes=nn)) self.connect('guidance.theta', 'eom.theta') # # Setup and solve the optimal control problem # p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring() traj = dm.Trajectory() p.model.add_subsystem('traj', traj) phase = dm.Phase(ode_class=LaunchVehicleLinearTangentODE, transcription=dm.GaussLobatto(num_segments=10, order=5, compressed=True)) traj.add_phase('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(10, 1000), targets=['guidance.time_phase']) phase.add_state('x', fix_initial=True, lower=0, rate_source='eom.xdot', units='m') phase.add_state('y', fix_initial=True, lower=0, rate_source='eom.ydot', units='m') phase.add_state('vx', fix_initial=True, lower=0, rate_source='eom.vxdot', targets=['eom.vx'], units='m/s') phase.add_state('vy', fix_initial=True, rate_source='eom.vydot', targets=['eom.vy'], units='m/s') phase.add_state('m', fix_initial=True, rate_source='eom.mdot', targets=['eom.m'], units='kg') phase.add_boundary_constraint('y', loc='final', equals=1.85E5, linear=True) phase.add_boundary_constraint('vx', loc='final', equals=1627.0) phase.add_boundary_constraint('vy', loc='final', equals=0) phase.add_parameter('a_ctrl', units='1/s', opt=True, targets=['guidance.a_ctrl']) phase.add_parameter('b_ctrl', units=None, opt=True, targets=['guidance.b_ctrl']) phase.add_parameter('thrust', units='N', opt=False, val=3.0 * 50000.0 * 1.61544, targets=['eom.thrust']) phase.add_parameter('Isp', units='s', opt=False, val=1.0E6, targets=['eom.Isp']) phase.add_objective('time', index=-1, scaler=0.01) p.model.linear_solver = om.DirectSolver() phase.add_timeseries_output('guidance.theta', units='deg') p.setup(check=True) p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 500.0 p['traj.phase0.states:x'] = phase.interpolate(ys=[0, 350000.0], nodes='state_input') p['traj.phase0.states:y'] = phase.interpolate(ys=[0, 185000.0], nodes='state_input') p['traj.phase0.states:vx'] = phase.interpolate(ys=[0, 1627.0], nodes='state_input') p['traj.phase0.states:vy'] = phase.interpolate(ys=[1.0E-6, 0], nodes='state_input') p['traj.phase0.states:m'] = phase.interpolate(ys=[50000, 50000], nodes='state_input') p['traj.phase0.parameters:a_ctrl'] = -0.01 p['traj.phase0.parameters:b_ctrl'] = 3.0 dm.run_problem(p) # # Check the results. # assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1], 481, tolerance=0.01) # # Get the explitly simulated results # exp_out = traj.simulate() # # Plot the results # plot_results( [('traj.phase0.timeseries.states:x', 'traj.phase0.timeseries.states:y', 'range (m)', 'altitude (m)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.theta', 'range (m)', 'altitude (m)')], title= 'Single Stage to Orbit Solution Using Linear Tangent Guidance', p_sol=p, p_sim=exp_out) plt.show()
def test_control_rate2_boundary_constraint_gl(self): p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=20, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=True, fix_final=False) phase.add_state('y', fix_initial=True, fix_final=False) phase.add_state('v', fix_initial=True, fix_final=False) phase.add_control('theta', continuity=True, rate_continuity=True, rate2_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', opt=False, units='m/s**2', val=9.80665) phase.add_boundary_constraint('theta_rate2', loc='final', equals=0.0, units='deg/s**2') # Minimize time at the end of the phase phase.add_objective('time') p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase.interp('x', [0, 10]) p['phase0.states:y'] = phase.interp('y', [10, 5]) p['phase0.states:v'] = phase.interp('v', [0, 9.9]) p['phase0.controls:theta'] = phase.interp('theta', [5, 100]) p['phase0.parameters:g'] = 8 p.run_driver() plt.plot(p.get_val('phase0.timeseries.states:x'), p.get_val('phase0.timeseries.states:y'), 'ko') plt.figure() plt.plot(p.get_val('phase0.timeseries.time'), p.get_val('phase0.timeseries.controls:theta'), 'ro') plt.plot(p.get_val('phase0.timeseries.time'), p.get_val('phase0.timeseries.control_rates:theta_rate'), 'bo') plt.plot(p.get_val('phase0.timeseries.time'), p.get_val('phase0.timeseries.control_rates:theta_rate2'), 'go') plt.show() assert_near_equal( p.get_val('phase0.timeseries.control_rates:theta_rate2')[-1], 0, tolerance=1.0E-6)
def _run_transcription(self, transcription): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # # First Phase: Standard Brachistochrone # num_segments = 10 transcription_order = 3 compressed = False if transcription == 'gauss-lobatto': tx0 = dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) tx1 = dm.GaussLobatto(num_segments=num_segments * 2, order=transcription_order * 3, compressed=compressed) elif transcription == 'radau-ps': tx0 = dm.Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) tx1 = dm.Radau(num_segments=num_segments * 2, order=transcription_order * 3, compressed=compressed) phase0 = dm.Phase(ode_class=BrachistochroneODE, transcription=tx0) p.model.add_subsystem('phase0', phase0) phase0.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase0.add_state('x', fix_initial=True, fix_final=False) phase0.add_state('y', fix_initial=True, fix_final=False) phase0.add_state('v', fix_initial=True) phase0.add_parameter('g', units='m/s**2', val=9.80665) phase0.add_control('theta', units='deg', rate_continuity=False, lower=0.01, upper=179.9) phase0.add_boundary_constraint('x', loc='final', equals=10) phase0.add_boundary_constraint('y', loc='final', equals=5) # Add alternative timeseries output to provide control inputs for the next phase phase0.add_timeseries('timeseries2', transcription=tx1, subset='control_input') # # Second Phase: Integration of ArcLength # phase1 = dm.Phase(ode_class=BrachistochroneArclengthODE, transcription=tx1) p.model.add_subsystem('phase1', phase1) phase1.set_time_options(fix_initial=True, input_duration=True) phase1.add_state('S', fix_initial=True, fix_final=False, rate_source='Sdot') phase1.add_control('theta', opt=False, units='deg', targets=['theta']) phase1.add_control('v', opt=False, units='m/s', targets=['v']) # # Connect the two phases # p.model.connect('phase0.t_duration', 'phase1.t_duration') p.model.connect('phase0.timeseries2.controls:theta', 'phase1.controls:theta') p.model.connect('phase0.timeseries2.states:v', 'phase1.controls:v') # Minimize time at the end of the phase # phase1.add_objective('time', loc='final', scaler=1) # phase1.add_boundary_constraint('S', loc='final', upper=12) phase1.add_objective('S', loc='final', ref=1) p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase0.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase0.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase0.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase0.interpolate(ys=[5, 100], nodes='control_input') p['phase0.parameters:g'] = 9.80665 p['phase1.states:S'] = 0.0 p.run_driver() expected = np.sqrt((10 - 0)**2 + (10 - 5)**2) assert_near_equal(p['phase1.timeseries.states:S'][-1], expected, tolerance=1.0E-3)
def test_parameter_boundary_constraint(self): p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=20, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=True, fix_final=True) phase.add_state('y', fix_initial=True, fix_final=True) phase.add_state('v', fix_initial=True, fix_final=False) phase.add_control('theta', continuity=True, rate_continuity=True, rate2_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', opt=True, units='m/s**2', val=9.80665) # We'll let g vary, but make sure it hits the desired value. # It's a static parameter, so it shouldn't matter whether we enforce it # at the start or the end of the phase, so here we'll do both. # Note if we make these equality constraints, some optimizers (SLSQP) will # see the problem as infeasible. phase.add_boundary_constraint('g', loc='initial', units='m/s**2', upper=9.80665) phase.add_boundary_constraint('g', loc='final', units='m/s**2', upper=9.80665) # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase.interp('x', [0, 10]) p['phase0.states:y'] = phase.interp('y', [10, 5]) p['phase0.states:v'] = phase.interp('v', [0, 9.9]) p['phase0.controls:theta'] = phase.interp('theta', [5, 100]) p['phase0.parameters:g'] = 5 p.run_driver() assert_near_equal(p.get_val('phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-4) assert_near_equal(p.get_val('phase0.timeseries.parameters:g')[0], 9.80665, tolerance=1.0E-6) assert_near_equal(p.get_val('phase0.timeseries.parameters:g')[-1], 9.80665, tolerance=1.0E-6)
def test_vanderpol_delay_mpi(self): import openmdao.api as om import dymos as dm from dymos.examples.vanderpol.vanderpol_ode import VanderpolODE from openmdao.utils.assert_utils import assert_near_equal DELAY = 0.005 p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # define a Trajectory object and add to model traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) t = dm.Radau(num_segments=30, order=3) # define a Phase as specified above and add to Phase phase = dm.Phase(ode_class=VanderpolODE, transcription=t, ode_init_kwargs={ 'delay': DELAY, 'distrib': True }) traj.add_phase(name='phase0', phase=phase) t_final = 15 phase.set_time_options(fix_initial=True, fix_duration=True, duration_val=t_final, units='s') # set the State time options phase.add_state('x0', fix_initial=False, fix_final=False, rate_source='x0dot', units='V/s', targets='x0') # target required because x0 is an input phase.add_state('x1', fix_initial=False, fix_final=False, rate_source='x1dot', units='V', targets='x1') # target required because x1 is an input phase.add_state('J', fix_initial=False, fix_final=False, rate_source='Jdot', units=None) # define the control phase.add_control(name='u', units=None, lower=-0.75, upper=1.0, continuity=True, rate_continuity=True, targets='u') # target required because u is an input # add constraints phase.add_boundary_constraint('x0', loc='initial', equals=1.0) phase.add_boundary_constraint('x1', loc='initial', equals=1.0) phase.add_boundary_constraint('J', loc='initial', equals=0.0) phase.add_boundary_constraint('x0', loc='final', equals=0.0) phase.add_boundary_constraint('x1', loc='final', equals=0.0) # define objective to minimize phase.add_objective('J', loc='final') # setup the problem p.setup(check=True) p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = t_final # add a linearly interpolated initial guess for the state and control curves p['traj.phase0.states:x0'] = phase.interp('x0', [1, 0]) p['traj.phase0.states:x1'] = phase.interp('x1', [1, 0]) p['traj.phase0.states:J'] = phase.interp('J', [0, 1]) p['traj.phase0.controls:u'] = phase.interp('u', [-0.75, -0.75]) dm.run_problem(p, run_driver=True, simulate=False) assert_near_equal(p.get_val('traj.phase0.states:x0')[-1, ...], 0.0) assert_near_equal(p.get_val('traj.phase0.states:x1')[-1, ...], 0.0) assert_near_equal(p.get_val('traj.phase0.states:J')[-1, ...], 5.2808, tolerance=1.0E-3) assert_near_equal(p.get_val('traj.phase0.controls:u')[-1, ...], 0.0, tolerance=1.0E-3)
def test_hyper_sensitive_for_docs(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.plotting import plot_results from dymos.examples.hyper_sensitive.hyper_sensitive_ode import HyperSensitiveODE # Initialize the problem and assign the driver p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # Setup the trajectory and its phase traj = p.model.add_subsystem('traj', dm.Trajectory()) transcription = dm.Radau(num_segments=30, order=3, compressed=False) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=HyperSensitiveODE, transcription=transcription)) phase.set_time_options(fix_initial=True, fix_duration=True) phase.add_state('x', fix_initial=True, fix_final=False, rate_source='x_dot', targets=['x']) phase.add_state('xL', fix_initial=True, fix_final=False, rate_source='L', targets=['xL']) phase.add_control('u', opt=True, targets=['u']) phase.add_boundary_constraint('x', loc='final', equals=1) phase.add_objective('xL', loc='final') p.setup(check=True) p.set_val('traj.phase0.states:x', phase.interp('x', [1.5, 1])) p.set_val('traj.phase0.states:xL', phase.interp('xL', [0, 1])) p.set_val('traj.phase0.t_initial', 0) p.set_val('traj.phase0.t_duration', tf) p.set_val('traj.phase0.controls:u', phase.interp('u', [-0.6, 2.4])) # # Solve the problem. # dm.run_problem(p) # # Verify that the results are correct. # ui, uf, J = solution() assert_near_equal(p.get_val('traj.phase0.timeseries.controls:u')[0], ui, tolerance=1.5e-2) assert_near_equal(p.get_val('traj.phase0.timeseries.controls:u')[-1], uf, tolerance=1.5e-2) assert_near_equal(p.get_val('traj.phase0.timeseries.states:xL')[-1], J, tolerance=1e-2) # # Simulate the explicit solution and plot the results. # exp_out = traj.simulate() plot_results( [('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:x', 'time (s)', 'x $(m)$'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.controls:u', 'time (s)', 'u $(m/s^2)$')], title= 'Hyper Sensitive Problem Solution\nRadau Pseudospectral Method', p_sol=p, p_sim=exp_out) plt.show()
def hp_transient(transcription='gauss-lobatto', num_segments=5, transcription_order=3, compressed=False, optimizer='SLSQP', run_driver=True, force_alloc_complex=True, solve_segments=False, show_plots=False, save=True, Tf_final=370): p = om.Problem(model=om.Group()) model = p.model nn = 1 p.driver = om.ScipyOptimizeDriver() p.driver = om.pyOptSparseDriver(optimizer=optimizer) p.driver.declare_coloring() traj = p.model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase( 'phase', dm.Phase(ode_class=HeatPipeRun, transcription=dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed))) phase.set_time_options(fix_initial=True, fix_duration=False, duration_bounds=(1., 3200.)) phase.add_state( 'T_cond', rate_source='cond.Tdot', targets='cond.T', units='K', # ref=333.15, defect_ref=333.15, fix_initial=True, fix_final=False, solve_segments=solve_segments) phase.add_state( 'T_cond2', rate_source='cond2.Tdot', targets='cond2.T', units='K', # ref=333.15, defect_ref=333.15, fix_initial=True, fix_final=False, solve_segments=solve_segments) phase.add_control('T_evap', targets='evap.Rex.T_in', units='K', opt=False) phase.add_boundary_constraint('T_cond', loc='final', equals=Tf_final) phase.add_objective('time', loc='final', ref=1) phase.add_timeseries_output('evap_bridge.Rv.q', output_name='eRvq', units='W') phase.add_timeseries_output('evap_bridge.Rwa.q', output_name='eRwaq', units='W') phase.add_timeseries_output('evap_bridge.Rwka.q', output_name='eRwkq', units='W') phase.add_timeseries_output('cond_bridge.Rv.q', output_name='cRvq', units='W') phase.add_timeseries_output('cond_bridge.Rwa.q', output_name='cRwaq', units='W') phase.add_timeseries_output('cond_bridge.Rwka.q', output_name='cRwkq', units='W') phase.add_timeseries_output('evap.pcm.PS', output_name='ePS', units=None) phase.add_timeseries_output('cond.pcm.PS', output_name='cPS', units=None) phase.add_timeseries_output('cond2.pcm.PS', output_name='c2PS', units=None) p.model.linear_solver = om.DirectSolver() p.setup(force_alloc_complex=force_alloc_complex) p['traj.phase.t_initial'] = 0.0 p['traj.phase.t_duration'] = 195. p['traj.phase.states:T_cond'] = phase.interpolate(ys=[293.15, 333.15], nodes='state_input') p['traj.phase.states:T_cond2'] = phase.interpolate(ys=[293.15, 333.15], nodes='state_input') p['traj.phase.controls:T_evap'] = phase.interpolate(ys=[333., 338.], nodes='control_input') p.run_model() opt = p.run_driver() # sim = traj.simulate(times_per_seg=10) print('********************************') # save_csv(p, sim, '../../output/output.csv', # y_name=['parameters:T_evap', 'states:T_cond', 'states:T_cond2', # 'eRvq', 'eRwaq', 'eRwkq', 'cRvq', 'cRwaq', 'cRwkq'], # y_units=['K', 'K', 'K', 'W', 'W', 'W', 'W', 'W', 'W']) if show_plots: import matplotlib.pyplot as plt # time = sim.get_val('traj.phase.timeseries.time', units='s') time_opt = p.get_val('traj.phase.timeseries.time', units='s') # T_cond = sim.get_val('traj.phase.timeseries.states:T_cond', units='K') T_cond_opt = p.get_val('traj.phase.timeseries.states:T_cond', units='K') # T_cond2 = sim.get_val('traj.phase.timeseries.states:T_cond2', units='K') T_cond2_opt = p.get_val('traj.phase.timeseries.states:T_cond2', units='K') # T_evap = sim.get_val('traj.phase.timeseries.controls:T_evap', units='K') T_evap_opt = p.get_val('traj.phase.timeseries.controls:T_evap', units='K') ePS_opt = p.get_val('traj.phase.timeseries.ePS') cPS_opt = p.get_val('traj.phase.timeseries.cPS') c2PS_opt = p.get_val('traj.phase.timeseries.c2PS') plt.plot(time_opt, T_cond_opt) # plt.plot(time, T_cond) plt.plot(time_opt, T_cond2_opt) # plt.plot(time, T_cond2) plt.plot(time_opt, T_evap_opt) # plt.plot(time, T_evap) plt.xlabel('time, s') plt.ylabel('T_cond, K') plt.show() plt.plot(time_opt, cPS_opt) # plt.plot(time, EPS) plt.plot(time_opt, c2PS_opt) # plt.plot(time, T_cond2) plt.plot(time_opt, ePS_opt) # plt.plot(time, T_evap) plt.xlabel('time, s') plt.ylabel('percent solid') plt.show() return p
nv = 25 ns = 25 p = om.Problem(model=om.Group()) traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) p.model.linear_solver = om.DirectSolver() gl = dm.GaussLobatto(num_segments=ns) #gl = dm.Radau(num_segments=ns, order=3) nn = gl.grid_data.num_nodes phase = dm.Phase(ode_class=Airspace, ode_init_kwargs={'num_vehicles' : nv}, transcription=gl) traj.add_phase(name='phase0', phase=phase) phase.set_time_options(fix_initial=True, fix_duration=False, units='s') traj.add_phase(name='phase0', phase=phase) ds=1e-1 phase.add_state('X', fix_initial=True, fix_final=True, shape=(nv,), rate_source='X_dot',
def _test_transcription(self, transcription=dm.GaussLobatto): # # Define the OpenMDAO problem # p = om.Problem(model=om.Group()) # # Define a Trajectory object # traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # # Define a Dymos Phase object with GaussLobatto Transcription # phase = dm.Phase(ode_class=BrachistochroneODE, transcription=transcription(num_segments=10, order=3, solve_segments='forward')) traj.add_phase(name='phase0', phase=phase) # # Set the time options # Time has no targets in our ODE. # We fix the initial time so that the it is not a design variable in the optimization. # The duration of the phase is allowed to be optimized, but is bounded on [0.5, 10]. # phase.set_time_options(fix_initial=True, fix_duration=True, units='s') # # Set the time options # Initial values of positions and velocity are all fixed. # The final value of position are fixed, but the final velocity is a free variable. # The equations of motion are not functions of position, so 'x' and 'y' have no targets. # The rate source points to the output in the ODE which provides the time derivative of the # given state. phase.add_state('x', fix_initial=True) phase.add_state('y', fix_initial=True) phase.add_state('v', fix_initial=True) phase.add_state('int_one', fix_initial=True, rate_source='one') phase.add_state('int_time', fix_initial=True, rate_source='time') phase.add_state('int_time_phase', fix_initial=True, rate_source='time_phase') phase.add_state('int_int_one', fix_initial=True, rate_source='int_one') # Define theta as a control. phase.add_control(name='theta', units='rad', lower=0, upper=np.pi) # With no targets we must explicitly assign units and shape to this parameter. # Its only purpose is to be integrated as the rate source for a state. phase.add_parameter(name='one', opt=False, units=None, shape=(1, )) # Minimize final time. phase.add_objective('time', loc='final') # Set the driver. p.driver = om.ScipyOptimizeDriver() # Allow OpenMDAO to automatically determine our sparsity pattern. # Doing so can significant speed up the execution of Dymos. p.driver.declare_coloring() # Setup the problem p.setup(check=True) # Now that the OpenMDAO problem is setup, we can set the values of the states. p.set_val('traj.phase0.t_initial', 0.0, units='s') p.set_val('traj.phase0.t_duration', 5.0, units='s') p.set_val('traj.phase0.parameters:one', 1.0) p.set_val('traj.phase0.states:x', phase.interp('x', [0, 10]), units='m') p.set_val('traj.phase0.states:y', phase.interp('y', [10, 5]), units='m') p.set_val('traj.phase0.states:v', phase.interp('v', [0, 5]), units='m/s') p.set_val('traj.phase0.controls:theta', phase.interp('theta', [0.1, 45], nodes='control_input'), units='deg') # Additional states to test rate sources p.set_val('traj.phase0.states:int_one', phase.interp('int_one', [0, 10]), units='s') p.set_val('traj.phase0.states:int_time', phase.interp('int_time', [0, 10]), units='s**2') p.set_val('traj.phase0.states:int_time_phase', phase.interp('int_time_phase', [0, 10]), units='s**2') p.set_val('traj.phase0.states:int_int_one', phase.interp('int_int_one', [0, 10]), units='s**2') # Run the driver to solve the problem dm.run_problem(p, simulate=True) time_sol = p.get_val('traj.phase0.timeseries.time') time_phase_sol = p.get_val('traj.phase0.timeseries.time_phase') int_one_sol = p.get_val('traj.phase0.timeseries.states:int_one') int_time_sol = p.get_val('traj.phase0.timeseries.states:int_time') int_time_phase_sol = p.get_val( 'traj.phase0.timeseries.states:int_time_phase') int_int_one_sol = p.get_val( 'traj.phase0.timeseries.states:int_int_one') time_sim = p.get_val('traj.phase0.timeseries.time') time_phase_sim = p.get_val('traj.phase0.timeseries.time_phase') int_one_sim = p.get_val('traj.phase0.timeseries.states:int_one') int_time_sim = p.get_val('traj.phase0.timeseries.states:int_time') int_time_phase_sim = p.get_val( 'traj.phase0.timeseries.states:int_time_phase') int_int_one_sim = p.get_val( 'traj.phase0.timeseries.states:int_int_one') # Integral of one should match time and time_phase in this case. assert_near_equal(int_one_sol, time_sol, tolerance=1.0E-12) assert_near_equal(int_one_sol, time_phase_sol, tolerance=1.0E-12) assert_near_equal(int_one_sim, time_sim, tolerance=1.0E-12) assert_near_equal(int_one_sim, time_phase_sim, tolerance=1.0E-12) # Integral of time and time_phase should be t**2/2 assert_near_equal(time_sol, time_phase_sol, tolerance=1.0E-12) assert_near_equal(int_time_sol, time_sol**2 / 2, tolerance=1.0E-12) assert_near_equal(int_time_phase_sol, time_phase_sol**2 / 2, tolerance=1.0E-12) assert_near_equal(time_sim, time_phase_sim, tolerance=1.0E-12) assert_near_equal(int_time_sim, time_sim**2 / 2, tolerance=1.0E-12) assert_near_equal(int_time_phase_sim, time_phase_sim**2 / 2, tolerance=1.0E-12) # Double integral of one should be the same as the integral of time assert_near_equal(int_int_one_sol, int_time_sol, tolerance=1.0E-12) assert_near_equal(int_int_one_sim, int_time_sim, tolerance=1.0E-12) assert_timeseries_near_equal(time_sol, int_int_one_sol, time_sim, int_int_one_sim)
def min_time_climb(optimizer='SLSQP', num_seg=3, transcription='gauss-lobatto', transcription_order=3, force_alloc_complex=False): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.declare_coloring() if optimizer == 'SNOPT': p.driver.opt_settings['Major iterations limit'] = 1000 p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings['Function precision'] = 1.0E-12 p.driver.opt_settings['Linesearch tolerance'] = 0.1 p.driver.opt_settings['Major step limit'] = 0.5 t = { 'gauss-lobatto': dm.GaussLobatto(num_segments=num_seg, order=transcription_order), 'radau-ps': dm.Radau(num_segments=num_seg, order=transcription_order) } traj = dm.Trajectory() phase = dm.Phase(ode_class=_TestODE, transcription=t[transcription]) traj.add_phase('phase0', phase) p.model.add_subsystem('traj', traj) phase.set_time_options(fix_initial=True, duration_bounds=(50, 400), duration_ref=100.0) phase.add_state('r', fix_initial=True, lower=0, upper=1.0E6, ref=1.0E3, defect_ref=1.0E3, units='m', rate_source='flight_dynamics.r_dot') phase.add_state('h', fix_initial=True, lower=0, upper=20000.0, ref=1.0E2, defect_ref=1.0E2, units='m', rate_source='flight_dynamics.h_dot', targets=['h']) phase.add_state('v', fix_initial=True, lower=10.0, ref=1.0E2, defect_ref=1.0E2, units='m/s', rate_source='flight_dynamics.v_dot', targets=['v']) phase.add_state('gam', fix_initial=True, lower=-1.5, upper=1.5, ref=1.0, defect_ref=1.0, units='rad', rate_source='flight_dynamics.gam_dot', targets=['gam']) phase.add_state('m', fix_initial=True, lower=10.0, upper=1.0E5, ref=1.0E3, defect_ref=1.0E3, units='kg', rate_source='prop.m_dot', targets=['m']) phase.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=True, rate_continuity_scaler=100.0, rate2_continuity=False, targets=['alpha']) phase.add_parameter('S', val=49.2386, units='m**2', opt=False, targets=['S']) phase.add_parameter('Isp', val=1600.0, units='s', opt=False, targets=['Isp']) phase.add_parameter('throttle', val=1.0, opt=False, targets=['throttle']) phase.add_parameter('test', val=40 * [1], opt=False, static_target=True, targets=['test']) phase.add_boundary_constraint('h', loc='final', equals=20000, scaler=1.0E-3) phase.add_boundary_constraint('aero.mach', loc='final', equals=1.0) phase.add_boundary_constraint('gam', loc='final', equals=0.0) phase.add_path_constraint(name='h', lower=100.0, upper=20000, ref=20000) phase.add_path_constraint(name='aero.mach', lower=0.1, upper=1.8) # Unnecessary but included to test capability phase.add_path_constraint(name='alpha', lower=-8, upper=8, units='deg') # Minimize time at the end of the phase phase.add_objective('time', loc='final', ref=1.0) # test mixing wildcard ODE variable expansion and unit overrides phase.add_timeseries_output(['aero.*', 'prop.thrust', 'prop.m_dot'], units={ 'aero.f_lift': 'lbf', 'prop.thrust': 'lbf' }) phase.set_refine_options(max_order=5) p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=force_alloc_complex) p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 300.0 p['traj.phase0.states:r'] = phase.interp('r', [0.0, 111319.54]) p['traj.phase0.states:h'] = phase.interp('h', [100.0, 20000.0]) p['traj.phase0.states:v'] = phase.interp('v', [135.964, 283.159]) p['traj.phase0.states:gam'] = phase.interp('gam', [0.0, 0.0]) p['traj.phase0.states:m'] = phase.interp('m', [19030.468, 16841.431]) p['traj.phase0.controls:alpha'] = phase.interp('alpha', [0.0, 0.0]) dm.run_problem(p, refine_iteration_limit=1) return p