def test_brachistochrone_for_docs_coloring_demo_solve_segments(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm
        from dymos.examples.plotting import plot_results
        from dymos.examples.brachistochrone import BrachistochroneODE

        #
        # Initialize the Problem and the optimization driver
        #
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver(optimizer='IPOPT')
        p.driver.opt_settings['print_level'] = 4
        # p.driver.declare_coloring()

        #
        # Create a trajectory and add a phase to it
        #
        traj = p.model.add_subsystem('traj', dm.Trajectory())

        #
        # In this case the phase has many segments to demonstrate the impact of coloring.
        #
        phase = traj.add_phase(
            'phase0',
            dm.Phase(ode_class=BrachistochroneODE,
                     transcription=dm.Radau(num_segments=100,
                                            solve_segments='forward')))

        #
        # Set the variables
        #
        phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

        phase.add_state('x', fix_initial=True)

        phase.add_state('y', fix_initial=True)

        phase.add_state('v', fix_initial=True)

        phase.add_control('theta',
                          continuity=True,
                          rate_continuity=True,
                          units='deg',
                          lower=0.01,
                          upper=179.9)

        phase.add_parameter('g', units='m/s**2', val=9.80665)

        #
        # Replace state terminal bounds with nonlinear constraints
        #
        phase.add_boundary_constraint('x', loc='final', equals=10)
        phase.add_boundary_constraint('y', loc='final', equals=5)

        #
        # Minimize time at the end of the phase
        #
        phase.add_objective('time', loc='final', scaler=10)

        p.model.linear_solver = om.DirectSolver()

        #
        # Setup the Problem
        #
        p.setup()

        #
        # Set the initial values
        #
        p['traj.phase0.t_initial'] = 0.0
        p['traj.phase0.t_duration'] = 2.0

        p.set_val('traj.phase0.states:x', phase.interp('x', ys=[0, 10]))
        p.set_val('traj.phase0.states:y', phase.interp('y', ys=[10, 5]))
        p.set_val('traj.phase0.states:v', phase.interp('v', ys=[0, 9.9]))
        p.set_val('traj.phase0.controls:theta',
                  phase.interp('theta', ys=[5, 100.5]))

        #
        # Solve for the optimal trajectory
        #
        dm.run_problem(p)

        # Test the results
        assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1],
                          1.8016,
                          tolerance=1.0E-3)

        # Generate the explicitly simulated trajectory
        exp_out = traj.simulate()

        plot_results(
            [('traj.phase0.timeseries.states:x',
              'traj.phase0.timeseries.states:y', 'x (m)', 'y (m)'),
             ('traj.phase0.timeseries.time',
              'traj.phase0.timeseries.controls:theta', 'time (s)',
              'theta (deg)')],
            title='Brachistochrone Solution\nRadau Pseudospectral Method',
            p_sol=p,
            p_sim=exp_out)

        plt.show()
Beispiel #2
0
import openmdao.api as om
import dymos as dm

from donner_sub_ode import DonnerSubODE

# Create the problem
p = om.Problem(model=om.Group())

# Add the trajectory (optional for single phase problems)
traj = dm.Trajectory()

# Create the phase
phase = dm.Phase(ode_class=DonnerSubODE,
                 transcription=dm.GaussLobatto(num_segments=30,
                                               order=3,
                                               compressed=False))

# Add the phase to the trajectory, and the trajectory to the model
traj.add_phase('phase0', phase=phase)
p.model.add_subsystem('traj', traj)

#
# Configure the phase
#
phase.set_time_options(units=None,
                       targets=['threat_comp.time'],
                       fix_initial=True,
                       duration_bounds=(0.1, 100))
phase.add_state('x',
                rate_source='eom_comp.dx_dt',
                targets=['nav_comp.x'],
Beispiel #3
0
    def _test_integrate_polynomial_control_rate2(self, transcription):
        #
        # Define the OpenMDAO problem
        #
        p = om.Problem(model=om.Group())

        #
        # Define a Trajectory object
        #
        traj = dm.Trajectory()

        p.model.add_subsystem('traj', subsys=traj)

        #
        # Define a Dymos Phase object with GaussLobatto Transcription
        #
        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=transcription(num_segments=20, order=3))

        traj.add_phase(name='phase0', phase=phase)

        #
        # Set the time options
        # Time has no targets in our ODE.
        # We fix the initial time so that the it is not a design variable in the optimization.
        # The duration of the phase is allowed to be optimized, but is bounded on [0.5, 10].
        #
        phase.set_time_options(fix_initial=True,
                               duration_bounds=(1.0, 10.0),
                               units='s')

        #
        # Set the time options
        # Initial values of positions and velocity are all fixed.
        # The final value of position are fixed, but the final velocity is a free variable.
        # The equations of motion are not functions of position, so 'x' and 'y' have no targets.
        # The rate source points to the output in the ODE which provides the time derivative of the
        # given state.
        phase.add_state('x', fix_initial=True, fix_final=True)
        phase.add_state('y', fix_initial=True, fix_final=True)
        phase.add_state('v', fix_initial=True)

        phase.add_state('int_theta_dot',
                        fix_initial=False,
                        rate_source='theta_rate2')
        phase.add_state('int_theta',
                        fix_initial=False,
                        rate_source='int_theta_dot',
                        targets=['theta'])

        # Define theta as a control.
        phase.add_polynomial_control(name='theta',
                                     order=11,
                                     units='rad',
                                     shape=(1, ),
                                     targets=None)

        # Force the initial value of the theta polynomial control to equal the initial value of the theta state.
        traj.add_linkage_constraint(phase_a='phase0',
                                    phase_b='phase0',
                                    var_a='theta',
                                    var_b='int_theta',
                                    loc_a='initial',
                                    loc_b='initial')

        traj.add_linkage_constraint(phase_a='phase0',
                                    phase_b='phase0',
                                    var_a='int_theta_dot',
                                    var_b='theta_rate',
                                    loc_a='initial',
                                    loc_b='initial',
                                    units='rad/s')

        # Minimize final time.
        phase.add_objective('time', loc='final')

        # Set the driver.
        p.driver = om.pyOptSparseDriver(optimizer='SLSQP')

        # Allow OpenMDAO to automatically determine our sparsity pattern.
        # Doing so can significant speed up the execution of Dymos.
        p.driver.declare_coloring()

        # Setup the problem
        p.setup(check=True)

        # Now that the OpenMDAO problem is setup, we can set the values of the states.

        p.set_val('traj.phase0.t_initial', 0.0, units='s')
        p.set_val('traj.phase0.t_duration', 5.0, units='s')

        p.set_val('traj.phase0.states:x',
                  phase.interp('x', [0, 10]),
                  units='m')
        p.set_val('traj.phase0.states:y',
                  phase.interp('y', [10, 5]),
                  units='m')
        p.set_val('traj.phase0.states:v',
                  phase.interp('v', [0, 5]),
                  units='m/s')
        p.set_val('traj.phase0.states:int_theta',
                  phase.interp('int_theta', [0.1, 45]),
                  units='deg')
        p.set_val('traj.phase0.states:int_theta_dot',
                  phase.interp('int_theta_dot', [0, 0]),
                  units='deg/s')
        p.set_val('traj.phase0.polynomial_controls:theta', 45.0, units='deg')

        # Run the driver to solve the problem
        dm.run_problem(p, simulate=True, make_plots=True)

        sol = om.CaseReader('dymos_solution.db').get_case('final')
        sim = om.CaseReader('dymos_simulation.db').get_case('final')

        t_sol = sol.get_val('traj.phase0.timeseries.time')
        t_sim = sim.get_val('traj.phase0.timeseries.time')

        x_sol = sol.get_val('traj.phase0.timeseries.states:x')
        x_sim = sim.get_val('traj.phase0.timeseries.states:x')

        y_sol = sol.get_val('traj.phase0.timeseries.states:y')
        y_sim = sim.get_val('traj.phase0.timeseries.states:y')

        v_sol = sol.get_val('traj.phase0.timeseries.states:v')
        v_sim = sim.get_val('traj.phase0.timeseries.states:v')

        int_theta_sol = sol.get_val('traj.phase0.timeseries.states:int_theta')
        int_theta_sim = sim.get_val('traj.phase0.timeseries.states:int_theta')

        theta_sol = sol.get_val(
            'traj.phase0.timeseries.polynomial_controls:theta')
        theta_sim = sim.get_val(
            'traj.phase0.timeseries.polynomial_controls:theta')

        assert_timeseries_near_equal(t_sol,
                                     x_sol,
                                     t_sim,
                                     x_sim,
                                     tolerance=1.0E-2)
        assert_timeseries_near_equal(t_sol,
                                     y_sol,
                                     t_sim,
                                     y_sim,
                                     tolerance=1.0E-2)
        assert_timeseries_near_equal(t_sol,
                                     v_sol,
                                     t_sim,
                                     v_sim,
                                     tolerance=1.0E-2)
        assert_timeseries_near_equal(t_sol,
                                     int_theta_sol,
                                     t_sim,
                                     int_theta_sim,
                                     tolerance=1.0E-2)
Beispiel #4
0
    def test_steady_aircraft_for_docs(self):
        import matplotlib.pyplot as plt

        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_rel_error

        import dymos as dm

        from dymos.examples.aircraft_steady_flight.aircraft_ode import AircraftODE
        from dymos.examples.plotting import plot_results
        from dymos.utils.lgl import lgl

        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.declare_coloring()

        num_seg = 15
        seg_ends, _ = lgl(num_seg + 1)

        traj = p.model.add_subsystem('traj', dm.Trajectory())

        phase = traj.add_phase(
            'phase0',
            dm.Phase(ode_class=AircraftODE,
                     transcription=dm.Radau(num_segments=num_seg,
                                            segment_ends=seg_ends,
                                            order=3,
                                            compressed=False)))

        # Pass Reference Area from an external source
        assumptions = p.model.add_subsystem('assumptions', om.IndepVarComp())
        assumptions.add_output('S', val=427.8, units='m**2')
        assumptions.add_output('mass_empty', val=1.0, units='kg')
        assumptions.add_output('mass_payload', val=1.0, units='kg')

        phase.set_time_options(initial_bounds=(0, 0),
                               duration_bounds=(300, 10000),
                               duration_ref=5600)

        phase.add_state('range',
                        units='NM',
                        rate_source='range_rate_comp.dXdt:range',
                        fix_initial=True,
                        fix_final=False,
                        ref=1e-3,
                        defect_ref=1e-3,
                        lower=0,
                        upper=2000)

        phase.add_state('mass_fuel',
                        units='lbm',
                        rate_source='propulsion.dXdt:mass_fuel',
                        targets=['mass_comp.mass_fuel'],
                        fix_initial=True,
                        fix_final=True,
                        upper=1.5E5,
                        lower=0.0,
                        ref=1e2,
                        defect_ref=1e2)

        phase.add_state('alt',
                        units='kft',
                        rate_source='climb_rate',
                        targets=['atmos.h', 'aero.alt', 'propulsion.alt'],
                        fix_initial=True,
                        fix_final=True,
                        lower=0.0,
                        upper=60,
                        ref=1e-3,
                        defect_ref=1e-3)

        phase.add_control('climb_rate',
                          units='ft/min',
                          opt=True,
                          lower=-3000,
                          upper=3000,
                          targets=['gam_comp.climb_rate'],
                          rate_continuity=True,
                          rate2_continuity=False)

        phase.add_control('mach',
                          targets=['tas_comp.mach', 'aero.mach'],
                          units=None,
                          opt=False)

        phase.add_input_parameter(
            'S',
            targets=['aero.S', 'flight_equilibrium.S', 'propulsion.S'],
            units='m**2')

        phase.add_input_parameter('mass_empty',
                                  targets=['mass_comp.mass_empty'],
                                  units='kg')
        phase.add_input_parameter('mass_payload',
                                  targets=['mass_comp.mass_payload'],
                                  units='kg')

        phase.add_path_constraint('propulsion.tau',
                                  lower=0.01,
                                  upper=2.0,
                                  shape=(1, ))

        p.model.connect('assumptions.S', 'traj.phase0.input_parameters:S')
        p.model.connect('assumptions.mass_empty',
                        'traj.phase0.input_parameters:mass_empty')
        p.model.connect('assumptions.mass_payload',
                        'traj.phase0.input_parameters:mass_payload')

        phase.add_objective('range', loc='final', ref=-1.0e-4)

        p.setup()

        p['traj.phase0.t_initial'] = 0.0
        p['traj.phase0.t_duration'] = 3600.0
        p['traj.phase0.states:range'][:] = phase.interpolate(
            ys=(0, 724.0), nodes='state_input')
        p['traj.phase0.states:mass_fuel'][:] = phase.interpolate(
            ys=(30000, 1e-3), nodes='state_input')
        p['traj.phase0.states:alt'][:] = 10.0

        p['traj.phase0.controls:mach'][:] = 0.8

        p['assumptions.S'] = 427.8
        p['assumptions.mass_empty'] = 0.15E6
        p['assumptions.mass_payload'] = 84.02869 * 400

        dm.run_problem(p)

        assert_rel_error(self,
                         p.get_val('traj.phase0.timeseries.states:range',
                                   units='NM')[-1],
                         726.85,
                         tolerance=1.0E-2)

        exp_out = traj.simulate()

        plot_results([('traj.phase0.timeseries.states:range',
                       'traj.phase0.timeseries.states:alt', 'range (NM)',
                       'altitude (kft)'),
                      ('traj.phase0.timeseries.time',
                       'traj.phase0.timeseries.states:mass_fuel', 'time (s)',
                       'fuel mass (lbm)')],
                     title='Commercial Aircraft Optimization',
                     p_sol=p,
                     p_sim=exp_out)

        plt.show()
    def test_min_time_climb_for_docs_gauss_lobatto(self):
        import matplotlib.pyplot as plt

        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal

        import dymos as dm
        from dymos.examples.min_time_climb.min_time_climb_ode import MinTimeClimbODE

        #
        # Instantiate the problem and configure the optimization driver
        #
        p = om.Problem(model=om.Group())

        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.declare_coloring()

        #
        # Instantiate the trajectory and phase
        #
        traj = dm.Trajectory()

        phase = dm.Phase(ode_class=MinTimeClimbODE,
                         transcription=dm.GaussLobatto(num_segments=15, compressed=False))

        traj.add_phase('phase0', phase)

        p.model.add_subsystem('traj', traj)

        #
        # Set the options on the optimization variables
        # Note the use of explicit state units here since much of the ODE uses imperial units
        # and we prefer to solve this problem using metric units.
        #
        phase.set_time_options(fix_initial=True, duration_bounds=(50, 400),
                               duration_ref=100.0)

        phase.add_state('r', fix_initial=True, lower=0, upper=1.0E6, units='m',
                        ref=1.0E3, defect_ref=1.0E3,
                        rate_source='flight_dynamics.r_dot')

        phase.add_state('h', fix_initial=True, lower=0, upper=20000.0, units='m',
                        ref=1.0E2, defect_ref=1.0E2,
                        rate_source='flight_dynamics.h_dot')

        phase.add_state('v', fix_initial=True, lower=10.0, units='m/s',
                        ref=1.0E2, defect_ref=1.0E2,
                        rate_source='flight_dynamics.v_dot')

        phase.add_state('gam', fix_initial=True, lower=-1.5, upper=1.5, units='rad',
                        ref=1.0, defect_ref=1.0,
                        rate_source='flight_dynamics.gam_dot')

        phase.add_state('m', fix_initial=True, lower=10.0, upper=1.0E5, units='kg',
                        ref=1.0E3, defect_ref=1.0E3,
                        rate_source='prop.m_dot')

        phase.add_control('alpha', units='deg', lower=-8.0, upper=8.0, scaler=1.0,
                          rate_continuity=True, rate_continuity_scaler=100.0,
                          rate2_continuity=False)

        phase.add_parameter('S', val=49.2386, units='m**2', opt=False, targets=['S'])
        phase.add_parameter('Isp', val=1600.0, units='s', opt=False, targets=['Isp'])
        phase.add_parameter('throttle', val=1.0, opt=False, targets=['throttle'])

        #
        # Setup the boundary and path constraints
        #
        phase.add_boundary_constraint('h', loc='final', equals=20000, scaler=1.0E-3)
        phase.add_boundary_constraint('aero.mach', loc='final', equals=1.0)
        phase.add_boundary_constraint('gam', loc='final', equals=0.0)

        phase.add_path_constraint(name='h', lower=100.0, upper=20000, ref=20000)
        phase.add_path_constraint(name='aero.mach', lower=0.1, upper=1.8)

        # Minimize time at the end of the phase
        phase.add_objective('time', loc='final', ref=1.0)

        p.model.linear_solver = om.DirectSolver()

        #
        # Setup the problem and set the initial guess
        #
        p.setup(check=True)

        p['traj.phase0.t_initial'] = 0.0
        p['traj.phase0.t_duration'] = 500

        p.set_val('traj.phase0.states:r', phase.interp('r', [0.0, 50000.0]))
        p.set_val('traj.phase0.states:h', phase.interp('h', [100.0, 20000.0]))
        p.set_val('traj.phase0.states:v', phase.interp('v', [135.964, 283.159]))
        p.set_val('traj.phase0.states:gam', phase.interp('gam', [0.0, 0.0]))
        p.set_val('traj.phase0.states:m', phase.interp('m', [19030.468, 10000.]))
        p.set_val('traj.phase0.controls:alpha', phase.interp('alpha', [0.0, 0.0]))

        #
        # Solve for the optimal trajectory
        #
        dm.run_problem(p, simulate=True)

        #
        # Test the results
        #
        assert_near_equal(p.get_val('traj.phase0.t_duration'), 321.0, tolerance=1.0E-1)
Beispiel #6
0
    print()
    print(p['max_I'], np.max(p['I']))
    raw = input("Continue with baseline sim run test? (y/n)")
    if raw != "y":
        quit()
    # test baseline model
    pop_total = 1.0
    infected0 = 0.01
    ns = 50

    p = om.Problem(model=om.Group())
    traj = dm.Trajectory()

    p.model.add_subsystem('traj', subsys=traj)
    phase = dm.Phase(ode_class=SIR,
                   transcription=dm.GaussLobatto(num_segments=ns, 
                                                 order=3))
    p.model.linear_solver = om.DirectSolver()
    phase.set_time_options(fix_initial=True, duration_bounds=(200.0, 301.0))

    ds = 1e-2
    phase.add_state('S', fix_initial=True, rate_source='Sdot', targets=['S'], lower=0.0,
                  upper=pop_total, ref=pop_total/2, defect_scaler = ds)
    phase.add_state('I', fix_initial=True, rate_source='Idot', targets=['I'], lower=0.0,
                  upper=pop_total, ref=pop_total/2, defect_scaler = ds)
    phase.add_state('R', fix_initial=True, rate_source='Rdot', targets=['R'], lower=0.0,
                  upper=pop_total, ref=pop_total/2, defect_scaler = ds)

    p.driver = om.pyOptSparseDriver()

    p.driver.options['optimizer'] = 'IPOPT'
    def test_ex_double_integrator_input_times_compressed(self):
        """
        Tests that externally connected t_initial and t_duration function as expected.
        """
        compressed = True
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.declare_coloring()

        times_ivc = p.model.add_subsystem('times_ivc',
                                          om.IndepVarComp(),
                                          promotes_outputs=['t0', 'tp'])
        times_ivc.add_output(name='t0', val=0.0, units='s')
        times_ivc.add_output(name='tp', val=1.0, units='s')

        transcription = dm.Radau(num_segments=20,
                                 order=3,
                                 compressed=compressed)
        phase = dm.Phase(ode_class=DoubleIntegratorODE,
                         transcription=transcription)
        p.model.add_subsystem('phase0', phase)

        p.model.connect('t0', 'phase0.t_initial')
        p.model.connect('tp', 'phase0.t_duration')

        phase.set_time_options(input_initial=True,
                               input_duration=True,
                               units='s')

        phase.add_state('v',
                        fix_initial=True,
                        fix_final=True,
                        rate_source='u',
                        units='m/s')
        phase.add_state('x', fix_initial=True, rate_source='v', units='m')

        phase.add_control('u',
                          units='m/s**2',
                          scaler=0.01,
                          continuity=False,
                          rate_continuity=False,
                          rate2_continuity=False,
                          shape=(1, ),
                          lower=-1.0,
                          upper=1.0)

        # Maximize distance travelled in one second.
        phase.add_objective('x', loc='final', scaler=-1)

        p.model.linear_solver = om.DirectSolver()

        p.setup(check=True)

        p['t0'] = 0.0
        p['tp'] = 1.0

        p['phase0.states:x'] = phase.interp('x', [0, 0.25])
        p['phase0.states:v'] = phase.interp('v', [0, 0])
        p['phase0.controls:u'] = phase.interp('u', [1, -1])

        p.run_driver()

        assert_near_equal(p.get_val('phase0.timeseries.states:x')[-1, ...],
                          [0.25],
                          tolerance=1.0E-8)
Beispiel #8
0
                    help='Optimizer name from pyOptSparse')
args = parser.parse_args()

optimizer = args.optimizer
algorithm = args.algorithm

# Define the OpenMDAO problem
p = om.Problem(model=om.Group())

# Define a Trajectory object
traj = dm.Trajectory()

p.model.add_subsystem('traj', subsys=traj)

# Define a Dymos Phase object with GaussLobatto Transcription
phase = dm.Phase(ode_class=SimpleODE,
                 transcription=dm.GaussLobatto(num_segments=10, order=3))

traj.add_phase(name='phase0', phase=phase)

# Set the time options
phase.set_time_options(fix_initial=True,
                       fix_duration=True,
                       duration_val=5.0,
                       units='s')

# Define state variables
phase.add_state('x',
                fix_initial=True,
                fix_final=True,
                units='m',
                rate_source='xdot')
def make_traj(transcription='gauss-lobatto',
              transcription_order=3,
              compressed=False,
              connected=False):

    t = {
        'gauss-lobatto':
        dm.GaussLobatto(num_segments=5,
                        order=transcription_order,
                        compressed=compressed),
        'radau':
        dm.Radau(num_segments=20,
                 order=transcription_order,
                 compressed=compressed),
        'runge-kutta':
        dm.RungeKutta(num_segments=5, compressed=compressed)
    }

    traj = dm.Trajectory()

    traj.add_design_parameter('c', opt=False, val=1.5, units='DU/TU')

    # First Phase (burn)

    burn1 = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription])

    burn1 = traj.add_phase('burn1', burn1)

    burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10))
    burn1.set_state_options('r',
                            fix_initial=True,
                            fix_final=False,
                            defect_scaler=100.0)
    burn1.set_state_options('theta',
                            fix_initial=True,
                            fix_final=False,
                            defect_scaler=100.0)
    burn1.set_state_options('vr',
                            fix_initial=True,
                            fix_final=False,
                            defect_scaler=100.0)
    burn1.set_state_options('vt',
                            fix_initial=True,
                            fix_final=False,
                            defect_scaler=100.0)
    burn1.set_state_options('accel', fix_initial=True, fix_final=False)
    burn1.set_state_options('deltav', fix_initial=True, fix_final=False)
    burn1.add_control('u1',
                      rate_continuity=True,
                      rate2_continuity=True,
                      units='deg',
                      scaler=0.01,
                      rate_continuity_scaler=0.001,
                      rate2_continuity_scaler=0.001,
                      lower=-30,
                      upper=30)
    # Second Phase (Coast)
    coast = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription])

    coast.set_time_options(initial_bounds=(0.5, 20),
                           duration_bounds=(.5, 50),
                           duration_ref=50)
    coast.set_state_options('r',
                            fix_initial=False,
                            fix_final=False,
                            defect_scaler=100.0)
    coast.set_state_options('theta',
                            fix_initial=False,
                            fix_final=False,
                            defect_scaler=100.0)
    coast.set_state_options('vr',
                            fix_initial=False,
                            fix_final=False,
                            defect_scaler=100.0)
    coast.set_state_options('vt',
                            fix_initial=False,
                            fix_final=False,
                            defect_scaler=100.0)
    coast.set_state_options('accel', fix_initial=True, fix_final=True)
    coast.set_state_options('deltav', fix_initial=False, fix_final=False)

    coast.add_design_parameter('u1', opt=False, val=0.0, units='deg')

    # Third Phase (burn)
    burn2 = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription])

    if connected:
        traj.add_phase('burn2', burn2)
        traj.add_phase('coast', coast)

        burn2.set_time_options(initial_bounds=(1.0, 60),
                               duration_bounds=(-10.0, -0.5),
                               initial_ref=10)
        burn2.set_state_options('r',
                                fix_initial=True,
                                fix_final=False,
                                defect_scaler=100.0)
        burn2.set_state_options('theta',
                                fix_initial=False,
                                fix_final=False,
                                defect_scaler=100.0)
        burn2.set_state_options('vr',
                                fix_initial=True,
                                fix_final=False,
                                defect_scaler=1000.0)
        burn2.set_state_options('vt',
                                fix_initial=True,
                                fix_final=False,
                                defect_scaler=1000.0)
        burn2.set_state_options('accel',
                                fix_initial=False,
                                fix_final=False,
                                defect_scaler=1.0)
        burn2.set_state_options('deltav',
                                fix_initial=False,
                                fix_final=False,
                                defect_scaler=1.0)

        burn2.add_objective('deltav', loc='initial', scaler=100.0)

        burn2.add_control('u1',
                          rate_continuity=True,
                          rate2_continuity=True,
                          units='deg',
                          scaler=0.01,
                          lower=-180,
                          upper=180)
    else:
        traj.add_phase('coast', coast)
        traj.add_phase('burn2', burn2)

        burn2.set_time_options(initial_bounds=(0.5, 50),
                               duration_bounds=(.5, 10),
                               initial_ref=10)
        burn2.set_state_options('r',
                                fix_initial=False,
                                fix_final=True,
                                defect_scaler=100.0)
        burn2.set_state_options('theta',
                                fix_initial=False,
                                fix_final=False,
                                defect_scaler=100.0)
        burn2.set_state_options('vr',
                                fix_initial=False,
                                fix_final=True,
                                defect_scaler=1000.0)
        burn2.set_state_options('vt',
                                fix_initial=False,
                                fix_final=True,
                                defect_scaler=1000.0)
        burn2.set_state_options('accel',
                                fix_initial=False,
                                fix_final=False,
                                defect_scaler=1.0)
        burn2.set_state_options('deltav',
                                fix_initial=False,
                                fix_final=False,
                                defect_scaler=1.0)

        burn2.add_objective('deltav', loc='final', scaler=100.0)

        burn2.add_control('u1',
                          rate_continuity=True,
                          rate2_continuity=True,
                          units='deg',
                          scaler=0.01)

    burn1.add_timeseries_output('pos_x', units='DU')
    coast.add_timeseries_output('pos_x', units='DU')
    burn2.add_timeseries_output('pos_x', units='DU')

    burn1.add_timeseries_output('pos_y', units='DU')
    coast.add_timeseries_output('pos_y', units='DU')
    burn2.add_timeseries_output('pos_y', units='DU')

    # Link Phases
    if connected:
        traj.link_phases(phases=['burn1', 'coast'],
                         vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav'],
                         connected=True)

        # No direct connections to the end of a phase.
        traj.link_phases(phases=['burn2', 'coast'],
                         vars=['r', 'theta', 'vr', 'vt', 'deltav'],
                         locs=('++', '++'))
        traj.link_phases(phases=['burn2', 'coast'],
                         vars=['time'],
                         locs=('++', '++'))

        traj.link_phases(phases=['burn1', 'burn2'],
                         vars=['accel'],
                         locs=('++', '++'))

    else:
        traj.link_phases(phases=['burn1', 'coast', 'burn2'],
                         vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav'])

        traj.link_phases(phases=['burn1', 'burn2'], vars=['accel'])

    return traj
Beispiel #10
0
def make_traj(transcription='gauss-lobatto', transcription_order=3, compressed=False,
              connected=False, param_mode='param_sequence'):

    t = {'gauss-lobatto': dm.GaussLobatto(num_segments=5, order=transcription_order, compressed=compressed),
         'radau': dm.Radau(num_segments=20, order=transcription_order, compressed=compressed)}

    traj = dm.Trajectory()

    if param_mode == 'param_sequence':
        traj.add_parameter('c', opt=False, val=1.5, units='DU/TU',
                           targets={'burn1': ['c'], 'coast': ['c'], 'burn2': ['c']})
    elif param_mode == 'param_sequence_missing_phase':
        traj.add_parameter('c', opt=False, val=1.5, units='DU/TU',
                           targets={'burn1': ['c'], 'burn2': ['c']})
    elif param_mode == 'param_no_targets':
        traj.add_parameter('c', val=1.5, units='DU/TU')

    # First Phase (burn)

    burn1 = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription])

    burn1 = traj.add_phase('burn1', burn1)

    burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10), units='TU')
    burn1.add_state('r', fix_initial=True, fix_final=False, defect_scaler=100.0,
                    rate_source='r_dot', targets=['r'], units='DU')
    burn1.add_state('theta', fix_initial=True, fix_final=False, defect_scaler=100.0,
                    rate_source='theta_dot', targets=['theta'], units='rad')
    burn1.add_state('vr', fix_initial=True, fix_final=False, defect_scaler=100.0,
                    rate_source='vr_dot', targets=['vr'], units='DU/TU')
    burn1.add_state('vt', fix_initial=True, fix_final=False, defect_scaler=100.0,
                    rate_source='vt_dot', targets=['vt'], units='DU/TU')
    burn1.add_state('accel', fix_initial=True, fix_final=False,
                    rate_source='at_dot', targets=['accel'], units='DU/TU**2')
    burn1.add_state('deltav', fix_initial=True, fix_final=False,
                    rate_source='deltav_dot', targets=None, units='DU/TU')
    burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01,
                      rate_continuity_scaler=0.001, rate2_continuity_scaler=0.001,
                      lower=-30, upper=30, targets=['u1'])
    # Second Phase (Coast)
    coast = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription])

    coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 50), duration_ref=50, units='TU')
    coast.add_state('r', fix_initial=False, fix_final=False, defect_scaler=100.0,
                    rate_source='r_dot', targets=['r'], units='DU')
    coast.add_state('theta', fix_initial=False, fix_final=False, defect_scaler=100.0,
                    rate_source='theta_dot', targets=['theta'], units='rad')
    coast.add_state('vr', fix_initial=False, fix_final=False, defect_scaler=100.0,
                    rate_source='vr_dot', targets=['vr'], units='DU/TU')
    coast.add_state('vt', fix_initial=False, fix_final=False, defect_scaler=100.0,
                    rate_source='vt_dot', targets=['vt'], units='DU/TU')
    coast.add_state('accel', fix_initial=True, fix_final=True,
                    rate_source='at_dot', targets=['accel'], units='DU/TU**2')
    coast.add_state('deltav', fix_initial=False, fix_final=False,
                    rate_source='deltav_dot', units='DU/TU', targets=None)

    coast.add_parameter('u1', opt=False, val=0.0, units='deg', targets=['u1'])

    # Third Phase (burn)
    burn2 = dm.Phase(ode_class=FiniteBurnODE, transcription=t[transcription])

    traj.add_phase('coast', coast)
    traj.add_phase('burn2', burn2)

    burn2.set_time_options(initial_bounds=(0.5, 50), duration_bounds=(.5, 10), initial_ref=10, units='TU')
    burn2.add_state('r', fix_initial=False, fix_final=True, defect_scaler=100.0,
                    rate_source='r_dot', targets=['r'], units='DU')
    burn2.add_state('theta', fix_initial=False, fix_final=False, defect_scaler=100.0,
                    rate_source='theta_dot', targets=['theta'], units='rad')
    burn2.add_state('vr', fix_initial=False, fix_final=True, defect_scaler=1000.0,
                    rate_source='vr_dot', targets=['vr'], units='DU/TU')
    burn2.add_state('vt', fix_initial=False, fix_final=True, defect_scaler=1000.0,
                    rate_source='vt_dot', targets=['vt'], units='DU/TU')
    burn2.add_state('accel', fix_initial=False, fix_final=False, defect_scaler=1.0,
                    rate_source='at_dot', targets=['accel'], units='DU/TU**2')
    burn2.add_state('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0,
                    rate_source='deltav_dot', units='DU/TU', targets=None)

    burn2.add_objective('deltav', loc='final', scaler=100.0)

    burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg',
                      scaler=0.01, lower=-180, upper=180, targets=['u1'])

    if 'sequence_missing_phase' in param_mode:
        coast.add_parameter('c', val=0.0, units='DU/TU', targets=['c'])
    elif 'no_targets' in param_mode:
        burn1.add_parameter('c', val=0.0, units='DU/TU', targets=['c'])
        coast.add_parameter('c', val=0.0, units='DU/TU', targets=['c'])
        burn2.add_parameter('c', val=0.0, units='DU/TU', targets=['c'])

    burn1.add_timeseries_output('pos_x')
    coast.add_timeseries_output('pos_x')
    burn2.add_timeseries_output('pos_x')

    burn1.add_timeseries_output('pos_y')
    coast.add_timeseries_output('pos_y')
    burn2.add_timeseries_output('pos_y')

    # Link Phases
    if connected:
        traj.link_phases(phases=['burn1', 'coast'],
                         vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav'],
                         connected=True)

        # No direct connections to the end of a phase.
        traj.link_phases(phases=['burn2', 'coast'],
                         vars=['r', 'theta', 'vr', 'vt', 'deltav'],
                         locs=('final', 'final'))
        traj.link_phases(phases=['burn2', 'coast'],
                         vars=['time'], locs=('final', 'final'))

        traj.link_phases(phases=['burn1', 'burn2'], vars=['accel'],
                         locs=('final', 'final'))

    else:
        traj.link_phases(phases=['burn1', 'coast', 'burn2'],
                         vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav'])

        traj.link_phases(phases=['burn1', 'burn2'], vars=['accel'])

    return traj
Beispiel #11
0
    def _make_problem(self,
                      transcription='gauss-lobatto',
                      num_segments=8,
                      transcription_order=3,
                      compressed=True,
                      optimizer='SLSQP',
                      run_driver=True,
                      force_alloc_complex=False,
                      solve_segments=False):

        p = om.Problem(model=om.Group())

        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = optimizer
        p.driver.declare_coloring(tol=1.0E-12)

        if transcription == 'gauss-lobatto':
            t = dm.GaussLobatto(num_segments=num_segments,
                                order=transcription_order,
                                compressed=compressed)
        elif transcription == 'radau-ps':
            t = dm.Radau(num_segments=num_segments,
                         order=transcription_order,
                         compressed=compressed)

        traj = dm.Trajectory()
        phase = dm.Phase(ode_class=self.ode, transcription=t)
        p.model.add_subsystem('traj0', traj)
        traj.add_phase('phase0', phase)

        phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

        phase.add_state('x',
                        fix_initial=True,
                        fix_final=False,
                        solve_segments=solve_segments,
                        rate_source='xdot')
        phase.add_state('y',
                        fix_initial=True,
                        fix_final=False,
                        solve_segments=solve_segments,
                        rate_source='ydot')

        # Note that by omitting the targets here Dymos will automatically attempt to connect
        # to a top-level input named 'v' in the ODE, and connect to nothing if it's not found.
        phase.add_state('v',
                        fix_initial=True,
                        fix_final=False,
                        solve_segments=solve_segments,
                        rate_source='vdot')

        phase.add_control('theta',
                          continuity=True,
                          rate_continuity=True,
                          units='deg',
                          lower=0.01,
                          upper=179.9)

        phase.add_parameter('g', units='m/s**2', dynamic=False)

        phase.add_boundary_constraint('x', loc='final', equals=10)
        phase.add_boundary_constraint('y', loc='final', equals=5)
        # Minimize time at the end of the phase
        phase.add_objective('time_phase', loc='final', scaler=10)

        p.setup(check=['unconnected_inputs'],
                force_alloc_complex=force_alloc_complex)

        p['traj0.phase0.t_initial'] = 0.0
        p['traj0.phase0.t_duration'] = 2.0

        p['traj0.phase0.states:x'] = phase.interpolate(ys=[0, 10],
                                                       nodes='state_input')
        p['traj0.phase0.states:y'] = phase.interpolate(ys=[10, 5],
                                                       nodes='state_input')
        p['traj0.phase0.states:v'] = phase.interpolate(ys=[0, 9.9],
                                                       nodes='state_input')
        p['traj0.phase0.controls:theta'] = phase.interpolate(
            ys=[5, 100], nodes='control_input')
        p['traj0.phase0.parameters:g'] = 9.80665

        dm.run_problem(p, run_driver=run_driver, simulate=True)

        return p
Beispiel #12
0
def brachistochrone_min_time(transcription='gauss-lobatto',
                             num_segments=8,
                             transcription_order=3,
                             compressed=True,
                             optimizer='SLSQP'):
    p = om.Problem(model=om.Group())

    p.driver = om.pyOptSparseDriver()
    p.driver.options['optimizer'] = optimizer
    p.driver.declare_coloring()

    if transcription == 'gauss-lobatto':
        t = dm.GaussLobatto(num_segments=num_segments,
                            order=transcription_order,
                            compressed=compressed)
    elif transcription == 'radau-ps':
        t = dm.Radau(num_segments=num_segments,
                     order=transcription_order,
                     compressed=compressed)
    elif transcription == 'runge-kutta':
        t = dm.RungeKutta(num_segments=num_segments,
                          order=transcription_order,
                          compressed=compressed)

    phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t)

    p.model.add_subsystem('phase0', phase)

    phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

    phase.add_state('x',
                    rate_source=BrachistochroneODE.states['x']['rate_source'],
                    units=BrachistochroneODE.states['x']['units'],
                    fix_initial=True,
                    fix_final=False,
                    solve_segments=False)
    phase.add_state('y',
                    rate_source=BrachistochroneODE.states['y']['rate_source'],
                    units=BrachistochroneODE.states['y']['units'],
                    fix_initial=True,
                    fix_final=False,
                    solve_segments=False)
    phase.add_state('v',
                    rate_source=BrachistochroneODE.states['v']['rate_source'],
                    targets=BrachistochroneODE.states['v']['targets'],
                    units=BrachistochroneODE.states['v']['units'],
                    fix_initial=True,
                    fix_final=False,
                    solve_segments=False)

    phase.add_control(
        'theta',
        targets=BrachistochroneODE.parameters['theta']['targets'],
        continuity=True,
        rate_continuity=True,
        units='deg',
        lower=0.01,
        upper=179.9)

    phase.add_input_parameter(
        'g',
        targets=BrachistochroneODE.parameters['g']['targets'],
        units='m/s**2',
        val=9.80665)

    phase.add_timeseries('timeseries2',
                         transcription=dm.Radau(num_segments=num_segments * 5,
                                                order=transcription_order,
                                                compressed=compressed),
                         subset='control_input')

    phase.add_boundary_constraint('x', loc='final', equals=10)
    phase.add_boundary_constraint('y', loc='final', equals=5)
    # Minimize time at the end of the phase
    phase.add_objective('time_phase', loc='final', scaler=10)

    p.model.linear_solver = om.DirectSolver()
    p.setup(check=['unconnected_inputs'])

    p['phase0.t_initial'] = 0.0
    p['phase0.t_duration'] = 2.0

    p['phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input')
    p['phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input')
    p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input')
    p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100],
                                                   nodes='control_input')
    p['phase0.input_parameters:g'] = 9.80665

    p.run_driver()

    # Plot results
    if SHOW_PLOTS:
        exp_out = phase.simulate()

        fig, ax = plt.subplots()
        fig.suptitle('Brachistochrone Solution')

        x_imp = p.get_val('phase0.timeseries.states:x')
        y_imp = p.get_val('phase0.timeseries.states:y')

        x_exp = exp_out.get_val('phase0.timeseries.states:x')
        y_exp = exp_out.get_val('phase0.timeseries.states:y')

        ax.plot(x_imp, y_imp, 'ro', label='implicit')
        ax.plot(x_exp, y_exp, 'b-', label='explicit')

        ax.set_xlabel('x (m)')
        ax.set_ylabel('y (m)')
        ax.grid(True)
        ax.legend(loc='upper right')

        fig, ax = plt.subplots()
        fig.suptitle('Brachistochrone Solution')

        x_imp = p.get_val('phase0.timeseries.time_phase')
        y_imp = p.get_val('phase0.timeseries.controls:theta')

        x_exp = exp_out.get_val('phase0.timeseries.time_phase')
        y_exp = exp_out.get_val('phase0.timeseries.controls:theta')

        ax.plot(x_imp, y_imp, 'ro', label='implicit')
        ax.plot(x_exp, y_exp, 'b-', label='explicit')

        ax.set_xlabel('time (s)')
        ax.set_ylabel('theta (rad)')
        ax.grid(True)
        ax.legend(loc='lower right')

        plt.show()

    return p
Beispiel #13
0
    def test_ivp_solver(self):
        import openmdao.api as om
        import dymos as dm
        import matplotlib.pyplot as plt
        plt.switch_backend('Agg')  # disable plotting to the screen

        from dymos.examples.oscillator.doc.oscillator_ode import OscillatorODE

        # Instantiate an OpenMDAO Problem instance.
        prob = om.Problem()

        # Instantiate a Dymos Trajectory and add it to the Problem model.
        traj = dm.Trajectory()
        prob.model.add_subsystem('traj', traj)

        # Instantiate a Phase and add it to the Trajectory.
        phase = dm.Phase(ode_class=OscillatorODE,
                         transcription=dm.Radau(num_segments=4,
                                                solve_segments='forward'))
        traj.add_phase('phase0', phase)

        # Tell Dymos the states to be propagated using the given ODE.
        phase.add_state('x',
                        fix_initial=True,
                        rate_source='v',
                        targets=['x'],
                        units='m')
        phase.add_state('v',
                        fix_initial=True,
                        rate_source='v_dot',
                        targets=['v'],
                        units='m/s')

        # The spring constant, damping coefficient, and mass are inputs to the system that are
        # constant throughout the phase.
        phase.add_parameter('k', units='N/m', targets=['k'])
        phase.add_parameter('c', units='N*s/m', targets=['c'])
        phase.add_parameter('m', units='kg', targets=['m'])

        # Setup the OpenMDAO problem
        prob.setup()

        # Assign values to the times and states
        prob.set_val('traj.phase0.t_initial', 0.0)
        prob.set_val('traj.phase0.t_duration', 15.0)

        prob.set_val('traj.phase0.states:x', 10.0)
        prob.set_val('traj.phase0.states:v', 0.0)

        prob.set_val('traj.phase0.parameters:k', 1.0)
        prob.set_val('traj.phase0.parameters:c', 0.5)
        prob.set_val('traj.phase0.parameters:m', 1.0)

        # Now we're using the optimization driver to iteratively run the model and vary the
        # phase duration until the final y value is 0.
        prob.run_model()

        # Perform an explicit simulation of our ODE from the initial conditions.
        sim_out = traj.simulate(times_per_seg=50)

        # Plot the state values obtained from the phase timeseries objects in the simulation output.
        t_sol = prob.get_val('traj.phase0.timeseries.time')
        t_sim = sim_out.get_val('traj.phase0.timeseries.time')

        states = ['x', 'v']
        fig, axes = plt.subplots(len(states), 1)
        for i, state in enumerate(states):
            sol = axes[i].plot(
                t_sol, prob.get_val(f'traj.phase0.timeseries.states:{state}'),
                'o')
            sim = axes[i].plot(
                t_sim,
                sim_out.get_val(f'traj.phase0.timeseries.states:{state}'), '-')
            axes[i].set_ylabel(state)
        axes[-1].set_xlabel('time (s)')
        fig.legend((sol[0], sim[0]), ('solution', 'simulation'),
                   'lower right',
                   ncol=2)
        plt.tight_layout()
        plt.show()
    def test_brachistochrone_for_docs_gauss_lobatto(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm
        from dymos.examples.plotting import plot_results
        from dymos.examples.brachistochrone import BrachistochroneODE
        import matplotlib.pyplot as plt

        #
        # Initialize the Problem and the optimization driver
        #
        p = om.Problem(model=om.Group())
        p.driver = om.ScipyOptimizeDriver()
        p.driver.declare_coloring()

        #
        # Create a trajectory and add a phase to it
        #
        traj = p.model.add_subsystem('traj', dm.Trajectory())

        phase = traj.add_phase(
            'phase0',
            dm.Phase(ode_class=BrachistochroneODE,
                     transcription=dm.GaussLobatto(num_segments=10)))

        #
        # Set the variables
        #
        phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

        phase.add_state('x', fix_initial=True, fix_final=True)

        phase.add_state('y', fix_initial=True, fix_final=True)

        phase.add_state('v', fix_initial=True, fix_final=False)

        phase.add_control('theta',
                          continuity=True,
                          rate_continuity=True,
                          units='deg',
                          lower=0.01,
                          upper=179.9)

        phase.add_parameter('g', units='m/s**2', val=9.80665)
        #
        # Minimize time at the end of the phase
        #
        phase.add_objective('time', loc='final', scaler=10)

        p.model.linear_solver = om.DirectSolver()

        #
        # Setup the Problem
        #
        p.setup()

        #
        # Set the initial values
        #
        p['traj.phase0.t_initial'] = 0.0
        p['traj.phase0.t_duration'] = 2.0

        p.set_val('traj.phase0.states:x', phase.interp('x', ys=[0, 10]))
        p.set_val('traj.phase0.states:y', phase.interp('y', ys=[10, 5]))
        p.set_val('traj.phase0.states:v', phase.interp('v', ys=[0, 9.9]))
        p.set_val('traj.phase0.controls:theta',
                  phase.interp('theta', ys=[5, 100.5]))

        #
        # Solve for the optimal trajectory
        #
        dm.run_problem(p)

        # Test the results
        assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1],
                          1.8016,
                          tolerance=1.0E-3)

        # Generate the explicitly simulated trajectory
        exp_out = traj.simulate()

        plot_results(
            [('traj.phase0.timeseries.states:x',
              'traj.phase0.timeseries.states:y', 'x (m)', 'y (m)'),
             ('traj.phase0.timeseries.time',
              'traj.phase0.timeseries.controls:theta', 'time (s)',
              'theta (deg)')],
            title='Brachistochrone Solution\nHigh-Order Gauss-Lobatto Method',
            p_sol=p,
            p_sim=exp_out)

        plt.show()
Beispiel #15
0
    def test_radau(self):
        p = om.Problem(model=om.Group())

        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.declare_coloring()

        t = dm.Radau(num_segments=20, order=[3, 5] * 10, compressed=True)

        phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t)

        p.model.add_subsystem('phase0', phase)

        phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

        phase.add_state(
            'x',
            rate_source=BrachistochroneODE.states['x']['rate_source'],
            units=BrachistochroneODE.states['x']['units'],
            fix_initial=True,
            fix_final=False,
            solve_segments=False)
        phase.add_state(
            'y',
            rate_source=BrachistochroneODE.states['y']['rate_source'],
            units=BrachistochroneODE.states['y']['units'],
            fix_initial=True,
            fix_final=False,
            solve_segments=False)
        phase.add_state(
            'v',
            rate_source=BrachistochroneODE.states['v']['rate_source'],
            targets=BrachistochroneODE.states['v']['targets'],
            units=BrachistochroneODE.states['v']['units'],
            fix_initial=True,
            fix_final=False,
            solve_segments=False)

        phase.add_control(
            'theta',
            targets=BrachistochroneODE.parameters['theta']['targets'],
            continuity=True,
            rate_continuity=True,
            units='deg',
            lower=0.01,
            upper=179.9)

        phase.add_input_parameter(
            'g',
            targets=BrachistochroneODE.parameters['g']['targets'],
            units='m/s**2',
            val=9.80665)

        phase.add_boundary_constraint('x', loc='final', equals=10)
        phase.add_boundary_constraint('y', loc='final', equals=5)
        # Minimize time at the end of the phase
        phase.add_objective('time_phase', loc='final', scaler=10)

        p.model.linear_solver = om.DirectSolver()
        p.setup(check=True)

        p['phase0.t_initial'] = 0.0
        p['phase0.t_duration'] = 2.0

        p['phase0.states:x'] = phase.interpolate(ys=[0, 10],
                                                 nodes='state_input')
        p['phase0.states:y'] = phase.interpolate(ys=[10, 5],
                                                 nodes='state_input')
        p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9],
                                                 nodes='state_input')
        p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100],
                                                       nodes='control_input')
        p['phase0.input_parameters:g'] = 9.80665

        p.run_driver()

        exp_out = phase.simulate()

        t_initial = p.get_val('phase0.timeseries.time')[0]
        tf = p.get_val('phase0.timeseries.time')[-1]

        x0 = p.get_val('phase0.timeseries.states:x')[0]
        xf = p.get_val('phase0.timeseries.states:x')[-1]

        y0 = p.get_val('phase0.timeseries.states:y')[0]
        yf = p.get_val('phase0.timeseries.states:y')[-1]

        v0 = p.get_val('phase0.timeseries.states:v')[0]
        vf = p.get_val('phase0.timeseries.states:v')[-1]

        g = p.get_val('phase0.timeseries.input_parameters:g')[0]

        thetaf = exp_out.get_val('phase0.timeseries.controls:theta')[-1]

        assert_almost_equal(t_initial, 0.0)
        assert_almost_equal(x0, 0.0)
        assert_almost_equal(y0, 10.0)
        assert_almost_equal(v0, 0.0)

        assert_almost_equal(tf, 1.8016, decimal=3)
        assert_almost_equal(xf, 10.0, decimal=3)
        assert_almost_equal(yf, 5.0, decimal=3)
        assert_almost_equal(vf, 9.902, decimal=3)
        assert_almost_equal(g, 9.80665, decimal=3)

        assert_almost_equal(thetaf, 100.12, decimal=0)
Beispiel #16
0
    def test_double_integrator_for_docs(self):
        import matplotlib.pyplot as plt
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm
        from dymos.examples.plotting import plot_results
        from dymos.examples.double_integrator.double_integrator_ode import DoubleIntegratorODE

        # Initialize the problem and assign the driver
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.declare_coloring()

        # Setup the trajectory and its phase
        traj = p.model.add_subsystem('traj', dm.Trajectory())

        transcription = dm.Radau(num_segments=30, order=3, compressed=False)

        phase = traj.add_phase(
            'phase0',
            dm.Phase(ode_class=DoubleIntegratorODE,
                     transcription=transcription))

        #
        # Set the options for our variables.
        #
        phase.set_time_options(fix_initial=True, fix_duration=True, units='s')
        phase.add_state('v',
                        fix_initial=True,
                        fix_final=True,
                        rate_source='u',
                        units='m/s')
        phase.add_state('x', fix_initial=True, rate_source='v', units='m')

        phase.add_control('u',
                          units='m/s**2',
                          scaler=0.01,
                          continuity=False,
                          rate_continuity=False,
                          rate2_continuity=False,
                          shape=(1, ),
                          lower=-1.0,
                          upper=1.0)

        #
        # Maximize distance travelled.
        #
        phase.add_objective('x', loc='final', scaler=-1)

        p.model.linear_solver = om.DirectSolver()

        #
        # Setup the problem and set our initial values.
        #
        p.setup(check=True)

        p['traj.phase0.t_initial'] = 0.0
        p['traj.phase0.t_duration'] = 1.0

        p['traj.phase0.states:x'] = phase.interpolate(ys=[0, 0.25],
                                                      nodes='state_input')
        p['traj.phase0.states:v'] = phase.interpolate(ys=[0, 0],
                                                      nodes='state_input')
        p['traj.phase0.controls:u'] = phase.interpolate(ys=[1, -1],
                                                        nodes='control_input')

        #
        # Solve the problem.
        #
        dm.run_problem(p)

        #
        # Verify that the results are correct.
        #
        x = p.get_val('traj.phase0.timeseries.states:x')
        v = p.get_val('traj.phase0.timeseries.states:v')

        assert_near_equal(x[0], 0.0, tolerance=1.0E-4)
        assert_near_equal(x[-1], 0.25, tolerance=1.0E-4)

        assert_near_equal(v[0], 0.0, tolerance=1.0E-4)
        assert_near_equal(v[-1], 0.0, tolerance=1.0E-4)

        #
        # Simulate the explicit solution and plot the results.
        #
        exp_out = traj.simulate()

        plot_results(
            [('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:x',
              'time (s)', 'x $(m)$'),
             ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:v',
              'time (s)', 'v $(m/s)$'),
             ('traj.phase0.timeseries.time',
              'traj.phase0.timeseries.controls:u', 'time (s)', 'u $(m/s^2)$')],
            title='Double Integrator Solution\nRadau Pseudospectral Method',
            p_sol=p,
            p_sim=exp_out)

        plt.show()
Beispiel #17
0
def _make_problem(transcription='gauss-lobatto', num_segments=8, transcription_order=3,
                  compressed=True, optimizer='SLSQP', force_alloc_complex=False,
                  solve_segments=False, y_bounds=None):
    p = om.Problem(model=om.Group())

    p.driver = om.pyOptSparseDriver()
    p.driver.options['optimizer'] = optimizer
    if optimizer == 'SNOPT':
        p.driver.opt_settings['iSumm'] = 6
        p.driver.opt_settings['Verify level'] = 3
    elif optimizer == 'IPOPT':
        p.driver.opt_settings['mu_init'] = 1e-3
        p.driver.opt_settings['max_iter'] = 500
        p.driver.opt_settings['print_level'] = 5
        p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based'  # for faster convergence
        p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas'
        p.driver.opt_settings['mu_strategy'] = 'monotone'
    p.driver.declare_coloring(tol=1.0E-12)

    if transcription == 'gauss-lobatto':
        t = dm.GaussLobatto(num_segments=num_segments,
                            order=transcription_order,
                            compressed=compressed)
    elif transcription == 'radau-ps':
        t = dm.Radau(num_segments=num_segments,
                     order=transcription_order,
                     compressed=compressed)

    traj = dm.Trajectory()
    phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t)
    p.model.add_subsystem('traj0', traj)
    traj.add_phase('phase0', phase)

    phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

    phase.add_state('x', fix_initial=False, fix_final=False, solve_segments=solve_segments)
    phase.add_state('y', fix_initial=False, fix_final=False, solve_segments=solve_segments)

    if y_bounds is not None:
        phase.set_state_options('y', lower=y_bounds[0], upper=y_bounds[1])

    # Note that by omitting the targets here Dymos will automatically attempt to connect
    # to a top-level input named 'v' in the ODE, and connect to nothing if it's not found.
    phase.add_state('v', fix_initial=False, fix_final=False, solve_segments=solve_segments)

    phase.add_control('theta',
                      continuity=True, rate_continuity=True,
                      units='deg', lower=0.01, upper=179.9)

    phase.add_parameter('g', targets=['g'], units='m/s**2')

    phase.add_boundary_constraint('x', loc='initial', equals=0)
    phase.add_boundary_constraint('y', loc='initial', equals=10)
    phase.add_boundary_constraint('v', loc='initial', equals=0)

    phase.add_boundary_constraint('x', loc='final', equals=10)
    phase.add_boundary_constraint('y', loc='final', equals=5)
    # Minimize time at the end of the phase
    phase.add_objective('time_phase', loc='final', scaler=10)

    p.set_solver_print(0)

    p.setup(check=['unconnected_inputs'], force_alloc_complex=force_alloc_complex)

    p['traj0.phase0.t_initial'] = 0.0
    p['traj0.phase0.t_duration'] = 1.5

    p['traj0.phase0.states:x'] = phase.interp('x', [0, 10])
    p['traj0.phase0.states:y'] = phase.interp('y', [10, 5])
    p['traj0.phase0.states:v'] = phase.interp('v', [0, 9.9])
    p['traj0.phase0.controls:theta'] = phase.interp('theta', [5, 100])
    p['traj0.phase0.parameters:g'] = 9.80665

    return p
Beispiel #18
0
    def test_brachistochrone_simulate_units(self):

        #
        # Define the OpenMDAO problem
        #
        p = om.Problem(model=om.Group())

        #
        # Define a Trajectory object
        #
        traj = dm.Trajectory()

        p.model.add_subsystem('traj', subsys=traj)

        #
        # Define a Dymos Phase object with GaussLobatto Transcription
        #
        phase = dm.Phase(ode_class=BrachistochroneODE,
                         ode_init_kwargs={'static_gravity': True},
                         transcription=dm.GaussLobatto(num_segments=7,
                                                       order=3))

        traj.add_phase(name='phase0', phase=phase)

        #
        # Set the time options
        # Time has no targets in our ODE.
        # We fix the initial time so that the it is not a design variable in the optimization.
        # The duration of the phase is allowed to be optimized, but is bounded on [0.5, 10].
        #
        phase.set_time_options(fix_initial=True,
                               duration_bounds=(0.5, 10.0),
                               units='s')

        #
        # Set the time options
        # Initial values of positions and velocity are all fixed.
        # The final value of position are fixed, but the final velocity is a free variable.
        # The equations of motion are not functions of position, so 'x' and 'y' have no targets.
        # The rate source points to the output in the ODE which provides the time derivative of the
        # given state.
        phase.add_state('x',
                        fix_initial=True,
                        fix_final=True,
                        rate_source='xdot')
        phase.add_state('y',
                        fix_initial=True,
                        fix_final=True,
                        rate_source='ydot')
        phase.add_state('v',
                        fix_initial=True,
                        fix_final=False,
                        rate_source='vdot')

        # Define theta as a control.
        phase.add_control(name='theta', units='rad', lower=0, upper=np.pi)

        phase.add_parameter(name='g',
                            units='m/s**2',
                            static_target=True,
                            opt=False)

        # Minimize final time.
        phase.add_objective('time', loc='final')

        # Set the driver.
        p.driver = om.ScipyOptimizeDriver()

        # Allow OpenMDAO to automatically determine our sparsity pattern.
        # Doing so can significant speed up the execution of Dymos.
        p.driver.declare_coloring()

        p.model.set_input_defaults("traj.phase0.parameters:g",
                                   val=9.80665 / 0.3048,
                                   units="ft/s**2")

        # Setup the problem
        p.setup(check=True)

        # Now that the OpenMDAO problem is setup, we can set the values of the states.
        p.set_val('traj.phase0.states:x',
                  phase.interp('x', [0, 10]),
                  units='m')

        p.set_val('traj.phase0.states:y',
                  phase.interp('y', [10, 5]),
                  units='m')

        p.set_val('traj.phase0.states:v',
                  phase.interp('v', [1.0E-6, 5]),
                  units='m/s')

        p.set_val('traj.phase0.controls:theta',
                  phase.interp('theta', [5, 100]),
                  units='deg')

        p.set_val('traj.phase0.parameters:g', 9.80665, units='m/s**2')

        # Run the driver to solve the problem
        dm.run_problem(p, simulate=True)

        sol_case = om.CaseReader('dymos_solution.db').get_case('final')
        sim_case = om.CaseReader('dymos_simulation.db').get_case('final')

        assert_near_equal(
            sim_case.get_val('traj.phase0.timeseries.parameters:g',
                             units='m/s**2')[0],
            sol_case.get_val('traj.phase0.timeseries.parameters:g',
                             units='m/s**2')[0])

        assert_near_equal(sol_case.get_val('traj.phase0.timeseries.time')[-1],
                          1.8016,
                          tolerance=1.0E-4)
        assert_near_equal(sim_case.get_val('traj.phase0.timeseries.time')[-1],
                          1.8016,
                          tolerance=1.0E-4)
Beispiel #19
0
    def test_tandem_phases_for_docs(self):
        p = om.Problem(model=om.Group())

        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.declare_coloring()

        #
        # First Phase: Standard Brachistochrone
        #
        num_segments = 10
        transcription_order = 3
        compressed = False

        tx0 = dm.GaussLobatto(num_segments=num_segments,
                              order=transcription_order,
                              compressed=compressed)

        tx1 = dm.Radau(num_segments=num_segments * 2,
                       order=transcription_order * 3,
                       compressed=compressed)

        phase0 = dm.Phase(ode_class=BrachistochroneODE, transcription=tx0)

        p.model.add_subsystem('phase0', phase0)

        phase0.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

        phase0.add_state(
            'x',
            rate_source=BrachistochroneODE.states['x']['rate_source'],
            units=BrachistochroneODE.states['x']['units'],
            fix_initial=True,
            fix_final=False,
            solve_segments=False)

        phase0.add_state(
            'y',
            rate_source=BrachistochroneODE.states['y']['rate_source'],
            units=BrachistochroneODE.states['y']['units'],
            fix_initial=True,
            fix_final=False,
            solve_segments=False)

        phase0.add_state(
            'v',
            rate_source=BrachistochroneODE.states['v']['rate_source'],
            targets=BrachistochroneODE.states['v']['targets'],
            units=BrachistochroneODE.states['v']['units'],
            fix_initial=True,
            fix_final=False,
            solve_segments=False)

        phase0.add_control(
            'theta',
            continuity=True,
            rate_continuity=True,
            targets=BrachistochroneODE.parameters['theta']['targets'],
            units='deg',
            lower=0.01,
            upper=179.9)

        phase0.add_input_parameter(
            'g',
            targets=BrachistochroneODE.parameters['g']['targets'],
            units='m/s**2',
            val=9.80665)

        phase0.add_boundary_constraint('x', loc='final', equals=10)
        phase0.add_boundary_constraint('y', loc='final', equals=5)

        # Add alternative timeseries output to provide control inputs for the next phase
        phase0.add_timeseries('timeseries2',
                              transcription=tx1,
                              subset='control_input')

        #
        # Second Phase: Integration of ArcLength
        #

        phase1 = dm.Phase(ode_class=BrachistochroneArclengthODE,
                          transcription=tx1)

        p.model.add_subsystem('phase1', phase1)

        phase1.set_time_options(fix_initial=True, input_duration=True)

        phase1.add_state('S',
                         fix_initial=True,
                         fix_final=False,
                         rate_source='Sdot',
                         units='m')

        phase1.add_control('theta', opt=False, units='deg', targets='theta')
        phase1.add_control('v', opt=False, units='m/s', targets='v')

        #
        # Connect the two phases
        #
        p.model.connect('phase0.t_duration', 'phase1.t_duration')

        p.model.connect('phase0.timeseries2.controls:theta',
                        'phase1.controls:theta')
        p.model.connect('phase0.timeseries2.states:v', 'phase1.controls:v')

        # Minimize time at the end of the phase
        # phase1.add_objective('time', loc='final', scaler=1)
        # phase1.add_boundary_constraint('S', loc='final', upper=12)

        phase1.add_objective('S', loc='final', ref=1)

        p.model.linear_solver = om.DirectSolver()
        p.setup(check=True)

        p['phase0.t_initial'] = 0.0
        p['phase0.t_duration'] = 2.0

        p['phase0.states:x'] = phase0.interpolate(ys=[0, 10],
                                                  nodes='state_input')
        p['phase0.states:y'] = phase0.interpolate(ys=[10, 5],
                                                  nodes='state_input')
        p['phase0.states:v'] = phase0.interpolate(ys=[0, 9.9],
                                                  nodes='state_input')
        p['phase0.controls:theta'] = phase0.interpolate(ys=[5, 100],
                                                        nodes='control_input')
        p['phase0.input_parameters:g'] = 9.80665

        p['phase1.states:S'] = 0.0

        p.run_driver()

        expected = np.sqrt((10 - 0)**2 + (10 - 5)**2)
        assert_rel_error(self,
                         p['phase1.timeseries.states:S'][-1],
                         expected,
                         tolerance=1.0E-3)

        fig, (ax0, ax1) = plt.subplots(2, 1)
        fig.tight_layout()
        ax0.plot(p.get_val('phase0.timeseries.states:x'),
                 p.get_val('phase0.timeseries.states:y'), '.')
        ax0.set_xlabel('x (m)')
        ax0.set_ylabel('y (m)')
        ax1.plot(p.get_val('phase1.timeseries.time'),
                 p.get_val('phase1.timeseries.states:S'), '+')
        ax1.set_xlabel('t (s)')
        ax1.set_ylabel('S (m)')
        plt.show()
Beispiel #20
0
def _run_racecar_problem(transcription, timeseries=False):
    # change track here and in curvature.py. Tracks are defined in tracks.py
    track = ovaltrack

    # generate nodes along the centerline for curvature calculation (different
    # than collocation nodes)
    points = get_track_points(track)

    # fit the centerline spline.
    finespline, gates, gatesd, curv, slope = get_spline(points, s=0.0)
    # by default 10000 points
    s_final = track.get_total_length()

    # Define the OpenMDAO problem
    p = om.Problem(model=om.Group())

    # Define a Trajectory object
    traj = dm.Trajectory()
    p.model.add_subsystem('traj', subsys=traj)

    # Define a Dymos Phase object with radau Transcription
    phase = dm.Phase(ode_class=CombinedODE,
                     transcription=transcription(num_segments=50,
                                                 order=3,
                                                 compressed=True))

    traj.add_phase(name='phase0', phase=phase)

    # Set the time options, in this problem we perform a change of variables. So 'time' is
    # actually 's' (distance along the track centerline)
    # This is done to fix the collocation nodes in space, which saves us the calculation of
    # the rate of change of curvature.
    # The state equations are written with respect to time, the variable change occurs in
    # timeODE.py
    phase.set_time_options(fix_initial=True,
                           fix_duration=True,
                           duration_val=s_final,
                           targets=['curv.s'],
                           units='m',
                           duration_ref=s_final,
                           duration_ref0=10)

    # Define states
    phase.add_state('t',
                    fix_initial=True,
                    fix_final=False,
                    units='s',
                    lower=0,
                    rate_source='dt_ds',
                    ref=100)  # time
    phase.add_state(
        'n',
        fix_initial=False,
        fix_final=False,
        units='m',
        upper=4.0,
        lower=-4.0,
        rate_source='dn_ds',
        targets=['n'],
        ref=4.0)  # normal distance to centerline. The bounds on n define the
    # width of the track
    phase.add_state('V',
                    fix_initial=False,
                    fix_final=False,
                    units='m/s',
                    ref=40,
                    ref0=5,
                    rate_source='dV_ds',
                    targets=['V'])  # velocity
    phase.add_state(
        'alpha',
        fix_initial=False,
        fix_final=False,
        units='rad',
        rate_source='dalpha_ds',
        targets=['alpha'],
        ref=0.15)  # vehicle heading angle with respect to centerline
    phase.add_state(
        'lambda',
        fix_initial=False,
        fix_final=False,
        units='rad',
        rate_source='dlambda_ds',
        targets=['lambda'],
        ref=0.01
    )  # vehicle slip angle, or angle between the axis of the vehicle
    # and velocity vector (all cars drift a little)
    phase.add_state('omega',
                    fix_initial=False,
                    fix_final=False,
                    units='rad/s',
                    rate_source='domega_ds',
                    targets=['omega'],
                    ref=0.3)  # yaw rate
    phase.add_state('ax',
                    fix_initial=False,
                    fix_final=False,
                    units='m/s**2',
                    rate_source='dax_ds',
                    targets=['ax'],
                    ref=8)  # longitudinal acceleration
    phase.add_state('ay',
                    fix_initial=False,
                    fix_final=False,
                    units='m/s**2',
                    rate_source='day_ds',
                    targets=['ay'],
                    ref=8)  # lateral acceleration

    # Define Controls
    phase.add_control(name='delta',
                      units='rad',
                      lower=None,
                      upper=None,
                      fix_initial=False,
                      fix_final=False,
                      targets=['delta'],
                      ref=0.04)  # steering angle
    phase.add_control(
        name='thrust',
        units=None,
        fix_initial=False,
        fix_final=False,
        targets=['thrust']
    )  # the thrust controls the longitudinal force of the rear tires and is
    # positive while accelerating, negative while braking

    # Performance Constraints
    pmax = 960000  # W
    phase.add_path_constraint('power', upper=pmax,
                              ref=100000)  # engine power limit

    # The following four constraints are the tire friction limits, with 'rr' designating the
    # rear right wheel etc. This limit is computed in tireConstraintODE.py
    phase.add_path_constraint('c_rr', upper=1)
    phase.add_path_constraint('c_rl', upper=1)
    phase.add_path_constraint('c_fr', upper=1)
    phase.add_path_constraint('c_fl', upper=1)

    # Some of the vehicle design parameters are available to set here. Other parameters can
    # be found in their respective ODE files.
    phase.add_parameter(
        'M',
        val=800.0,
        units='kg',
        opt=False,
        targets=['car.M', 'tire.M', 'tireconstraint.M', 'normal.M'],
        static_target=True)  # vehicle mass
    phase.add_parameter('beta',
                        val=0.62,
                        units=None,
                        opt=False,
                        targets=['tire.beta'],
                        static_target=True)  # brake bias
    phase.add_parameter('CoP',
                        val=1.6,
                        units='m',
                        opt=False,
                        targets=['normal.CoP'],
                        static_target=True)  # center of pressure location
    phase.add_parameter('h',
                        val=0.3,
                        units='m',
                        opt=False,
                        targets=['normal.h'],
                        static_target=True)  # center of gravity height
    phase.add_parameter('chi',
                        val=0.5,
                        units=None,
                        opt=False,
                        targets=['normal.chi'],
                        static_target=True)  # roll stiffness
    phase.add_parameter('ClA',
                        val=4.0,
                        units='m**2',
                        opt=False,
                        targets=['normal.ClA'],
                        static_target=True)  # downforce coefficient*area
    phase.add_parameter('CdA',
                        val=2.0,
                        units='m**2',
                        opt=False,
                        targets=['car.CdA'],
                        static_target=True)  # drag coefficient*area

    # Minimize final time.
    # note that we use the 'state' time instead of Dymos 'time'
    phase.add_objective('t', loc='final')

    # Add output timeseries
    if timeseries:
        phase.add_timeseries_output('*')

    # Link the states at the start and end of the phase in order to ensure a continous lap
    traj.link_phases(phases=['phase0', 'phase0'],
                     vars=['V', 'n', 'alpha', 'omega', 'lambda', 'ax', 'ay'],
                     locs=('final', 'initial'))

    # Set the driver. IPOPT or SNOPT are recommended but SLSQP might work.
    p.driver = om.pyOptSparseDriver(optimizer='IPOPT')

    p.driver.opt_settings['mu_init'] = 1e-3
    p.driver.opt_settings['max_iter'] = 500
    p.driver.opt_settings['acceptable_tol'] = 1e-3
    p.driver.opt_settings['constr_viol_tol'] = 1e-3
    p.driver.opt_settings['compl_inf_tol'] = 1e-3
    p.driver.opt_settings['acceptable_iter'] = 0
    p.driver.opt_settings['tol'] = 1e-3
    p.driver.opt_settings['print_level'] = 5
    p.driver.opt_settings[
        'nlp_scaling_method'] = 'gradient-based'  # for faster convergence
    p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas'
    p.driver.opt_settings['mu_strategy'] = 'monotone'
    p.driver.opt_settings['bound_mult_init_method'] = 'mu-based'

    # Allow OpenMDAO to automatically determine our sparsity pattern.
    # Doing so can significant speed up the execution of Dymos.
    p.driver.declare_coloring()

    # Setup the problem
    p.setup(check=True)  # force_alloc_complex=True
    # Now that the OpenMDAO problem is setup, we can set the values of the states.

    # States
    # non-zero velocity in order to protect against 1/0 errors.
    p.set_val('traj.phase0.states:V', phase.interp('V', [20, 20]), units='m/s')
    p.set_val('traj.phase0.states:lambda',
              phase.interp('lambda', [0.0, 0.0]),
              units='rad')
    # all other states start at 0
    p.set_val('traj.phase0.states:omega',
              phase.interp('omega', [0.0, 0.0]),
              units='rad/s')
    p.set_val('traj.phase0.states:alpha',
              phase.interp('alpha', [0.0, 0.0]),
              units='rad')
    p.set_val('traj.phase0.states:ax',
              phase.interp('ax', [0.0, 0.0]),
              units='m/s**2')
    p.set_val('traj.phase0.states:ay',
              phase.interp('ay', [0.0, 0.0]),
              units='m/s**2')
    p.set_val('traj.phase0.states:n', phase.interp('n', [0.0, 0.0]), units='m')
    # initial guess for what the final time should be
    p.set_val('traj.phase0.states:t',
              phase.interp('t', [0.0, 100.0]),
              units='s')

    # Controls
    p.set_val('traj.phase0.controls:delta',
              phase.interp('delta', [0.0, 0.0]),
              units='rad')
    p.set_val('traj.phase0.controls:thrust',
              phase.interp('thrust', [0.1, 0.1]),
              units=None)
    # a small amount of thrust can speed up convergence

    dm.run_problem(p, run_driver=True, simulate=False, make_plots=False)
    print('Optimization finished')

    t = p.get_val('traj.phase0.timeseries.states:t')
    assert_near_equal(t[-1], 22.2657, tolerance=0.01)
Beispiel #21
0
    def test_doc_ssto_linear_tangent_guidance(self):
        import numpy as np
        import matplotlib.pyplot as plt
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm
        from dymos.examples.plotting import plot_results

        g = 1.61544  # lunar gravity, m/s**2

        class LaunchVehicle2DEOM(om.ExplicitComponent):
            """
            Simple 2D Cartesian Equations of Motion for a launch vehicle subject to thrust and drag.
            """
            def initialize(self):
                self.options.declare('num_nodes', types=int)

            def setup(self):
                nn = self.options['num_nodes']

                # Inputs
                self.add_input('vx',
                               val=np.zeros(nn),
                               desc='x velocity',
                               units='m/s')

                self.add_input('vy',
                               val=np.zeros(nn),
                               desc='y velocity',
                               units='m/s')

                self.add_input('m', val=np.zeros(nn), desc='mass', units='kg')

                self.add_input('theta',
                               val=np.zeros(nn),
                               desc='pitch angle',
                               units='rad')

                self.add_input('thrust',
                               val=2100000 * np.ones(nn),
                               desc='thrust',
                               units='N')

                self.add_input('Isp',
                               val=265.2 * np.ones(nn),
                               desc='specific impulse',
                               units='s')

                # Outputs
                self.add_output('xdot',
                                val=np.zeros(nn),
                                desc='velocity component in x',
                                units='m/s')

                self.add_output('ydot',
                                val=np.zeros(nn),
                                desc='velocity component in y',
                                units='m/s')

                self.add_output('vxdot',
                                val=np.zeros(nn),
                                desc='x acceleration magnitude',
                                units='m/s**2')

                self.add_output('vydot',
                                val=np.zeros(nn),
                                desc='y acceleration magnitude',
                                units='m/s**2')

                self.add_output('mdot',
                                val=np.zeros(nn),
                                desc='mass rate of change',
                                units='kg/s')

                # Setup partials
                ar = np.arange(self.options['num_nodes'])

                self.declare_partials(of='xdot',
                                      wrt='vx',
                                      rows=ar,
                                      cols=ar,
                                      val=1.0)
                self.declare_partials(of='ydot',
                                      wrt='vy',
                                      rows=ar,
                                      cols=ar,
                                      val=1.0)

                self.declare_partials(of='vxdot', wrt='vx', rows=ar, cols=ar)
                self.declare_partials(of='vxdot', wrt='m', rows=ar, cols=ar)
                self.declare_partials(of='vxdot',
                                      wrt='theta',
                                      rows=ar,
                                      cols=ar)
                self.declare_partials(of='vxdot',
                                      wrt='thrust',
                                      rows=ar,
                                      cols=ar)

                self.declare_partials(of='vydot', wrt='m', rows=ar, cols=ar)
                self.declare_partials(of='vydot',
                                      wrt='theta',
                                      rows=ar,
                                      cols=ar)
                self.declare_partials(of='vydot', wrt='vy', rows=ar, cols=ar)
                self.declare_partials(of='vydot',
                                      wrt='thrust',
                                      rows=ar,
                                      cols=ar)

                self.declare_partials(of='mdot',
                                      wrt='thrust',
                                      rows=ar,
                                      cols=ar)
                self.declare_partials(of='mdot', wrt='Isp', rows=ar, cols=ar)

            def compute(self, inputs, outputs):
                theta = inputs['theta']
                cos_theta = np.cos(theta)
                sin_theta = np.sin(theta)
                vx = inputs['vx']
                vy = inputs['vy']
                m = inputs['m']
                F_T = inputs['thrust']
                Isp = inputs['Isp']

                outputs['xdot'] = vx
                outputs['ydot'] = vy
                outputs['vxdot'] = F_T * cos_theta / m
                outputs['vydot'] = F_T * sin_theta / m - g
                outputs['mdot'] = -F_T / (g * Isp)

            def compute_partials(self, inputs, jacobian):
                theta = inputs['theta']
                cos_theta = np.cos(theta)
                sin_theta = np.sin(theta)
                m = inputs['m']
                F_T = inputs['thrust']
                Isp = inputs['Isp']

                # jacobian['vxdot', 'vx'] = -CDA * rho * vx / m
                jacobian['vxdot', 'm'] = -(F_T * cos_theta) / m**2
                jacobian['vxdot', 'theta'] = -(F_T / m) * sin_theta
                jacobian['vxdot', 'thrust'] = cos_theta / m

                # jacobian['vydot', 'vy'] = -CDA * rho * vy / m
                jacobian['vydot', 'm'] = -(F_T * sin_theta) / m**2
                jacobian['vydot', 'theta'] = (F_T / m) * cos_theta
                jacobian['vydot', 'thrust'] = sin_theta / m

                jacobian['mdot', 'thrust'] = -1.0 / (g * Isp)
                jacobian['mdot', 'Isp'] = F_T / (g * Isp**2)

        class LinearTangentGuidanceComp(om.ExplicitComponent):
            """ Compute pitch angle from static controls governing linear expression for
                pitch angle tangent as function of time.
            """
            def initialize(self):
                self.options.declare('num_nodes', types=int)

            def setup(self):
                nn = self.options['num_nodes']

                self.add_input('a_ctrl',
                               val=np.zeros(nn),
                               desc='linear tangent slope',
                               units='1/s')

                self.add_input('b_ctrl',
                               val=np.zeros(nn),
                               desc='tangent of theta at t=0',
                               units=None)

                self.add_input('time_phase',
                               val=np.zeros(nn),
                               desc='time',
                               units='s')

                self.add_output('theta',
                                val=np.zeros(nn),
                                desc='pitch angle',
                                units='rad')

                # Setup partials
                arange = np.arange(self.options['num_nodes'])

                self.declare_partials(of='theta',
                                      wrt='a_ctrl',
                                      rows=arange,
                                      cols=arange,
                                      val=1.0)
                self.declare_partials(of='theta',
                                      wrt='b_ctrl',
                                      rows=arange,
                                      cols=arange,
                                      val=1.0)
                self.declare_partials(of='theta',
                                      wrt='time_phase',
                                      rows=arange,
                                      cols=arange,
                                      val=1.0)

            def compute(self, inputs, outputs):
                a = inputs['a_ctrl']
                b = inputs['b_ctrl']
                t = inputs['time_phase']
                outputs['theta'] = np.arctan(a * t + b)

            def compute_partials(self, inputs, jacobian):
                a = inputs['a_ctrl']
                b = inputs['b_ctrl']
                t = inputs['time_phase']

                x = a * t + b
                denom = x**2 + 1.0

                jacobian['theta', 'a_ctrl'] = t / denom
                jacobian['theta', 'b_ctrl'] = 1.0 / denom
                jacobian['theta', 'time_phase'] = a / denom

        class LaunchVehicleLinearTangentODE(om.Group):
            """
            The LaunchVehicleLinearTangentODE for this case consists of a guidance component and
            the EOM.  Guidance is simply an OpenMDAO ExecComp which computes the arctangent of the
            tan_theta variable.
            """
            def initialize(self):
                self.options.declare(
                    'num_nodes',
                    types=int,
                    desc='Number of nodes to be evaluated in the RHS')

            def setup(self):
                nn = self.options['num_nodes']
                self.add_subsystem('guidance',
                                   LinearTangentGuidanceComp(num_nodes=nn))
                self.add_subsystem('eom', LaunchVehicle2DEOM(num_nodes=nn))
                self.connect('guidance.theta', 'eom.theta')

        #
        # Setup and solve the optimal control problem
        #
        p = om.Problem(model=om.Group())

        p.driver = om.pyOptSparseDriver()
        p.driver.declare_coloring()

        traj = dm.Trajectory()
        p.model.add_subsystem('traj', traj)

        phase = dm.Phase(ode_class=LaunchVehicleLinearTangentODE,
                         transcription=dm.GaussLobatto(num_segments=10,
                                                       order=5,
                                                       compressed=True))

        traj.add_phase('phase0', phase)

        phase.set_time_options(fix_initial=True,
                               duration_bounds=(10, 1000),
                               targets=['guidance.time_phase'])

        phase.add_state('x',
                        fix_initial=True,
                        lower=0,
                        rate_source='eom.xdot',
                        units='m')
        phase.add_state('y',
                        fix_initial=True,
                        lower=0,
                        rate_source='eom.ydot',
                        units='m')
        phase.add_state('vx',
                        fix_initial=True,
                        lower=0,
                        rate_source='eom.vxdot',
                        targets=['eom.vx'],
                        units='m/s')
        phase.add_state('vy',
                        fix_initial=True,
                        rate_source='eom.vydot',
                        targets=['eom.vy'],
                        units='m/s')
        phase.add_state('m',
                        fix_initial=True,
                        rate_source='eom.mdot',
                        targets=['eom.m'],
                        units='kg')

        phase.add_boundary_constraint('y',
                                      loc='final',
                                      equals=1.85E5,
                                      linear=True)
        phase.add_boundary_constraint('vx', loc='final', equals=1627.0)
        phase.add_boundary_constraint('vy', loc='final', equals=0)

        phase.add_parameter('a_ctrl',
                            units='1/s',
                            opt=True,
                            targets=['guidance.a_ctrl'])
        phase.add_parameter('b_ctrl',
                            units=None,
                            opt=True,
                            targets=['guidance.b_ctrl'])
        phase.add_parameter('thrust',
                            units='N',
                            opt=False,
                            val=3.0 * 50000.0 * 1.61544,
                            targets=['eom.thrust'])
        phase.add_parameter('Isp',
                            units='s',
                            opt=False,
                            val=1.0E6,
                            targets=['eom.Isp'])

        phase.add_objective('time', index=-1, scaler=0.01)

        p.model.linear_solver = om.DirectSolver()

        phase.add_timeseries_output('guidance.theta', units='deg')

        p.setup(check=True)

        p['traj.phase0.t_initial'] = 0.0
        p['traj.phase0.t_duration'] = 500.0
        p['traj.phase0.states:x'] = phase.interpolate(ys=[0, 350000.0],
                                                      nodes='state_input')
        p['traj.phase0.states:y'] = phase.interpolate(ys=[0, 185000.0],
                                                      nodes='state_input')
        p['traj.phase0.states:vx'] = phase.interpolate(ys=[0, 1627.0],
                                                       nodes='state_input')
        p['traj.phase0.states:vy'] = phase.interpolate(ys=[1.0E-6, 0],
                                                       nodes='state_input')
        p['traj.phase0.states:m'] = phase.interpolate(ys=[50000, 50000],
                                                      nodes='state_input')
        p['traj.phase0.parameters:a_ctrl'] = -0.01
        p['traj.phase0.parameters:b_ctrl'] = 3.0

        dm.run_problem(p)

        #
        # Check the results.
        #
        assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1],
                          481,
                          tolerance=0.01)

        #
        # Get the explitly simulated results
        #
        exp_out = traj.simulate()

        #
        # Plot the results
        #
        plot_results(
            [('traj.phase0.timeseries.states:x',
              'traj.phase0.timeseries.states:y', 'range (m)', 'altitude (m)'),
             ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.theta',
              'range (m)', 'altitude (m)')],
            title=
            'Single Stage to Orbit Solution Using Linear Tangent Guidance',
            p_sol=p,
            p_sim=exp_out)

        plt.show()
Beispiel #22
0
    def test_control_rate2_boundary_constraint_gl(self):
        p = om.Problem(model=om.Group())

        p.driver = om.ScipyOptimizeDriver()

        p.driver.declare_coloring()

        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=dm.GaussLobatto(num_segments=20,
                                                       order=3,
                                                       compressed=True))

        p.model.add_subsystem('phase0', phase)

        phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

        phase.add_state('x', fix_initial=True, fix_final=False)

        phase.add_state('y', fix_initial=True, fix_final=False)

        phase.add_state('v', fix_initial=True, fix_final=False)

        phase.add_control('theta',
                          continuity=True,
                          rate_continuity=True,
                          rate2_continuity=True,
                          units='deg',
                          lower=0.01,
                          upper=179.9)

        phase.add_parameter('g', opt=False, units='m/s**2', val=9.80665)

        phase.add_boundary_constraint('theta_rate2',
                                      loc='final',
                                      equals=0.0,
                                      units='deg/s**2')

        # Minimize time at the end of the phase
        phase.add_objective('time')

        p.model.linear_solver = om.DirectSolver()
        p.setup(check=True)

        p['phase0.t_initial'] = 0.0
        p['phase0.t_duration'] = 2.0

        p['phase0.states:x'] = phase.interp('x', [0, 10])
        p['phase0.states:y'] = phase.interp('y', [10, 5])
        p['phase0.states:v'] = phase.interp('v', [0, 9.9])
        p['phase0.controls:theta'] = phase.interp('theta', [5, 100])
        p['phase0.parameters:g'] = 8

        p.run_driver()

        plt.plot(p.get_val('phase0.timeseries.states:x'),
                 p.get_val('phase0.timeseries.states:y'), 'ko')

        plt.figure()

        plt.plot(p.get_val('phase0.timeseries.time'),
                 p.get_val('phase0.timeseries.controls:theta'), 'ro')

        plt.plot(p.get_val('phase0.timeseries.time'),
                 p.get_val('phase0.timeseries.control_rates:theta_rate'), 'bo')

        plt.plot(p.get_val('phase0.timeseries.time'),
                 p.get_val('phase0.timeseries.control_rates:theta_rate2'),
                 'go')
        plt.show()

        assert_near_equal(
            p.get_val('phase0.timeseries.control_rates:theta_rate2')[-1],
            0,
            tolerance=1.0E-6)
Beispiel #23
0
    def _run_transcription(self, transcription):
        p = om.Problem(model=om.Group())

        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.declare_coloring()

        #
        # First Phase: Standard Brachistochrone
        #
        num_segments = 10
        transcription_order = 3
        compressed = False

        if transcription == 'gauss-lobatto':
            tx0 = dm.GaussLobatto(num_segments=num_segments,
                                  order=transcription_order,
                                  compressed=compressed)
            tx1 = dm.GaussLobatto(num_segments=num_segments * 2,
                                  order=transcription_order * 3,
                                  compressed=compressed)

        elif transcription == 'radau-ps':
            tx0 = dm.Radau(num_segments=num_segments,
                           order=transcription_order,
                           compressed=compressed)
            tx1 = dm.Radau(num_segments=num_segments * 2,
                           order=transcription_order * 3,
                           compressed=compressed)

        phase0 = dm.Phase(ode_class=BrachistochroneODE, transcription=tx0)

        p.model.add_subsystem('phase0', phase0)

        phase0.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

        phase0.add_state('x', fix_initial=True, fix_final=False)
        phase0.add_state('y', fix_initial=True, fix_final=False)
        phase0.add_state('v', fix_initial=True)

        phase0.add_parameter('g', units='m/s**2', val=9.80665)

        phase0.add_control('theta',
                           units='deg',
                           rate_continuity=False,
                           lower=0.01,
                           upper=179.9)

        phase0.add_boundary_constraint('x', loc='final', equals=10)
        phase0.add_boundary_constraint('y', loc='final', equals=5)

        # Add alternative timeseries output to provide control inputs for the next phase
        phase0.add_timeseries('timeseries2',
                              transcription=tx1,
                              subset='control_input')

        #
        # Second Phase: Integration of ArcLength
        #

        phase1 = dm.Phase(ode_class=BrachistochroneArclengthODE,
                          transcription=tx1)

        p.model.add_subsystem('phase1', phase1)

        phase1.set_time_options(fix_initial=True, input_duration=True)

        phase1.add_state('S',
                         fix_initial=True,
                         fix_final=False,
                         rate_source='Sdot')

        phase1.add_control('theta', opt=False, units='deg', targets=['theta'])
        phase1.add_control('v', opt=False, units='m/s', targets=['v'])

        #
        # Connect the two phases
        #
        p.model.connect('phase0.t_duration', 'phase1.t_duration')

        p.model.connect('phase0.timeseries2.controls:theta',
                        'phase1.controls:theta')
        p.model.connect('phase0.timeseries2.states:v', 'phase1.controls:v')

        # Minimize time at the end of the phase
        # phase1.add_objective('time', loc='final', scaler=1)
        # phase1.add_boundary_constraint('S', loc='final', upper=12)

        phase1.add_objective('S', loc='final', ref=1)

        p.model.linear_solver = om.DirectSolver()
        p.setup(check=True)

        p['phase0.t_initial'] = 0.0
        p['phase0.t_duration'] = 2.0

        p['phase0.states:x'] = phase0.interpolate(ys=[0, 10],
                                                  nodes='state_input')
        p['phase0.states:y'] = phase0.interpolate(ys=[10, 5],
                                                  nodes='state_input')
        p['phase0.states:v'] = phase0.interpolate(ys=[0, 9.9],
                                                  nodes='state_input')
        p['phase0.controls:theta'] = phase0.interpolate(ys=[5, 100],
                                                        nodes='control_input')
        p['phase0.parameters:g'] = 9.80665

        p['phase1.states:S'] = 0.0

        p.run_driver()

        expected = np.sqrt((10 - 0)**2 + (10 - 5)**2)
        assert_near_equal(p['phase1.timeseries.states:S'][-1],
                          expected,
                          tolerance=1.0E-3)
Beispiel #24
0
    def test_parameter_boundary_constraint(self):
        p = om.Problem(model=om.Group())

        p.driver = om.ScipyOptimizeDriver()
        p.driver.declare_coloring()

        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=dm.GaussLobatto(num_segments=20,
                                                       order=3,
                                                       compressed=True))

        p.model.add_subsystem('phase0', phase)

        phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10))

        phase.add_state('x', fix_initial=True, fix_final=True)

        phase.add_state('y', fix_initial=True, fix_final=True)

        phase.add_state('v', fix_initial=True, fix_final=False)

        phase.add_control('theta',
                          continuity=True,
                          rate_continuity=True,
                          rate2_continuity=True,
                          units='deg',
                          lower=0.01,
                          upper=179.9)

        phase.add_parameter('g', opt=True, units='m/s**2', val=9.80665)

        # We'll let g vary, but make sure it hits the desired value.
        # It's a static parameter, so it shouldn't matter whether we enforce it
        # at the start or the end of the phase, so here we'll do both.
        # Note if we make these equality constraints, some optimizers (SLSQP) will
        # see the problem as infeasible.
        phase.add_boundary_constraint('g',
                                      loc='initial',
                                      units='m/s**2',
                                      upper=9.80665)
        phase.add_boundary_constraint('g',
                                      loc='final',
                                      units='m/s**2',
                                      upper=9.80665)

        # Minimize time at the end of the phase
        phase.add_objective('time_phase', loc='final', scaler=10)

        p.model.linear_solver = om.DirectSolver()
        p.setup(check=True)

        p['phase0.t_initial'] = 0.0
        p['phase0.t_duration'] = 2.0

        p['phase0.states:x'] = phase.interp('x', [0, 10])
        p['phase0.states:y'] = phase.interp('y', [10, 5])
        p['phase0.states:v'] = phase.interp('v', [0, 9.9])
        p['phase0.controls:theta'] = phase.interp('theta', [5, 100])
        p['phase0.parameters:g'] = 5

        p.run_driver()

        assert_near_equal(p.get_val('phase0.timeseries.time')[-1],
                          1.8016,
                          tolerance=1.0E-4)
        assert_near_equal(p.get_val('phase0.timeseries.parameters:g')[0],
                          9.80665,
                          tolerance=1.0E-6)
        assert_near_equal(p.get_val('phase0.timeseries.parameters:g')[-1],
                          9.80665,
                          tolerance=1.0E-6)
    def test_vanderpol_delay_mpi(self):
        import openmdao.api as om
        import dymos as dm
        from dymos.examples.vanderpol.vanderpol_ode import VanderpolODE
        from openmdao.utils.assert_utils import assert_near_equal

        DELAY = 0.005

        p = om.Problem(model=om.Group())
        p.driver = om.ScipyOptimizeDriver()

        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.declare_coloring()

        # define a Trajectory object and add to model
        traj = dm.Trajectory()
        p.model.add_subsystem('traj', subsys=traj)

        t = dm.Radau(num_segments=30, order=3)

        # define a Phase as specified above and add to Phase
        phase = dm.Phase(ode_class=VanderpolODE,
                         transcription=t,
                         ode_init_kwargs={
                             'delay': DELAY,
                             'distrib': True
                         })
        traj.add_phase(name='phase0', phase=phase)

        t_final = 15
        phase.set_time_options(fix_initial=True,
                               fix_duration=True,
                               duration_val=t_final,
                               units='s')

        # set the State time options
        phase.add_state('x0',
                        fix_initial=False,
                        fix_final=False,
                        rate_source='x0dot',
                        units='V/s',
                        targets='x0')  # target required because x0 is an input
        phase.add_state('x1',
                        fix_initial=False,
                        fix_final=False,
                        rate_source='x1dot',
                        units='V',
                        targets='x1')  # target required because x1 is an input
        phase.add_state('J',
                        fix_initial=False,
                        fix_final=False,
                        rate_source='Jdot',
                        units=None)

        # define the control
        phase.add_control(name='u',
                          units=None,
                          lower=-0.75,
                          upper=1.0,
                          continuity=True,
                          rate_continuity=True,
                          targets='u')  # target required because u is an input

        # add constraints
        phase.add_boundary_constraint('x0', loc='initial', equals=1.0)
        phase.add_boundary_constraint('x1', loc='initial', equals=1.0)
        phase.add_boundary_constraint('J', loc='initial', equals=0.0)

        phase.add_boundary_constraint('x0', loc='final', equals=0.0)
        phase.add_boundary_constraint('x1', loc='final', equals=0.0)

        # define objective to minimize
        phase.add_objective('J', loc='final')

        # setup the problem
        p.setup(check=True)

        p['traj.phase0.t_initial'] = 0.0
        p['traj.phase0.t_duration'] = t_final

        # add a linearly interpolated initial guess for the state and control curves
        p['traj.phase0.states:x0'] = phase.interp('x0', [1, 0])
        p['traj.phase0.states:x1'] = phase.interp('x1', [1, 0])
        p['traj.phase0.states:J'] = phase.interp('J', [0, 1])
        p['traj.phase0.controls:u'] = phase.interp('u', [-0.75, -0.75])

        dm.run_problem(p, run_driver=True, simulate=False)

        assert_near_equal(p.get_val('traj.phase0.states:x0')[-1, ...], 0.0)
        assert_near_equal(p.get_val('traj.phase0.states:x1')[-1, ...], 0.0)
        assert_near_equal(p.get_val('traj.phase0.states:J')[-1, ...],
                          5.2808,
                          tolerance=1.0E-3)
        assert_near_equal(p.get_val('traj.phase0.controls:u')[-1, ...],
                          0.0,
                          tolerance=1.0E-3)
Beispiel #26
0
    def test_hyper_sensitive_for_docs(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm
        from dymos.examples.plotting import plot_results
        from dymos.examples.hyper_sensitive.hyper_sensitive_ode import HyperSensitiveODE

        # Initialize the problem and assign the driver
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.declare_coloring()

        # Setup the trajectory and its phase
        traj = p.model.add_subsystem('traj', dm.Trajectory())

        transcription = dm.Radau(num_segments=30, order=3, compressed=False)

        phase = traj.add_phase(
            'phase0',
            dm.Phase(ode_class=HyperSensitiveODE, transcription=transcription))

        phase.set_time_options(fix_initial=True, fix_duration=True)
        phase.add_state('x',
                        fix_initial=True,
                        fix_final=False,
                        rate_source='x_dot',
                        targets=['x'])
        phase.add_state('xL',
                        fix_initial=True,
                        fix_final=False,
                        rate_source='L',
                        targets=['xL'])
        phase.add_control('u', opt=True, targets=['u'])

        phase.add_boundary_constraint('x', loc='final', equals=1)

        phase.add_objective('xL', loc='final')

        p.setup(check=True)

        p.set_val('traj.phase0.states:x', phase.interp('x', [1.5, 1]))
        p.set_val('traj.phase0.states:xL', phase.interp('xL', [0, 1]))
        p.set_val('traj.phase0.t_initial', 0)
        p.set_val('traj.phase0.t_duration', tf)
        p.set_val('traj.phase0.controls:u', phase.interp('u', [-0.6, 2.4]))

        #
        # Solve the problem.
        #
        dm.run_problem(p)

        #
        # Verify that the results are correct.
        #
        ui, uf, J = solution()

        assert_near_equal(p.get_val('traj.phase0.timeseries.controls:u')[0],
                          ui,
                          tolerance=1.5e-2)

        assert_near_equal(p.get_val('traj.phase0.timeseries.controls:u')[-1],
                          uf,
                          tolerance=1.5e-2)

        assert_near_equal(p.get_val('traj.phase0.timeseries.states:xL')[-1],
                          J,
                          tolerance=1e-2)

        #
        # Simulate the explicit solution and plot the results.
        #
        exp_out = traj.simulate()

        plot_results(
            [('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:x',
              'time (s)', 'x $(m)$'),
             ('traj.phase0.timeseries.time',
              'traj.phase0.timeseries.controls:u', 'time (s)', 'u $(m/s^2)$')],
            title=
            'Hyper Sensitive Problem Solution\nRadau Pseudospectral Method',
            p_sol=p,
            p_sim=exp_out)

        plt.show()
Beispiel #27
0
def hp_transient(transcription='gauss-lobatto',
                 num_segments=5,
                 transcription_order=3,
                 compressed=False,
                 optimizer='SLSQP',
                 run_driver=True,
                 force_alloc_complex=True,
                 solve_segments=False,
                 show_plots=False,
                 save=True,
                 Tf_final=370):
    p = om.Problem(model=om.Group())
    model = p.model
    nn = 1
    p.driver = om.ScipyOptimizeDriver()
    p.driver = om.pyOptSparseDriver(optimizer=optimizer)

    p.driver.declare_coloring()

    traj = p.model.add_subsystem('traj', dm.Trajectory())

    phase = traj.add_phase(
        'phase',
        dm.Phase(ode_class=HeatPipeRun,
                 transcription=dm.GaussLobatto(num_segments=num_segments,
                                               order=transcription_order,
                                               compressed=compressed)))

    phase.set_time_options(fix_initial=True,
                           fix_duration=False,
                           duration_bounds=(1., 3200.))

    phase.add_state(
        'T_cond',
        rate_source='cond.Tdot',
        targets='cond.T',
        units='K',  # ref=333.15, defect_ref=333.15,
        fix_initial=True,
        fix_final=False,
        solve_segments=solve_segments)
    phase.add_state(
        'T_cond2',
        rate_source='cond2.Tdot',
        targets='cond2.T',
        units='K',  # ref=333.15, defect_ref=333.15,
        fix_initial=True,
        fix_final=False,
        solve_segments=solve_segments)

    phase.add_control('T_evap', targets='evap.Rex.T_in', units='K', opt=False)

    phase.add_boundary_constraint('T_cond', loc='final', equals=Tf_final)

    phase.add_objective('time', loc='final', ref=1)

    phase.add_timeseries_output('evap_bridge.Rv.q',
                                output_name='eRvq',
                                units='W')
    phase.add_timeseries_output('evap_bridge.Rwa.q',
                                output_name='eRwaq',
                                units='W')
    phase.add_timeseries_output('evap_bridge.Rwka.q',
                                output_name='eRwkq',
                                units='W')
    phase.add_timeseries_output('cond_bridge.Rv.q',
                                output_name='cRvq',
                                units='W')
    phase.add_timeseries_output('cond_bridge.Rwa.q',
                                output_name='cRwaq',
                                units='W')
    phase.add_timeseries_output('cond_bridge.Rwka.q',
                                output_name='cRwkq',
                                units='W')
    phase.add_timeseries_output('evap.pcm.PS', output_name='ePS', units=None)
    phase.add_timeseries_output('cond.pcm.PS', output_name='cPS', units=None)
    phase.add_timeseries_output('cond2.pcm.PS', output_name='c2PS', units=None)

    p.model.linear_solver = om.DirectSolver()
    p.setup(force_alloc_complex=force_alloc_complex)

    p['traj.phase.t_initial'] = 0.0
    p['traj.phase.t_duration'] = 195.
    p['traj.phase.states:T_cond'] = phase.interpolate(ys=[293.15, 333.15],
                                                      nodes='state_input')
    p['traj.phase.states:T_cond2'] = phase.interpolate(ys=[293.15, 333.15],
                                                       nodes='state_input')
    p['traj.phase.controls:T_evap'] = phase.interpolate(ys=[333., 338.],
                                                        nodes='control_input')

    p.run_model()

    opt = p.run_driver()
    # sim = traj.simulate(times_per_seg=10)

    print('********************************')

    # save_csv(p, sim, '../../output/output.csv',
    #          y_name=['parameters:T_evap', 'states:T_cond', 'states:T_cond2',
    #                  'eRvq', 'eRwaq', 'eRwkq', 'cRvq', 'cRwaq', 'cRwkq'],
    #          y_units=['K', 'K', 'K', 'W', 'W', 'W', 'W', 'W', 'W'])

    if show_plots:
        import matplotlib.pyplot as plt

        # time = sim.get_val('traj.phase.timeseries.time', units='s')
        time_opt = p.get_val('traj.phase.timeseries.time', units='s')
        # T_cond = sim.get_val('traj.phase.timeseries.states:T_cond', units='K')
        T_cond_opt = p.get_val('traj.phase.timeseries.states:T_cond',
                               units='K')
        # T_cond2 = sim.get_val('traj.phase.timeseries.states:T_cond2', units='K')
        T_cond2_opt = p.get_val('traj.phase.timeseries.states:T_cond2',
                                units='K')
        # T_evap = sim.get_val('traj.phase.timeseries.controls:T_evap', units='K')
        T_evap_opt = p.get_val('traj.phase.timeseries.controls:T_evap',
                               units='K')

        ePS_opt = p.get_val('traj.phase.timeseries.ePS')
        cPS_opt = p.get_val('traj.phase.timeseries.cPS')
        c2PS_opt = p.get_val('traj.phase.timeseries.c2PS')

        plt.plot(time_opt, T_cond_opt)
        # plt.plot(time, T_cond)

        plt.plot(time_opt, T_cond2_opt)
        # plt.plot(time, T_cond2)

        plt.plot(time_opt, T_evap_opt)
        # plt.plot(time, T_evap)

        plt.xlabel('time, s')
        plt.ylabel('T_cond, K')

        plt.show()

        plt.plot(time_opt, cPS_opt)
        # plt.plot(time, EPS)

        plt.plot(time_opt, c2PS_opt)
        # plt.plot(time, T_cond2)

        plt.plot(time_opt, ePS_opt)
        # plt.plot(time, T_evap)

        plt.xlabel('time, s')
        plt.ylabel('percent solid')

        plt.show()

    return p
Beispiel #28
0
nv = 25
ns = 25

p = om.Problem(model=om.Group())
traj = dm.Trajectory()

p.model.add_subsystem('traj', subsys=traj)
p.model.linear_solver = om.DirectSolver()

gl = dm.GaussLobatto(num_segments=ns)
#gl = dm.Radau(num_segments=ns, order=3)
nn = gl.grid_data.num_nodes

phase = dm.Phase(ode_class=Airspace,
                 ode_init_kwargs={'num_vehicles' : nv},
                 transcription=gl)

traj.add_phase(name='phase0', phase=phase)


phase.set_time_options(fix_initial=True, fix_duration=False, units='s')

traj.add_phase(name='phase0', phase=phase)

ds=1e-1
phase.add_state('X', 
                fix_initial=True,
                fix_final=True, 
                shape=(nv,),
                rate_source='X_dot', 
Beispiel #29
0
    def _test_transcription(self, transcription=dm.GaussLobatto):
        #
        # Define the OpenMDAO problem
        #
        p = om.Problem(model=om.Group())

        #
        # Define a Trajectory object
        #
        traj = dm.Trajectory()

        p.model.add_subsystem('traj', subsys=traj)

        #
        # Define a Dymos Phase object with GaussLobatto Transcription
        #
        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=transcription(num_segments=10,
                                                     order=3,
                                                     solve_segments='forward'))

        traj.add_phase(name='phase0', phase=phase)

        #
        # Set the time options
        # Time has no targets in our ODE.
        # We fix the initial time so that the it is not a design variable in the optimization.
        # The duration of the phase is allowed to be optimized, but is bounded on [0.5, 10].
        #
        phase.set_time_options(fix_initial=True, fix_duration=True, units='s')

        #
        # Set the time options
        # Initial values of positions and velocity are all fixed.
        # The final value of position are fixed, but the final velocity is a free variable.
        # The equations of motion are not functions of position, so 'x' and 'y' have no targets.
        # The rate source points to the output in the ODE which provides the time derivative of the
        # given state.
        phase.add_state('x', fix_initial=True)
        phase.add_state('y', fix_initial=True)
        phase.add_state('v', fix_initial=True)

        phase.add_state('int_one', fix_initial=True, rate_source='one')
        phase.add_state('int_time', fix_initial=True, rate_source='time')
        phase.add_state('int_time_phase',
                        fix_initial=True,
                        rate_source='time_phase')
        phase.add_state('int_int_one', fix_initial=True, rate_source='int_one')

        # Define theta as a control.
        phase.add_control(name='theta', units='rad', lower=0, upper=np.pi)

        # With no targets we must explicitly assign units and shape to this parameter.
        # Its only purpose is to be integrated as the rate source for a state.
        phase.add_parameter(name='one', opt=False, units=None, shape=(1, ))

        # Minimize final time.
        phase.add_objective('time', loc='final')

        # Set the driver.
        p.driver = om.ScipyOptimizeDriver()

        # Allow OpenMDAO to automatically determine our sparsity pattern.
        # Doing so can significant speed up the execution of Dymos.
        p.driver.declare_coloring()

        # Setup the problem
        p.setup(check=True)

        # Now that the OpenMDAO problem is setup, we can set the values of the states.

        p.set_val('traj.phase0.t_initial', 0.0, units='s')
        p.set_val('traj.phase0.t_duration', 5.0, units='s')

        p.set_val('traj.phase0.parameters:one', 1.0)

        p.set_val('traj.phase0.states:x',
                  phase.interp('x', [0, 10]),
                  units='m')

        p.set_val('traj.phase0.states:y',
                  phase.interp('y', [10, 5]),
                  units='m')

        p.set_val('traj.phase0.states:v',
                  phase.interp('v', [0, 5]),
                  units='m/s')

        p.set_val('traj.phase0.controls:theta',
                  phase.interp('theta', [0.1, 45], nodes='control_input'),
                  units='deg')

        # Additional states to test rate sources
        p.set_val('traj.phase0.states:int_one',
                  phase.interp('int_one', [0, 10]),
                  units='s')

        p.set_val('traj.phase0.states:int_time',
                  phase.interp('int_time', [0, 10]),
                  units='s**2')

        p.set_val('traj.phase0.states:int_time_phase',
                  phase.interp('int_time_phase', [0, 10]),
                  units='s**2')

        p.set_val('traj.phase0.states:int_int_one',
                  phase.interp('int_int_one', [0, 10]),
                  units='s**2')

        # Run the driver to solve the problem
        dm.run_problem(p, simulate=True)

        time_sol = p.get_val('traj.phase0.timeseries.time')
        time_phase_sol = p.get_val('traj.phase0.timeseries.time_phase')
        int_one_sol = p.get_val('traj.phase0.timeseries.states:int_one')
        int_time_sol = p.get_val('traj.phase0.timeseries.states:int_time')
        int_time_phase_sol = p.get_val(
            'traj.phase0.timeseries.states:int_time_phase')
        int_int_one_sol = p.get_val(
            'traj.phase0.timeseries.states:int_int_one')

        time_sim = p.get_val('traj.phase0.timeseries.time')
        time_phase_sim = p.get_val('traj.phase0.timeseries.time_phase')
        int_one_sim = p.get_val('traj.phase0.timeseries.states:int_one')
        int_time_sim = p.get_val('traj.phase0.timeseries.states:int_time')
        int_time_phase_sim = p.get_val(
            'traj.phase0.timeseries.states:int_time_phase')
        int_int_one_sim = p.get_val(
            'traj.phase0.timeseries.states:int_int_one')

        # Integral of one should match time and time_phase in this case.
        assert_near_equal(int_one_sol, time_sol, tolerance=1.0E-12)
        assert_near_equal(int_one_sol, time_phase_sol, tolerance=1.0E-12)

        assert_near_equal(int_one_sim, time_sim, tolerance=1.0E-12)
        assert_near_equal(int_one_sim, time_phase_sim, tolerance=1.0E-12)

        # Integral of time and time_phase should be t**2/2
        assert_near_equal(time_sol, time_phase_sol, tolerance=1.0E-12)
        assert_near_equal(int_time_sol, time_sol**2 / 2, tolerance=1.0E-12)
        assert_near_equal(int_time_phase_sol,
                          time_phase_sol**2 / 2,
                          tolerance=1.0E-12)

        assert_near_equal(time_sim, time_phase_sim, tolerance=1.0E-12)
        assert_near_equal(int_time_sim, time_sim**2 / 2, tolerance=1.0E-12)
        assert_near_equal(int_time_phase_sim,
                          time_phase_sim**2 / 2,
                          tolerance=1.0E-12)

        # Double integral of one should be the same as the integral of time
        assert_near_equal(int_int_one_sol, int_time_sol, tolerance=1.0E-12)
        assert_near_equal(int_int_one_sim, int_time_sim, tolerance=1.0E-12)

        assert_timeseries_near_equal(time_sol, int_int_one_sol, time_sim,
                                     int_int_one_sim)
Beispiel #30
0
def min_time_climb(optimizer='SLSQP',
                   num_seg=3,
                   transcription='gauss-lobatto',
                   transcription_order=3,
                   force_alloc_complex=False):

    p = om.Problem(model=om.Group())

    p.driver = om.pyOptSparseDriver()
    p.driver.options['optimizer'] = optimizer
    p.driver.declare_coloring()

    if optimizer == 'SNOPT':
        p.driver.opt_settings['Major iterations limit'] = 1000
        p.driver.opt_settings['iSumm'] = 6
        p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6
        p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6
        p.driver.opt_settings['Function precision'] = 1.0E-12
        p.driver.opt_settings['Linesearch tolerance'] = 0.1
        p.driver.opt_settings['Major step limit'] = 0.5

    t = {
        'gauss-lobatto':
        dm.GaussLobatto(num_segments=num_seg, order=transcription_order),
        'radau-ps':
        dm.Radau(num_segments=num_seg, order=transcription_order)
    }

    traj = dm.Trajectory()

    phase = dm.Phase(ode_class=_TestODE, transcription=t[transcription])
    traj.add_phase('phase0', phase)

    p.model.add_subsystem('traj', traj)

    phase.set_time_options(fix_initial=True,
                           duration_bounds=(50, 400),
                           duration_ref=100.0)

    phase.add_state('r',
                    fix_initial=True,
                    lower=0,
                    upper=1.0E6,
                    ref=1.0E3,
                    defect_ref=1.0E3,
                    units='m',
                    rate_source='flight_dynamics.r_dot')

    phase.add_state('h',
                    fix_initial=True,
                    lower=0,
                    upper=20000.0,
                    ref=1.0E2,
                    defect_ref=1.0E2,
                    units='m',
                    rate_source='flight_dynamics.h_dot',
                    targets=['h'])

    phase.add_state('v',
                    fix_initial=True,
                    lower=10.0,
                    ref=1.0E2,
                    defect_ref=1.0E2,
                    units='m/s',
                    rate_source='flight_dynamics.v_dot',
                    targets=['v'])

    phase.add_state('gam',
                    fix_initial=True,
                    lower=-1.5,
                    upper=1.5,
                    ref=1.0,
                    defect_ref=1.0,
                    units='rad',
                    rate_source='flight_dynamics.gam_dot',
                    targets=['gam'])

    phase.add_state('m',
                    fix_initial=True,
                    lower=10.0,
                    upper=1.0E5,
                    ref=1.0E3,
                    defect_ref=1.0E3,
                    units='kg',
                    rate_source='prop.m_dot',
                    targets=['m'])

    phase.add_control('alpha',
                      units='deg',
                      lower=-8.0,
                      upper=8.0,
                      scaler=1.0,
                      rate_continuity=True,
                      rate_continuity_scaler=100.0,
                      rate2_continuity=False,
                      targets=['alpha'])

    phase.add_parameter('S',
                        val=49.2386,
                        units='m**2',
                        opt=False,
                        targets=['S'])
    phase.add_parameter('Isp',
                        val=1600.0,
                        units='s',
                        opt=False,
                        targets=['Isp'])
    phase.add_parameter('throttle', val=1.0, opt=False, targets=['throttle'])
    phase.add_parameter('test',
                        val=40 * [1],
                        opt=False,
                        static_target=True,
                        targets=['test'])

    phase.add_boundary_constraint('h',
                                  loc='final',
                                  equals=20000,
                                  scaler=1.0E-3)
    phase.add_boundary_constraint('aero.mach', loc='final', equals=1.0)
    phase.add_boundary_constraint('gam', loc='final', equals=0.0)

    phase.add_path_constraint(name='h', lower=100.0, upper=20000, ref=20000)
    phase.add_path_constraint(name='aero.mach', lower=0.1, upper=1.8)

    # Unnecessary but included to test capability
    phase.add_path_constraint(name='alpha', lower=-8, upper=8, units='deg')

    # Minimize time at the end of the phase
    phase.add_objective('time', loc='final', ref=1.0)

    # test mixing wildcard ODE variable expansion and unit overrides
    phase.add_timeseries_output(['aero.*', 'prop.thrust', 'prop.m_dot'],
                                units={
                                    'aero.f_lift': 'lbf',
                                    'prop.thrust': 'lbf'
                                })

    phase.set_refine_options(max_order=5)

    p.model.linear_solver = om.DirectSolver()

    p.setup(check=True, force_alloc_complex=force_alloc_complex)

    p['traj.phase0.t_initial'] = 0.0
    p['traj.phase0.t_duration'] = 300.0

    p['traj.phase0.states:r'] = phase.interp('r', [0.0, 111319.54])
    p['traj.phase0.states:h'] = phase.interp('h', [100.0, 20000.0])
    p['traj.phase0.states:v'] = phase.interp('v', [135.964, 283.159])
    p['traj.phase0.states:gam'] = phase.interp('gam', [0.0, 0.0])
    p['traj.phase0.states:m'] = phase.interp('m', [19030.468, 16841.431])
    p['traj.phase0.controls:alpha'] = phase.interp('alpha', [0.0, 0.0])

    dm.run_problem(p, refine_iteration_limit=1)

    return p