def test_simple_integration_forward_connected_initial(self): p = om.Problem(model=om.Group()) traj = p.model.add_subsystem('traj', subsys=dm.Trajectory()) phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4')) traj.add_phase('phase0', phase) phase.set_time_options(fix_initial=True, fix_duration=True, targets=['t']) phase.add_state('y', fix_initial=False, connected_initial=True, targets=['y'], rate_source='ydot', units='m') phase.add_timeseries_output('ydot', output_name='state_rate:y', units='m/s') p.setup(check=True, force_alloc_complex=True) p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 2.0 # The initial guess of states at the segment boundaries p['traj.phase0.states:y'] = 0.0 # The initial value of the states from which the integration proceeds p['traj.phase0.initial_states:y'] = 0.5 p.run_model() expected = _test_ode_solution(p['traj.phase0.ode.y'], p['traj.phase0.ode.t']) assert_near_equal(p['traj.phase0.ode.y'], expected, tolerance=1.0E-3)
def test_simple_integration_backward_connected_initial(self): p = om.Problem(model=om.Group()) phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4')) p.model.add_subsystem('phase0', subsys=phase) phase.set_time_options(fix_initial=True, fix_duration=True) phase.add_state('y', connected_initial=True) phase.add_timeseries_output('ydot', output_name='state_rate:y', units='m/s') p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 2.0 p['phase0.t_duration'] = -2.0 # The initial guess of state values at the segment boundaries p['phase0.states:y'] = 0 # The initial value of the states from which the integration proceeds p['phase0.initial_states:y'] = 5.305471950534675 p.run_model() expected = np.atleast_2d( _test_ode_solution(p['phase0.ode.y'], p['phase0.timeseries.time'])) assert_rel_error(self, p['phase0.timeseries.states:y'], expected, tolerance=1.0E-3)
def test_simple_integration_forward_connected_initial_fixed_initial(self): p = om.Problem(model=om.Group()) phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4')) p.model.add_subsystem('phase0', subsys=phase) phase.set_time_options(fix_initial=True, fix_duration=True, targets=['t']) phase.add_state('y', fix_initial=True, connected_initial=True, targets=['y'], rate_source='ydot', units='m') phase.add_timeseries_output('ydot', output_name='state_rate:y', units='m/s') with self.assertRaises(ValueError) as e: p.setup(check=True, force_alloc_complex=True) expected = "Cannot specify 'fix_initial=True' and specify 'connected_initial=True' for " \ "state y in phase phase0." self.assertEqual(str(e.exception), expected)
def test_load_case_rk4_to_lgl(self): import openmdao.api as om import dymos as dm from openmdao.utils.assert_utils import assert_near_equal p = setup_problem(dm.RungeKutta(num_segments=50)) # Solve for the optimal trajectory dm.run_problem(p) # Load the solution case = om.CaseReader('dymos_solution.db').get_case('final') # create a problem with a different transcription with a different number of variables q = setup_problem(dm.GaussLobatto(num_segments=10)) # Load the values from the previous solution dm.load_case(q, case) # Run the model to ensure we find the same output values as those that we recorded q.run_driver() outputs = dict([ (o[0], o[1]) for o in case.list_outputs(units=True, shape=True, out_stream=None) ]) time_val = outputs['phase0.timeseries.time']['value'] theta_val = outputs['phase0.timeseries.controls:theta']['value'] assert_near_equal(q['phase0.timeseries.controls:theta'], q.model.phase0.interpolate(xs=time_val, ys=theta_val, nodes='all'), tolerance=1.0E-1)
def test_single_phase_reverse_propagation_rk(self): prob = om.Problem() num_seg = 10 seg_ends, _ = lgl(num_seg + 1) # First phase: normal operation. transcription = dm.RungeKutta(num_segments=num_seg) phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = prob.model.add_subsystem('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.add_state('state_of_charge', fix_initial=True, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') prob.setup() prob['phase0.t_initial'] = 0 prob['phase0.t_duration'] = -1.0 * 3600 prob['phase0.states:state_of_charge'][:] = 0.63464982 prob.set_solver_print(level=0) prob.run_model() soc0 = prob['phase0.states:state_of_charge'] assert_near_equal(soc0[-1], 1.0, 1e-6)
def test_simple_integration_forward(self): p = om.Problem(model=om.Group()) phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4')) p.model.add_subsystem('phase0', subsys=phase) phase.set_time_options(fix_initial=True, fix_duration=True, targets=['t']) phase.add_state('y', fix_initial=True, targets=['y'], rate_source='ydot', units='m') phase.add_timeseries_output('ydot', output_name='state_rate:y', units='m/s') p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:y'] = 0.5 p.run_model() expected = _test_ode_solution(p['phase0.ode.y'], p['phase0.ode.t']) assert_near_equal(p['phase0.ode.y'], expected, tolerance=1.0E-3)
def _make_problem(self, transcription, num_seg, transcription_order=3): p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() # Compute sparsity/coloring when run_driver is called p.driver.declare_coloring() t = { 'gauss-lobatto': dm.GaussLobatto(num_segments=num_seg, order=transcription_order), 'radau-ps': dm.Radau(num_segments=num_seg, order=transcription_order), 'runge-kutta': dm.RungeKutta(num_segments=num_seg) } phase = dm.Phase(ode_class=_BrachistochroneTestODE, transcription=t[transcription]) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(1, 1), 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', units='deg', rate_continuity=True, lower=0.01, upper=179.9) phase.add_design_parameter('g', units='m/s**2', opt=False, 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', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup() p['phase0.t_initial'] = 1.0 p['phase0.t_duration'] = 3.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.5], nodes='control_input') return p
def test_double_integrator_rk4(self, compressed=True): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring() t = dm.RungeKutta(num_segments=30, order=3, compressed=compressed) traj = p.model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=DoubleIntegratorODE, transcription=t)) phase.set_time_options(fix_initial=True, fix_duration=True, units='s') phase.add_state('v', fix_initial=True, fix_final=False, rate_source='u', shape=(1, ), 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) phase.add_boundary_constraint(name='v', loc='final', equals=0, units='m/s') # 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['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') p.run_driver() return p
def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP', simul_derivs=True): p = Problem(model=Group()) # if optimizer == 'SNOPT': p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = simul_derivs 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.set_state_options('x', fix_initial=True, fix_final=False, solve_segments=False) phase.set_state_options('y', fix_initial=True, fix_final=False, solve_segments=False) phase.set_state_options('v', fix_initial=True, fix_final=False, solve_segments=False) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_input_parameter('g', 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 = 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() return p
def test_load_case_lgl_to_rk4(self): import openmdao.api as om import dymos as dm from openmdao.utils.assert_utils import assert_rel_error from scipy.interpolate import interp1d import numpy as np p = setup_problem(dm.GaussLobatto(num_segments=20)) # Solve for the optimal trajectory p.run_driver() # Load the solution cr = om.CaseReader('brachistochrone_solution.db') system_cases = cr.list_cases('root') case = cr.get_case(system_cases[-1]) # create a problem with a different transcription with a different number of variables q = setup_problem(dm.RungeKutta(num_segments=50)) # Load the values from the previous solution dm.load_case(q, case) # Run the model to ensure we find the same output values as those that we recorded q.run_driver() outputs = dict([ (o[0], o[1]) for o in case.list_outputs(units=True, shape=True, out_stream=None) ]) time_val = outputs['phase0.timeseries.time']['value'][:, 0] theta_val = outputs['phase0.timeseries.controls:theta']['value'][:, 0] nodup = np.insert(time_val[1:] != time_val[:-1], 0, True) # remove duplicate times time_val = time_val[nodup] theta_val = theta_val[nodup] q_time = q['phase0.timeseries.time'][:, 0] q_theta = q['phase0.timeseries.controls:theta'][:, 0] nodup = np.insert(q_time[1:] != q_time[:-1], 0, True) # remove duplicate times q_time = q_time[nodup] q_theta = q_theta[nodup] fq_theta = interp1d(q_time, q_theta, kind='cubic', bounds_error=False, fill_value='extrapolate') assert_rel_error(self, fq_theta(time_val), theta_val, tolerance=1.0E-2)
def test_brachistochrone_undecorated_ode_rk(self): import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(.5, 10), units='s') phase.add_state('x', fix_initial=True, rate_source='xdot', units='m') phase.add_state('y', fix_initial=True, rate_source='ydot', units='m') phase.add_state('v', fix_initial=True, rate_source='vdot', targets=['v'], units='m/s') phase.add_control('theta', units='deg', rate_continuity=False, lower=0.01, upper=179.9, targets=['theta']) phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665, targets=['g']) 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() p.setup() 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.5], nodes='control_input') # Solve for the optimal trajectory p.run_driver() # Test the results assert_near_equal(p.get_val('phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-3)
def make_brachistochrone_phase(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True): 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) return phase
def test_ex_brachistochrone_vs_rungekutta_compressed(self): import openmdao.api as om import dymos as dm from dymos.examples.brachistochrone.brachistochrone_vector_states_ode import \ BrachistochroneVectorStatesODE p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, transcription=dm.RungeKutta(num_segments=20, compressed=True)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state( 'pos', shape=(2, ), rate_source=BrachistochroneVectorStatesODE.states['pos'] ['rate_source'], units=BrachistochroneVectorStatesODE.states['pos']['units'], fix_initial=True, fix_final=False) phase.add_state( 'v', rate_source=BrachistochroneVectorStatesODE.states['v'] ['rate_source'], targets=BrachistochroneVectorStatesODE.states['v']['targets'], units=BrachistochroneVectorStatesODE.states['v']['units'], fix_initial=True, fix_final=False) phase.add_control( 'theta', units='deg', targets=BrachistochroneVectorStatesODE.parameters['theta'] ['targets'], rate_continuity=False, lower=0.01, upper=179.9) phase.add_design_parameter( 'g', targets=BrachistochroneVectorStatesODE.parameters['g']['targets'], units='m/s**2', opt=False, val=9.80665) phase.add_boundary_constraint('pos', loc='final', lower=[10, 5]) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 1.80162174 pos0 = [0, 10] posf = [10, 5] p['phase0.states:pos'] = phase.interpolate(ys=[pos0, posf], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[0.46, 100.22900215], nodes='control_input') p['phase0.design_parameters:g'] = 9.80665 p.run_driver() self.assert_results(p) self.tearDown()
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) traj = dm.Trajectory() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) traj.add_phase('phase0', phase) p.model.add_subsystem('traj0', traj) 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['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.input_parameters:g'] = 9.80665 p.final_setup() return p
def test_brachistochrone_vector_state_path_constraints_rk_partial_indices( self): p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, transcription=dm.RungeKutta(num_segments=50)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state( 'pos', shape=(2, ), rate_source=BrachistochroneVectorStatesODE.states['pos'] ['rate_source'], units=BrachistochroneVectorStatesODE.states['pos']['units'], fix_initial=True, fix_final=False) phase.add_state( 'v', rate_source=BrachistochroneVectorStatesODE.states['v'] ['rate_source'], targets=BrachistochroneVectorStatesODE.states['v']['targets'], units=BrachistochroneVectorStatesODE.states['v']['units'], fix_initial=True, fix_final=False) phase.add_control( 'theta', units='deg', targets=BrachistochroneVectorStatesODE.parameters['theta'] ['targets'], rate_continuity=True, lower=0.01, upper=179.9) phase.add_parameter( 'g', targets=BrachistochroneVectorStatesODE.parameters['g']['targets'], units='m/s**2', opt=False, val=9.80665) phase.add_boundary_constraint('pos', loc='final', equals=[10, 5]) phase.add_path_constraint('pos', indices=[1], lower=5) phase.add_timeseries_output('pos_dot', shape=(2, ), units='m/s') # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 pos0 = [0, 10] posf = [10, 5] p['phase0.states:pos'] = phase.interpolate(ys=[pos0, posf], 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.parameters:g'] = 9.80665 p.run_driver() assert_near_equal(np.min( p.get_val('phase0.timeseries.states:pos')[:, 1]), 5.0, tolerance=1.0E-3) # Plot results if SHOW_PLOTS: exp_out = phase.simulate(times_per_seg=20) fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.states:pos')[:, 0] y_imp = p.get_val('phase0.timeseries.states:pos')[:, 1] x_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 0] y_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 1] 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\nVelocity') t_imp = p.get_val('phase0.timeseries.time') t_exp = exp_out.get_val('phase0.timeseries.time') xdot_imp = p.get_val('phase0.timeseries.pos_dot')[:, 0] ydot_imp = p.get_val('phase0.timeseries.pos_dot')[:, 1] xdot_exp = exp_out.get_val('phase0.timeseries.pos_dot')[:, 0] ydot_exp = exp_out.get_val('phase0.timeseries.pos_dot')[:, 1] ax.plot(t_imp, xdot_imp, 'bo', label='implicit') ax.plot(t_exp, xdot_exp, 'b-', label='explicit') ax.plot(t_imp, ydot_imp, 'ro', label='implicit') ax.plot(t_exp, ydot_exp, 'r-', label='explicit') ax.set_xlabel('t (s)') ax.set_ylabel('v (m/s)') ax.grid(True) ax.legend(loc='upper right') fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.time') y_imp = p.get_val('phase0.timeseries.control_rates:theta_rate2') x_exp = exp_out.get_val('phase0.timeseries.time') y_exp = exp_out.get_val( 'phase0.timeseries.control_rates:theta_rate2') 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 rate2 (rad/s**2)') ax.grid(True) ax.legend(loc='lower right') plt.show() return p
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) elif transcription == 'runge-kutta': tx0 = dm.RungeKutta(num_segments=20, compressed=compressed) tx1 = dm.RungeKutta(num_segments=20 * 4, 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, rate_source=BrachistochroneODE.states['x']['rate_source'], units=BrachistochroneODE.states['x']['units']) phase0.add_state( 'y', fix_initial=True, fix_final=False, rate_source=BrachistochroneODE.states['y']['rate_source'], units=BrachistochroneODE.states['y']['units']) phase0.add_state( 'v', fix_initial=True, rate_source=BrachistochroneODE.states['v']['rate_source'], targets=BrachistochroneODE.states['v']['targets'], units=BrachistochroneODE.states['v']['units']) phase0.add_input_parameter( 'g', targets=BrachistochroneODE.parameters['g']['targets'], units=BrachistochroneODE.parameters['g']['units'], val=9.80665) phase0.add_control( 'theta', units='deg', targets=BrachistochroneODE.parameters['theta']['targets'], 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', 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)
def test_brachistochrone_for_docs_runge_kutta_polynomial_controls(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.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.RungeKutta(num_segments=10))) # # Set the variables # phase.set_time_options(initial_bounds=(0, 0), 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_polynomial_control( 'theta', order=1, targets=BrachistochroneODE.parameters['theta']['targets'], 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) # # Final state values are not optimization variables, so we must enforce final values # with boundary constraints, not simple bounds. # 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['traj.phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['traj.phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['traj.phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['traj.phase0.polynomial_controls:theta'][:] = 5.0 # # 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.polynomial_controls:theta', 'time (s)', 'theta (deg)')], title= 'Brachistochrone Solution\nRK4 Shooting and Polynomial Controls', p_sol=p, p_sim=exp_out) plt.show()
def brachistochrone_min_time(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) elif transcription == 'runge-kutta': t = dm.RungeKutta(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) # p.model.add_subsystem('traj0', traj) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', rate_source=BrachistochroneODE.states['x']['rate_source'], fix_initial=True, fix_final=False, solve_segments=solve_segments) phase.add_state('y', rate_source=BrachistochroneODE.states['y']['rate_source'], fix_initial=True, fix_final=False, solve_segments=solve_segments) # 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', rate_source=BrachistochroneODE.states['v']['rate_source'], fix_initial=True, 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_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.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) # Plot results if SHOW_PLOTS: exp_out = traj.simulate() fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('traj0.phase0.timeseries.states:x') y_imp = p.get_val('traj0.phase0.timeseries.states:y') x_exp = exp_out.get_val('traj0.phase0.timeseries.states:x') y_exp = exp_out.get_val('traj0.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('traj0.phase0.timeseries.time_phase') y_imp = p.get_val('traj0.phase0.timeseries.controls:theta') x_exp = exp_out.get_val('traj0.phase0.timeseries.time_phase') y_exp = exp_out.get_val('traj0.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 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_parameter('c', opt=False, val=1.5, units='DU/TU', targets={ 'burn1': ['c'], 'burn2': ['c'] }) # 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', 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') coast.add_parameter('u1', opt=False, val=0.0, units='deg', targets=['u1']) coast.add_parameter('c', val=0.0, units='DU/TU', targets=['c']) # 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, units='TU') burn2.add_state('r', fix_initial=True, fix_final=False, 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=True, fix_final=False, defect_scaler=1000.0, rate_source='vr_dot', targets=['vr'], units='DU/TU') burn2.add_state('vt', fix_initial=True, fix_final=False, 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') 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, targets=['u1']) 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, 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') 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']) 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 test_promotes_parameter(self): transcription = 'radau-ps' optimizer = 'SNOPT' num_segments = 10 transcription_order = 3 compressed = False p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() OPT, OPTIMIZER = set_pyoptsparse_opt(optimizer, fallback=True) 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) traj = dm.Trajectory() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) traj.add_phase( 'phase0', phase, promotes_inputs=['t_initial', 't_duration', 'parameters:g']) p.model.add_subsystem('traj', traj) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10), units='s') phase.add_state('x', fix_initial=True, fix_final=False, solve_segments=False, units='m', rate_source='xdot') phase.add_state('y', fix_initial=True, fix_final=False, solve_segments=False, units='m', rate_source='ydot') phase.add_state('v', fix_initial=True, fix_final=False, solve_segments=False, units='m/s', rate_source='vdot', targets=['v']) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9, targets=['theta']) phase.add_parameter('g', units='m/s**2', val=9.80665, targets=['g']) 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['traj.t_initial'] = 0.0 p['traj.t_duration'] = 2.0 p['traj.phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['traj.phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['traj.phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['traj.phase0.controls:theta'] = phase.interpolate( ys=[5, 100], nodes='control_input') p['traj.parameters:g'] = 9.80665 p.run_driver() assert_near_equal(p['traj.t_duration'], 1.8016, tolerance=1.0E-4)
def test_static_ode_output_runge_kutta(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=BrachODEStaticOutput, transcription=dm.RungeKutta(num_segments=10)) 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) phase.add_state('y', fix_initial=True) phase.add_state('v', fix_initial=True) # Define theta as a control. phase.add_control(name='theta', units='rad', lower=0.01, upper=np.pi-0.01, shape=(1,)) phase.add_timeseries_output('*') phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # 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 with warnings.catch_warnings(record=True) as ctx: warnings.simplefilter('always') p.setup(check=True) expected_warning = "Cannot add ODE output foo to the timeseries output. It is sized " \ "such that its first dimension != num_nodes." self.assertIn(expected_warning, [str(w.message) for w in ctx]) # 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.interpolate(ys=[0, 10], nodes='state_input'), units='m') p.set_val('traj.phase0.states:y', phase.interpolate(ys=[10, 5], nodes='state_input'), units='m') p.set_val('traj.phase0.states:v', phase.interpolate(ys=[0, 5], nodes='state_input'), units='m/s') p.set_val('traj.phase0.controls:theta', phase.interpolate(ys=[0.01, 90], nodes='control_input'), units='deg') # Run the driver to solve the problem with warnings.catch_warnings(record=True) as ctx: warnings.simplefilter('always') dm.run_problem(p, simulate=True, make_plots=False) expected_warning = "Cannot add ODE output foo to the timeseries output. It is sized " \ "such that its first dimension != num_nodes." self.assertIn(expected_warning, [str(w.message) for w in ctx]) sol = om.CaseReader('dymos_solution.db').get_case('final') sim = om.CaseReader('dymos_simulation.db').get_case('final') with self.assertRaises(expected_exception=KeyError) as e: sol.get_val('traj.phase0.timeseries.foo') self.assertEqual(str(e.exception), "'Variable name \"traj.phase0.timeseries.foo\" not found.'") with self.assertRaises(expected_exception=KeyError) as e: sim.get_val('traj.phase0.timeseries.foo') self.assertEqual(str(e.exception), "'Variable name \"traj.phase0.timeseries.foo\" not found.'")
def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP', dynamic_simul_derivs=True, force_alloc_complex=False, solve_segments=False, run_driver=True): p = om.Problem(model=om.Group()) if optimizer == 'SNOPT': p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings['iSumm'] = 6 else: p.driver = om.ScipyOptimizeDriver() if dynamic_simul_derivs: p.driver.declare_coloring() if transcription == 'runge-kutta': transcription = dm.RungeKutta(num_segments=num_segments, compressed=compressed) fix_final = False elif transcription == 'gauss-lobatto': transcription = dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) fix_final = not solve_segments elif transcription == 'radau-ps': transcription = dm.Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) fix_final = not solve_segments traj = dm.Trajectory() phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, transcription=transcription) traj.add_phase('phase0', phase) p.model.add_subsystem('traj0', traj) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10), units='s') # can't fix final position if you're solving the segments phase.add_state( 'pos', rate_source=BrachistochroneVectorStatesODE.states['pos'] ['rate_source'], units=BrachistochroneVectorStatesODE.states['pos']['units'], shape=BrachistochroneVectorStatesODE.states['pos']['shape'], fix_initial=True, fix_final=fix_final, solve_segments=solve_segments) # phase.add_state( 'v', rate_source=BrachistochroneVectorStatesODE.states['v']['rate_source'], targets=BrachistochroneVectorStatesODE.states['v']['targets'], units=BrachistochroneVectorStatesODE.states['v']['units'], fix_initial=True, fix_final=False, solve_segments=solve_segments) # phase.add_control( 'theta', targets=BrachistochroneVectorStatesODE.parameters['theta']['targets'], continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_design_parameter( 'g', targets=BrachistochroneVectorStatesODE.parameters['g']['targets'], opt=False, units='m/s**2', val=9.80665) if not fix_final: phase.add_boundary_constraint('pos', loc='final', units='m', shape=(2, ), equals=[10, 5]) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=force_alloc_complex) p['traj0.phase0.t_initial'] = 0.0 p['traj0.phase0.t_duration'] = 1.8016 pos0 = [0, 10] posf = [10, 5] p['traj0.phase0.states:pos'] = phase.interpolate(ys=[pos0, posf], 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.design_parameters:g'] = 9.80665 p.run_model() if run_driver: p.run_driver() return p
def test_brachistochrone_forward_shooting(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("always") # Trigger a warning. phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.RungeKutta(num_segments=20)) assert issubclass(w[-1].category, DeprecationWarning) expected_msg = 'The RungeKutta transcription is deprecated and ' \ 'will be removed in Dymos v1.0.0.\nFor equivalent behavior, users ' \ 'should switch to GaussLobatto(order=3, solve_segments=True)' self.assertEqual(str(w[-1].message), expected_msg) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(0.5, 2.0)) phase.add_state( 'x', rate_source=BrachistochroneODE.states['x']['rate_source'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'y', rate_source=BrachistochroneODE.states['y']['rate_source'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'v', rate_source=BrachistochroneODE.states['v']['rate_source'], fix_initial=True, fix_final=False, solve_segments=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', opt=False, val=9.80665) # Final state values can't be controlled with simple bounds in ExplicitPhase, # so use nonlinear boundary constraints instead. 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'] = 0 p['phase0.states:y'] = 10 p['phase0.states:v'] = 0 p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5], nodes='control_input') # Solve for the optimal trajectory p.run_driver() # Test the results assert_near_equal(p['phase0.time'][-1], 1.8016, tolerance=1.0E-3) # Generate the explicitly simulated trajectory exp_out = phase.simulate() assert_near_equal(exp_out.get_val('phase0.timeseries.states:x')[-1, 0], 10, tolerance=1.0E-3) assert_near_equal(exp_out.get_val('phase0.timeseries.states:y')[-1, 0], 5, tolerance=1.0E-3)
def test_connected_linkages_rk(self): prob = om.Problem() if optimizer == 'SNOPT': opt = prob.driver = om.pyOptSparseDriver() opt.options['optimizer'] = optimizer opt.declare_coloring() opt.opt_settings['Major iterations limit'] = 1000 opt.opt_settings['Major feasibility tolerance'] = 1.0E-6 opt.opt_settings['Major optimality tolerance'] = 1.0E-6 opt.opt_settings["Linesearch tolerance"] = 0.10 opt.opt_settings['iSumm'] = 6 else: opt = prob.driver = om.ScipyOptimizeDriver() opt.declare_coloring() num_seg = 20 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. transcription = dm.RungeKutta(num_segments=num_seg) phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.add_state('state_of_charge', fix_initial=True, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') # Second phase: normal operation. phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) traj_p1.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') traj_p1.add_objective('time', loc='final') # Second phase, but with battery failure. phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_bfail.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') # Second phase, but with motor failure. phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_mfail.add_state('state_of_charge', fix_initial=False, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) prob.model.options['assembled_jac_type'] = 'csc' prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() prob['traj.phase0.t_initial'] = 0 prob['traj.phase0.t_duration'] = 1.0 * 3600 prob['traj.phase1.t_initial'] = 1.0 * 3600 prob['traj.phase1.t_duration'] = 1.0 * 3600 prob['traj.phase1_bfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_bfail.t_duration'] = 1.0 * 3600 prob['traj.phase1_mfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_mfail.t_duration'] = 1.0 * 3600 prob.set_solver_print(level=0) dm.run_problem(prob) soc0 = prob['traj.phase0.states:state_of_charge'] soc1 = prob['traj.phase1.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.states:state_of_charge'] # Final value for State of Chrage in each segment should be a good test. assert_near_equal(soc0[-1], 0.63464982, 5e-5) assert_near_equal(soc1[-1], 0.23794217, 5e-5) assert_near_equal(soc1b[-1], 0.0281523, 5e-5) assert_near_equal(soc1m[-1], 0.18625395, 5e-5)
def test_brachistochrone_forward_shooting_path_constrained_time(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(0.5, 2.0)) phase.add_state( 'x', rate_source=BrachistochroneODE.states['x']['rate_source'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'y', rate_source=BrachistochroneODE.states['y']['rate_source'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'v', rate_source=BrachistochroneODE.states['v']['rate_source'], fix_initial=True, fix_final=False, solve_segments=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', opt=False, val=9.80665) # Final state values can't be controlled with simple bounds in ExplicitPhase, # so use nonlinear boundary constraints instead. phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) phase.add_path_constraint('time', lower=0.0, upper=2.0) phase.add_path_constraint('time_phase', lower=0.0, upper=2.0) # 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'] = 0 p['phase0.states:y'] = 10 p['phase0.states:v'] = 0 p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5], nodes='control_input') # Solve for the optimal trajectory p.run_driver() # Test the results assert_near_equal(p['phase0.time'][-1], 1.8016, tolerance=1.0E-3) # Generate the explicitly simulated trajectory exp_out = phase.simulate() assert_near_equal(exp_out.get_val('phase0.timeseries.states:x')[-1, 0], 10, tolerance=1.0E-3) assert_near_equal(exp_out.get_val('phase0.timeseries.states:y')[-1, 0], 5, tolerance=1.0E-3)
def test_two_burn_orbit_raise_gl_rk_gl_constrained(self): import numpy as np import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error from openmdao.utils.general_utils import set_pyoptsparse_opt import dymos as dm from dymos.examples.finite_burn_orbit_raise.finite_burn_eom import FiniteBurnODE traj = dm.Trajectory() p = om.Problem(model=om.Group()) p.model.add_subsystem('traj', traj) p.driver = om.pyOptSparseDriver() _, optimizer = set_pyoptsparse_opt('SNOPT', fallback=True) p.driver.options['optimizer'] = optimizer p.driver.declare_coloring() traj.add_design_parameter('c', opt=False, val=1.5, units='DU/TU', targets={ 'burn1': ['c'], 'coast': ['c'], 'burn2': ['c'] }) # First Phase (burn) burn1 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=10, order=3, compressed=True)) burn1 = traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10), 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', 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=dm.RungeKutta(num_segments=20)) traj.add_phase('coast', coast) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), duration_ref=10, units='TU') # TODO Moving add_state('theta'... after add_state('r',... causes the # coloring to be invalid with scipy > 1.0.1 coast.add_state('theta', fix_initial=False, fix_final=False, defect_scaler=100.0, units='rad', rate_source='theta_dot', targets=['theta']) 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('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=False, ref=1.0E-12, defect_ref=1.0E-12, 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') coast.add_control('u1', targets=['u1'], opt=False, val=0.0, units='deg') # Third Phase (burn) burn2 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=10, order=3, compressed=True)) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), initial_ref=10, units='TU') burn2.add_state('r', fix_initial=False, fix_final=True, rate_source='r_dot', targets=['r'], units='DU') burn2.add_state('theta', fix_initial=False, fix_final=False, rate_source='theta_dot', targets=['theta'], units='rad') burn2.add_state('vr', fix_initial=False, fix_final=True, rate_source='vr_dot', targets=['vr'], units='DU/TU') burn2.add_state('vt', fix_initial=False, fix_final=True, rate_source='vt_dot', targets=['vt'], units='DU/TU') burn2.add_state('accel', fix_initial=False, fix_final=False, defect_ref=1.0E-6, rate_source='at_dot', targets=['accel'], units='DU/TU**2') burn2.add_state('deltav', fix_initial=False, fix_final=False, rate_source='deltav_dot', units='DU/TU') burn2.add_control('u1', targets=['u1'], rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, lower=-30, upper=30) burn2.add_objective('deltav', loc='final', scaler=1.0) burn1.add_timeseries_output('pos_x', units='DU') coast.add_timeseries_output('pos_x', units='DU') burn2.add_timeseries_output('pos_x', units='DU') burn1.add_timeseries_output('pos_y', units='DU') coast.add_timeseries_output('pos_y', units='DU') burn2.add_timeseries_output('pos_y', units='DU') # Link Phases traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) # Finish Problem Setup p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) # Set Initial Guesses p.set_val('traj.design_parameters:c', value=1.5) p.set_val('traj.burn1.t_initial', value=0.0) p.set_val('traj.burn1.t_duration', value=2.25) p.set_val('traj.burn1.states:r', value=burn1.interpolate(ys=[1, 1.5], nodes='state_input')) p.set_val('traj.burn1.states:theta', value=burn1.interpolate(ys=[0, 1.7], nodes='state_input')) p.set_val('traj.burn1.states:vr', value=burn1.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('traj.burn1.states:vt', value=burn1.interpolate(ys=[1, 1], nodes='state_input')) p.set_val('traj.burn1.states:accel', value=burn1.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val( 'traj.burn1.states:deltav', value=burn1.interpolate(ys=[0, 0.1], nodes='state_input'), ) p.set_val('traj.burn1.controls:u1', value=burn1.interpolate(ys=[-3.5, 13.0], nodes='control_input')) p.set_val('traj.coast.t_initial', value=2.25) p.set_val('traj.coast.t_duration', value=3.0) p.set_val('traj.coast.states:r', value=coast.interpolate(ys=[1.3, 1.5], nodes='state_input')) p.set_val('traj.coast.states:theta', value=coast.interpolate(ys=[2.1767, 1.7], nodes='state_input')) p.set_val('traj.coast.states:vr', value=coast.interpolate(ys=[0.3285, 0], nodes='state_input')) p.set_val('traj.coast.states:vt', value=coast.interpolate(ys=[0.97, 1], nodes='state_input')) p.set_val('traj.coast.states:accel', value=coast.interpolate(ys=[0, 0], nodes='state_input')) # p.set_val('traj.coast.controls:u1', # value=coast.interpolate(ys=[0, 0], nodes='control_input')) p.set_val('traj.burn2.t_initial', value=5.25) p.set_val('traj.burn2.t_duration', value=1.75) p.set_val('traj.burn2.states:r', value=burn2.interpolate(ys=[1.8, 3], nodes='state_input')) p.set_val('traj.burn2.states:theta', value=burn2.interpolate(ys=[3.2, 4.0], nodes='state_input')) p.set_val('traj.burn2.states:vr', value=burn2.interpolate(ys=[.5, 0], nodes='state_input')) p.set_val('traj.burn2.states:vt', value=burn2.interpolate(ys=[1, np.sqrt(1 / 3)], nodes='state_input')) p.set_val('traj.burn2.states:accel', value=burn2.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('traj.burn2.states:deltav', value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input')) p.set_val('traj.burn2.controls:u1', value=burn2.interpolate(ys=[1, 1], nodes='control_input')) p.run_driver() assert_rel_error(self, p.get_val('traj.burn2.timeseries.states:deltav')[-1], 0.3995, tolerance=2.0E-3) # Plot results exp_out = traj.simulate() fig = plt.figure(figsize=(8, 4)) fig.suptitle('Two Burn Orbit Raise Solution') ax_u1 = plt.subplot2grid((2, 2), (0, 0)) ax_deltav = plt.subplot2grid((2, 2), (1, 0)) ax_xy = plt.subplot2grid((2, 2), (0, 1), rowspan=2) span = np.linspace(0, 2 * np.pi, 100) ax_xy.plot(np.cos(span), np.sin(span), 'k--', lw=1) ax_xy.plot(3 * np.cos(span), 3 * np.sin(span), 'k--', lw=1) ax_xy.set_xlim(-4.5, 4.5) ax_xy.set_ylim(-4.5, 4.5) ax_xy.set_xlabel('x ($R_e$)') ax_xy.set_ylabel('y ($R_e$)') ax_u1.set_xlabel('time ($TU$)') ax_u1.set_ylabel('$u_1$ ($deg$)') ax_u1.grid(True) ax_deltav.set_xlabel('time ($TU$)') ax_deltav.set_ylabel('${\Delta}v$ ($DU/TU$)') ax_deltav.grid(True) t_sol = dict((phs, p.get_val('traj.{0}.timeseries.time'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) x_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_x'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) y_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_y'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) dv_sol = dict( (phs, p.get_val('traj.{0}.timeseries.states:deltav'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) u1_sol = dict((phs, p.get_val('traj.{0}.timeseries.controls:u1'.format(phs), units='deg')) for phs in ['burn1', 'burn2']) t_exp = dict( (phs, exp_out.get_val('traj.{0}.timeseries.time'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) x_exp = dict( (phs, exp_out.get_val('traj.{0}.timeseries.pos_x'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) y_exp = dict( (phs, exp_out.get_val('traj.{0}.timeseries.pos_y'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) dv_exp = dict( (phs, exp_out.get_val('traj.{0}.timeseries.states:deltav'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) u1_exp = dict( (phs, exp_out.get_val('traj.{0}.timeseries.controls:u1'.format(phs), units='deg')) for phs in ['burn1', 'burn2']) for phs in ['burn1', 'coast', 'burn2']: try: ax_u1.plot(t_sol[phs], u1_sol[phs], 'ro', ms=3) ax_u1.plot(t_exp[phs], u1_exp[phs], 'b-') except KeyError: pass ax_deltav.plot(t_sol[phs], dv_sol[phs], 'ro', ms=3) ax_deltav.plot(t_exp[phs], dv_exp[phs], 'b-') ax_xy.plot(x_sol[phs], y_sol[phs], 'ro', ms=3, label='implicit') ax_xy.plot(x_exp[phs], y_exp[phs], 'b-', label='explicit') plt.show()
def test_static_params(self): prob = om.Problem(model=om.Group()) traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. # NOTE: using RK4 integration here P_DEMAND = 2.0 phase0 = dm.Phase(ode_class=BatteryODE, transcription=dm.RungeKutta(num_segments=200)) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.add_state('state_of_charge', fix_initial=True, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') phase0.add_timeseries_output('battery.V_oc', output_name='V_oc') phase0.add_timeseries_output('battery.V_pack', output_name='V_pack') phase0.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li') traj.add_phase('phase0', phase0) # Second phase: normal operation. transcription = dm.Radau(num_segments=5, order=5, compressed=True) phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) phase1.set_time_options(fix_initial=False, fix_duration=True) phase1.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments='forward', targets=['SOC'], rate_source='dXdt:SOC') phase1.add_timeseries_output('battery.V_oc', output_name='V_oc') phase1.add_timeseries_output('battery.V_pack', output_name='V_pack') phase1.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li') traj.add_phase('phase1', phase1) # Second phase, but with battery failure. phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) phase1_bfail.set_time_options(fix_initial=False, fix_duration=True) phase1_bfail.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments='forward', targets=['SOC'], rate_source='dXdt:SOC') phase1_bfail.add_timeseries_output('battery.V_oc', output_name='V_oc') phase1_bfail.add_timeseries_output('battery.V_pack', output_name='V_pack') phase1_bfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li') traj.add_phase('phase1_bfail', phase1_bfail) # Second phase, but with motor failure. phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) phase1_mfail.set_time_options(fix_initial=False, fix_duration=True) phase1_mfail.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments='forward', targets=['SOC'], rate_source='dXdt:SOC') phase1_mfail.add_timeseries_output('battery.V_oc', output_name='V_oc') phase1_mfail.add_timeseries_output('battery.V_pack', output_name='V_pack') phase1_mfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li') traj.add_phase('phase1_mfail', phase1_mfail) traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) # prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() prob.final_setup() prob['traj.phases.phase0.time_extents.t_initial'] = 0 prob['traj.phases.phase0.time_extents.t_duration'] = 1.0 * 3600 # prob['traj.phases.phase1.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1.time_extents.t_duration'] = 1.0 * 3600 # prob['traj.phases.phase1_bfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_bfail.time_extents.t_duration'] = 1.0 * 3600 # prob['traj.phases.phase1_mfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_mfail.time_extents.t_duration'] = 1.0 * 3600 prob.set_solver_print(level=0) prob.run_model() plot = True if plot: import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt t0 = prob['traj.phase0.timeseries.time'] t1 = prob['traj.phase1.timeseries.time'] t1b = prob['traj.phase1_bfail.timeseries.time'] t1m = prob['traj.phase1_mfail.timeseries.time'] soc0 = prob['traj.phase0.timeseries.states:state_of_charge'] soc1 = prob['traj.phase1.timeseries.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.timeseries.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.timeseries.states:state_of_charge'] plt.subplot(2, 2, 1) plt.plot(t0, soc0, 'b') plt.plot(t1, soc1, 'b') plt.plot(t1b, soc1b, 'r') plt.plot(t1m, soc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('State of Charge (percent)') V_oc0 = prob['traj.phase0.timeseries.V_oc'] V_oc1 = prob['traj.phase1.timeseries.V_oc'] V_oc1b = prob['traj.phase1_bfail.timeseries.V_oc'] V_oc1m = prob['traj.phase1_mfail.timeseries.V_oc'] plt.subplot(2, 2, 2) plt.plot(t0, V_oc0, 'b') plt.plot(t1, V_oc1, 'b') plt.plot(t1b, V_oc1b, 'r') plt.plot(t1m, V_oc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Open Circuit Voltage (V)') V_pack0 = prob['traj.phase0.timeseries.V_pack'] V_pack1 = prob['traj.phase1.timeseries.V_pack'] V_pack1b = prob['traj.phase1_bfail.timeseries.V_pack'] V_pack1m = prob['traj.phase1_mfail.timeseries.V_pack'] plt.subplot(2, 2, 3) plt.plot(t0, V_pack0, 'b') plt.plot(t1, V_pack1, 'b') plt.plot(t1b, V_pack1b, 'r') plt.plot(t1m, V_pack1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Terminal Voltage (V)') I_Li0 = prob['traj.phase0.timeseries.I_Li'] I_Li1 = prob['traj.phase1.timeseries.I_Li'] I_Li1b = prob['traj.phase1_bfail.timeseries.I_Li'] I_Li1m = prob['traj.phase1_mfail.timeseries.I_Li'] plt.subplot(2, 2, 4) plt.plot(t0, I_Li0, 'b') plt.plot(t1, I_Li1, 'b') plt.plot(t1b, I_Li1b, 'r') plt.plot(t1m, I_Li1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Line Current (A)') plt.show()
def make_prob(self, transcription, num_segments, transcription_order, compressed): p = om.Problem(model=om.Group()) 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) 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=True, fix_final=False, solve_segments='forward') phase.add_state('y', fix_initial=True, fix_final=False, solve_segments='forward') # 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='forward') 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='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(force_alloc_complex=True) 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 return p
def vanderpol(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP', use_pyoptsparse=False, delay=None): """Dymos problem definition for optimal control of a Van der Pol oscillator""" # define the OpenMDAO problem p = om.Problem(model=om.Group()) if not use_pyoptsparse: p.driver = om.ScipyOptimizeDriver() else: p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer if use_pyoptsparse and optimizer == 'SNOPT': p.driver.opt_settings['iSumm'] = 6 # show detailed SNOPT output p.driver.declare_coloring() # define a Trajectory object and add to model traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # define a Transcription 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) # define a Phase as specified above and add to Phase if not delay: phase = dm.Phase(ode_class=vanderpol_ode, transcription=t) else: phase = dm.Phase(ode_class=vanderpol_ode_group, transcription=t) # distributed component group traj.add_phase(name='phase0', phase=phase) t_final = 15.0 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) # TODO - Dymos API will soon provide a way to specify this. # the linear solver used to compute derivatives is not working on MPI, so switch to LinearRunOnce for phase in traj._phases.values(): phase.linear_solver = om.LinearRunOnce() 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.interpolate(ys=[1, 0], nodes='state_input') p['traj.phase0.states:x1'] = phase.interpolate(ys=[1, 0], nodes='state_input') p['traj.phase0.states:J'] = phase.interpolate(ys=[0, 1], nodes='state_input') p['traj.phase0.controls:u'] = phase.interpolate(ys=[-0.75, -0.75], nodes='control_input') p.final_setup() # debugging helpers: # om.n2(p) # show n2 diagram # # with np.printoptions(linewidth=1024): # display partials for manual checking # p.check_partials(compact_print=True) return p
def min_time_climb(optimizer='SLSQP', num_seg=3, transcription='gauss-lobatto', transcription_order=3): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.declare_coloring() p.driver.add_recorder( om.SqliteRecorder(f'min_time_climb_solution_{transcription}.sql')) p.driver.recording_options['includes'] = ['*'] p.driver.recording_options['record_objectives'] = True p.driver.recording_options['record_constraints'] = True p.driver.recording_options['record_desvars'] = True 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), 'runge-kutta': dm.RungeKutta(num_segments=num_seg) } traj = dm.Trajectory() phase = dm.Phase(ode_class=MinTimeClimbODE, 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_design_parameter('S', val=49.2386, units='m**2', opt=False, targets=['S']) phase.add_design_parameter('Isp', val=1600.0, units='s', opt=False, targets=['Isp']) phase.add_design_parameter('throttle', val=1.0, opt=False, targets=['throttle']) phase.add_boundary_constraint('h', loc='final', equals=20000, scaler=1.0E-3, units='m') phase.add_boundary_constraint('aero.mach', loc='final', equals=1.0) phase.add_boundary_constraint('gam', loc='final', equals=0.0, units='rad') 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) phase.add_timeseries('timeseries2', transcription=dm.GaussLobatto(num_segments=50, order=3)) # Minimize time at the end of the phase phase.add_objective('time', loc='final', ref=1.0) p.model.linear_solver = om.DirectSolver() p.setup() p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 300.0 p['traj.phase0.states:r'] = phase.interpolate(ys=[0.0, 111319.54], nodes='state_input') p['traj.phase0.states:h'] = phase.interpolate(ys=[100.0, 20000.0], nodes='state_input') p['traj.phase0.states:v'] = phase.interpolate(ys=[135.964, 283.159], nodes='state_input') p['traj.phase0.states:gam'] = phase.interpolate(ys=[0.0, 0.0], nodes='state_input') p['traj.phase0.states:m'] = phase.interpolate(ys=[19030.468, 16841.431], nodes='state_input') p['traj.phase0.controls:alpha'] = phase.interpolate(ys=[0.0, 0.0], nodes='control_input') p.run_driver() traj.simulate(record_file=f'min_time_climb_simulation_{transcription}.sql') return p