def _make_problem(self, transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP', run_driver=True, force_alloc_complex=False, solve_segments=False): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.declare_coloring(tol=1.0E-12) if transcription == 'gauss-lobatto': t = dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'radau-ps': t = dm.Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) traj = dm.Trajectory() phase = dm.Phase(ode_class=self.ode, transcription=t) p.model.add_subsystem('traj0', traj) traj.add_phase('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=True, fix_final=False, solve_segments=solve_segments, rate_source='xdot') phase.add_state('y', fix_initial=True, fix_final=False, solve_segments=solve_segments, rate_source='ydot') # Note that by omitting the targets here Dymos will automatically attempt to connect # to a top-level input named 'v' in the ODE, and connect to nothing if it's not found. phase.add_state('v', fix_initial=True, fix_final=False, solve_segments=solve_segments, rate_source='vdot') phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', units='m/s**2', static_target=True) phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) p.setup(check=['unconnected_inputs'], force_alloc_complex=force_alloc_complex) p['traj0.phase0.t_initial'] = 0.0 p['traj0.phase0.t_duration'] = 2.0 p['traj0.phase0.states:x'] = phase.interp('x', [0, 10]) p['traj0.phase0.states:y'] = phase.interp('y', [10, 5]) p['traj0.phase0.states:v'] = phase.interp('v', [0, 9.9]) p['traj0.phase0.controls:theta'] = phase.interp('theta', [5, 100]) p['traj0.phase0.parameters:g'] = 9.80665 dm.run_problem(p, run_driver=run_driver, simulate=True) return p
# self.add_subsystem(name='hp_mass', # subsys=heatPipeMass(num_nodes=nn), # promotes_inputs=['D_od','D_v','L_heatpipe','t_w','t_wk','cu_density',('fill_wk','epsilon'),'liq_density','fill_liq'], # promotes_outputs=['mass_heatpipe', 'mass_wick', 'mass_liquid']) thermal_link(self, 'evap', 'cond', num_nodes=nn) thermal_link(self, 'cond', 'cond2', num_nodes=nn) self.connect('evap_bridge.k_wk', ['evap.k_wk', 'cond.k_wk', 'cond2.k_wk']) load_inputs('boring.input.assumptions2', self, nn) if __name__ == "__main__": p = om.Problem(model=om.Group()) nn = 1 p.model.add_subsystem(name='hp', subsys=HeatPipeRun(num_nodes=nn), promotes_inputs=['*'], promotes_outputs=['*']) p.setup(force_alloc_complex=True) p['L_eff'] = (0.02 + 0.1) / 2. + 0.03 p['evap.Rex.T_in'] = 100 p['cond.Rex.T_in'] = 20 p['cond2.Rex.T_in'] = 20 # p.set_val('L_evap',0.01)
def test_rk4_scalar_nonlinearblockgs(self): num_seg = 4 num_stages = 4 state_options = {'y': {'shape': (1, ), 'units': 'm', 'targets': ['y']}} p = om.Problem(model=om.Group()) ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states_per_seg:y', shape=(num_seg, 1), units='m') ivc.add_output('h', shape=(num_seg, 1), units='s') ivc.add_output('t', shape=(num_seg * num_stages, 1), units='s') p.model.add_subsystem( 'k_iter_group', RungeKuttaKIterGroup(num_segments=num_seg, method='RK4', state_options=state_options, time_units='s', ode_class=TestODE, ode_init_kwargs={}, solver_class=om.NonlinearBlockGS, solver_options={'iprint': 2})) p.model.connect('t', 'k_iter_group.ode.t') p.model.connect('h', 'k_iter_group.h') p.model.connect('initial_states_per_seg:y', 'k_iter_group.initial_states_per_seg:y') src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1)) p.model.connect('k_iter_group.ode.ydot', 'k_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) p.setup(check=True, force_alloc_complex=True) p['t'] = np.array([[ 0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, 1.00, 1.25, 1.25, 1.50, 1.50, 1.75, 1.75, 2.00 ]]).T p['h'] = np.array([[0.5, 0.5, 0.5, 0.5]]).T p['initial_states_per_seg:y'] = np.array([[0.50000000], [1.425130208333333], [2.639602661132812], [4.006818970044454]]) # Start k with a terrible guess p['k_iter_group.k_comp.k:y'][...] = 0 p.run_model() # Test that the residuals of k are zero (we started k at the expected converged value) outputs = p.model.list_outputs(print_arrays=True, residuals=True, out_stream=False) op_dict = dict([op for op in outputs]) assert_almost_equal(op_dict['k_iter_group.k_comp.k:y']['resids'], 0.0) # Test the partials cpd = p.check_partials(method='cs', out_stream=None) assert_check_partials(cpd)
def test_simple_external_code_implicit_comp(self): import sys import openmdao.api as om class MachExternalCodeComp(om.ExternalCodeImplicitComp): def initialize(self): self.options.declare('super_sonic', types=bool) def setup(self): self.add_input('area_ratio', val=1.0, units=None) self.add_output('mach', val=1., units=None) self.declare_partials(of='mach', wrt='area_ratio', method='fd') self.input_file = 'mach_input.dat' self.output_file = 'mach_output.dat' # providing these are optional; the component will verify that any input # files exist before execution and that the output files exist after. self.options['external_input_files'] = [self.input_file] self.options['external_output_files'] = [self.output_file] self.options['command_apply'] = [ sys.executable, 'extcode_mach.py', self.input_file, self.output_file, ] self.options['command_solve'] = [ sys.executable, 'extcode_mach.py', self.input_file, self.output_file, ] # If you want to write your own string command, the code below will also work. # self.options['command_apply'] = ('python extcode_mach.py {} {}').format(self.input_file, self.output_file) def apply_nonlinear(self, inputs, outputs, residuals): with open(self.input_file, 'w') as input_file: input_file.write('residuals\n') input_file.write('{}\n'.format(inputs['area_ratio'][0])) input_file.write('{}\n'.format(outputs['mach'][0])) # the parent apply_nonlinear function actually runs the external code super(MachExternalCodeComp, self).apply_nonlinear(inputs, outputs, residuals) # parse the output file from the external code and set the value of mach with open(self.output_file, 'r') as output_file: mach = float(output_file.read()) residuals['mach'] = mach def solve_nonlinear(self, inputs, outputs): with open(self.input_file, 'w') as input_file: input_file.write('outputs\n') input_file.write('{}\n'.format(inputs['area_ratio'][0])) input_file.write('{}\n'.format( self.options['super_sonic'])) # the parent apply_nonlinear function actually runs the external code super(MachExternalCodeComp, self).solve_nonlinear(inputs, outputs) # parse the output file from the external code and set the value of mach with open(self.output_file, 'r') as output_file: mach = float(output_file.read()) outputs['mach'] = mach group = om.Group() group.add_subsystem('ar', om.IndepVarComp('area_ratio', 0.5)) mach_comp = group.add_subsystem('comp', MachExternalCodeComp(), promotes=['*']) prob = om.Problem(model=group) group.nonlinear_solver = om.NewtonSolver() group.nonlinear_solver.options['solve_subsystems'] = True group.nonlinear_solver.options['iprint'] = 0 group.nonlinear_solver.options['maxiter'] = 20 group.linear_solver = om.DirectSolver() prob.setup() area_ratio = 1.3 super_sonic = False prob['area_ratio'] = area_ratio mach_comp.options['super_sonic'] = super_sonic prob.run_model() assert_near_equal(prob['mach'], mach_solve(area_ratio, super_sonic=super_sonic), 1e-8) area_ratio = 1.3 super_sonic = True prob['area_ratio'] = area_ratio mach_comp.options['super_sonic'] = super_sonic prob.run_model() assert_near_equal(prob['mach'], mach_solve(area_ratio, super_sonic=super_sonic), 1e-8)
def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP', simul_derivs=True): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() OPT, OPTIMIZER = set_pyoptsparse_opt(optimizer, fallback=True) p.driver.options['optimizer'] = OPTIMIZER if simul_derivs: p.driver.declare_coloring() if transcription == 'gauss-lobatto': t = dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'radau-ps': t = dm.Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'runge-kutta': t = dm.RungeKutta(num_segments=num_segments, order=transcription_order, compressed=compressed) phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10), units='s') phase.add_state('x', fix_initial=True, fix_final=False, solve_segments=False, units='m', rate_source='xdot') phase.add_state('y', fix_initial=True, fix_final=False, solve_segments=False, units='m', rate_source='ydot') phase.add_state('v', fix_initial=True, fix_final=False, solve_segments=False, units='m/s', rate_source='vdot', targets=['v']) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9, targets=['theta']) phase.add_input_parameter('g', units='m/s**2', val=9.80665, targets=['g']) phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100], nodes='control_input') p['phase0.input_parameters:g'] = 9.80665 p.run_driver() return p
def test_continuity_comp_connected_scalar_no_iteration_fwd(self): num_seg = 4 state_options = { 'y': { 'shape': (1, ), 'units': 'm', 'targets': ['y'], 'defect_scaler': None, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': True } } p = om.Problem(model=om.Group()) ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states:y', units='m', shape=(1, 1)) p.model.add_subsystem('continuity_comp', RungeKuttaStateContinuityComp( num_segments=num_seg, state_options=state_options), promotes_inputs=['*'], promotes_outputs=['*']) p.model.nonlinear_solver = om.NonlinearRunOnce() p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['initial_states:y'] = 0.5 p['states:y'] = np.array([[0.50000000], [1.425130208333333], [2.639602661132812], [4.006818970044454], [5.301605229265987]]) p['state_integrals:y'] = np.array([[1.0], [1.0], [1.0], [1.0]]) p.run_model() p.model.run_apply_nonlinear() # Test that the residuals of the states are the expected values outputs = p.model.list_outputs(print_arrays=True, residuals=True, out_stream=None) y_f = p['states:y'][1:, ...] y_i = p['states:y'][:-1, ...] dy_given = y_f - y_i dy_computed = p['state_integrals:y'] expected_resids = np.zeros((num_seg + 1, 1)) expected_resids[1:, ...] = dy_given - dy_computed op_dict = dict([op for op in outputs]) assert_rel_error(self, op_dict['continuity_comp.states:y']['resids'], expected_resids) # Test the partials cpd = p.check_partials(method='cs') J_fwd = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_fwd'] J_rev = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_rev'] J_fd = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_fd'] assert_rel_error(self, J_fwd, J_rev) assert_rel_error(self, J_fwd, J_fd) J_fwd = cpd['continuity_comp']['states:y', 'states:y']['J_fwd'] J_rev = cpd['continuity_comp']['states:y', 'states:y']['J_rev'] J_fd = cpd['continuity_comp']['states:y', 'states:y']['J_fd'] J_fd[0, 0] = -1.0 assert_rel_error(self, J_fwd, J_rev) assert_rel_error(self, J_fwd, J_fd)
def test_reentry(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.shuttle_reentry.shuttle_ode import ShuttleODE from dymos.examples.plotting import plot_results # Instantiate the problem, add the driver, and allow it to use coloring p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring() p.driver.options['optimizer'] = 'SLSQP' # Instantiate the trajectory and add a phase to it traj = p.model.add_subsystem('traj', dm.Trajectory()) phase0 = traj.add_phase( 'phase0', dm.Phase(ode_class=ShuttleODE, transcription=dm.Radau(num_segments=15, order=3))) phase0.set_time_options(fix_initial=True, units='s', duration_ref=200) phase0.add_state('h', fix_initial=True, fix_final=True, units='ft', rate_source='hdot', targets=['h'], lower=0, ref0=75000, ref=300000, defect_ref=1000) phase0.add_state('gamma', fix_initial=True, fix_final=True, units='rad', rate_source='gammadot', targets=['gamma'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('phi', fix_initial=True, fix_final=False, units='rad', rate_source='phidot', lower=0, upper=89. * np.pi / 180) phase0.add_state('psi', fix_initial=True, fix_final=False, units='rad', rate_source='psidot', targets=['psi'], lower=0, upper=90. * np.pi / 180) phase0.add_state('theta', fix_initial=True, fix_final=False, units='rad', rate_source='thetadot', targets=['theta'], lower=-89. * np.pi / 180, upper=89. * np.pi / 180) phase0.add_state('v', fix_initial=True, fix_final=True, units='ft/s', rate_source='vdot', targets=['v'], lower=0, ref0=2500, ref=25000) phase0.add_control('alpha', units='rad', opt=True, lower=-np.pi / 2, upper=np.pi / 2, targets=['alpha']) phase0.add_control('beta', units='rad', opt=True, lower=-89 * np.pi / 180, upper=1 * np.pi / 180, targets=['beta']) # The original implementation by Betts includes a heating rate path constraint. # This will work with the SNOPT optimizer but SLSQP has difficulty converging the solution. # phase0.add_path_constraint('q', lower=0, upper=70, units='Btu/ft**2/s', ref=70) phase0.add_timeseries_output('q', shape=(1, ), units='Btu/ft**2/s') phase0.add_objective('theta', loc='final', ref=-0.01) p.setup(check=True) p.set_val('traj.phase0.states:h', phase0.interpolate(ys=[260000, 80000], nodes='state_input'), units='ft') p.set_val('traj.phase0.states:gamma', phase0.interpolate(ys=[-1, -5], nodes='state_input'), units='deg') p.set_val('traj.phase0.states:phi', phase0.interpolate(ys=[0, 75], nodes='state_input'), units='deg') p.set_val('traj.phase0.states:psi', phase0.interpolate(ys=[90, 10], nodes='state_input'), units='deg') p.set_val('traj.phase0.states:theta', phase0.interpolate(ys=[0, 25], nodes='state_input'), units='deg') p.set_val('traj.phase0.states:v', phase0.interpolate(ys=[25600, 2500], nodes='state_input'), units='ft/s') p.set_val('traj.phase0.t_initial', 0, units='s') p.set_val('traj.phase0.t_duration', 2000, units='s') p.set_val('traj.phase0.controls:alpha', phase0.interpolate(ys=[17.4, 17.4], nodes='control_input'), units='deg') p.set_val('traj.phase0.controls:beta', phase0.interpolate(ys=[-75, 0], nodes='control_input'), units='deg') # Run the driver dm.run_problem(p) # Check the validity of the solution assert_rel_error(self, p.get_val('traj.phase0.timeseries.time')[-1], 2008.59, tolerance=1e-3) assert_rel_error(self, p.get_val('traj.phase0.timeseries.states:theta', units='deg')[-1], 34.1412, tolerance=1e-3) # assert_rel_error(self, p.get_val('traj.phase0.timeseries.time')[-1], 2181.90371131, tolerance=1e-3) # assert_rel_error(self, p.get_val('traj.phase0.timeseries.states:theta')[-1], .53440626, tolerance=1e-3) # Run the simulation to check if the model is physically valid sim_out = traj.simulate() # Plot the results plot_results([ ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.controls:alpha', 'time (s)', 'alpha (rad)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.controls:beta', 'time (s)', 'beta (rad)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:theta', 'time (s)', 'theta (rad)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.q', 'time (s)', 'q (btu/ft/ft/s') ], title='Reentry Solution', p_sol=p, p_sim=sim_out) plt.show()
def test_brachistochrone_quick_start(self): import numpy as np import openmdao.api as om import dymos as dm import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # # Define the OpenMDAO problem # p = om.Problem(model=om.Group()) # # Define a Trajectory object # traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # # Define a Dymos Phase object with GaussLobatto Transcription # phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=10, order=3)) traj.add_phase(name='phase0', phase=phase) # # Set the time options # Time has no targets in our ODE. # We fix the initial time so that the it is not a design variable in the optimization. # The duration of the phase is allowed to be optimized, but is bounded on [0.5, 10]. # phase.set_time_options(fix_initial=True, duration_bounds=(0.5, 10.0), units='s') # # Set the time options # Initial values of positions and velocity are all fixed. # The final value of position are fixed, but the final velocity is a free variable. # The equations of motion are not functions of position, so 'x' and 'y' have no targets. # The rate source points to the output in the ODE which provides the time derivative of the # given state. phase.add_state('x', fix_initial=True, fix_final=True, rate_source='xdot') phase.add_state('y', fix_initial=True, fix_final=True, rate_source='ydot') phase.add_state('v', fix_initial=True, fix_final=False, rate_source='vdot') # Define theta as a control. phase.add_control(name='theta', units='rad', lower=0, upper=np.pi) # Minimize final time. phase.add_objective('time', loc='final') # Set the driver. p.driver = om.ScipyOptimizeDriver() # Allow OpenMDAO to automatically determine our sparsity pattern. # Doing so can significant speed up the execution of Dymos. p.driver.declare_coloring() # Setup the problem p.setup(check=True) # Now that the OpenMDAO problem is setup, we can set the values of the states. p.set_val('traj.phase0.states:x', phase.interpolate(ys=[0, 10], nodes='state_input'), units='m') p.set_val('traj.phase0.states:y', phase.interpolate(ys=[10, 5], nodes='state_input'), units='m') p.set_val('traj.phase0.states:v', phase.interpolate(ys=[0, 5], nodes='state_input'), units='m/s') p.set_val('traj.phase0.controls:theta', phase.interpolate(ys=[90, 90], nodes='control_input'), units='deg') # Run the driver to solve the problem p.run_driver() # Check the validity of our results by using scipy.integrate.solve_ivp to # integrate the solution. sim_out = traj.simulate() # Plot the results fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 4.5)) axes[0].plot(p.get_val('traj.phase0.timeseries.states:x'), p.get_val('traj.phase0.timeseries.states:y'), 'ro', label='solution') axes[0].plot(sim_out.get_val('traj.phase0.timeseries.states:x'), sim_out.get_val('traj.phase0.timeseries.states:y'), 'b-', label='simulation') axes[0].set_xlabel('x (m)') axes[0].set_ylabel('y (m/s)') axes[0].legend() axes[0].grid() axes[1].plot(p.get_val('traj.phase0.timeseries.time'), p.get_val('traj.phase0.timeseries.controls:theta', units='deg'), 'ro', label='solution') axes[1].plot(sim_out.get_val('traj.phase0.timeseries.time'), sim_out.get_val('traj.phase0.timeseries.controls:theta', units='deg'), 'b-', label='simulation') axes[1].set_xlabel('time (s)') axes[1].set_ylabel(r'$\theta$ (deg)') axes[1].legend() axes[1].grid() plt.show()
def test_brachistochrone_tandem_phases(self): from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE import numpy as np import matplotlib.pyplot as plt plt.switch_backend('Agg') import openmdao.api as om import dymos as dm from openmdao.utils.assert_utils import assert_near_equal p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # The transcription of the first phase tx0 = dm.GaussLobatto(num_segments=10, order=3, compressed=False) # The transcription for the second phase (and the secondary timeseries outputs from the first phase) tx1 = dm.Radau(num_segments=20, order=9, compressed=False) # # First Phase: Integrate the standard brachistochrone ODE # phase0 = dm.Phase(ode_class=BrachistochroneODE, transcription=tx0) p.model.add_subsystem('phase0', phase0) phase0.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase0.add_state( 'x', rate_source=BrachistochroneODE.states['x']['rate_source'], units=BrachistochroneODE.states['x']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase0.add_state( 'y', rate_source=BrachistochroneODE.states['y']['rate_source'], units=BrachistochroneODE.states['y']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase0.add_state( 'v', rate_source=BrachistochroneODE.states['v']['rate_source'], units=BrachistochroneODE.states['v']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase0.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase0.add_parameter('g', units='m/s**2', val=9.80665) phase0.add_boundary_constraint('x', loc='final', equals=10) phase0.add_boundary_constraint('y', loc='final', equals=5) # Add alternative timeseries output to provide control inputs for the next phase phase0.add_timeseries('timeseries2', transcription=tx1, subset='control_input') # # Second Phase: Integration of ArcLength # phase1 = dm.Phase(ode_class=BrachistochroneArclengthODE, transcription=tx1) p.model.add_subsystem('phase1', phase1) phase1.set_time_options(fix_initial=True, input_duration=True) phase1.add_state('S', fix_initial=True, fix_final=False, rate_source='Sdot', units='m') phase1.add_control('theta', opt=False, units='deg', targets='theta') phase1.add_control('v', opt=False, units='m/s', targets='v') # # Connect the two phases # p.model.connect('phase0.t_duration', 'phase1.t_duration') p.model.connect('phase0.timeseries2.controls:theta', 'phase1.controls:theta') p.model.connect('phase0.timeseries2.states:v', 'phase1.controls:v') # Minimize arclength at the end of the second phase phase1.add_objective('S', loc='final', ref=1) p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase0.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase0.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase0.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase0.interpolate(ys=[5, 100], nodes='control_input') p['phase0.parameters:g'] = 9.80665 p['phase1.states:S'] = 0.0 dm.run_problem(p) expected = np.sqrt((10 - 0)**2 + (10 - 5)**2) assert_near_equal(p.get_val('phase1.timeseries.states:S')[-1], expected, tolerance=1.0E-3) fig, (ax0, ax1) = plt.subplots(2, 1) fig.tight_layout() ax0.plot(p.get_val('phase0.timeseries.states:x'), p.get_val('phase0.timeseries.states:y'), '.') ax0.set_xlabel('x (m)') ax0.set_ylabel('y (m)') ax1.plot(p.get_val('phase1.timeseries.time'), p.get_val('phase1.timeseries.states:S'), '+') ax1.set_xlabel('t (s)') ax1.set_ylabel('S (m)') plt.show()
def test_double_integrator_for_docs(self): import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.plotting import plot_results from dymos.examples.double_integrator.double_integrator_ode import DoubleIntegratorODE # Initialize the problem and assign the driver p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # Setup the trajectory and its phase traj = p.model.add_subsystem('traj', dm.Trajectory()) transcription = dm.Radau(num_segments=30, order=3, compressed=False) phase = traj.add_phase('phase0', dm.Phase(ode_class=DoubleIntegratorODE, transcription=transcription)) # # Set the options for our variables. # phase.set_time_options(fix_initial=True, fix_duration=True, units='s') phase.add_state('x', fix_initial=True, rate_source='v', units='m') phase.add_state('v', fix_initial=True, fix_final=True, rate_source='u', units='m/s') phase.add_control('u', units='m/s**2', scaler=0.01, continuity=False, rate_continuity=False, rate2_continuity=False, lower=-1.0, upper=1.0) # # Maximize distance travelled. # phase.add_objective('x', loc='final', scaler=-1) p.model.linear_solver = om.DirectSolver() # # Setup the problem and set our initial values. # p.setup(check=True) p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 1.0 p['traj.phase0.states:x'] = phase.interpolate(ys=[0, 0.25], nodes='state_input') p['traj.phase0.states:v'] = phase.interpolate(ys=[0, 0], nodes='state_input') p['traj.phase0.controls:u'] = phase.interpolate(ys=[1, -1], nodes='control_input') # # Solve the problem. # dm.run_problem(p) # # Verify that the results are correct. # x = p.get_val('traj.phase0.timeseries.states:x') v = p.get_val('traj.phase0.timeseries.states:v') assert_rel_error(self, x[0], 0.0, tolerance=1.0E-4) assert_rel_error(self, x[-1], 0.25, tolerance=1.0E-4) assert_rel_error(self, v[0], 0.0, tolerance=1.0E-4) assert_rel_error(self, v[-1], 0.0, tolerance=1.0E-4) # # Simulate the explicit solution and plot the results. # exp_out = traj.simulate() plot_results([('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:x', 'time (s)', 'x $(m)$'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:v', 'time (s)', 'v $(m/s)$'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.controls:u', 'time (s)', 'u $(m/s^2)$')], title='Double Integrator Solution\nRadau Pseudospectral Method', p_sol=p, p_sim=exp_out) plt.show()
def eval_ode_on_grid(phase, transcription): """ Evaluate the ODE from the given phase at all nodes of the given transcription. Parameters ---------- phase : Phase A Phase object which has been executed and whose ODE is to be run at all nodes of the given transcription. transcription : Radau or GaussLobatto transcription instance The transcription object at which to execute the ODE of the given phase at all nodes. Returns ------- dict of (str: ndarray) A dictionary of the state values from the phase interpolated to the new transcription. dict of (str: ndarray) A dictionary of the control values from the phase interpolated to the new transcription. dict of (str: ndarray) A dictionary of the polynomial control values from the phase interpolated to the new transcription. dict of (str: ndarray) A dictionary of the state rates computed in the phase's ODE at the new transcription points. """ x = {} u = {} u_rate = {} u_rate2 = {} p = {} p_rate = {} p_rate2 = {} param = {} f = {} # Build the interpolation matrix which interpolates from all nodes on the old grid to # all nodes on the new grid. grid_data = transcription.grid_data L, _ = interpolation_lagrange_matrix(old_grid=phase.options['transcription'].grid_data, new_grid=grid_data) # Create a new problem for the grid_refinement # For this test, use the same grid as the original problem. p_refine = om.Problem(model=om.Group()) grid_refinement_system = GridRefinementODESystem(grid_data=grid_data, time=phase.time_options, states=phase.state_options, controls=phase.control_options, polynomial_controls=phase.polynomial_control_options, parameters=phase.parameter_options, ode_class=phase.options['ode_class'], ode_init_kwargs=phase.options[ 'ode_init_kwargs']) p_refine.model.add_subsystem('grid_refinement_system', grid_refinement_system, promotes=['*']) p_refine.setup() # Set the values in the refinement problem using the outputs from the first ode = p_refine.model.grid_refinement_system.ode t_prev = phase.get_val('timeseries.time', units=phase.time_options['units']) t_phase_prev = phase.get_val('timeseries.time_phase', units=phase.time_options['units']) t_initial = np.repeat(t_prev[0, 0], repeats=transcription.grid_data.num_nodes, axis=0) t_duration = np.repeat(t_prev[-1, 0], repeats=transcription.grid_data.num_nodes, axis=0) t = np.dot(L, t_prev) t_phase = np.dot(L, t_phase_prev) targets = get_targets(ode, 'time', phase.time_options['targets']) time_phase_targets = get_targets(ode, 'time_phase', phase.time_options['time_phase_targets']) t_initial_targets = get_targets(ode, 't_initial', phase.time_options['t_initial_targets']) t_duration_targets = get_targets(ode, 't_duration', phase.time_options['t_duration_targets']) if targets: p_refine.set_val(f'time', t) if time_phase_targets: p_refine.set_val(f'time_phase', t_phase) if t_initial_targets: p_refine.set_val(f't_initial', t_initial) if t_duration_targets: p_refine.set_val(f't_duration', t_duration) for name, options in phase.state_options.items(): x_prev = phase.get_val(f'timeseries.states:{name}', units=options['units']) x[name] = np.dot(L, x_prev) targets = get_targets(ode, name, options['targets']) if targets: p_refine.set_val(f'states:{name}', x[name]) for name, options in phase.control_options.items(): targets = get_targets(ode, name, options['targets']) rate_targets = get_targets(ode, f'{name}_rate', options['rate_targets']) rate2_targets = get_targets(ode, f'{name}_rate12', options['rate2_targets']) u_prev = phase.get_val(f'timeseries.controls:{name}', units=options['units']) u[name] = np.dot(L, u_prev) if targets: p_refine.set_val(f'controls:{name}', u[name]) u_rate_prev = phase.get_val(f'timeseries.control_rates:{name}_rate') u_rate[name] = np.dot(L, u_rate_prev) if rate_targets: p_refine.set_val(f'control_rates:{name}_rate', u_rate[name]) u_rate2_prev = phase.get_val(f'timeseries.control_rates:{name}_rate2') u_rate2[name] = np.dot(L, u_rate2_prev) if rate2_targets: p_refine.set_val(f'control_rates:{name}_rate2', u_rate2[name]) for name, options in phase.polynomial_control_options.items(): targets = get_targets(ode, name, options['targets']) rate_targets = get_targets(ode, f'{name}_rate', options['rate_targets']) rate2_targets = get_targets(ode, f'{name}_rate2', options['rate2_targets']) p_prev = phase.get_val(f'timeseries.polynomial_controls:{name}', units=options['units']) p[name] = np.dot(L, p_prev) if targets: p_refine.set_val(f'polynomial_controls:{name}', p[name]) p_rate_prev = phase.get_val(f'timeseries.polynomial_control_rates:{name}_rate') p_rate[name] = np.dot(L, p_rate_prev) if rate_targets: p_refine.set_val(f'polynomial_control_rates:{name}_rate', p_rate[name]) p_rate2_prev = phase.get_val(f'timeseries.polynomial_control_rates:{name}_rate2') p_rate2[name] = np.dot(L, p_rate2_prev) if rate2_targets: p_refine.set_val(f'polynomial_control_rates:{name}_rate2', p_rate2[name]) # Configure the parameters for name, options in phase.parameter_options.items(): targets = get_targets(ode, name, options['targets']) # The value of the parameter at one node d = phase.get_val(f'timeseries.parameters:{name}', units=options['units'])[0, ...] # Duplicate along the first axis by the number of nodes in the new transcription param[name] = np.atleast_2d(np.repeat(d, repeats=transcription.grid_data.num_nodes, axis=0)) if targets: p_refine.set_val(f'parameters:{name}', param[name], units=options['units']) # Execute the model p_refine.run_model() # Assign the state rates on the new grid to f for name, options in phase.state_options.items(): rate_units = get_rate_units(options['units'], phase.time_options['units']) rate_source = options['rate_source'] rate_source_class = phase.classify_var(rate_source) if rate_source_class in {'time'}: src_units = phase.time_options['units'] f[name] = om.convert_units(t, src_units, rate_units) elif rate_source_class in {'time_phase'}: src_units = phase.time_options['units'] f[name] = om.convert_units(t_phase, src_units, rate_units) elif rate_source_class in {'state'}: src_units = phase.state_options[rate_source]['units'] f[name] = om.convert_units(x[rate_source], src_units, rate_units) elif rate_source_class in {'input_control', 'indep_control'}: src_units = phase.control_options[rate_source]['units'] f[name] = om.convert_units(u[rate_source], src_units, rate_units) elif rate_source_class in {'control_rate'}: u_name = rate_source[:-5] u_units = phase.control_options[u_name]['units'] src_units = get_rate_units(u_units, phase.time_options['units'], deriv=1) f[name] = om.convert_units(u_rate[rate_source], src_units, rate_units) elif rate_source_class in {'control_rate2'}: u_name = rate_source[:-6] u_units = phase.control_options[u_name]['units'] src_units = get_rate_units(u_units, phase.time_options['units'], deriv=2) f[name] = om.convert_units(u_rate2[rate_source], src_units, rate_units) elif rate_source_class in {'input_polynomial_control', 'indep_polynomial_control'}: src_units = phase.polynomial_control_options[rate_source]['units'] f[name] = om.convert_units(p[rate_source], src_units, rate_units) elif rate_source_class in {'polynomial_control_rate'}: pc_name = rate_source[:-5] pc_units = phase.polynomial_control_options[pc_name]['units'] src_units = get_rate_units(pc_units, phase.time_options['units'], deriv=1) f[name] = om.convert_units(p_rate[rate_source], src_units, rate_units) elif rate_source_class in {'polynomial_control_rate2'}: pc_name = rate_source[:-6] pc_units = phase.polynomial_control_options[pc_name]['units'] src_units = get_rate_units(pc_units, phase.time_options['units'], deriv=2) f[name] = om.convert_units(p_rate2[rate_source], src_units, rate_units) elif rate_source_class in {'parameter'}: src_units = phase.parameter_options[rate_source]['units'] f[name] = om.convert_units(param[rate_source], src_units, rate_units) elif rate_source_class in {'ode'}: f[name] = np.atleast_2d(p_refine.get_val(f'ode.{rate_source}', units=rate_units)) if options['shape'] == (1,): f[name] = f[name].T return x, u, p, f
def run_wisdem(fname_wt_input, fname_modeling_options, fname_opt_options, overridden_values=None): # Load all yaml inputs and validate (also fills in defaults) wt_initial = WindTurbineOntologyPython(fname_wt_input, fname_modeling_options, fname_opt_options) wt_init, modeling_options, opt_options = wt_initial.get_input_data() # Initialize openmdao problem. If running with multiple processors in MPI, use parallel finite differencing equal to the number of cores used. # Otherwise, initialize the WindPark system normally. Get the rank number for parallelization. We only print output files using the root processor. myopt = PoseOptimization(modeling_options, opt_options) if MPI: n_DV = myopt.get_number_design_variables() # Extract the number of cores available max_cores = MPI.COMM_WORLD.Get_size() if max_cores / 2.0 != np.round(max_cores / 2.0): raise ValueError( "ERROR: the parallelization logic only works for an even number of cores available" ) # Define the color map for the parallelization, determining the maximum number of parallel finite difference (FD) evaluations based on the number of design variables (DV). n_FD = min([max_cores, n_DV]) # Define the color map for the cores n_FD = max([n_FD, 1]) comm_map_down, comm_map_up, color_map = map_comm_heirarchical(n_FD, 1) rank = MPI.COMM_WORLD.Get_rank() color_i = color_map[rank] comm_i = MPI.COMM_WORLD.Split(color_i, 1) else: color_i = 0 rank = 0 folder_output = opt_options["general"]["folder_output"] if rank == 0 and not os.path.isdir(folder_output): os.mkdir(folder_output) if color_i == 0: # the top layer of cores enters if MPI: # Parallel settings for OpenMDAO wt_opt = om.Problem(model=om.Group(num_par_fd=n_FD), comm=comm_i) wt_opt.model.add_subsystem("comp", WindPark( modeling_options=modeling_options, opt_options=opt_options), promotes=["*"]) else: # Sequential finite differencing wt_opt = om.Problem(model=WindPark( modeling_options=modeling_options, opt_options=opt_options)) # If at least one of the design variables is active, setup an optimization if opt_options["opt_flag"]: wt_opt = myopt.set_driver(wt_opt) wt_opt = myopt.set_objective(wt_opt) wt_opt = myopt.set_design_variables(wt_opt, wt_init) wt_opt = myopt.set_constraints(wt_opt) wt_opt = myopt.set_recorders(wt_opt) # Setup openmdao problem wt_opt.setup() # Load initial wind turbine data from wt_initial to the openmdao problem wt_opt = yaml2openmdao(wt_opt, modeling_options, wt_init, opt_options) wt_opt = myopt.set_initial(wt_opt, wt_init) # If the user provides values in this dict, they overwrite # whatever values have been set by the yaml files. # This is useful for performing black-box wrapped optimization without # needing to modify the yaml files. if overridden_values is not None: for key in overridden_values: wt_opt[key][:] = overridden_values[key] # Place the last design variables from a previous run into the problem. # This needs to occur after the above setup() and yaml2openmdao() calls # so these values are correctly placed in the problem. wt_opt = myopt.set_restart(wt_opt) if "check_totals" in opt_options["driver"]: if opt_options["driver"]["check_totals"]: wt_opt.run_model() totals = wt_opt.compute_totals() if "check_partials" in opt_options["driver"]: if opt_options["driver"]["check_partials"]: wt_opt.run_model() checks = wt_opt.check_partials(compact_print=True) sys.stdout.flush() # Run openmdao problem if opt_options["opt_flag"]: wt_opt.run_driver() else: wt_opt.run_model() if (not MPI) or (MPI and rank == 0): # Save data coming from openmdao to an output yaml file froot_out = os.path.join(folder_output, opt_options["general"]["fname_output"]) wt_initial.write_ontology(wt_opt, froot_out) wt_initial.write_options(froot_out) # Save data to numpy and matlab arrays fileIO.save_data(froot_out, wt_opt) if rank == 0: return wt_opt, modeling_options, opt_options else: return [], [], []
def test_control_interp_scalar(self, transcription='gauss-lobatto', compressed=True): segends = np.array([0.0, 3.0, 10.0]) gd = GridData(num_segments=2, transcription_order=5, segment_ends=segends, transcription=transcription, compressed=compressed) p = om.Problem(model=om.Group()) controls = { 'a': { 'units': 'm', 'shape': (1, ), 'dynamic': True }, 'b': { 'units': 'm', 'shape': (1, ), 'dynamic': True } } ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('controls:a', val=np.zeros((gd.subset_num_nodes['control_input'], 1)), units='m') ivc.add_output('controls:b', val=np.zeros((gd.subset_num_nodes['control_input'], 1)), units='m') ivc.add_output('t_initial', val=0.0, units='s') ivc.add_output('t_duration', val=10.0, units='s') p.model.add_subsystem('time_comp', subsys=TimeComp( num_nodes=gd.num_nodes, node_ptau=gd.node_ptau, node_dptau_dstau=gd.node_dptau_dstau, units='s'), promotes_inputs=['t_initial', 't_duration'], promotes_outputs=['time', 'dt_dstau']) p.model.add_subsystem('control_interp_comp', subsys=ControlInterpComp( grid_data=gd, control_options=controls, time_units='s'), promotes_inputs=['controls:*']) p.model.connect('dt_dstau', 'control_interp_comp.dt_dstau') p.setup(force_alloc_complex=True) p['t_initial'] = 0.0 p['t_duration'] = 3.0 p.run_model() t = p['time'] p['controls:a'][:, 0] = f_a(t[gd.subset_node_indices['control_input']]) p['controls:b'][:, 0] = f_b(t[gd.subset_node_indices['control_input']]) p.run_model() a_value_expected = f_a(t) b_value_expected = f_b(t) a_rate_expected = f1_a(t) b_rate_expected = f1_b(t) a_rate2_expected = f2_a(t) b_rate2_expected = f2_b(t) assert_almost_equal(p['control_interp_comp.control_values:a'], np.atleast_2d(a_value_expected).T) assert_almost_equal(p['control_interp_comp.control_values:b'], np.atleast_2d(b_value_expected).T) assert_almost_equal(p['control_interp_comp.control_rates:a_rate'], np.atleast_2d(a_rate_expected).T) assert_almost_equal(p['control_interp_comp.control_rates:b_rate'], np.atleast_2d(b_rate_expected).T) assert_almost_equal(p['control_interp_comp.control_rates:a_rate2'], np.atleast_2d(a_rate2_expected).T) assert_almost_equal(p['control_interp_comp.control_rates:b_rate2'], np.atleast_2d(b_rate2_expected).T) np.set_printoptions(linewidth=1024) cpd = p.check_partials(compact_print=False, method='cs') assert_check_partials(cpd)
def test_control_interp_matrix_2x2(self, transcription='gauss-lobatto', compressed=True): segends = np.array([0.0, 3.0, 10.0]) gd = GridData(num_segments=2, transcription_order=5, segment_ends=segends, transcription=transcription, compressed=compressed) p = om.Problem(model=om.Group()) controls = {'a': {'units': 'm', 'shape': (2, 2), 'dynamic': True}} ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('controls:a', val=np.zeros( (gd.subset_num_nodes['control_input'], 2, 2)), units='m') ivc.add_output('t_initial', val=0.0, units='s') ivc.add_output('t_duration', val=10.0, units='s') p.model.add_subsystem('time_comp', subsys=TimeComp( num_nodes=gd.num_nodes, node_ptau=gd.node_ptau, node_dptau_dstau=gd.node_dptau_dstau, units='s'), promotes_inputs=['t_initial', 't_duration'], promotes_outputs=['time', 'dt_dstau']) p.model.add_subsystem('control_interp_comp', subsys=ControlInterpComp( grid_data=gd, control_options=controls, time_units='s'), promotes_inputs=['controls:*']) p.model.connect('dt_dstau', 'control_interp_comp.dt_dstau') p.setup(force_alloc_complex=True) p['t_initial'] = 0.0 p['t_duration'] = 3.0 p.run_model() t = p['time'] control_input_idxs = gd.subset_node_indices['control_input'] p['controls:a'][:, 0, 0] = f_a(t[control_input_idxs]) p['controls:a'][:, 0, 1] = f_b(t[control_input_idxs]) p['controls:a'][:, 1, 0] = f_c(t[control_input_idxs]) p['controls:a'][:, 1, 1] = f_d(t[control_input_idxs]) p.run_model() a0_value_expected = f_a(t) a1_value_expected = f_b(t) a2_value_expected = f_c(t) a3_value_expected = f_d(t) a0_rate_expected = f1_a(t) a1_rate_expected = f1_b(t) a2_rate_expected = f1_c(t) a3_rate_expected = f1_d(t) a0_rate2_expected = f2_a(t) a1_rate2_expected = f2_b(t) a2_rate2_expected = f2_c(t) a3_rate2_expected = f2_d(t) assert_almost_equal(p['control_interp_comp.control_values:a'][:, 0, 0], a0_value_expected) assert_almost_equal(p['control_interp_comp.control_values:a'][:, 0, 1], a1_value_expected) assert_almost_equal(p['control_interp_comp.control_values:a'][:, 1, 0], a2_value_expected) assert_almost_equal(p['control_interp_comp.control_values:a'][:, 1, 1], a3_value_expected) assert_almost_equal( p['control_interp_comp.control_rates:a_rate'][:, 0, 0], a0_rate_expected) assert_almost_equal( p['control_interp_comp.control_rates:a_rate'][:, 0, 1], a1_rate_expected) assert_almost_equal( p['control_interp_comp.control_rates:a_rate'][:, 1, 0], a2_rate_expected) assert_almost_equal( p['control_interp_comp.control_rates:a_rate'][:, 1, 1], a3_rate_expected) assert_almost_equal( p['control_interp_comp.control_rates:a_rate2'][:, 0, 0], a0_rate2_expected) assert_almost_equal( p['control_interp_comp.control_rates:a_rate2'][:, 0, 1], a1_rate2_expected) assert_almost_equal( p['control_interp_comp.control_rates:a_rate2'][:, 1, 0], a2_rate2_expected) assert_almost_equal( p['control_interp_comp.control_rates:a_rate2'][:, 1, 1], a3_rate2_expected) with np.printoptions(linewidth=100000, edgeitems=100000): cpd = p.check_partials(compact_print=True, method='cs') assert_check_partials(cpd)
def test_simulate_array_param(self): # # Initialize the Problem and the optimization driver # p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() # # Create a trajectory and add a phase to it # traj = p.model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=10))) # # Set the variables # phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=True, fix_final=True, rate_source='xdot') phase.add_state('y', fix_initial=True, fix_final=True, rate_source='ydot') phase.add_state('v', fix_initial=True, fix_final=False, rate_source='vdot') phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', units='m/s**2', val=9.80665) phase.add_parameter('array', units=None, shape=(10, ), dynamic=False) # dummy array of data indeps = p.model.add_subsystem('indeps', om.IndepVarComp(), promotes=['*']) indeps.add_output('array', np.linspace(1, 10, 10), units=None) # add dummy array as a parameter and connect it p.model.connect('array', 'traj.phase0.parameters:array') # # Minimize time at the end of the phase # phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() # # Setup the Problem # p.setup() # # Set the initial values # p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 2.0 p['traj.phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['traj.phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['traj.phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['traj.phase0.controls:theta'] = phase.interpolate( ys=[5, 100.5], nodes='control_input') # # Solve for the optimal trajectory # dm.run_problem(p, simulate=True) # Test the results sol_results = om.CaseReader('dymos_solution.db').get_case('final') sim_results = om.CaseReader('dymos_solution.db').get_case('final') sol = sol_results.get_val('traj.phase0.timeseries.parameters:array') sim = sim_results.get_val('traj.phase0.timeseries.parameters:array') assert_near_equal(sol - sim, np.zeros_like(sol)) # Test that the parameter is available in the solution and simulation files sol = sol_results.get_val('traj.phase0.parameters:array') sim = sim_results.get_val('traj.phase0.parameters:array') assert_near_equal(sol - sim, np.zeros_like(sol))
def test_doc_ssto_earth(self): import matplotlib.pyplot as plt import openmdao.api as om import dymos as dm # # Setup and solve the optimal control problem # p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring() from dymos.examples.ssto.launch_vehicle_ode import LaunchVehicleODE # # Initialize our Trajectory and Phase # traj = dm.Trajectory() phase = dm.Phase(ode_class=LaunchVehicleODE, ode_init_kwargs={'central_body': 'earth'}, transcription=dm.GaussLobatto(num_segments=12, order=3, compressed=False)) traj.add_phase('phase0', phase) p.model.add_subsystem('traj', traj) # # Set the options for the variables # phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(10, 500)) phase.add_state('x', fix_initial=True, ref=1.0E5, defect_ref=1.0, rate_source='eom.xdot', units='m') phase.add_state('y', fix_initial=True, ref=1.0E5, defect_ref=1.0, rate_source='eom.ydot', targets=['atmos.y'], units='m') phase.add_state('vx', fix_initial=True, ref=1.0E3, defect_ref=1.0, rate_source='eom.vxdot', targets=['eom.vx'], units='m/s') phase.add_state('vy', fix_initial=True, ref=1.0E3, defect_ref=1.0, rate_source='eom.vydot', targets=['eom.vy'], units='m/s') phase.add_state('m', fix_initial=True, ref=1.0E3, defect_ref=1.0, rate_source='eom.mdot', targets=['eom.m'], units='kg') phase.add_control('theta', units='rad', lower=-1.57, upper=1.57, targets=['eom.theta']) phase.add_parameter('thrust', units='N', opt=False, val=2100000.0, targets=['eom.thrust']) # # Set the options for our constraints and objective # 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_objective('time', loc='final', scaler=0.01) p.model.linear_solver = om.DirectSolver() # # Setup and set initial values # p.setup(check=True) p.set_val('traj.phase0.t_initial', 0.0) p.set_val('traj.phase0.t_duration', 150.0) p.set_val('traj.phase0.states:x', phase.interpolate(ys=[0, 1.15E5], nodes='state_input')) p.set_val('traj.phase0.states:y', phase.interpolate(ys=[0, 1.85E5], nodes='state_input')) p.set_val('traj.phase0.states:vx', phase.interpolate(ys=[0, 7796.6961], nodes='state_input')) p.set_val('traj.phase0.states:vy', phase.interpolate(ys=[1.0E-6, 0], nodes='state_input')) p.set_val('traj.phase0.states:m', phase.interpolate(ys=[117000, 1163], nodes='state_input')) p.set_val('traj.phase0.controls:theta', phase.interpolate(ys=[1.5, -0.76], nodes='control_input')) p.set_val('traj.phase0.parameters:thrust', 2.1, units='MN') # # Solve the Problem # dm.run_problem(p) assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1], 143, tolerance=0.05) assert_near_equal(p.get_val('traj.phase0.timeseries.states:y')[-1], 1.85E5, 1e-4) assert_near_equal(p.get_val('traj.phase0.timeseries.states:vx')[-1], 7796.6961, 1e-4) assert_near_equal(p.get_val('traj.phase0.timeseries.states:vy')[-1], 0, 1e-4) # # Get the explicitly simulated results # exp_out = traj.simulate() # # Plot the results # fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(10, 8)) axes[0].plot(p.get_val('traj.phase0.timeseries.states:x'), p.get_val('traj.phase0.timeseries.states:y'), marker='o', ms=4, linestyle='None', label='solution') axes[0].plot(exp_out.get_val('traj.phase0.timeseries.states:x'), exp_out.get_val('traj.phase0.timeseries.states:y'), marker=None, linestyle='-', label='simulation') axes[0].set_xlabel('range (m)') axes[0].set_ylabel('altitude (m)') axes[0].set_aspect('equal') axes[1].plot(p.get_val('traj.phase0.timeseries.time'), p.get_val('traj.phase0.timeseries.controls:theta'), marker='o', ms=4, linestyle='None') axes[1].plot(exp_out.get_val('traj.phase0.timeseries.time'), exp_out.get_val('traj.phase0.timeseries.controls:theta'), linestyle='-', marker=None) axes[1].set_xlabel('time (s)') axes[1].set_ylabel('theta (deg)') plt.suptitle('Single Stage to Orbit Solution Using Linear Tangent Guidance') fig.legend(loc='lower center', ncol=2) plt.show()
def test_continuity_comp_vector_newton_fwd(self): num_seg = 2 state_options = { 'y': { 'shape': (2, ), 'units': 'm', 'targets': ['y'], 'fix_initial': True, 'fix_final': False, 'defect_ref': 1, 'lower': None, 'upper': None, 'connected_initial': False } } p = om.Problem(model=om.Group()) p.model.add_subsystem('continuity_comp', RungeKuttaStateContinuityComp( num_segments=num_seg, state_options=state_options), promotes_inputs=['*'], promotes_outputs=['*']) p.model.nonlinear_solver = om.NewtonSolver(iprint=2) p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['states:y'] = np.array([[0.50000000, 2.639602661132812], [1.425130208333333, 4.006818970044454], [2.639602661132812, 5.301605229265987]]) p['state_integrals:y'] = np.array([[1.0, 1.0], [1.0, 1.0]]) p.run_model() # Test that the residuals of the states are the expected values outputs = p.model.list_outputs(print_arrays=True, residuals=True, out_stream=None) expected_resids = np.zeros((num_seg + 1, 2)) op_dict = dict([op for op in outputs]) assert_rel_error(self, op_dict['continuity_comp.states:y']['resids'], expected_resids) # Test the partials cpd = p.check_partials(method='cs', out_stream=None) J_fwd = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_fwd'] J_rev = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_rev'] J_fd = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_fd'] assert_rel_error(self, J_fwd, J_rev) assert_rel_error(self, J_fwd, J_fd) J_fwd = cpd['continuity_comp']['states:y', 'states:y']['J_fwd'] J_rev = cpd['continuity_comp']['states:y', 'states:y']['J_rev'] J_fd = cpd['continuity_comp']['states:y', 'states:y']['J_fd'] size = np.prod(state_options['y']['shape']) J_fd[:size, :size] = -np.eye(size) assert_rel_error(self, J_fwd, J_rev) assert_rel_error(self, J_fwd, J_fd)
def test_hyper_sensitive_for_docs(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.plotting import plot_results from dymos.examples.hyper_sensitive.hyper_sensitive_ode import HyperSensitiveODE # Initialize the problem and assign the driver p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # Setup the trajectory and its phase traj = p.model.add_subsystem('traj', dm.Trajectory()) transcription = dm.Radau(num_segments=30, order=3, compressed=False) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=HyperSensitiveODE, transcription=transcription)) phase.set_time_options(fix_initial=True, fix_duration=True) phase.add_state('x', fix_initial=True, fix_final=False, rate_source='x_dot', targets=['x']) phase.add_state('xL', fix_initial=True, fix_final=False, rate_source='L', targets=['xL']) phase.add_control('u', opt=True, targets=['u']) phase.add_boundary_constraint('x', loc='final', equals=1) phase.add_objective('xL', loc='final') p.setup(check=True) p.set_val('traj.phase0.states:x', phase.interpolate(ys=[1.5, 1], nodes='state_input')) p.set_val('traj.phase0.states:xL', phase.interpolate(ys=[0, 1], nodes='state_input')) p.set_val('traj.phase0.t_initial', 0) p.set_val('traj.phase0.t_duration', tf) p.set_val('traj.phase0.controls:u', phase.interpolate(ys=[-0.6, 2.4], nodes='control_input')) # # Solve the problem. # dm.run_problem(p) # # Verify that the results are correct. # ui, uf, J = solution() assert_near_equal(p.get_val('traj.phase0.timeseries.controls:u')[0], ui, tolerance=1.5e-2) assert_near_equal(p.get_val('traj.phase0.timeseries.controls:u')[-1], uf, tolerance=1.5e-2) assert_near_equal(p.get_val('traj.phase0.timeseries.states:xL')[-1], J, tolerance=1e-2) # # Simulate the explicit solution and plot the results. # exp_out = traj.simulate() plot_results( [('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:x', 'time (s)', 'x $(m)$'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.controls:u', 'time (s)', 'u $(m/s^2)$')], title= 'Hyper Sensitive Problem Solution\nRadau Pseudospectral Method', p_sol=p, p_sim=exp_out) plt.show()
def test_simple_list_vars_options(self): import openmdao.api as om class QuadraticComp(om.ImplicitComponent): """ A Simple Implicit Component representing a Quadratic Equation. R(a, b, c, x) = ax^2 + bx + c Solution via Quadratic Formula: x = (-b + sqrt(b^2 - 4ac)) / 2a """ def setup(self): self.add_input('a', val=1., units='ft') self.add_input('b', val=1., units='inch') self.add_input('c', val=1., units='ft') self.add_output('x', val=0., lower=1.0, upper=100.0, ref=1.1, ref0=2.1, units='inch') self.declare_partials(of='*', wrt='*') def apply_nonlinear(self, inputs, outputs, residuals): a = inputs['a'] b = inputs['b'] c = inputs['c'] x = outputs['x'] residuals['x'] = a * x**2 + b * x + c def solve_nonlinear(self, inputs, outputs): a = inputs['a'] b = inputs['b'] c = inputs['c'] outputs['x'] = (-b + (b**2 - 4 * a * c)**0.5) / (2 * a) group = om.Group() comp1 = group.add_subsystem('comp1', om.IndepVarComp()) comp1.add_output('a', 1.0, units='ft') comp1.add_output('b', 1.0, units='inch') comp1.add_output('c', 1.0, units='ft') sub = group.add_subsystem('sub', om.Group()) sub.add_subsystem('comp2', QuadraticComp()) sub.add_subsystem('comp3', QuadraticComp()) group.connect('comp1.a', 'sub.comp2.a') group.connect('comp1.b', 'sub.comp2.b') group.connect('comp1.c', 'sub.comp2.c') group.connect('comp1.a', 'sub.comp3.a') group.connect('comp1.b', 'sub.comp3.b') group.connect('comp1.c', 'sub.comp3.c') global prob prob = om.Problem(model=group) prob.setup() prob['comp1.a'] = 1. prob['comp1.b'] = -4. prob['comp1.c'] = 3. prob.run_model() # list_inputs test stream = cStringIO() inputs = prob.model.list_inputs(values=False, out_stream=stream) text = stream.getvalue() self.assertEqual(sorted(inputs), [ ('sub.comp2.a', {}), ('sub.comp2.b', {}), ('sub.comp2.c', {}), ('sub.comp3.a', {}), ('sub.comp3.b', {}), ('sub.comp3.c', {}), ]) self.assertEqual(1, text.count("6 Input(s) in 'model'")) self.assertEqual(1, text.count("top")) self.assertEqual(1, text.count(" sub")) self.assertEqual(1, text.count(" comp2")) self.assertEqual(2, text.count(" a")) num_non_empty_lines = sum([1 for s in text.splitlines() if s.strip()]) self.assertEqual(num_non_empty_lines, 14) # list_outputs tests # list implicit outputs outputs = prob.model.list_outputs(explicit=False, out_stream=None) text = stream.getvalue() self.assertEqual(sorted(outputs), [('sub.comp2.x', { 'value': [3.] }), ('sub.comp3.x', { 'value': [3.] })]) # list explicit outputs stream = cStringIO() outputs = prob.model.list_outputs(implicit=False, out_stream=None) self.assertEqual(sorted(outputs), [ ('comp1.a', { 'value': [1.] }), ('comp1.b', { 'value': [-4.] }), ('comp1.c', { 'value': [3.] }), ])
def test_min_time_climb_for_docs_gauss_lobatto(self): import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.min_time_climb.min_time_climb_ode import MinTimeClimbODE from dymos.examples.plotting import plot_results # # Instantiate the problem and configure the optimization driver # p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() # # Instantiate the trajectory and phase # traj = dm.Trajectory() phase = dm.Phase(ode_class=MinTimeClimbODE, transcription=dm.GaussLobatto(num_segments=15, compressed=False)) traj.add_phase('phase0', phase) p.model.add_subsystem('traj', traj) # # Set the options on the optimization variables # Note the use of explicit state units here since much of the ODE uses imperial units # and we prefer to solve this problem using metric units. # phase.set_time_options(fix_initial=True, duration_bounds=(50, 400), duration_ref=100.0) phase.add_state('r', fix_initial=True, lower=0, upper=1.0E6, units='m', ref=1.0E3, defect_ref=1.0E3, rate_source='flight_dynamics.r_dot') phase.add_state('h', fix_initial=True, lower=0, upper=20000.0, units='m', ref=1.0E2, defect_ref=1.0E2, rate_source='flight_dynamics.h_dot') phase.add_state('v', fix_initial=True, lower=10.0, units='m/s', ref=1.0E2, defect_ref=1.0E2, rate_source='flight_dynamics.v_dot') phase.add_state('gam', fix_initial=True, lower=-1.5, upper=1.5, units='rad', ref=1.0, defect_ref=1.0, rate_source='flight_dynamics.gam_dot') phase.add_state('m', fix_initial=True, lower=10.0, upper=1.0E5, units='kg', ref=1.0E3, defect_ref=1.0E3, rate_source='prop.m_dot') phase.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0, rate_continuity=True, rate_continuity_scaler=100.0, rate2_continuity=False) phase.add_parameter('S', val=49.2386, units='m**2', opt=False, targets=['S']) phase.add_parameter('Isp', val=1600.0, units='s', opt=False, targets=['Isp']) phase.add_parameter('throttle', val=1.0, opt=False, targets=['throttle']) # # Setup the boundary and path constraints # phase.add_boundary_constraint('h', loc='final', equals=20000, scaler=1.0E-3) phase.add_boundary_constraint('aero.mach', loc='final', equals=1.0) phase.add_boundary_constraint('gam', loc='final', equals=0.0) phase.add_path_constraint(name='h', lower=100.0, upper=20000, ref=20000) phase.add_path_constraint(name='aero.mach', lower=0.1, upper=1.8) # Minimize time at the end of the phase phase.add_objective('time', loc='final', ref=1.0) p.model.linear_solver = om.DirectSolver() # # Setup the problem and set the initial guess # p.setup(check=True) p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 500 p['traj.phase0.states:r'] = phase.interpolate(ys=[0.0, 50000.0], nodes='state_input') p['traj.phase0.states:h'] = phase.interpolate(ys=[100.0, 20000.0], nodes='state_input') p['traj.phase0.states:v'] = phase.interpolate(ys=[135.964, 283.159], nodes='state_input') p['traj.phase0.states:gam'] = phase.interpolate(ys=[0.0, 0.0], nodes='state_input') p['traj.phase0.states:m'] = phase.interpolate(ys=[19030.468, 10000.], nodes='state_input') p['traj.phase0.controls:alpha'] = phase.interpolate( ys=[0.0, 0.0], nodes='control_input') # # Solve for the optimal trajectory # dm.run_problem(p) # # Test the results # assert_near_equal(p.get_val('traj.phase0.t_duration'), 321.0, tolerance=1.0E-1) # # Get the explicitly simulated solution and plot the results # exp_out = traj.simulate() plot_results( [('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:h', 'time (s)', 'altitude (m)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.controls:alpha', 'time (s)', 'alpha (deg)')], title='Supersonic Minimum Time-to-Climb Solution', p_sol=p, p_sim=exp_out) plt.show()
rows = np.arange(n_in) cols = rows self.declare_partials('GLs', 'k', rows=rows, cols=cols) def compute(self, inputs, outputs): SF = self.options['SF'] outputs['GLs'] = SF * inputs['k'] def compute_partials(self, inputs, partials): SF = self.options['SF'] partials['GLs', 'k'] = SF #for testing if __name__ == "__main__": model = om.Group() n = 4 SF = list(range(1, n)) comp = om.IndepVarComp() comp.add_output('k', shape=n) model.add_subsystem('input', comp) model.add_subsystem('example', LinearCondComp(SF=SF)) model.connect('input.k', 'example.k') problem = om.Problem(model=model) problem.setup() problem.run_model() totals = problem.compute_totals(['example.GLs'], ['input.k'])
def setup(self): surfaces = self.options['surfaces'] rotational = self.options['rotational'] coupled = om.Group() for surface in surfaces: name = surface['name'] # Connect the output of the loads component with the FEM # displacement parameter. This links the coupling within the coupled # group that necessitates the subgroup solver. coupled.connect(name + '_loads.loads', name + '.loads') # Perform the connections with the modified names within the # 'aero_states' group. coupled.connect(name + '.normals', 'aero_states.' + name + '_normals') coupled.connect(name + '.def_mesh', 'aero_states.' + name + '_def_mesh') # Connect the results from 'coupled' to the performance groups coupled.connect(name + '.def_mesh', name + '_loads.def_mesh') coupled.connect('aero_states.' + name + '_sec_forces', name + '_loads.sec_forces') # Connect the results from 'aero_states' to the performance groups self.connect('coupled.aero_states.' + name + '_sec_forces', name + '_perf' + '.sec_forces') # Connection performance functional variables self.connect(name + '_perf.CL', 'total_perf.' + name + '_CL') self.connect(name + '_perf.CD', 'total_perf.' + name + '_CD') self.connect('coupled.aero_states.' + name + '_sec_forces', 'total_perf.' + name + '_sec_forces') self.connect('coupled.' + name + '.chords', name + '_perf.aero_funcs.chords') # Connect parameters from the 'coupled' group to the performance # groups for the individual surfaces. self.connect('coupled.' + name + '.disp', name + '_perf.disp') self.connect('coupled.' + name + '.S_ref', name + '_perf.S_ref') self.connect('coupled.' + name + '.widths', name + '_perf.widths') # self.connect('coupled.' + name + '.chords', name + '_perf.chords') self.connect('coupled.' + name + '.lengths', name + '_perf.lengths') self.connect('coupled.' + name + '.cos_sweep', name + '_perf.cos_sweep') # Connect parameters from the 'coupled' group to the total performance group. self.connect('coupled.' + name + '.S_ref', 'total_perf.' + name + '_S_ref') self.connect('coupled.' + name + '.widths', 'total_perf.' + name + '_widths') self.connect('coupled.' + name + '.chords', 'total_perf.' + name + '_chords') self.connect('coupled.' + name + '.b_pts', 'total_perf.' + name + '_b_pts') # Add components to the 'coupled' group for each surface. # The 'coupled' group must contain all components and parameters # needed to converge the aerostructural system. coupled_AS_group = CoupledAS(surface=surface) if surface[ 'distributed_fuel_weight'] or 'n_point_masses' in surface.keys( ) or surface['struct_weight_relief']: prom_in = ['load_factor'] else: prom_in = [] coupled.add_subsystem(name, coupled_AS_group, promotes_inputs=prom_in) if self.options['compressible'] == True: aero_states = CompressibleVLMStates(surfaces=surfaces, rotational=rotational) prom_in = ['v', 'alpha', 'beta', 'rho', 'Mach_number'] else: aero_states = VLMStates(surfaces=surfaces, rotational=rotational) prom_in = ['v', 'alpha', 'beta', 'rho'] # Add a single 'aero_states' component for the whole system within the # coupled group. coupled.add_subsystem('aero_states', aero_states, promotes_inputs=prom_in) # Explicitly connect parameters from each surface's group and the common # 'aero_states' group. for surface in surfaces: name = surface['name'] # Add a loads component to the coupled group coupled.add_subsystem(name + '_loads', LoadTransfer(surface=surface)) """ ### Change the solver settings here ### """ # Set solver properties for the coupled group # coupled.linear_solver = ScipyKrylov() # coupled.linear_solver.precon = om.LinearRunOnce() coupled.nonlinear_solver = om.NonlinearBlockGS(use_aitken=True) coupled.nonlinear_solver.options['maxiter'] = 100 coupled.nonlinear_solver.options['atol'] = 1e-7 coupled.nonlinear_solver.options['rtol'] = 1e-30 coupled.nonlinear_solver.options['iprint'] = 2 coupled.nonlinear_solver.options['err_on_non_converge'] = True # coupled.linear_solver = om.DirectSolver() coupled.linear_solver = om.DirectSolver(assemble_jac=True) coupled.options['assembled_jac_type'] = 'csc' # coupled.nonlinear_solver = om.NewtonSolver(solve_subsystems=True) # coupled.nonlinear_solver.options['maxiter'] = 50 """ ### End change of solver settings ### """ prom_in = ['v', 'alpha', 'beta', 'rho'] if self.options['compressible'] == True: prom_in.append('Mach_number') # Add the coupled group to the model problem self.add_subsystem('coupled', coupled, promotes_inputs=prom_in) for surface in surfaces: name = surface['name'] # Add a performance group which evaluates the data after solving # the coupled system perf_group = CoupledPerformance(surface=surface) self.add_subsystem(name + '_perf', perf_group, promotes_inputs=[ 'rho', 'v', 'alpha', 'beta', 're', 'Mach_number' ]) # Add functionals to evaluate performance of the system. # Note that only the interesting results are promoted here; not all # of the parameters. self.add_subsystem( 'total_perf', TotalPerformance( surfaces=surfaces, user_specified_Sref=self.options['user_specified_Sref'], internally_connect_fuelburn=self. options['internally_connect_fuelburn']), promotes_inputs=[ 'v', 'rho', 'empty_cg', 'total_weight', 'CT', 'speed_of_sound', 'R', 'Mach_number', 'W0', 'load_factor', 'S_ref_total' ], promotes_outputs=[ 'L_equals_W', 'fuelburn', 'CL', 'CD', 'CM', 'cg' ])
def test_connect_control_to_parameter(self): """ Test that the final value of a control in one phase can be connected as the value of a parameter in a subsequent phase. """ import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.cannonball.size_comp import CannonballSizeComp p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() external_params = p.model.add_subsystem('external_params', om.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', dm.Trajectory()) transcription = dm.Radau(num_segments=5, order=3, compressed=True) ascent = dm.Phase(ode_class=CannonballODEVectorCD, 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.add_state('r', fix_initial=True, fix_final=False, rate_source='r_dot', units='m') ascent.add_state('h', fix_initial=True, fix_final=False, units='m', rate_source='h_dot') ascent.add_state('gam', fix_initial=False, fix_final=True, units='rad', rate_source='gam_dot') ascent.add_state('v', fix_initial=False, fix_final=False, units='m/s', rate_source='v_dot') ascent.add_parameter('S', targets=['S'], units='m**2', dynamic=False) ascent.add_parameter('mass', targets=['m'], units='kg', dynamic=False) ascent.add_control('CD', targets=['CD'], opt=False, val=0.05) # Limit the muzzle energy ascent.add_boundary_constraint('ke', loc='initial', upper=400000, lower=0, ref=100000) # Second Phase (descent) transcription = dm.GaussLobatto(num_segments=5, order=3, compressed=True) descent = dm.Phase(ode_class=CannonballODEVectorCD, 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, units='s') descent.add_state('r', units='m', rate_source='r_dot') descent.add_state('h', units='m', rate_source='h_dot', fix_initial=False, fix_final=True) descent.add_state('gam', units='rad', rate_source='gam_dot', fix_initial=False, fix_final=False) descent.add_state('v', units='m/s', rate_source='v_dot', fix_initial=False, fix_final=False) descent.add_parameter('S', targets=['S'], units='m**2', dynamic=False) descent.add_parameter('mass', targets=['m'], units='kg', dynamic=False) descent.add_parameter('CD', targets=['CD'], val=0.01) descent.add_objective('r', loc='final', scaler=-1.0) # Add externally-provided design parameters to the trajectory. # In this case, we connect 'm' to pre-existing input parameters named 'mass' in each phase. traj.add_parameter('m', units='kg', val=1.0, targets={'ascent': 'mass', 'descent': 'mass'}, dynamic=False) # In this case, by omitting targets, we're connecting these parameters to parameters # with the same name in each phase. traj.add_parameter('S', units='m**2', val=0.005, dynamic=False) # 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.parameters:m') p.model.connect('size_comp.S', 'traj.parameters:S') traj.connect('ascent.timeseries.controls:CD', 'descent.parameters:CD', src_indices=[-1]) # A linear solver at the top level can improve performance. p.model.linear_solver = om.DirectSolver() # Finish Problem Setup p.setup() # 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.ascent.controls:CD', 0.5) 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') dm.run_problem(p, simulate=True, make_plots=True) assert_near_equal(p.get_val('traj.descent.states:r')[-1], 3183.25, tolerance=1.0E-2) assert_near_equal(p.get_val('traj.ascent.timeseries.controls:CD')[-1], p.get_val('traj.descent.timeseries.parameters:CD')[0])
def test_static_params(self): prob = om.Problem(model=om.Group()) traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. # NOTE: using RK4 integration here P_DEMAND = 2.0 phase0 = dm.Phase(ode_class=BatteryODE, transcription=dm.RungeKutta(num_segments=200)) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.add_state('state_of_charge', fix_initial=True, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') phase0.add_timeseries_output('battery.V_oc', output_name='V_oc', 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') traj.add_phase('phase0', phase0) # Second phase: normal operation. transcription = dm.Radau(num_segments=5, order=5, compressed=True) phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) phase1.set_time_options(fix_initial=False, fix_duration=True) phase1.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') 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') traj.add_phase('phase1', phase1) # Second phase, but with battery failure. phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, transcription=transcription) phase1_bfail.set_time_options(fix_initial=False, fix_duration=True) phase1_bfail.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') 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') traj.add_phase('phase1_bfail', phase1_bfail) # Second phase, but with motor failure. phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, transcription=transcription) phase1_mfail.set_time_options(fix_initial=False, fix_duration=True) phase1_mfail.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') 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') traj.add_phase('phase1_mfail', phase1_mfail) traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) # prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() prob.final_setup() prob['traj.phases.phase0.time_extents.t_initial'] = 0 prob['traj.phases.phase0.time_extents.t_duration'] = 1.0 * 3600 # prob['traj.phases.phase1.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1.time_extents.t_duration'] = 1.0 * 3600 # prob['traj.phases.phase1_bfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_bfail.time_extents.t_duration'] = 1.0 * 3600 # prob['traj.phases.phase1_mfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_mfail.time_extents.t_duration'] = 1.0 * 3600 prob.set_solver_print(level=0) prob.run_model() plot = True if plot: import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt t0 = prob['traj.phase0.timeseries.time'] t1 = prob['traj.phase1.timeseries.time'] t1b = prob['traj.phase1_bfail.timeseries.time'] t1m = prob['traj.phase1_mfail.timeseries.time'] soc0 = prob['traj.phase0.timeseries.states:state_of_charge'] soc1 = prob['traj.phase1.timeseries.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.timeseries.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.timeseries.states:state_of_charge'] plt.subplot(2, 2, 1) plt.plot(t0, soc0, 'b') plt.plot(t1, soc1, 'b') plt.plot(t1b, soc1b, 'r') plt.plot(t1m, soc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('State of Charge (percent)') V_oc0 = prob['traj.phase0.timeseries.V_oc'] V_oc1 = prob['traj.phase1.timeseries.V_oc'] V_oc1b = prob['traj.phase1_bfail.timeseries.V_oc'] V_oc1m = prob['traj.phase1_mfail.timeseries.V_oc'] plt.subplot(2, 2, 2) plt.plot(t0, V_oc0, 'b') plt.plot(t1, V_oc1, 'b') plt.plot(t1b, V_oc1b, 'r') plt.plot(t1m, V_oc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Open Circuit Voltage (V)') V_pack0 = prob['traj.phase0.timeseries.V_pack'] V_pack1 = prob['traj.phase1.timeseries.V_pack'] V_pack1b = prob['traj.phase1_bfail.timeseries.V_pack'] V_pack1m = prob['traj.phase1_mfail.timeseries.V_pack'] plt.subplot(2, 2, 3) plt.plot(t0, V_pack0, 'b') plt.plot(t1, V_pack1, 'b') plt.plot(t1b, V_pack1b, 'r') plt.plot(t1m, V_pack1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Terminal Voltage (V)') I_Li0 = prob['traj.phase0.timeseries.I_Li'] I_Li1 = prob['traj.phase1.timeseries.I_Li'] I_Li1b = prob['traj.phase1_bfail.timeseries.I_Li'] I_Li1m = prob['traj.phase1_mfail.timeseries.I_Li'] plt.subplot(2, 2, 4) plt.plot(t0, I_Li0, 'b') plt.plot(t1, I_Li1, 'b') plt.plot(t1b, I_Li1b, 'r') plt.plot(t1m, I_Li1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Line Current (A)') plt.show()
def test_brachistochrone_polynomial_control_rate_targets_radau(self): import matplotlib.pyplot as plt plt.switch_backend('Agg') import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() phase = dm.Phase(ode_class=BrachistochroneRateTargetODE, transcription=dm.Radau(num_segments=10)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', rate_source='xdot', units='m', fix_initial=True, fix_final=True, solve_segments=False) phase.add_state('y', rate_source='ydot', units='m', fix_initial=True, fix_final=True, solve_segments=False) phase.add_state('v', rate_source='vdot', units='m/s', fix_initial=True, fix_final=False, solve_segments=False) phase.add_polynomial_control('theta', order=3, units='deg*s', lower=0.01, upper=179.9, rate_targets=['theta_rate'], fix_initial=True) phase.add_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 = om.DirectSolver() p.setup() p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase.interp('x', [0, 10]) p['phase0.states:y'] = phase.interp('y', [10, 5]) p['phase0.states:v'] = phase.interp('v', [0, 9.9]) p['phase0.polynomial_controls:theta'] = phase.interp('theta', [0, 100]) # Solve for the optimal trajectory p.run_driver() # Test the results assert_near_equal(p.get_val('phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-3) # Generate the explicitly simulated trajectory 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='solution') ax.plot(x_exp, y_exp, 'b-', label='simulated') ax.set_xlabel('x (m)') ax.set_ylabel('y (m)') ax.grid(True) ax.legend(loc='upper right') fig, ax = plt.subplots() t_imp = p.get_val('phase0.timeseries.time') theta_imp = p.get_val( 'phase0.timeseries.polynomial_control_rates:theta_rate') t_exp = exp_out.get_val('phase0.timeseries.time') theta_exp = exp_out.get_val( 'phase0.timeseries.polynomial_control_rates:theta_rate') ax.plot(t_imp, theta_imp, 'ro', label='solution') ax.plot(t_exp, theta_exp, 'b-', label='simulated') ax.set_xlabel('time (s)') ax.set_ylabel(r'$\theta$ (deg)') ax.grid(True) ax.legend(loc='upper right') plt.show()
def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP', dynamic_simul_derivs=True, force_alloc_complex=False, solve_segments=False, run_driver=True): p = om.Problem(model=om.Group()) if optimizer == 'SNOPT': p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings['iSumm'] = 6 else: p.driver = om.ScipyOptimizeDriver() if dynamic_simul_derivs: p.driver.declare_coloring() if transcription == 'runge-kutta': transcription = dm.RungeKutta(num_segments=num_segments, compressed=compressed) fix_final = False elif transcription == 'gauss-lobatto': transcription = dm.GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) fix_final = not solve_segments elif transcription == 'radau-ps': transcription = dm.Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) fix_final = not solve_segments traj = dm.Trajectory() phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, transcription=transcription) traj.add_phase('phase0', phase) p.model.add_subsystem('traj0', traj) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10), units='s') # can't fix final position if you're solving the segments phase.add_state( 'pos', rate_source=BrachistochroneVectorStatesODE.states['pos'] ['rate_source'], units=BrachistochroneVectorStatesODE.states['pos']['units'], shape=BrachistochroneVectorStatesODE.states['pos']['shape'], fix_initial=True, fix_final=fix_final, solve_segments=solve_segments) # phase.add_state( 'v', rate_source=BrachistochroneVectorStatesODE.states['v']['rate_source'], targets=BrachistochroneVectorStatesODE.states['v']['targets'], units=BrachistochroneVectorStatesODE.states['v']['units'], fix_initial=True, fix_final=False, solve_segments=solve_segments) # phase.add_control( 'theta', targets=BrachistochroneVectorStatesODE.parameters['theta']['targets'], continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter( 'g', targets=BrachistochroneVectorStatesODE.parameters['g']['targets'], opt=False, units='m/s**2', val=9.80665) if not fix_final: phase.add_boundary_constraint('pos', loc='final', units='m', shape=(2, ), equals=[10, 5]) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=force_alloc_complex) p['traj0.phase0.t_initial'] = 0.0 p['traj0.phase0.t_duration'] = 1.8016 pos0 = [0, 10] posf = [10, 5] p['traj0.phase0.states:pos'] = phase.interpolate(ys=[pos0, posf], nodes='state_input') p['traj0.phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['traj0.phase0.controls:theta'] = phase.interpolate(ys=[5, 100], nodes='control_input') p['traj0.phase0.parameters:g'] = 9.80665 p.run_model() if run_driver: p.run_driver() return p
def test_rk4_scalar_no_iteration(self): num_seg = 4 num_stages = 4 state_options = {'y': {'shape': (1, ), 'units': 'm', 'targets': ['y']}} p = om.Problem(model=om.Group()) ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states_per_seg:y', shape=(num_seg, 1), units='m') ivc.add_output('h', shape=(num_seg, 1), units='s') ivc.add_output('t', shape=(num_seg * num_stages, 1), units='s') p.model.add_subsystem( 'k_iter_group', RungeKuttaKIterGroup(num_segments=num_seg, method='RK4', state_options=state_options, time_units='s', ode_class=TestODE, ode_init_kwargs={}, solver_class=om.NonlinearRunOnce)) p.model.connect('t', 'k_iter_group.ode.t') p.model.connect('h', 'k_iter_group.h') p.model.connect('initial_states_per_seg:y', 'k_iter_group.initial_states_per_seg:y') src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1)) p.model.connect('k_iter_group.ode.ydot', 'k_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) p.setup(check=True, force_alloc_complex=True) p['t'] = np.array([[ 0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, 1.00, 1.25, 1.25, 1.50, 1.50, 1.75, 1.75, 2.00 ]]).T p['h'] = np.array([[0.5, 0.5, 0.5, 0.5]]).T p['initial_states_per_seg:y'] = np.array([[0.50000000], [1.425130208333333], [2.639602661132812], [4.006818970044454]]) p['k_iter_group.k_comp.k:y'] = np.array([[[0.75000000], [0.90625000], [0.94531250], [1.09765625]], [[1.087565104166667], [1.203206380208333], [1.232116699218750], [1.328623453776042]], [[1.319801330566406], [1.368501663208008], [1.380676746368408], [1.385139703750610]], [[1.378409485022227], [1.316761856277783], [1.301349949091673], [1.154084459568063]]]) p.run_model() # Test that the residuals of k are zero (we started k at the expected converged value) outputs = p.model.list_outputs(print_arrays=True, residuals=True, out_stream=False) op_dict = dict([op for op in outputs]) assert_almost_equal(op_dict['k_iter_group.k_comp.k:y']['resids'], 0.0) # Test the partials cpd = p.check_partials(method='cs', out_stream=None) assert_check_partials(cpd)
def test_run_HS_problem_radau(self): p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring() p.driver.options['optimizer'] = optimizer if optimizer == 'SNOPT': p.driver.opt_settings['Major iterations limit'] = 200 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 elif optimizer == 'IPOPT': p.driver.opt_settings['hessian_approximation'] = 'limited-memory' # p.driver.opt_settings['nlp_scaling_method'] = 'user-scaling' p.driver.opt_settings['print_level'] = 4 p.driver.opt_settings['max_iter'] = 200 p.driver.opt_settings['linear_solver'] = 'mumps' traj = p.model.add_subsystem('traj', dm.Trajectory()) phase0 = traj.add_phase( 'phase0', dm.Phase(ode_class=HyperSensitiveODE, transcription=dm.Radau(num_segments=10, order=3))) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.add_state('x', fix_initial=True, fix_final=False, rate_source='x_dot', targets=['x']) phase0.add_state('xL', fix_initial=True, fix_final=False, rate_source='L', targets=['xL']) phase0.add_control('u', opt=True, targets=['u'], rate_continuity=False) phase0.add_boundary_constraint('x', loc='final', equals=1) phase0.add_objective('xL', loc='final') phase0.set_refine_options(refine=True, tol=1e-6) p.setup(check=True) tf = np.float128(20) p.set_val('traj.phase0.states:x', phase0.interpolate(ys=[1.5, 1], nodes='state_input')) p.set_val('traj.phase0.states:xL', phase0.interpolate(ys=[0, 1], nodes='state_input')) p.set_val('traj.phase0.t_initial', 0) p.set_val('traj.phase0.t_duration', tf) p.set_val('traj.phase0.controls:u', phase0.interpolate(ys=[-0.6, 2.4], nodes='control_input')) dm.run_problem(p, refine_method='hp', refine_iteration_limit=10) sqrt_two = np.sqrt(2) val = sqrt_two * tf c1 = (1.5 * np.exp(-val) - 1) / (np.exp(-val) - np.exp(val)) c2 = (1 - 1.5 * np.exp(val)) / (np.exp(-val) - np.exp(val)) ui = c1 * (1 + sqrt_two) + c2 * (1 - sqrt_two) uf = c1 * (1 + sqrt_two) * np.exp(val) + c2 * (1 - sqrt_two) * np.exp(-val) J = 0.5 * (c1**2 * (1 + sqrt_two) * np.exp(2 * val) + c2**2 * (1 - sqrt_two) * np.exp(-2 * val) - (1 + sqrt_two) * c1**2 - (1 - sqrt_two) * c2**2) assert_near_equal(p.get_val('traj.phase0.timeseries.controls:u')[0], ui, tolerance=5e-4) assert_near_equal(p.get_val('traj.phase0.timeseries.controls:u')[-1], uf, tolerance=5e-4) assert_near_equal(p.get_val('traj.phase0.timeseries.states:xL')[-1], J, tolerance=5e-4)
def setup_problem( trans=dm.GaussLobatto(num_segments=10), polynomial_control=False): from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE from dymos.transcriptions.runge_kutta.runge_kutta import RungeKutta p = om.Problem(model=om.Group()) if isinstance(trans, RungeKutta): p.driver = om.pyOptSparseDriver() else: p.driver = om.ScipyOptimizeDriver() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=trans) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=True, fix_final=not isinstance(trans, RungeKutta), rate_source=BrachistochroneODE.states['x']['rate_source'], units=BrachistochroneODE.states['x']['units']) phase.add_state('y', fix_initial=True, fix_final=not isinstance(trans, RungeKutta), rate_source=BrachistochroneODE.states['y']['rate_source'], units=BrachistochroneODE.states['y']['units']) phase.add_state('v', fix_initial=True, rate_source=BrachistochroneODE.states['v']['rate_source'], units=BrachistochroneODE.states['v']['units']) if not polynomial_control: phase.add_control('theta', units='deg', rate_continuity=False, lower=0.01, upper=179.9) else: phase.add_polynomial_control('theta', order=1, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', units='m/s**2', opt=False, val=9.80665) if isinstance(trans, RungeKutta): phase.add_timeseries_output('check', units='m/s', shape=(1, )) phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() # Recording rec = om.SqliteRecorder('brachistochrone_solution.db') p.driver.recording_options['record_desvars'] = True p.driver.recording_options['record_responses'] = True p.driver.recording_options['record_objectives'] = True p.driver.recording_options['record_constraints'] = True p.model.recording_options['record_metadata'] = True p.model.add_recorder(rec) 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') if not polynomial_control: p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5], nodes='control_input') else: p['phase0.polynomial_controls:theta'][:] = 5.0 return p
def _make_problem(self, transcription, num_seg, transcription_order=3): p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() # Compute sparsity/coloring when run_driver is called p.driver.declare_coloring() t = { 'gauss-lobatto': dm.GaussLobatto(num_segments=num_seg, order=transcription_order), 'radau-ps': dm.Radau(num_segments=num_seg, order=transcription_order), 'runge-kutta': dm.RungeKutta(num_segments=num_seg) } phase = dm.Phase(ode_class=_BrachistochroneTestODE, transcription=t[transcription]) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(1, 1), duration_bounds=(.5, 10), units='s', time_phase_targets=['time_phase'], t_duration_targets=['t_duration'], t_initial_targets=['t_initial'], targets=['time']) phase.add_state('x', fix_initial=True, rate_source='xdot', units='m') phase.add_state('y', fix_initial=True, rate_source='ydot', units='m') phase.add_state('v', fix_initial=True, rate_source='vdot', targets=['v'], units='m/s') phase.add_control('theta', units='deg', rate_continuity=True, lower=0.01, upper=179.9, targets=['theta']) phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665, targets=['g']) phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True) 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