def test_initial_val_and_final_val_stick(self): p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneODE, transcription=GaussLobatto(num_segments=8, order=3)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=False, fix_duration=False, initial_val=0.01, duration_val=1.9) phase.set_state_options('x', fix_initial=True, fix_final=True) phase.set_state_options('y', fix_initial=True, fix_final=True) 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) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) phase.add_boundary_constraint('time', loc='initial', equals=0) p.model.linear_solver = DirectSolver() p.setup(check=True) assert_rel_error(self, p['phase0.t_initial'], 0.01) assert_rel_error(self, p['phase0.t_duration'], 1.9)
def test_brachistochrone_forward_shooting_path_constrained_ode_output(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=(0.5, 2.0)) 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', 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=10) phase.add_boundary_constraint('y', loc='final', equals=5) phase.add_path_constraint('check', lower=-500, upper=500, shape=(1,), units='m/s') # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) 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'] = 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_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], 10, tolerance=1.0E-3) assert_rel_error(self, exp_out.get_val('phase0.timeseries.states:y')[-1, 0], 5, 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 test_unbounded_time(self): p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase('gauss-lobatto', ode_class=BrachistochroneODE, num_segments=8, transcription_order=3) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=False, fix_duration=False) phase.set_state_options('x', fix_initial=True, fix_final=True) phase.set_state_options('y', fix_initial=True, fix_final=True) 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) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) phase.add_boundary_constraint('time', loc='initial', equals=0) p.model.options['assembled_jac_type'] = 'csc' p.model.linear_solver = DirectSolver(assemble_jac=True) 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.design_parameters:g'] = 9.80665 p.run_driver() self.assertTrue(p.driver.result.success, msg='Brachistochrone with outbounded times has failed')
def test_invalid_boundary_loc(self): p = Phase(ode_class=BrachistochroneODE, transcription=GaussLobatto(num_segments=8, order=3, compressed=True)) with self.assertRaises(ValueError) as e: p.add_boundary_constraint('x', loc='foo') expected = 'Invalid boundary constraint location "foo". Must be "initial" or "final".' self.assertEqual(str(e.exception), expected)
def ssto_moon(transcription='gauss-lobatto', num_seg=10, optimizer='SLSQP', top_level_jacobian='csc', transcription_order=5, compressed=False): p = Problem(model=Group()) if optimizer == 'SNOPT': p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = True p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Verify level'] = 3 else: p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(transcription, ode_class=LaunchVehicleODE, ode_init_kwargs={'central_body': 'moon'}, num_segments=num_seg, compressed=compressed, transcription_order=3) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(10, 1000)) phase.set_state_options('x', fix_initial=True, scaler=1.0E-5, lower=0) phase.set_state_options('y', fix_initial=True, scaler=1.0E-5, lower=0) phase.set_state_options('vx', fix_initial=True, scaler=1.0E-3, lower=0) phase.set_state_options('vy', fix_initial=True, scaler=1.0E-3) phase.set_state_options('m', fix_initial=True, scaler=1.0E-3) phase.add_boundary_constraint('y', loc='final', equals=1.85E5, linear=True) phase.add_boundary_constraint('vx', loc='final', equals=1627.0) phase.add_boundary_constraint('vy', loc='final', equals=0) if transcription == 'radau-ps': # This constraint is necessary using the Radau-Pseudospectral method since the # last value of the control does not impact the collocation defects. phase.add_boundary_constraint('theta_rate2', loc='final', equals=0) phase.add_control('theta', units='rad', lower=-1.57, upper=1.57) phase.add_design_parameter('thrust', units='N', opt=False, val=3.0 * 50000.0 * 1.61544) phase.add_design_parameter('Isp', units='s', opt=False, val=1.0E6) phase.add_objective('time', index=-1, scaler=0.01) p.model.options['assembled_jac_type'] = top_level_jacobian.lower() p.model.linear_solver = DirectSolver(assemble_jac=True) return p
def test_fixed_time_invalid_options(self): p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneODE, transcription=GaussLobatto(num_segments=8, order=3)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, fix_duration=True, initial_bounds=(1.0, 5.0), initial_adder=0.0, initial_scaler=1.0, initial_ref0=0.0, initial_ref=1.0, duration_bounds=(1.0, 5.0), duration_adder=0.0, duration_scaler=1.0, duration_ref0=0.0, duration_ref=1.0) phase.set_state_options('x', fix_initial=True, fix_final=True) phase.set_state_options('y', fix_initial=True, fix_final=True) 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) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) phase.add_boundary_constraint('time', loc='initial', equals=0) p.model.linear_solver = DirectSolver() expected_msg0 = 'Phase time options have no effect because fix_initial=True for ' \ 'phase \'phase0\': initial_bounds, initial_scaler, initial_adder, ' \ 'initial_ref, initial_ref0' expected_msg1 = 'Phase time options have no effect because fix_duration=True for' \ ' phase \'phase0\': duration_bounds, duration_scaler, ' \ 'duration_adder, duration_ref, duration_ref0' with warnings.catch_warnings(record=True) as ctx: warnings.simplefilter('always') p.setup(check=True) self.assertIn(expected_msg0, [str(w.message) for w in ctx]) self.assertIn(expected_msg1, [str(w.message) for w in ctx])
def test_ex_double_integrator_input_and_fixed_times_warns(self): """ Tests that time optimization options cause a ValueError to be raised when t_initial and t_duration are connected to external sources. """ p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneODE, transcription=GaussLobatto(num_segments=8, order=3)) p.model.add_subsystem('phase0', phase) phase.set_time_options(input_initial=True, fix_initial=True, input_duration=True, fix_duration=True) phase.set_state_options('x', fix_initial=True, fix_final=True) phase.set_state_options('y', fix_initial=True, fix_final=True) 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) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) phase.add_boundary_constraint('time', loc='initial', equals=0) p.model.linear_solver = DirectSolver() with warnings.catch_warnings(record=True) as ctx: warnings.simplefilter('always') p.setup(check=True) expected_msg0 = 'Phase \'phase0\' initial time is an externally-connected input, therefore ' \ 'fix_initial has no effect.' expected_msg1 = 'Phase \'phase0\' time duration is an externally-connected input, ' \ 'therefore fix_duration has no effect.' self.assertIn(expected_msg0, [str(w.message) for w in ctx]) self.assertIn(expected_msg1, [str(w.message) for w in ctx])
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 ssto_earth(transcription='gauss-lobatto', num_seg=10, transcription_order=5, top_level_jacobian='csc', optimizer='SLSQP', compressed=False): p = Problem(model=Group()) if optimizer == 'SNOPT': p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = True p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Verify level'] = 3 else: p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(transcription, ode_class=LaunchVehicleODE, ode_init_kwargs={'central_body': 'earth'}, num_segments=num_seg, transcription_order=transcription_order, compressed=compressed) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(10, 500)) phase.set_state_options('x', fix_initial=True, scaler=1.0E-5) phase.set_state_options('y', fix_initial=True, scaler=1.0E-5) phase.set_state_options('vx', fix_initial=True, scaler=1.0E-3) phase.set_state_options('vy', fix_initial=True, scaler=1.0E-3) phase.set_state_options('m', fix_initial=True, scaler=1.0E-3) phase.add_boundary_constraint('y', loc='final', equals=1.85E5, linear=True) phase.add_boundary_constraint('vx', loc='final', equals=7796.6961) phase.add_boundary_constraint('vy', loc='final', equals=0) phase.add_control('theta', units='rad', lower=-1.57, upper=1.57) phase.add_design_parameter('thrust', units='N', opt=False, val=2100000.0) phase.add_objective('time', loc='final', scaler=0.01) p.model.options['assembled_jac_type'] = top_level_jacobian.lower() p.model.linear_solver = DirectSolver(assemble_jac=True) return p
def min_time_climb_problem(num_seg=3, transcription_order=5, transcription='gauss-lobatto', top_level_densejacobian=True): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SNOPT' p.driver.opt_settings['Major iterations limit'] = 500 p.driver.opt_settings['Iterations limit'] = 1000000000 p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-10 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-10 p.driver.opt_settings['Verify level'] = 1 p.driver.opt_settings['Function precision'] = 1.0E-6 p.driver.opt_settings['Linesearch tolerance'] = .1 p.driver.opt_settings['Major step limit'] = .1 p.driver.options['dynamic_simul_derivs'] = True phase = Phase(transcription, ode_class=MinTimeClimbODE, num_segments=num_seg, transcription_order=transcription_order) p.model.add_subsystem('phase', phase) phase.set_time_options(opt_initial=False, duration_bounds=(50, 1e8), duration_ref=100.0) phase.set_state_options('r', fix_initial=True, lower=0, upper=1.0E8, scaler=1.0E-4, defect_scaler=1.0E-3, units='m') phase.set_state_options('h', fix_initial=True, lower=0, upper=20000.0, scaler=1.0E-3, defect_scaler=1.0E-3, units='m') phase.set_state_options('v', fix_initial=True, lower=10.0, upper=500., scaler=1.0E-2, defect_scaler=1.0E-2, units='m/s') phase.set_state_options('gam', fix_initial=True, lower=-1.5, upper=1.5, ref=1.0, defect_scaler=1.0, units='rad') phase.set_state_options('m', fix_initial=True, lower=10.0, upper=1.0E5, scaler=1.0E-3, defect_scaler=1.0E-3, units='kg') phase.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=True) phase.add_design_parameter('S', val=49.2386, units='m**2', opt=False) # phase.add_design_parameter('throttle', val=1.0, opt=False) phase.add_control('throttle', val=1.0, opt=True, lower=0., upper=1., rate_continuity=False) phase.add_boundary_constraint('h', loc='final', equals=100., scaler=1.0E-3, units='m') # phase.add_boundary_constraint('aero.mach', loc='final', equals=1., units=None) # phase.add_boundary_constraint('gam', loc='final', equals=0.0, units='rad') phase.add_boundary_constraint('r', loc='final', equals=1e6, units='m') 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_path_constraint(name='prop.m_dot', upper=0.) # phase.add_path_constraint(name='flight_dynamics.r_dot', lower=0.) # Minimize time at the end of the phase # phase.add_objective('time', loc='final', ref=100.0) phase.add_objective('m', loc='final', ref=-1000.0) p.model.linear_solver = DirectSolver(assemble_jac=True) p.model.options['assembled_jac_type'] = 'csc' p.setup(mode='fwd', check=True) p['phase.t_initial'] = 0.0 p['phase.t_duration'] = 2000. p['phase.states:r'] = phase.interpolate(ys=[0.0, 1e6], nodes='state_input') p['phase.states:h'] = phase.interpolate(ys=[100.0, 1e4], nodes='state_input') p['phase.states:v'] = phase.interpolate(ys=[135.964, 283.159], nodes='state_input') p['phase.states:gam'] = phase.interpolate(ys=[0.0, 0.0], nodes='state_input') p['phase.states:m'] = phase.interpolate(ys=[30e3, 29e3], nodes='state_input') # p['phase.controls:alpha'] = phase.interpolate(ys=[0.50, 0.50], nodes='all') return p
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_min_time_climb_for_docs_gauss_lobatto(self): import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase from dymos.examples.min_time_climb.min_time_climb_ode import MinTimeClimbODE p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' # Compute sparsity/coloring when run_driver is called p.driver.options['dynamic_simul_derivs'] = True phase = Phase('gauss-lobatto', ode_class=MinTimeClimbODE, num_segments=12, compressed=True, transcription_order=3) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(50, 400), duration_ref=100.0) phase.set_state_options('r', fix_initial=True, lower=0, upper=1.0E6, ref=1.0E3, defect_ref=1000.0, units='m') phase.set_state_options('h', fix_initial=True, lower=0, upper=20000.0, ref=1.0E2, defect_ref=100.0, units='m') phase.set_state_options('v', fix_initial=True, lower=10.0, ref=1.0E2, defect_ref=0.1, units='m/s') phase.set_state_options('gam', fix_initial=True, lower=-1.5, upper=1.5, ref=1.0, defect_scaler=1.0, units='rad') phase.set_state_options('m', fix_initial=True, lower=10.0, upper=1.0E5, ref=1.0E3, defect_ref=0.1) rate_continuity = True phase.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=rate_continuity, rate_continuity_scaler=100.0, rate2_continuity=False) phase.add_design_parameter('S', val=49.2386, units='m**2', opt=False) phase.add_design_parameter('Isp', val=1600.0, units='s', opt=False) phase.add_design_parameter('throttle', val=1.0, opt=False) 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, units=None) 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_path_constraint(name='alpha', lower=-8, upper=8) # Minimize time at the end of the phase phase.add_objective('time', loc='final') p.driver.options['dynamic_simul_derivs'] = True p.model.options['assembled_jac_type'] = 'csc' p.model.linear_solver = DirectSolver(assemble_jac=True) p.setup(check=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 500 p['phase0.states:r'] = phase.interpolate(ys=[0.0, 50000.0], nodes='state_input') p['phase0.states:h'] = phase.interpolate(ys=[100.0, 20000.0], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[135.964, 283.159], nodes='state_input') p['phase0.states:gam'] = phase.interpolate(ys=[0.0, 0.0], nodes='state_input') p['phase0.states:m'] = phase.interpolate(ys=[19030.468, 10000.], nodes='state_input') p['phase0.controls:alpha'] = phase.interpolate(ys=[0.0, 0.0], nodes='control_input') # Solve for the optimal trajectory p.run_driver() # Test the results assert_rel_error(self, p.model.phase0.get_values('time')[-1], 321.0, tolerance=2) exp_out = phase.simulate(times=50) fig, axes = plt.subplots(2, 1, sharex=True) axes[0].plot(phase.get_values('time'), phase.get_values('h'), 'ro') axes[0].plot(exp_out.get_values('time'), exp_out.get_values('h'), 'b-') axes[0].set_xlabel('time (s)') axes[0].set_ylabel('altitude (m)') axes[1].plot(phase.get_values('time'), phase.get_values('alpha', units='deg'), 'ro') axes[1].plot(exp_out.get_values('time'), exp_out.get_values('alpha', units='deg'), 'b-') axes[1].set_xlabel('time (s)') axes[1].set_ylabel('alpha (deg)') plt.show()
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)
defect_scaler=0.01, fix_initial=True, fix_final=False) phase.set_state_options('p%dy' % i, scaler=0.1, defect_scaler=0.01, fix_initial=True, fix_final=False) # phase.set_state_options('p%dmass' % i, # scaler=0.01, defect_scaler=0.1, fix_initial=True, # lower=0.0) # phase.set_state_options('p%dimpulse' % i, # scaler=0.01, defect_scaler=0.1, fix_initial=True) phase.add_boundary_constraint('space%d.err_space_dist' % i, constraint_name='space%d_err_space_dist' % i, loc='final', lower=0.0) phase.add_design_parameter('speed%d' % i, opt=True, val=1.0, upper=20, lower=1e-9, units='m/s') phase.add_design_parameter('heading%d' % i, opt=False, val=heading, units='rad') phase.add_objective('time', loc='final', scaler=1.0)
def test_two_phase_cannonball_for_docs(self): from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, SqliteRecorder, \ pyOptSparseDriver from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase, Trajectory, Radau, GaussLobatto from dymos.examples.cannonball.cannonball_ode import CannonballODE from dymos.examples.cannonball.size_comp import CannonballSizeComp p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.options['dynamic_simul_derivs'] = True external_params = p.model.add_subsystem('external_params', IndepVarComp()) external_params.add_output('radius', val=0.10, units='m') external_params.add_output('dens', val=7.87, units='g/cm**3') external_params.add_design_var('radius', lower=0.01, upper=0.10, ref0=0.01, ref=0.10) p.model.add_subsystem('size_comp', CannonballSizeComp()) traj = p.model.add_subsystem('traj', Trajectory()) transcription = Radau(num_segments=5, order=3, compressed=True) ascent = Phase(ode_class=CannonballODE, transcription=transcription) ascent = traj.add_phase('ascent', ascent) # All initial states except flight path angle are fixed # Final flight path angle is fixed (we will set it to zero so that the phase ends at apogee) ascent.set_time_options(fix_initial=True, duration_bounds=(1, 100), duration_ref=100, units='s') ascent.set_state_options('r', fix_initial=True, fix_final=False) ascent.set_state_options('h', fix_initial=True, fix_final=False) ascent.set_state_options('gam', fix_initial=False, fix_final=True) ascent.set_state_options('v', fix_initial=False, fix_final=False) # Limit the muzzle energy ascent.add_boundary_constraint('kinetic_energy.ke', loc='initial', units='J', upper=400000, lower=0, ref=100000, shape=(1,)) # Second Phase (descent) transcription = GaussLobatto(num_segments=5, order=3, compressed=True) descent = Phase(ode_class=CannonballODE, transcription=transcription) traj.add_phase('descent', descent) # All initial states and time are free (they will be linked to the final states of ascent. # Final altitude is fixed (we will set it to zero so that the phase ends at ground impact) descent.set_time_options(initial_bounds=(.5, 100), duration_bounds=(.5, 100), duration_ref=100) descent.set_state_options('r', fix_initial=False, fix_final=False) descent.set_state_options('h', fix_initial=False, fix_final=True) descent.set_state_options('gam', fix_initial=False, fix_final=False) descent.set_state_options('v', fix_initial=False, fix_final=False) descent.add_objective('r', loc='final', scaler=-1.0) # Add internally-managed design parameters to the trajectory. traj.add_design_parameter('CD', val=0.5, units=None, opt=False) traj.add_design_parameter('CL', val=0.0, units=None, opt=False) traj.add_design_parameter('T', val=0.0, units='N', opt=False) traj.add_design_parameter('alpha', val=0.0, units='deg', opt=False) # Add externally-provided design parameters to the trajectory. traj.add_input_parameter('mass', target_params={'ascent': 'm', 'descent': 'm'}, val=1.0) traj.add_input_parameter('S', val=0.005) # Link Phases (link time and all state variables) traj.link_phases(phases=['ascent', 'descent'], vars=['*']) # Issue Connections p.model.connect('external_params.radius', 'size_comp.radius') p.model.connect('external_params.dens', 'size_comp.dens') p.model.connect('size_comp.mass', 'traj.input_parameters:mass') p.model.connect('size_comp.S', 'traj.input_parameters:S') # Finish Problem Setup p.model.linear_solver = DirectSolver() p.driver.add_recorder(SqliteRecorder('ex_two_phase_cannonball.db')) p.setup(check=True) # Set Initial Guesses p.set_val('external_params.radius', 0.05, units='m') p.set_val('external_params.dens', 7.87, units='g/cm**3') p.set_val('traj.design_parameters:CD', 0.5) p.set_val('traj.design_parameters:CL', 0.0) p.set_val('traj.design_parameters:T', 0.0) p.set_val('traj.ascent.t_initial', 0.0) p.set_val('traj.ascent.t_duration', 10.0) p.set_val('traj.ascent.states:r', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:h', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:v', ascent.interpolate(ys=[200, 150], nodes='state_input')) p.set_val('traj.ascent.states:gam', ascent.interpolate(ys=[25, 0], nodes='state_input'), units='deg') p.set_val('traj.descent.t_initial', 10.0) p.set_val('traj.descent.t_duration', 10.0) p.set_val('traj.descent.states:r', descent.interpolate(ys=[100, 200], nodes='state_input')) p.set_val('traj.descent.states:h', descent.interpolate(ys=[100, 0], nodes='state_input')) p.set_val('traj.descent.states:v', descent.interpolate(ys=[150, 200], nodes='state_input')) p.set_val('traj.descent.states:gam', descent.interpolate(ys=[0, -45], nodes='state_input'), units='deg') p.run_driver() assert_rel_error(self, p.get_val('traj.descent.states:r')[-1], 3183.25, tolerance=1.0E-2) exp_out = traj.simulate() print('optimal radius: {0:6.4f} m '.format(p.get_val('external_params.radius', units='m')[0])) print('cannonball mass: {0:6.4f} kg '.format(p.get_val('size_comp.mass', units='kg')[0])) print('launch angle: {0:6.4f} ' 'deg '.format(p.get_val('traj.ascent.timeseries.states:gam', units='deg')[0, 0])) print('maximum range: {0:6.4f} ' 'm '.format(p.get_val('traj.descent.timeseries.states:r')[-1, 0])) fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(10, 6)) time_imp = {'ascent': p.get_val('traj.ascent.timeseries.time'), 'descent': p.get_val('traj.descent.timeseries.time')} time_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.time'), 'descent': exp_out.get_val('traj.descent.timeseries.time')} r_imp = {'ascent': p.get_val('traj.ascent.timeseries.states:r'), 'descent': p.get_val('traj.descent.timeseries.states:r')} r_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.states:r'), 'descent': exp_out.get_val('traj.descent.timeseries.states:r')} h_imp = {'ascent': p.get_val('traj.ascent.timeseries.states:h'), 'descent': p.get_val('traj.descent.timeseries.states:h')} h_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.states:h'), 'descent': exp_out.get_val('traj.descent.timeseries.states:h')} axes.plot(r_imp['ascent'], h_imp['ascent'], 'bo') axes.plot(r_imp['descent'], h_imp['descent'], 'ro') axes.plot(r_exp['ascent'], h_exp['ascent'], 'b--') axes.plot(r_exp['descent'], h_exp['descent'], 'r--') axes.set_xlabel('range (m)') axes.set_ylabel('altitude (m)') fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(10, 6)) states = ['r', 'h', 'v', 'gam'] for i, state in enumerate(states): x_imp = {'ascent': p.get_val('traj.ascent.timeseries.states:{0}'.format(state)), 'descent': p.get_val('traj.descent.timeseries.states:{0}'.format(state))} x_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.states:{0}'.format(state)), 'descent': exp_out.get_val('traj.descent.timeseries.states:{0}'.format(state))} axes[i].set_ylabel(state) axes[i].plot(time_imp['ascent'], x_imp['ascent'], 'bo') axes[i].plot(time_imp['descent'], x_imp['descent'], 'ro') axes[i].plot(time_exp['ascent'], x_exp['ascent'], 'b--') axes[i].plot(time_exp['descent'], x_exp['descent'], 'r--') params = ['CL', 'CD', 'T', 'alpha', 'm', 'S'] fig, axes = plt.subplots(nrows=6, ncols=1, figsize=(12, 6)) for i, param in enumerate(params): p_imp = { 'ascent': p.get_val('traj.ascent.timeseries.traj_parameters:{0}'.format(param)), 'descent': p.get_val('traj.descent.timeseries.traj_parameters:{0}'.format(param))} p_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.' 'traj_parameters:{0}'.format(param)), 'descent': exp_out.get_val('traj.descent.timeseries.' 'traj_parameters:{0}'.format(param))} axes[i].set_ylabel(param) axes[i].plot(time_imp['ascent'], p_imp['ascent'], 'bo') axes[i].plot(time_imp['descent'], p_imp['descent'], 'ro') axes[i].plot(time_exp['ascent'], p_exp['ascent'], 'b--') axes[i].plot(time_exp['descent'], p_exp['descent'], 'r--') plt.show()
scaler=1.0E-3, defect_scaler=1.0E-3, units='m') phase.set_state_options('v', fix_initial=True, lower=0.01, scaler=1.0E-2, defect_scaler=1.0E-2, units='m/s') phase.set_state_options('gam', fix_initial=True, lower=-1.5, upper=1.5, ref=1.0, defect_scaler=1.0, units='rad') phase.set_state_options('m', fix_initial=True, lower=1e3, upper=1.0E6, scaler=1.0E-3, defect_scaler=1.0E-3) phase.add_control('alpha', units='rad', lower=-8. * np.pi/180., upper=8. * np.pi/180., scaler=1, rate_continuity=True) phase.add_control('throttle', val=1.0, lower=0., upper=1., opt=True, rate_continuity=True) phase.add_boundary_constraint('h', loc='final', equals=100., scaler=1.0E-3, units='m') phase.add_boundary_constraint('r', loc='final', equals=1500., units='km') # phase.add_boundary_constraint('gam', loc='final', equals=0.0, units='rad') phase.add_path_constraint(name='aero.mach', lower=0.01, upper=.9) # phase.add_path_constraint(name='prop.m_dot', upper=0.) # phase.add_path_constraint(name='flight_dynamics.r_dot', lower=0.) # phase.add_path_constraint(name='m', lower=1e4) phase.add_path_constraint(name='h', lower=0.) # phase.set_objective('time', loc='final', ref=10.0) phase.add_objective('m', loc='final', ref=-10000.0) # phase.set_objective('r', loc='final', ref=-100000.0) p.model.linear_solver = DirectSolver(assemble_jac=True) p.model.options['assembled_jac_type'] = 'csc'
def escort_problem(optimizer='SLSQP', num_seg=3, transcription_order=5, transcription='gauss-lobatto', meeting_altitude=14000., climb_time=350., starting_mass=19030.468): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer if optimizer == 'SNOPT': p.driver.opt_settings['Major iterations limit'] = 1000 p.driver.opt_settings['Iterations limit'] = 100000000 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-5 p.driver.opt_settings['Verify level'] = -1 p.driver.opt_settings['Function precision'] = 1.0E-6 p.driver.opt_settings['Linesearch tolerance'] = 0.10 p.driver.opt_settings['Major step limit'] = 0.5 phase_class = _phase_map[transcription] climb = Phase('gauss-lobatto', ode_class=MinTimeClimbODE, num_segments=num_seg, transcription_order=transcription_order) climb.set_time_options(duration_bounds=(50, climb_time), duration_ref=100.0) climb.set_state_options('r', fix_initial=True, lower=0, upper=1.0E6, scaler=1.0E-3, defect_scaler=1.0E-2, units='m') climb.set_state_options('h', fix_initial=True, lower=0, upper=20000.0, scaler=1.0E-3, defect_scaler=1.0E-3, units='m') climb.set_state_options('v', fix_initial=True, lower=10.0, scaler=1.0E-2, defect_scaler=1.0E-2, units='m/s') climb.set_state_options('gam', fix_initial=True, lower=-1.5, upper=1.5, ref=1.0, defect_scaler=1.0, units='rad') climb.set_state_options('m', fix_initial=True, lower=10.0, upper=1.0E5, scaler=1.0E-3, defect_scaler=1.0E-3) climb.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=True) climb.add_control('S', val=49.2386, units='m**2', dynamic=False, opt=False) climb.add_control('Isp', val=5000.0, units='s', dynamic=False, opt=False) climb.add_control('throttle', val=1.0, dynamic=False, opt=False) climb.add_boundary_constraint('h', loc='final', equals=meeting_altitude, scaler=1.0E-3, units='m') climb.add_boundary_constraint('aero.mach', loc='final', equals=1.0, units=None) climb.add_boundary_constraint('gam', loc='final', equals=0.0, units='rad') # climb.add_boundary_constraint('time', loc='final', upper=climb_time, units='s') climb.add_path_constraint(name='h', lower=100.0, upper=20000, ref=20000) climb.add_path_constraint(name='aero.mach', lower=0.1, upper=1.8) # Minimize time at the end of the climb climb.set_objective('time', loc='final', ref=100.0) p.model.add_subsystem('climb', climb) escort = Phase('gauss-lobatto', ode_class=MinTimeClimbODE, num_segments=num_seg * 2, transcription_order=transcription_order) escort.set_time_options(duration_bounds=(50, 10000), opt_initial=True, duration_ref=100.0) escort.set_state_options('r', lower=0, upper=1.0E6, scaler=1.0E-3, defect_scaler=1.0E-2, units='m') escort.set_state_options('h', lower=0, upper=20000.0, scaler=1.0E-3, defect_scaler=1.0E-3, units='m') escort.set_state_options('v', lower=10.0, scaler=1.0E-2, defect_scaler=1.0E-2, units='m/s') escort.set_state_options('gam', lower=-1.5, upper=1.5, ref=1.0, defect_scaler=1.0, units='rad') escort.set_state_options('m', lower=10.0, upper=1.0E5, scaler=1.0E-3, defect_scaler=1.0E-3) escort.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=True) escort.add_control('S', val=49.2386, units='m**2', dynamic=False, opt=False) escort.add_control('Isp', val=1600.0, units='s', dynamic=False, opt=False) escort.add_control('throttle', val=1.0, lower=0., upper=1., opt=True) # escort.add_control('throttle', val=1.0, dynamic=False, opt=False) # escort.add_boundary_constraint('h', loc='final', equals=20000, scaler=1.0E-3, units='m') # escort.add_boundary_constraint('aero.mach', loc='final', equals=1.0, units=None) # escort.add_boundary_constraint('gam', loc='final', equals=0.0, units='rad') escort.add_boundary_constraint('m', loc='final', equals=15000.0, units='kg') escort.add_path_constraint(name='h', lower=meeting_altitude, upper=meeting_altitude, ref=meeting_altitude) escort.add_path_constraint(name='aero.mach', equals=1.0) # Maximize distance at the end of the escort # escort.set_objective('r', loc='final', ref=-1e5) p.model.add_subsystem('escort', escort) # Connect the phases linkage_comp = PhaseLinkageComp() linkage_comp.add_linkage(name='L01', vars=['t'], units='s', equals=0.0, linear=True) linkage_comp.add_linkage(name='L01', vars=['r'], units='m', equals=0.0, linear=True) linkage_comp.add_linkage(name='L01', vars=['h'], units='m', equals=0.0, linear=True) linkage_comp.add_linkage(name='L01', vars=['v'], units='m/s', equals=0.0, linear=True) linkage_comp.add_linkage(name='L01', vars=['gam'], units='rad', equals=0.0, linear=True) linkage_comp.add_linkage(name='L01', vars=['m'], units='kg', equals=0.0, linear=True) linkage_comp.add_linkage(name='L01', vars=['alpha'], units='rad', equals=0.0, linear=True) linkage_comp.add_linkage(name='L01', vars=['throttle'], equals=0.0, linear=True) p.model.connect('climb.time++', 'linkages.L01_t:lhs') p.model.connect('escort.time--', 'linkages.L01_t:rhs') p.model.connect('climb.states:r++', 'linkages.L01_r:lhs') p.model.connect('escort.states:r--', 'linkages.L01_r:rhs') p.model.connect('climb.states:h++', 'linkages.L01_h:lhs') p.model.connect('escort.states:h--', 'linkages.L01_h:rhs') # p.model.connect('climb.states:v++', 'linkages.L01_v:lhs') p.model.connect('escort.states:v--', 'linkages.L01_v:rhs') # p.model.connect('climb.states:gam++', 'linkages.L01_gam:lhs') p.model.connect('escort.states:gam--', 'linkages.L01_gam:rhs') p.model.connect('climb.states:m++', 'linkages.L01_m:lhs') p.model.connect('escort.states:m--', 'linkages.L01_m:rhs') p.model.connect('climb.controls:alpha++', 'linkages.L01_alpha:lhs') p.model.connect('escort.controls:alpha--', 'linkages.L01_alpha:rhs') p.model.connect('climb.controls:throttle++', 'linkages.L01_throttle:lhs') p.model.connect('escort.controls:throttle--', 'linkages.L01_throttle:rhs') p.model.add_subsystem('linkages', linkage_comp) p.model.linear_solver = DirectSolver(assemble_jac=True) p.model.options['assembled_jac_type'] = 'csc' # p.driver.add_recorder(SqliteRecorder('escort.db')) p.setup(mode='fwd', check=True) p['climb.t_initial'] = 0.0 p['climb.t_duration'] = 200. p['climb.states:r'] = climb.interpolate(ys=[0.0, 111319.54], nodes='disc') p['climb.states:h'] = climb.interpolate(ys=[100.0, 20000.0], nodes='disc') p['climb.states:v'] = climb.interpolate(ys=[135.964, 283.159], nodes='disc') p['climb.states:gam'] = climb.interpolate(ys=[0.0, 0.0], nodes='disc') p['climb.states:m'] = climb.interpolate(ys=[starting_mass, 16841.431], nodes='disc') p['climb.controls:alpha'] = climb.interpolate(ys=[0.0, 0.0], nodes='all') p['escort.t_initial'] = 200. p['escort.t_duration'] = 1000. p['escort.states:r'] = escort.interpolate(ys=[111319.54, 400000.], nodes='disc') p['escort.states:h'] = escort.interpolate( ys=[meeting_altitude, meeting_altitude], nodes='disc') p['escort.states:v'] = escort.interpolate(ys=[250., 250.], nodes='disc') p['escort.states:gam'] = escort.interpolate(ys=[0.0, 0.0], nodes='disc') p['escort.states:m'] = escort.interpolate(ys=[17000., 15000.], nodes='disc') p['escort.controls:alpha'] = escort.interpolate(ys=[0.0, 0.0], nodes='all') return p
def thermal_mission_problem(num_seg=5, transcription_order=3, meeting_altitude=20000., Q_env=0., Q_sink=0., Q_out=0., m_recirculated=0., opt_m_recirculated=False, opt_m_burn=False, opt_throttle=True, engine_heat_coeff=0., pump_heat_coeff=0., T=None, T_o=None, opt_m=False, m_initial=20.e3, transcription='gauss-lobatto'): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SNOPT' p.driver.opt_settings['Major iterations limit'] = 5000 p.driver.opt_settings['Iterations limit'] = 5000000000000000 p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-8 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-8 p.driver.opt_settings['Verify level'] = -1 p.driver.opt_settings['Linesearch tolerance'] = .1 p.driver.opt_settings['Major step limit'] = .1 p.driver.options['dynamic_simul_derivs'] = True phase = Phase(transcription, ode_class=ThermalMissionODE, ode_init_kwargs={'engine_heat_coeff':engine_heat_coeff, 'pump_heat_coeff':pump_heat_coeff}, num_segments=num_seg, transcription_order=transcription_order) p.model.add_subsystem('phase', phase) phase.set_time_options(opt_initial=False, duration_bounds=(50, 400), duration_ref=100.0) phase.set_state_options('r', fix_initial=True, lower=0, upper=1.0E6, scaler=1.0E-3, defect_scaler=1.0E-2, units='m') phase.set_state_options('h', fix_initial=True, lower=0, upper=20000.0, scaler=1.0E-3, defect_scaler=1.0E-3, units='m') phase.set_state_options('v', fix_initial=True, lower=10.0, scaler=1.0E-2, defect_scaler=5.0E-0, units='m/s') phase.set_state_options('gam', fix_initial=True, lower=-1.5, upper=1.5, ref=1.0, defect_scaler=1.0, units='rad') phase.set_state_options('m', fix_initial=not opt_m, lower=15.e3, upper=80e3, scaler=1.0E-3, defect_scaler=1.0E-3, units='kg') phase.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=True) phase.add_design_parameter('S', val=1., units='m**2', opt=False) if opt_throttle: phase.add_control('throttle', val=1.0, lower=0.0, upper=1.0, opt=True, rate_continuity=True) else: phase.add_design_parameter('throttle', val=1.0, opt=False) phase.add_design_parameter('W0', val=10.5e3, opt=False, units='kg') phase.add_boundary_constraint('h', loc='final', equals=meeting_altitude, scaler=1.0E-3, units='m') phase.add_boundary_constraint('aero.mach', loc='final', equals=1., units=None) 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_path_constraint(name='time', upper=110.) # Minimize time at the end of the phase phase.add_objective('time', loc='final', ref=100.0) # phase.add_objective('energy', loc='final', ref=100.0) # phase.add_objective('m', loc='final', ref=-10000.0) # Set the state options for mass, temperature, and energy. phase.set_state_options('T', fix_initial=True, ref=300, defect_scaler=1e-2) phase.set_state_options('energy', fix_initial=True, ref=10e3, defect_scaler=1e-4) # Allow the optimizer to vary the fuel flow if opt_m_recirculated: phase.add_control('m_recirculated', val=m_recirculated, lower=0., opt=True, rate_continuity=True, ref=20.) else: phase.add_control('m_recirculated', val=m_recirculated, opt=False) phase.add_design_parameter('Q_env', val=Q_env, opt=False) phase.add_design_parameter('Q_sink', val=Q_sink, opt=False) phase.add_design_parameter('Q_out', val=Q_out, opt=False) # Constrain the temperature, 2nd derivative of fuel mass in the tank, and make # sure that the amount recirculated is at least 0, otherwise we'd burn # more fuel than we pumped. if opt_m_recirculated: phase.add_path_constraint('m_flow', lower=0., upper=50., units='kg/s', ref=10.) if T is not None: phase.add_path_constraint('T', upper=T, units='K') if T_o is not None: phase.add_path_constraint('T_o', upper=T_o, units='K', ref=300.) # phase.add_path_constraint('m_flow', lower=0., upper=20., units='kg/s', ref=10.) p.setup(mode='fwd', check=True) p['phase.t_initial'] = 0.0 p['phase.t_duration'] = 200. p['phase.states:r'] = phase.interpolate(ys=[0.0, 111319.54], nodes='state_input') p['phase.states:h'] = phase.interpolate(ys=[100.0, meeting_altitude], nodes='state_input') # p['phase.states:h'][:] = 10000. p['phase.states:v'] = phase.interpolate(ys=[135.964, 283.159], nodes='state_input') # p['phase.states:v'][:] = 200. p['phase.states:gam'] = phase.interpolate(ys=[0.0, 0.0], nodes='state_input') p['phase.states:m'] = phase.interpolate(ys=[m_initial, 12.e3], nodes='state_input') p['phase.controls:alpha'] = phase.interpolate(ys=[1., 1.], nodes='control_input') # Give initial values for the phase states, controls, and time p['phase.states:T'] = 310. return p
def test_control_rate2_boundary_constraint_gl(self): p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneODE, transcription=GaussLobatto(num_segments=20, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(0.1, 10)) phase.set_state_options('x', fix_initial=True, fix_final=True) phase.set_state_options('y', fix_initial=True, fix_final=True) phase.set_state_options('v', fix_initial=True, fix_final=False) phase.add_control('theta', continuity=True, rate_continuity=True, rate2_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665) phase.add_boundary_constraint('theta_rate2', loc='final', equals=0.0, units='deg/s**2') # Minimize time at the end of the phase phase.add_objective('time') p.model.linear_solver = 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.design_parameters:g'] = 8 p.run_driver() plt.plot(p.get_val('phase0.timeseries.states:x'), p.get_val('phase0.timeseries.states:y'), 'ko') plt.figure() plt.plot(p.get_val('phase0.timeseries.time'), p.get_val('phase0.timeseries.controls:theta'), 'ro') plt.plot(p.get_val('phase0.timeseries.time'), p.get_val('phase0.timeseries.control_rates:theta_rate'), 'bo') plt.plot(p.get_val('phase0.timeseries.time'), p.get_val('phase0.timeseries.control_rates:theta_rate2'), 'go') plt.show() assert_rel_error( self, p.get_val('phase0.timeseries.control_rates:theta_rate2')[-1], 0, tolerance=1.0E-6)
def test_two_phase_cannonball_for_docs(self): from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, SqliteRecorder, \ pyOptSparseDriver from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase, Trajectory, load_simulation_results from dymos.examples.cannonball.cannonball_ode import CannonballODE from dymos.examples.cannonball.size_comp import CannonballSizeComp p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.options['dynamic_simul_derivs'] = True external_params = p.model.add_subsystem('external_params', IndepVarComp()) external_params.add_output('radius', val=0.10, units='m') external_params.add_output('dens', val=7.87, units='g/cm**3') external_params.add_design_var('radius', lower=0.01, upper=0.10, ref0=0.01, ref=0.10) p.model.add_subsystem('size_comp', CannonballSizeComp()) traj = p.model.add_subsystem('traj', Trajectory()) # First Phase (ascent) ascent = Phase('radau-ps', ode_class=CannonballODE, num_segments=5, transcription_order=3, compressed=True) ascent = traj.add_phase('ascent', ascent) # All initial states except flight path angle are fixed # Final flight path angle is fixed (we will set it to zero so that the phase ends at apogee) ascent.set_time_options(fix_initial=True, duration_bounds=(1, 100), duration_ref=100) ascent.set_state_options('r', fix_initial=True, fix_final=False) ascent.set_state_options('h', fix_initial=True, fix_final=False) ascent.set_state_options('gam', fix_initial=False, fix_final=True) ascent.set_state_options('v', fix_initial=False, fix_final=False) # Limit the muzzle energy ascent.add_boundary_constraint('kinetic_energy.ke', loc='initial', units='J', upper=400000, lower=0, ref=100000) # Second Phase (descent) descent = Phase('gauss-lobatto', ode_class=CannonballODE, num_segments=5, transcription_order=3, compressed=True) traj.add_phase('descent', descent) # All initial states and time are free (they will be linked to the final states of ascent. # Final altitude is fixed (we will set it to zero so that the phase ends at ground impact) descent.set_time_options(initial_bounds=(.5, 100), duration_bounds=(.5, 100), duration_ref=100) descent.set_state_options('r', fix_initial=False, fix_final=False) descent.set_state_options('h', fix_initial=False, fix_final=True) descent.set_state_options('gam', fix_initial=False, fix_final=False) descent.set_state_options('v', fix_initial=False, fix_final=False) descent.add_objective('r', loc='final', scaler=-1.0) # Add internally-managed design parameters to the trajectory. traj.add_design_parameter('CD', val=0.5, units=None, opt=False) traj.add_design_parameter('CL', val=0.0, units=None, opt=False) traj.add_design_parameter('T', val=0.0, units='N', opt=False) traj.add_design_parameter('alpha', val=0.0, units='deg', opt=False) # Add externally-provided design parameters to the trajectory. traj.add_input_parameter('mass', targets={ 'ascent': 'm', 'descent': 'm' }, val=1.0, units='kg') traj.add_input_parameter('S', val=0.005, units='m**2') # Link Phases (link time and all state variables) traj.link_phases(phases=['ascent', 'descent'], vars=['*']) # Issue Connections p.model.connect('external_params.radius', 'size_comp.radius') p.model.connect('external_params.dens', 'size_comp.dens') p.model.connect('size_comp.mass', 'traj.input_parameters:mass') p.model.connect('size_comp.S', 'traj.input_parameters:S') # Finish Problem Setup p.model.options['assembled_jac_type'] = 'csc' p.model.linear_solver = DirectSolver(assemble_jac=True) p.driver.add_recorder(SqliteRecorder('ex_two_phase_cannonball.db')) p.setup(check=True) # Set Initial Guesses p.set_val('external_params.radius', 0.05, units='m') p.set_val('external_params.dens', 7.87, units='g/cm**3') p.set_val('traj.design_parameters:CD', 0.5) p.set_val('traj.design_parameters:CL', 0.0) p.set_val('traj.design_parameters:T', 0.0) p.set_val('traj.ascent.t_initial', 0.0) p.set_val('traj.ascent.t_duration', 10.0) p.set_val('traj.ascent.states:r', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:h', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:v', ascent.interpolate(ys=[200, 150], nodes='state_input')) p.set_val('traj.ascent.states:gam', ascent.interpolate(ys=[25, 0], nodes='state_input'), units='deg') p.set_val('traj.descent.t_initial', 10.0) p.set_val('traj.descent.t_duration', 10.0) p.set_val('traj.descent.states:r', descent.interpolate(ys=[100, 200], nodes='state_input')) p.set_val('traj.descent.states:h', descent.interpolate(ys=[100, 0], nodes='state_input')) p.set_val('traj.descent.states:v', descent.interpolate(ys=[150, 200], nodes='state_input')) p.set_val('traj.descent.states:gam', descent.interpolate(ys=[0, -45], nodes='state_input'), units='deg') p.run_driver() assert_rel_error(self, traj.get_values('r')['descent'][-1], 3191.83945861, tolerance=1.0E-2) exp_out = traj.simulate(times=100, record_file='ex_two_phase_cannonball_sim.db') # exp_out_loaded = load_simulation_results('ex_two_phase_cannonball_sim.db') print('optimal radius: {0:6.4f} m '.format( p.get_val('external_params.radius', units='m')[0])) print('cannonball mass: {0:6.4f} kg '.format( p.get_val('size_comp.mass', units='kg')[0])) fig, axes = plt.subplots(nrows=3, ncols=1, figsize=(8, 6)) axes[0].plot( traj.get_values('r')['ascent'], traj.get_values('h')['ascent'], 'bo') axes[0].plot( traj.get_values('r')['descent'], traj.get_values('h')['descent'], 'ro') axes[0].plot( exp_out.get_values('r')['ascent'], exp_out.get_values('h')['ascent'], 'b--') axes[0].plot( exp_out.get_values('r')['descent'], exp_out.get_values('h')['descent'], 'r--') axes[0].set_xlabel('range (m)') axes[0].set_ylabel('altitude (m)') # plt.suptitle('Kinetic Energy vs Time') axes[1].plot( traj.get_values('time')['ascent'], traj.get_values('kinetic_energy.ke')['ascent'], 'bo') axes[1].plot( traj.get_values('time')['descent'], traj.get_values('kinetic_energy.ke')['descent'], 'ro') axes[1].plot( exp_out.get_values('time')['ascent'], exp_out.get_values('kinetic_energy.ke')['ascent'], 'b--') axes[1].plot( exp_out.get_values('time')['descent'], exp_out.get_values('kinetic_energy.ke')['descent'], 'r--') # axes[1].plot(exp_out_loaded.get_values('time')['ascent'], # exp_out_loaded.get_values('kinetic_energy.ke')['ascent'], # 'b--') # # axes[1].plot(exp_out_loaded.get_values('time')['descent'], # exp_out_loaded.get_values('kinetic_energy.ke')['descent'], # 'r--') axes[1].set_xlabel('time (s)') axes[1].set_ylabel(r'kinetic energy (J)') # plt.figure() axes[2].plot( traj.get_values('time')['ascent'], traj.get_values('gam', units='deg')['ascent'], 'bo') axes[2].plot( traj.get_values('time')['descent'], traj.get_values('gam', units='deg')['descent'], 'ro') axes[2].plot( exp_out.get_values('time')['ascent'], exp_out.get_values('gam', units='deg')['ascent'], 'b--') axes[2].plot( exp_out.get_values('time')['descent'], exp_out.get_values('gam', units='deg')['descent'], 'r--') axes[2].set_xlabel('time (s)') axes[2].set_ylabel(r'flight path angle (deg)') plt.show()
def test_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 test_design_parameter_boundary_constraint(self): p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneODE, transcription=GaussLobatto(num_segments=20, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.set_state_options('x', fix_initial=True, fix_final=True) phase.set_state_options('y', fix_initial=True, fix_final=True) 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=True, val=9.80665) # We'll let g vary, but make sure it hits the desired value. # It's a static design parameter, so it shouldn't matter whether we enforce it # at the start or the end of the phase, so here we'll do both. # Note if we make these equality constraints, some optimizers (SLSQP) will # see the problem as infeasible. phase.add_boundary_constraint('g', loc='initial', units='m/s**2', upper=9.80665) phase.add_boundary_constraint('g', loc='final', units='m/s**2', upper=9.80665) # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) p.model.linear_solver = 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.design_parameters:g'] = 5 p.run_driver() assert_rel_error(self, p.get_val('phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-4) assert_rel_error(self, p.get_val('phase0.timeseries.design_parameters:g')[0], 9.80665, tolerance=1.0E-6) assert_rel_error( self, p.get_val('phase0.timeseries.design_parameters:g')[-1], 9.80665, tolerance=1.0E-6)
end_y = center_y + r * np.sin(theta + theta2) locations.append([start_x, end_x, start_y, end_y]) #print("location", i, locations[-1]) phase.add_input_parameter('sx%d' % i, val=start_x, units='m') phase.add_input_parameter('sy%d' % i, val=start_y, units='m') phase.add_input_parameter('ex%d' % i, val=end_x, units='m') phase.add_input_parameter('ey%d' % i, val=end_y, units='m') phase.add_input_parameter('ts%d' % i, val=t_start, units='s') phase.add_input_parameter('te%d' % i, val=t_end, units='s') phase.set_state_options('x%d' % i, scaler=0.01, defect_scaler=0.1) phase.set_state_options('y%d' % i, scaler=0.01, defect_scaler=0.1) phase.add_boundary_constraint('x%d' % i, loc='initial', equals=start_x) phase.add_boundary_constraint('y%d' % i, loc='initial', equals=start_y) phase.add_boundary_constraint('x%d' % i, loc='final', equals=end_x) phase.add_boundary_constraint('y%d' % i, loc='final', equals=end_y) # phase.set_state_options('v%d' % i, fix_initial=False, fix_final=False, # scaler=0.01, defect_scaler=0.01, lower=0.0) phase.add_control('vx%d' % i, rate_continuity=False, units='m/s', opt=True, upper=10, lower=-10.0, scaler=200.0, adder=-10) phase.add_control('vy%d' % i,
def min_time_climb(optimizer='SLSQP', num_seg=3, transcription='gauss-lobatto', transcription_order=3, top_level_jacobian='csc', simul_derivs=True, force_alloc_complex=False): p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer if simul_derivs: p.driver.options['dynamic_simul_derivs'] = 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-6 p.driver.opt_settings['Linesearch tolerance'] = 0.10 p.driver.opt_settings['Major step limit'] = 0.5 # p.driver.opt_settings['Verify level'] = 3 phase = Phase(transcription, ode_class=MinTimeClimbODE, num_segments=num_seg, compressed=True, transcription_order=transcription_order) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(50, 400), duration_ref=100.0) phase.set_state_options('r', fix_initial=True, lower=0, upper=1.0E6, scaler=1.0E-3, defect_scaler=1.0E-2, units='m') phase.set_state_options('h', fix_initial=True, lower=0, upper=20000.0, scaler=1.0E-3, defect_scaler=1.0E-3, units='m') phase.set_state_options('v', fix_initial=True, lower=10.0, scaler=1.0E-2, defect_scaler=1.0E-2, units='m/s') phase.set_state_options('gam', fix_initial=True, lower=-1.5, upper=1.5, ref=1.0, defect_scaler=1.0, units='rad') phase.set_state_options('m', fix_initial=True, lower=10.0, upper=1.0E5, scaler=1.0E-3, defect_scaler=1.0E-3) phase.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, continuity=True, rate_continuity=True, rate2_continuity=False) phase.add_design_parameter('S', val=49.2386, units='m**2', opt=False) phase.add_design_parameter('Isp', val=1600.0, units='s', opt=False) phase.add_design_parameter('throttle', val=1.0, opt=False) 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, units=None) 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_path_constraint(name='alpha', lower=-8, upper=8) # Minimize time at the end of the phase phase.add_objective('time', loc='final') p.model.options['assembled_jac_type'] = top_level_jacobian.lower() p.model.linear_solver = DirectSolver(assemble_jac=True) p.setup(check=True, force_alloc_complex=force_alloc_complex) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 298.46902 p['phase0.states:r'] = phase.interpolate(ys=[0.0, 111319.54], nodes='state_input') p['phase0.states:h'] = phase.interpolate(ys=[100.0, 20000.0], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[135.964, 283.159], nodes='state_input') p['phase0.states:gam'] = phase.interpolate(ys=[0.0, 0.0], nodes='state_input') p['phase0.states:m'] = phase.interpolate(ys=[19030.468, 16841.431], nodes='state_input') p['phase0.controls:alpha'] = phase.interpolate(ys=[0.0, 0.0], nodes='control_input') p.run_driver() if SHOW_PLOTS: exp_out = phase.simulate(times=np.linspace(0, p['phase0.t_duration'], 100)) import matplotlib.pyplot as plt plt.plot(phase.get_values('time'), phase.get_values('h'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('h'), 'b-') plt.xlabel('time (s)') plt.ylabel('altitude (m)') plt.figure() plt.plot(phase.get_values('v'), phase.get_values('h'), 'ro') plt.plot(exp_out.get_values('v'), exp_out.get_values('h'), 'b-') plt.xlabel('airspeed (m/s)') plt.ylabel('altitude (m)') plt.figure() plt.plot(phase.get_values('time'), phase.get_values('alpha'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('alpha'), 'b-') plt.xlabel('time (s)') plt.ylabel('alpha (rad)') plt.figure() plt.plot(phase.get_values('time'), phase.get_values('prop.thrust', units='lbf'), 'ro') plt.plot(exp_out.get_values('time'), exp_out.get_values('prop.thrust', units='lbf'), 'b-') plt.xlabel('time (s)') plt.ylabel('thrust (lbf)') plt.show() return p