def __init__(self, body, sc, method, nb_seg, order, solver, ode_class, ode_kwargs, ph_name, snopt_opts=None, rec_file=None): if isinstance(order, int): order = tuple(order for _ in range(len(nb_seg))) if isinstance(method, str): method = tuple(method for _ in range(len(nb_seg))) NLP.__init__(self, body, sc, method, nb_seg, order, solver, snopt_opts=snopt_opts, rec_file=rec_file) # Transcription objects list self.transcription = [] for i in range(len(self.nb_seg)): if self.method[i] == 'gauss-lobatto': t = GaussLobatto(num_segments=self.nb_seg[i], order=self.order[i], compressed=True) elif self.method[i] == 'radau-ps': t = Radau(num_segments=self.nb_seg[i], order=self.order[i], compressed=True) elif self.method[i] == 'runge-kutta': t = RungeKutta(num_segments=self.nb_seg[i], order=self.order[i], compressed=True) else: raise ValueError('method must be either gauss-lobatto, radau-ps or runge-kutta') self.transcription.append(t) # Phase objects list self.phase = [] self.phase_name = [] for i in range(len(self.nb_seg)): ph = self.trajectory.add_phase(ph_name[i], Phase(ode_class=ode_class[i], ode_init_kwargs=ode_kwargs[i], transcription=self.transcription[i])) self.phase.append(ph) self.phase_name.append(''.join(['traj.', ph_name[i]]))
def test_single_phase_reverse_propagation_rk(self): prob = Problem() num_seg = 10 seg_ends, _ = lgl(num_seg + 1) # First phase: normal operation. transcription = RungeKutta(num_segments=num_seg) phase0 = Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = prob.model.add_subsystem('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.set_state_options('state_of_charge', fix_initial=True, fix_final=False) prob.setup() prob['phase0.t_initial'] = 0 prob['phase0.t_duration'] = -1.0 * 3600 prob['phase0.states:state_of_charge'][:] = 0.63464982 prob.set_solver_print(level=0) prob.run_model() soc0 = prob['phase0.states:state_of_charge'] assert_rel_error(self, soc0[-1], 1.0, 1e-6)
def __init__(self, body, sc, method, nb_seg, order, solver, ode_class, ode_kwargs, ph_name, snopt_opts=None, rec_file=None): NLP.__init__(self, body, sc, method, nb_seg, order, solver, snopt_opts=snopt_opts, rec_file=rec_file) # Transcription object if self.method == 'gauss-lobatto': self.transcription = GaussLobatto(num_segments=self.nb_seg, order=self.order, compressed=True) elif self.method == 'radau-ps': self.transcription = Radau(num_segments=self.nb_seg, order=self.order, compressed=True) elif self.method == 'runge-kutta': self.transcription = RungeKutta(num_segments=self.nb_seg, order=self.order, compressed=True) else: raise ValueError('method must be either gauss-lobatto or radau-ps') # Phase object self.phase = self.trajectory.add_phase(ph_name, Phase(ode_class=ode_class, ode_init_kwargs=ode_kwargs, transcription=self.transcription)) self.phase_name = ''.join(['traj.', ph_name]) # discretization nodes self.state_nodes = None self.control_nodes = None self.t_all = None self.t_state = None self.t_control = None self.idx_state_control = None # time of flight self.tof = None
def test_brachistochrone_backward_shooting(self): from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase, RungeKutta from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneODE, transcription=RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(-2.0, -0.5)) phase.set_state_options('x', fix_initial=True) phase.set_state_options('y', fix_initial=True) phase.set_state_options('v', fix_initial=False) phase.add_control('theta', units='deg', lower=0.01, upper=179.9, ref0=0, ref=180.0, rate_continuity=True, rate2_continuity=True) phase.add_design_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=0) phase.add_boundary_constraint('y', loc='final', equals=10) phase.add_boundary_constraint('v', loc='final', equals=0) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=-1) p.model.linear_solver = DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 1.8016 p['phase0.t_duration'] = -1.8016 p['phase0.states:x'] = 10 p['phase0.states:y'] = 5 p['phase0.states:v'] = 10 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_rel_error(self, p['phase0.time'][-1], -1.8016, tolerance=1.0E-3) # Generate the explicitly simulated trajectory exp_out = phase.simulate() assert_rel_error(self, exp_out.get_val('phase0.timeseries.states:x')[-1, 0], 0, tolerance=1.0E-3) assert_rel_error(self, exp_out.get_val('phase0.timeseries.states:y')[-1, 0], 10, tolerance=1.0E-3)
def test_ex_brachistochrone_vs_rungekutta_compressed(self): from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver from dymos import Phase, RungeKutta from dymos.examples.brachistochrone.brachistochrone_vector_states_ode import \ BrachistochroneVectorStatesODE p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneVectorStatesODE, transcription=RungeKutta(num_segments=20, compressed=True)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.set_state_options('pos', fix_initial=True, fix_final=False) phase.set_state_options('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_design_parameter('g', 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 = 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 _make_problem(self, transcription, num_seg, transcription_order=3): p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() # Compute sparsity/coloring when run_driver is called p.driver.options['dynamic_simul_derivs'] = True t = {'gauss-lobatto': GaussLobatto(num_segments=num_seg, order=transcription_order), 'radau-ps': Radau(num_segments=num_seg, order=transcription_order), 'runge-kutta': RungeKutta(num_segments=num_seg)} phase = 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.set_state_options('x', fix_initial=True) phase.set_state_options('y', fix_initial=True) phase.set_state_options('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 = 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_two_burn_orbit_raise_gl_rk_gl_constrained(self): import numpy as np import matplotlib.pyplot as plt from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver from openmdao.utils.assert_utils import assert_rel_error from openmdao.utils.general_utils import set_pyoptsparse_opt from dymos import Phase, GaussLobatto, RungeKutta, Trajectory from dymos.examples.finite_burn_orbit_raise.finite_burn_eom import FiniteBurnODE traj = Trajectory() p = Problem(model=Group()) p.model.add_subsystem('traj', traj) p.driver = pyOptSparseDriver() _, optimizer = set_pyoptsparse_opt('SNOPT', fallback=True) p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = True traj.add_design_parameter('c', opt=False, val=1.5, units='DU/TU') # First Phase (burn) burn1 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=10, order=3, compressed=True)) burn1 = traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) burn1.set_state_options('r', fix_initial=True, fix_final=False) burn1.set_state_options('theta', fix_initial=True, fix_final=False) burn1.set_state_options('vr', fix_initial=True, fix_final=False) burn1.set_state_options('vt', fix_initial=True, fix_final=False) burn1.set_state_options('accel', fix_initial=True, fix_final=False) burn1.set_state_options('deltav', fix_initial=True, fix_final=False) burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, lower=-30, upper=30) # Second Phase (Coast) coast = Phase(ode_class=FiniteBurnODE, transcription=RungeKutta(num_segments=20, compressed=True)) traj.add_phase('coast', coast) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), duration_ref=10) coast.set_state_options('r', fix_initial=False, fix_final=False) coast.set_state_options('theta', fix_initial=False, fix_final=False) coast.set_state_options('vr', fix_initial=False, fix_final=False) coast.set_state_options('vt', fix_initial=False, fix_final=False) coast.set_state_options('accel', fix_initial=True, fix_final=False) coast.set_state_options('deltav', fix_initial=False, fix_final=False) coast.add_design_parameter('u1', opt=False, val=0.0) # Third Phase (burn) burn2 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=10, order=3, compressed=True)) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 10), initial_ref=10) burn2.set_state_options('r', fix_initial=False, fix_final=True) burn2.set_state_options('theta', fix_initial=False, fix_final=False) burn2.set_state_options('vr', fix_initial=False, fix_final=True) burn2.set_state_options('vt', fix_initial=False, fix_final=True) burn2.set_state_options('accel', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.set_state_options('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, lower=-30, upper=30) burn2.add_objective('deltav', loc='final', scaler=1.0) burn1.add_timeseries_output('pos_x', units='DU') coast.add_timeseries_output('pos_x', units='DU') burn2.add_timeseries_output('pos_x', units='DU') burn1.add_timeseries_output('pos_y', units='DU') coast.add_timeseries_output('pos_y', units='DU') burn2.add_timeseries_output('pos_y', units='DU') # Link Phases traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) # Finish Problem Setup p.model.linear_solver = DirectSolver() p.setup(check=True, force_alloc_complex=True) # Set Initial Guesses p.set_val('traj.design_parameters:c', value=1.5) p.set_val('traj.burn1.t_initial', value=0.0) p.set_val('traj.burn1.t_duration', value=2.25) p.set_val('traj.burn1.states:r', value=burn1.interpolate(ys=[1, 1.5], nodes='state_input')) p.set_val('traj.burn1.states:theta', value=burn1.interpolate(ys=[0, 1.7], nodes='state_input')) p.set_val('traj.burn1.states:vr', value=burn1.interpolate(ys=[0, 0], nodes='state_input')) p.set_val('traj.burn1.states:vt', value=burn1.interpolate(ys=[1, 1], nodes='state_input')) p.set_val('traj.burn1.states:accel', value=burn1.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('traj.burn1.states:deltav', value=burn1.interpolate(ys=[0, 0.1], nodes='state_input'), ) p.set_val('traj.burn1.controls:u1', value=burn1.interpolate(ys=[-3.5, 13.0], nodes='control_input')) p.set_val('traj.coast.t_initial', value=2.25) p.set_val('traj.coast.t_duration', value=3.0) p.set_val('traj.coast.states:r', value=coast.interpolate(ys=[1.3, 1.5], nodes='state_input')) p.set_val('traj.coast.states:theta', value=coast.interpolate(ys=[2.1767, 1.7], nodes='state_input')) p.set_val('traj.coast.states:vr', value=coast.interpolate(ys=[0.3285, 0], nodes='state_input')) p.set_val('traj.coast.states:vt', value=coast.interpolate(ys=[0.97, 1], nodes='state_input')) p.set_val('traj.coast.states:accel', value=coast.interpolate(ys=[0, 0], nodes='state_input')) # p.set_val('traj.coast.controls:u1', # value=coast.interpolate(ys=[0, 0], nodes='control_input')) p.set_val('traj.burn2.t_initial', value=5.25) p.set_val('traj.burn2.t_duration', value=1.75) p.set_val('traj.burn2.states:r', value=burn2.interpolate(ys=[1.8, 3], nodes='state_input')) p.set_val('traj.burn2.states:theta', value=burn2.interpolate(ys=[3.2, 4.0], nodes='state_input')) p.set_val('traj.burn2.states:vr', value=burn2.interpolate(ys=[.5, 0], nodes='state_input')) p.set_val('traj.burn2.states:vt', value=burn2.interpolate(ys=[1, np.sqrt(1 / 3)], nodes='state_input')) p.set_val('traj.burn2.states:accel', value=burn2.interpolate(ys=[0.1, 0], nodes='state_input')) p.set_val('traj.burn2.states:deltav', value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input')) p.set_val('traj.burn2.controls:u1', value=burn2.interpolate(ys=[1, 1], nodes='control_input')) p.run_driver() assert_rel_error(self, p.get_val('traj.burn2.timeseries.states:deltav')[-1], 0.3995, tolerance=2.0E-3) # Plot results exp_out = traj.simulate() fig = plt.figure(figsize=(8, 4)) fig.suptitle('Two Burn Orbit Raise Solution') ax_u1 = plt.subplot2grid((2, 2), (0, 0)) ax_deltav = plt.subplot2grid((2, 2), (1, 0)) ax_xy = plt.subplot2grid((2, 2), (0, 1), rowspan=2) span = np.linspace(0, 2 * np.pi, 100) ax_xy.plot(np.cos(span), np.sin(span), 'k--', lw=1) ax_xy.plot(3 * np.cos(span), 3 * np.sin(span), 'k--', lw=1) ax_xy.set_xlim(-4.5, 4.5) ax_xy.set_ylim(-4.5, 4.5) ax_xy.set_xlabel('x ($R_e$)') ax_xy.set_ylabel('y ($R_e$)') ax_u1.set_xlabel('time ($TU$)') ax_u1.set_ylabel('$u_1$ ($deg$)') ax_u1.grid(True) ax_deltav.set_xlabel('time ($TU$)') ax_deltav.set_ylabel('${\Delta}v$ ($DU/TU$)') ax_deltav.grid(True) t_sol = dict((phs, p.get_val('traj.{0}.timeseries.time'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) x_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_x'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) y_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_y'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) dv_sol = dict((phs, p.get_val('traj.{0}.timeseries.states:deltav'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) u1_sol = dict((phs, p.get_val('traj.{0}.timeseries.controls:u1'.format(phs), units='deg')) for phs in ['burn1', 'burn2']) t_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.time'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) x_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.pos_x'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) y_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.pos_y'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) dv_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.states:deltav'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) u1_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.controls:u1'.format(phs), units='deg')) for phs in ['burn1', 'burn2']) for phs in ['burn1', 'coast', 'burn2']: try: ax_u1.plot(t_sol[phs], u1_sol[phs], 'ro', ms=3) ax_u1.plot(t_exp[phs], u1_exp[phs], 'b-') except KeyError: pass ax_deltav.plot(t_sol[phs], dv_sol[phs], 'ro', ms=3) ax_deltav.plot(t_exp[phs], dv_exp[phs], 'b-') ax_xy.plot(x_sol[phs], y_sol[phs], 'ro', ms=3, label='implicit') ax_xy.plot(x_exp[phs], y_exp[phs], 'b-', label='explicit') plt.show()
def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, run_driver=True, compressed=True, optimizer='SLSQP'): p = Problem(model=Group()) # if optimizer == 'SNOPT': p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = True if transcription == 'gauss-lobatto': t = GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'radau-ps': t = Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'runge-kutta': t = RungeKutta(num_segments=num_segments, order=transcription_order, compressed=compressed) phase = 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_model() if run_driver: 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_dynamic_input_params(self): prob = Problem(model=Group()) traj = prob.model.add_subsystem('traj', Trajectory()) # First phase: normal operation. # NOTE: using RK4 integration here P_DEMAND = 2.0 phase0 = Phase(ode_class=BatteryODE, transcription=RungeKutta(num_segments=200)) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.set_state_options('state_of_charge', fix_initial=True, fix_final=False) phase0.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') phase0.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V') phase0.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A') phase0.add_input_parameter('P_demand', val=P_DEMAND, units='W') traj.add_phase('phase0', phase0) # Second phase: normal operation. transcription = Radau(num_segments=5, order=5, compressed=True) phase1 = Phase(ode_class=BatteryODE, transcription=transcription) phase1.set_time_options(fix_initial=False, fix_duration=True) phase1.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) phase1.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') phase1.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V') phase1.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A') phase1.add_input_parameter('P_demand', val=P_DEMAND, units='W') traj.add_phase('phase1', phase1) # Second phase, but with battery failure. phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) phase1_bfail.set_time_options(fix_initial=False, fix_duration=True) phase1_bfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) phase1_bfail.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') phase1_bfail.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V') phase1_bfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A') phase1_bfail.add_input_parameter('P_demand', val=P_DEMAND, units='W') traj.add_phase('phase1_bfail', phase1_bfail) # Second phase, but with motor failure. phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) phase1_mfail.set_time_options(fix_initial=False, fix_duration=True) phase1_mfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) phase1_mfail.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') phase1_mfail.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V') phase1_mfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A') phase1_mfail.add_input_parameter('P_demand', val=P_DEMAND, units='W') traj.add_phase('phase1_mfail', phase1_mfail) traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) # prob.model.linear_solver = DirectSolver(assemble_jac=True) prob.setup() prob.final_setup() prob['traj.phases.phase0.time_extents.t_initial'] = 0 prob['traj.phases.phase0.time_extents.t_duration'] = 1.0*3600 # prob['traj.phases.phase1.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1.time_extents.t_duration'] = 1.0*3600 # prob['traj.phases.phase1_bfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_bfail.time_extents.t_duration'] = 1.0*3600 # prob['traj.phases.phase1_mfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_mfail.time_extents.t_duration'] = 1.0*3600 prob.set_solver_print(level=0) prob.run_model() plot = True if plot: import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt t0 = prob['traj.phase0.timeseries.time'] t1 = prob['traj.phase1.timeseries.time'] t1b = prob['traj.phase1_bfail.timeseries.time'] t1m = prob['traj.phase1_mfail.timeseries.time'] soc0 = prob['traj.phase0.timeseries.states:state_of_charge'] soc1 = prob['traj.phase1.timeseries.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.timeseries.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.timeseries.states:state_of_charge'] plt.subplot(2, 2, 1) plt.plot(t0, soc0, 'b') plt.plot(t1, soc1, 'b') plt.plot(t1b, soc1b, 'r') plt.plot(t1m, soc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('State of Charge (percent)') V_oc0 = prob['traj.phase0.timeseries.V_oc'] V_oc1 = prob['traj.phase1.timeseries.V_oc'] V_oc1b = prob['traj.phase1_bfail.timeseries.V_oc'] V_oc1m = prob['traj.phase1_mfail.timeseries.V_oc'] plt.subplot(2, 2, 2) plt.plot(t0, V_oc0, 'b') plt.plot(t1, V_oc1, 'b') plt.plot(t1b, V_oc1b, 'r') plt.plot(t1m, V_oc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Open Circuit Voltage (V)') V_pack0 = prob['traj.phase0.timeseries.V_pack'] V_pack1 = prob['traj.phase1.timeseries.V_pack'] V_pack1b = prob['traj.phase1_bfail.timeseries.V_pack'] V_pack1m = prob['traj.phase1_mfail.timeseries.V_pack'] plt.subplot(2, 2, 3) plt.plot(t0, V_pack0, 'b') plt.plot(t1, V_pack1, 'b') plt.plot(t1b, V_pack1b, 'r') plt.plot(t1m, V_pack1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Terminal Voltage (V)') I_Li0 = prob['traj.phase0.timeseries.I_Li'] I_Li1 = prob['traj.phase1.timeseries.I_Li'] I_Li1b = prob['traj.phase1_bfail.timeseries.I_Li'] I_Li1m = prob['traj.phase1_mfail.timeseries.I_Li'] plt.subplot(2, 2, 4) plt.plot(t0, I_Li0, 'b') plt.plot(t1, I_Li1, 'b') plt.plot(t1b, I_Li1b, 'r') plt.plot(t1m, I_Li1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Line Current (A)') plt.show()
def test_brachistochrone_vector_ode_path_constraints_rk_partial_indices( self): p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneVectorStatesODE, transcription=RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.set_state_options('pos', fix_initial=True, fix_final=False) phase.set_state_options('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_design_parameter('g', units='m/s**2', opt=False, val=9.80665) phase.add_boundary_constraint('pos', loc='final', equals=[10, 5]) phase.add_path_constraint('pos_dot', shape=(2, ), units='m/s', indices=[1], lower=-4, upper=4) 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 = 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.design_parameters:g'] = 9.80665 p.run_driver() assert_rel_error(self, np.min(p.get_val('phase0.timeseries.pos_dot')[:, -1]), -4, tolerance=1.0E-2) # 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 brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, sim_record='brach_min_time_sim.db', optimizer='SLSQP', dynamic_simul_derivs=True, force_alloc_complex=False, solve_segments=False, run_driver=True): p = Problem(model=Group()) if optimizer == 'SNOPT': p.driver = 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 = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = dynamic_simul_derivs if transcription == 'runge-kutta': transcription = RungeKutta(num_segments=num_segments, compressed=compressed) elif transcription == 'gauss-lobatto': transcription = GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'radau-ps': transcription = Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) phase = Phase(ode_class=BrachistochroneVectorStatesODE, transcription=transcription) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) fix_final = not solve_segments # can't fix final position if you're solving the segments phase.set_state_options('pos', fix_initial=True, fix_final=fix_final, solve_segments=solve_segments) phase.set_state_options('v', 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_design_parameter('g', units='m/s**2', opt=False, val=9.80665) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = DirectSolver() p.setup(check=True, force_alloc_complex=force_alloc_complex) 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.design_parameters:g'] = 9.80665 p.run_model() if run_driver: p.run_driver() # Plot results if SHOW_PLOTS: p.run_driver() exp_out = phase.simulate(record_file=sim_record) 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') 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 test_connected_linkages_rk(self): prob = Problem() if optimizer == 'SNOPT': opt = prob.driver = pyOptSparseDriver() opt.options['optimizer'] = optimizer opt.options['dynamic_simul_derivs'] = True opt.opt_settings['Major iterations limit'] = 1000 opt.opt_settings['Major feasibility tolerance'] = 1.0E-6 opt.opt_settings['Major optimality tolerance'] = 1.0E-6 opt.opt_settings["Linesearch tolerance"] = 0.10 opt.opt_settings['iSumm'] = 6 else: opt = prob.driver = ScipyOptimizeDriver() opt.options['dynamic_simul_derivs'] = True num_seg = 20 seg_ends, _ = lgl(num_seg + 1) traj = prob.model.add_subsystem('traj', Trajectory()) # First phase: normal operation. transcription = RungeKutta(num_segments=num_seg) phase0 = Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.set_state_options('state_of_charge', fix_initial=True, fix_final=False) # Second phase: normal operation. phase1 = Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) traj_p1.set_state_options('state_of_charge', fix_initial=False, fix_final=False) traj_p1.add_objective('time', loc='final') # Second phase, but with battery failure. phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_bfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False) # Second phase, but with motor failure. phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_mfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False) traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) prob.model.options['assembled_jac_type'] = 'csc' prob.model.linear_solver = DirectSolver(assemble_jac=True) prob.setup() prob['traj.phase0.t_initial'] = 0 prob['traj.phase0.t_duration'] = 1.0 * 3600 prob['traj.phase1.t_initial'] = 1.0 * 3600 prob['traj.phase1.t_duration'] = 1.0 * 3600 prob['traj.phase1_bfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_bfail.t_duration'] = 1.0 * 3600 prob['traj.phase1_mfail.t_initial'] = 1.0 * 3600 prob['traj.phase1_mfail.t_duration'] = 1.0 * 3600 prob.set_solver_print(level=0) prob.run_driver() soc0 = prob['traj.phase0.states:state_of_charge'] soc1 = prob['traj.phase1.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.states:state_of_charge'] # Final value for State of Chrage in each segment should be a good test. assert_rel_error(self, soc0[-1], 0.63464982, 5e-5) assert_rel_error(self, soc1[-1], 0.23794217, 5e-5) assert_rel_error(self, soc1b[-1], 0.0281523, 5e-5) assert_rel_error(self, soc1m[-1], 0.18625395, 5e-5)
def test_brachistochrone_undecorated_ode_rk(self): import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase, RungeKutta p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() phase = Phase(ode_class=BrachistochroneODE, transcription=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.set_state_options('x', fix_initial=True, rate_source='xdot', units='m') phase.set_state_options('y', fix_initial=True, rate_source='ydot', units='m') phase.set_state_options('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 = 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_rel_error(self, p.get_val('phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-3)