def test_gauss_lobatto(self):
        p = om.Problem(model=om.Group())

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

        t = dm.GaussLobatto(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', 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,
                          units='deg',
                          lower=0.01,
                          upper=179.9)

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

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

        p.model.linear_solver = 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'] = 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.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=4)
        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)
    def test_brachistochrone_integrated_param_gauss_lobatto(self):
        import numpy as np
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm

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

        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=dm.GaussLobatto(num_segments=10))

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

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

        phase.add_state('x', fix_initial=True, fix_final=True, rate_source='xdot', units='m')
        phase.add_state('y', fix_initial=True, fix_final=True, rate_source='ydot', units='m')
        phase.add_state('v', fix_initial=True, rate_source='vdot', units='m/s')
        phase.add_state('theta', fix_initial=False, rate_source='theta_dot', lower=1E-3)

        # theta_dot has no target, therefore we need to explicitly set the units and shape.
        phase.add_parameter('theta_dot', units='deg/s', shape=(1,), opt=True, lower=0, upper=100)

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

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

        p.model.linear_solver = om.DirectSolver()

        p.setup()

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

        p['phase0.states:x'] = phase.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.states:theta'] = np.radians(phase.interpolate(ys=[0.05, 100.0], nodes='state_input'))
        p['phase0.parameters:theta_dot'] = 60.0

        # Solve for the optimal trajectory
        dm.run_problem(p, refine_iteration_limit=5)

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

        sim_out = phase.simulate(times_per_seg=20)

        t_sol = p.get_val('phase0.timeseries.time')
        x_sol = p.get_val('phase0.timeseries.states:x')
        y_sol = p.get_val('phase0.timeseries.states:y')
        v_sol = p.get_val('phase0.timeseries.states:v')
        theta_sol = p.get_val('phase0.timeseries.states:theta')

        t_sim = sim_out.get_val('phase0.timeseries.time')
        x_sim = sim_out.get_val('phase0.timeseries.states:x')
        y_sim = sim_out.get_val('phase0.timeseries.states:y')
        v_sim = sim_out.get_val('phase0.timeseries.states:v')
        theta_sim = sim_out.get_val('phase0.timeseries.states:theta')

        assert_timeseries_near_equal(t_sol, x_sol, t_sim, x_sim, tolerance=5.0E-3)
        assert_timeseries_near_equal(t_sol, y_sol, t_sim, y_sim, tolerance=5.0E-3)
        assert_timeseries_near_equal(t_sol, v_sol, t_sim, v_sim, tolerance=5.0E-3)
        assert_timeseries_near_equal(t_sol, theta_sol, t_sim, theta_sim, tolerance=5.0E-3)
Beispiel #3
0
    def test_two_burn_orbit_raise_gl_rk_gl_constrained(self):
        import numpy as np

        import matplotlib.pyplot as plt

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

        import dymos as dm
        from dymos.examples.finite_burn_orbit_raise.finite_burn_eom import FiniteBurnODE

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

        p.driver = om.pyOptSparseDriver()
        _, optimizer = set_pyoptsparse_opt('SNOPT', fallback=True)
        p.driver.options['optimizer'] = optimizer

        p.driver.declare_coloring()

        traj.add_design_parameter('c',
                                  opt=False,
                                  val=1.5,
                                  units='DU/TU',
                                  targets={
                                      'burn1': ['c'],
                                      'coast': ['c'],
                                      'burn2': ['c']
                                  })

        # First Phase (burn)

        burn1 = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.GaussLobatto(num_segments=10,
                                                       order=3,
                                                       compressed=True))

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

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

        # Second Phase (Coast)
        coast = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.RungeKutta(num_segments=20))

        traj.add_phase('coast', coast)

        coast.set_time_options(initial_bounds=(0.5, 20),
                               duration_bounds=(.5, 10),
                               duration_ref=10,
                               units='TU')

        # TODO Moving add_state('theta'... after add_state('r',... causes the
        # coloring to be invalid with scipy > 1.0.1
        coast.add_state('theta',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        units='rad',
                        rate_source='theta_dot',
                        targets=['theta'])
        coast.add_state('r',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='r_dot',
                        targets=['r'],
                        units='DU')
        coast.add_state('vr',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='vr_dot',
                        targets=['vr'],
                        units='DU/TU')
        coast.add_state('vt',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='vt_dot',
                        targets=['vt'],
                        units='DU/TU')
        coast.add_state('accel',
                        fix_initial=True,
                        fix_final=False,
                        ref=1.0E-12,
                        defect_ref=1.0E-12,
                        rate_source='at_dot',
                        targets=['accel'],
                        units='DU/TU**2')
        coast.add_state('deltav',
                        fix_initial=False,
                        fix_final=False,
                        rate_source='deltav_dot',
                        units='DU/TU')
        coast.add_control('u1',
                          targets=['u1'],
                          opt=False,
                          val=0.0,
                          units='deg')

        # Third Phase (burn)

        burn2 = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.GaussLobatto(num_segments=10,
                                                       order=3,
                                                       compressed=True))

        traj.add_phase('burn2', burn2)

        burn2.set_time_options(initial_bounds=(0.5, 20),
                               duration_bounds=(.5, 10),
                               initial_ref=10,
                               units='TU')
        burn2.add_state('r',
                        fix_initial=False,
                        fix_final=True,
                        rate_source='r_dot',
                        targets=['r'],
                        units='DU')
        burn2.add_state('theta',
                        fix_initial=False,
                        fix_final=False,
                        rate_source='theta_dot',
                        targets=['theta'],
                        units='rad')
        burn2.add_state('vr',
                        fix_initial=False,
                        fix_final=True,
                        rate_source='vr_dot',
                        targets=['vr'],
                        units='DU/TU')
        burn2.add_state('vt',
                        fix_initial=False,
                        fix_final=True,
                        rate_source='vt_dot',
                        targets=['vt'],
                        units='DU/TU')
        burn2.add_state('accel',
                        fix_initial=False,
                        fix_final=False,
                        defect_ref=1.0E-6,
                        rate_source='at_dot',
                        targets=['accel'],
                        units='DU/TU**2')
        burn2.add_state('deltav',
                        fix_initial=False,
                        fix_final=False,
                        rate_source='deltav_dot',
                        units='DU/TU')
        burn2.add_control('u1',
                          targets=['u1'],
                          rate_continuity=True,
                          rate2_continuity=True,
                          units='deg',
                          scaler=0.01,
                          lower=-30,
                          upper=30)

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

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

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

        # Link Phases
        traj.link_phases(phases=['burn1', 'coast', 'burn2'],
                         vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav'])
        traj.link_phases(phases=['burn1', 'burn2'], vars=['accel'])

        # Finish Problem Setup
        p.model.linear_solver = om.DirectSolver()

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

        # Set Initial Guesses
        p.set_val('traj.design_parameters:c', value=1.5)

        p.set_val('traj.burn1.t_initial', value=0.0)
        p.set_val('traj.burn1.t_duration', value=2.25)

        p.set_val('traj.burn1.states:r',
                  value=burn1.interpolate(ys=[1, 1.5], nodes='state_input'))
        p.set_val('traj.burn1.states:theta',
                  value=burn1.interpolate(ys=[0, 1.7], nodes='state_input'))
        p.set_val('traj.burn1.states:vr',
                  value=burn1.interpolate(ys=[0, 0], nodes='state_input'))
        p.set_val('traj.burn1.states:vt',
                  value=burn1.interpolate(ys=[1, 1], nodes='state_input'))
        p.set_val('traj.burn1.states:accel',
                  value=burn1.interpolate(ys=[0.1, 0], nodes='state_input'))
        p.set_val(
            'traj.burn1.states:deltav',
            value=burn1.interpolate(ys=[0, 0.1], nodes='state_input'),
        )
        p.set_val('traj.burn1.controls:u1',
                  value=burn1.interpolate(ys=[-3.5, 13.0],
                                          nodes='control_input'))

        p.set_val('traj.coast.t_initial', value=2.25)
        p.set_val('traj.coast.t_duration', value=3.0)

        p.set_val('traj.coast.states:r',
                  value=coast.interpolate(ys=[1.3, 1.5], nodes='state_input'))
        p.set_val('traj.coast.states:theta',
                  value=coast.interpolate(ys=[2.1767, 1.7],
                                          nodes='state_input'))
        p.set_val('traj.coast.states:vr',
                  value=coast.interpolate(ys=[0.3285, 0], nodes='state_input'))
        p.set_val('traj.coast.states:vt',
                  value=coast.interpolate(ys=[0.97, 1], nodes='state_input'))
        p.set_val('traj.coast.states:accel',
                  value=coast.interpolate(ys=[0, 0], nodes='state_input'))
        # p.set_val('traj.coast.controls:u1',
        #           value=coast.interpolate(ys=[0, 0], nodes='control_input'))

        p.set_val('traj.burn2.t_initial', value=5.25)
        p.set_val('traj.burn2.t_duration', value=1.75)

        p.set_val('traj.burn2.states:r',
                  value=burn2.interpolate(ys=[1.8, 3], nodes='state_input'))
        p.set_val('traj.burn2.states:theta',
                  value=burn2.interpolate(ys=[3.2, 4.0], nodes='state_input'))
        p.set_val('traj.burn2.states:vr',
                  value=burn2.interpolate(ys=[.5, 0], nodes='state_input'))
        p.set_val('traj.burn2.states:vt',
                  value=burn2.interpolate(ys=[1, np.sqrt(1 / 3)],
                                          nodes='state_input'))
        p.set_val('traj.burn2.states:accel',
                  value=burn2.interpolate(ys=[0.1, 0], nodes='state_input'))
        p.set_val('traj.burn2.states:deltav',
                  value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input'))
        p.set_val('traj.burn2.controls:u1',
                  value=burn2.interpolate(ys=[1, 1], nodes='control_input'))

        p.run_driver()

        assert_near_equal(p.get_val('traj.burn2.timeseries.states:deltav')[-1],
                          0.3995,
                          tolerance=2.0E-3)

        # Plot results
        exp_out = traj.simulate()

        fig = plt.figure(figsize=(8, 4))
        fig.suptitle('Two Burn Orbit Raise Solution')
        ax_u1 = plt.subplot2grid((2, 2), (0, 0))
        ax_deltav = plt.subplot2grid((2, 2), (1, 0))
        ax_xy = plt.subplot2grid((2, 2), (0, 1), rowspan=2)

        span = np.linspace(0, 2 * np.pi, 100)
        ax_xy.plot(np.cos(span), np.sin(span), 'k--', lw=1)
        ax_xy.plot(3 * np.cos(span), 3 * np.sin(span), 'k--', lw=1)
        ax_xy.set_xlim(-4.5, 4.5)
        ax_xy.set_ylim(-4.5, 4.5)

        ax_xy.set_xlabel('x ($R_e$)')
        ax_xy.set_ylabel('y ($R_e$)')

        ax_u1.set_xlabel('time ($TU$)')
        ax_u1.set_ylabel('$u_1$ ($deg$)')
        ax_u1.grid(True)

        ax_deltav.set_xlabel('time ($TU$)')
        ax_deltav.set_ylabel('${\Delta}v$ ($DU/TU$)')
        ax_deltav.grid(True)

        t_sol = dict((phs, p.get_val('traj.{0}.timeseries.time'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        x_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_x'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        y_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_y'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        dv_sol = dict(
            (phs, p.get_val('traj.{0}.timeseries.states:deltav'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        u1_sol = dict((phs,
                       p.get_val('traj.{0}.timeseries.controls:u1'.format(phs),
                                 units='deg')) for phs in ['burn1', 'burn2'])

        t_exp = dict(
            (phs, exp_out.get_val('traj.{0}.timeseries.time'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        x_exp = dict(
            (phs, exp_out.get_val('traj.{0}.timeseries.pos_x'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        y_exp = dict(
            (phs, exp_out.get_val('traj.{0}.timeseries.pos_y'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        dv_exp = dict(
            (phs,
             exp_out.get_val('traj.{0}.timeseries.states:deltav'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        u1_exp = dict(
            (phs,
             exp_out.get_val('traj.{0}.timeseries.controls:u1'.format(phs),
                             units='deg')) for phs in ['burn1', 'burn2'])

        for phs in ['burn1', 'coast', 'burn2']:
            try:
                ax_u1.plot(t_sol[phs], u1_sol[phs], 'ro', ms=3)
                ax_u1.plot(t_exp[phs], u1_exp[phs], 'b-')
            except KeyError:
                pass

            ax_deltav.plot(t_sol[phs], dv_sol[phs], 'ro', ms=3)
            ax_deltav.plot(t_exp[phs], dv_exp[phs], 'b-')

            ax_xy.plot(x_sol[phs], y_sol[phs], 'ro', ms=3, label='implicit')
            ax_xy.plot(x_exp[phs], y_exp[phs], 'b-', label='explicit')

        plt.show()
Beispiel #4
0
    def test_run_HS_problem_gl(self):
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.declare_coloring()
        optimizer = 'IPOPT'
        p.driver.options['optimizer'] = optimizer

        if optimizer == 'SNOPT':
            p.driver.opt_settings['Major iterations limit'] = 100
            p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6
            p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6
        elif optimizer == 'IPOPT':
            p.driver.opt_settings['hessian_approximation'] = 'limited-memory'
            # p.driver.opt_settings['nlp_scaling_method'] = 'user-scaling'
            p.driver.opt_settings['print_level'] = 5
            p.driver.opt_settings['linear_solver'] = 'mumps'

        traj = p.model.add_subsystem('traj', dm.Trajectory())
        phase0 = traj.add_phase('phase0', dm.Phase(ode_class=HyperSensitiveODE,
                                                   transcription=dm.GaussLobatto(num_segments=30, order=3)))
        phase0.set_time_options(fix_initial=True, fix_duration=True)
        phase0.add_state('x', fix_initial=True, fix_final=False, rate_source='x_dot', targets=['x'])
        phase0.add_state('xL', fix_initial=True, fix_final=False, rate_source='L', targets=['xL'])
        phase0.add_control('u', opt=True, targets=['u'], rate_continuity=False)

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

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

        phase0.set_refine_options(refine=True)

        p.setup(check=True)

        tf = 100

        p.set_val('traj.phase0.states:x', phase0.interpolate(ys=[1.5, 1], nodes='state_input'))
        p.set_val('traj.phase0.states:xL', phase0.interpolate(ys=[0, 1], nodes='state_input'))
        p.set_val('traj.phase0.t_initial', 0)
        p.set_val('traj.phase0.t_duration', tf)
        p.set_val('traj.phase0.controls:u', phase0.interpolate(ys=[-0.6, 2.4],
                                                               nodes='control_input'))
        dm.run_problem(p, refine=True)

        sqrt_two = np.sqrt(2)
        val = sqrt_two * tf
        c1 = (1.5 * np.exp(-val) - 1) / (np.exp(-val) - np.exp(val))
        c2 = (1 - 1.5 * np.exp(val)) / (np.exp(-val) - np.exp(val))

        ui = c1 * (1 + sqrt_two) + c2 * (1 - sqrt_two)
        uf = c1 * (1 + sqrt_two) * np.exp(val) + c2 * (1 - sqrt_two) * np.exp(-val)
        J = 0.5 * (c1 ** 2 * (1 + sqrt_two) * np.exp(2 * val) + c2 ** 2 * (1 - sqrt_two) * np.exp(-2 * val) -
                   (1 + sqrt_two) * c1 ** 2 - (1 - sqrt_two) * c2 ** 2)

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

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

        assert_near_equal(p.get_val('traj.phase0.timeseries.states:xL')[-1],
                          J,
                          tolerance=5e-4)
Beispiel #5
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', static_target=True)

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

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

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

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

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

        return p
    def test_two_phase_cannonball_for_docs(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal

        import dymos as dm
        from dymos.examples.cannonball.size_comp import CannonballSizeComp
        from dymos.examples.cannonball.cannonball_phase import CannonballPhase

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

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

        external_params = p.model.add_subsystem('external_params',
                                                om.IndepVarComp())

        external_params.add_output('radius', val=0.10, units='m')
        external_params.add_output('dens', val=7.87, units='g/cm**3')

        external_params.add_design_var('radius',
                                       lower=0.01,
                                       upper=0.10,
                                       ref0=0.01,
                                       ref=0.10)

        p.model.add_subsystem('size_comp', CannonballSizeComp())

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

        transcription = dm.Radau(num_segments=5, order=3, compressed=True)
        ascent = CannonballPhase(transcription=transcription)

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

        # All initial states except flight path angle are fixed
        # Final flight path angle is fixed (we will set it to zero so that the phase ends at apogee)
        ascent.set_time_options(fix_initial=True,
                                duration_bounds=(1, 100),
                                duration_ref=100,
                                units='s')
        ascent.set_state_options('r', fix_initial=True, fix_final=False)
        ascent.set_state_options('h', fix_initial=True, fix_final=False)
        ascent.set_state_options('gam', fix_initial=False, fix_final=True)
        ascent.set_state_options('v', fix_initial=False, fix_final=False)

        ascent.add_input_parameter('S', targets=['aero.S'], units='m**2')
        ascent.add_input_parameter('mass',
                                   targets=['eom.m', 'kinetic_energy.m'],
                                   units='kg')

        # Limit the muzzle energy
        ascent.add_boundary_constraint('kinetic_energy.ke',
                                       loc='initial',
                                       units='J',
                                       upper=400000,
                                       lower=0,
                                       ref=100000,
                                       shape=(1, ))

        # Second Phase (descent)
        transcription = dm.GaussLobatto(num_segments=5,
                                        order=3,
                                        compressed=True)
        descent = CannonballPhase(transcription=transcription)

        traj.add_phase('descent', descent)

        # All initial states and time are free (they will be linked to the final states of ascent.
        # Final altitude is fixed (we will set it to zero so that the phase ends at ground impact)
        descent.set_time_options(initial_bounds=(.5, 100),
                                 duration_bounds=(.5, 100),
                                 duration_ref=100,
                                 units='s')
        descent.add_state('r', )
        descent.add_state('h', fix_initial=False, fix_final=True)
        descent.add_state('gam', fix_initial=False, fix_final=False)
        descent.add_state('v', fix_initial=False, fix_final=False)

        descent.add_input_parameter('S', targets=['aero.S'], units='m**2')
        descent.add_input_parameter('mass',
                                    targets=['eom.m', 'kinetic_energy.m'],
                                    units='kg')

        descent.add_objective('r', loc='final', scaler=-1.0)

        # Add internally-managed design parameters to the trajectory.
        traj.add_design_parameter('CD',
                                  targets={
                                      'ascent': ['aero.CD'],
                                      'descent': ['aero.CD']
                                  },
                                  val=0.5,
                                  units=None,
                                  opt=False)
        traj.add_design_parameter('CL',
                                  targets={
                                      'ascent': ['aero.CL'],
                                      'descent': ['aero.CL']
                                  },
                                  val=0.0,
                                  units=None,
                                  opt=False)
        traj.add_design_parameter('T',
                                  targets={
                                      'ascent': ['eom.T'],
                                      'descent': ['eom.T']
                                  },
                                  val=0.0,
                                  units='N',
                                  opt=False)
        traj.add_design_parameter('alpha',
                                  targets={
                                      'ascent': ['eom.alpha'],
                                      'descent': ['eom.alpha']
                                  },
                                  val=0.0,
                                  units='deg',
                                  opt=False)

        # Add externally-provided design parameters to the trajectory.
        # In this case, we connect 'm' to pre-existing input parameters named 'mass' in each phase.
        traj.add_input_parameter('m',
                                 units='kg',
                                 val=1.0,
                                 targets={
                                     'ascent': 'mass',
                                     'descent': 'mass'
                                 })

        # In this case, by omitting targets, we're connecting these parameters to parameters
        # with the same name in each phase.
        traj.add_input_parameter('S', units='m**2', val=0.005)

        # Link Phases (link time and all state variables)
        traj.link_phases(phases=['ascent', 'descent'], vars=['*'])

        # Issue Connections
        p.model.connect('external_params.radius', 'size_comp.radius')
        p.model.connect('external_params.dens', 'size_comp.dens')

        p.model.connect('size_comp.mass', 'traj.input_parameters:m')
        p.model.connect('size_comp.S', 'traj.input_parameters:S')

        # Finish Problem Setup
        p.model.linear_solver = om.DirectSolver()

        p.driver.add_recorder(om.SqliteRecorder('ex_two_phase_cannonball.db'))

        p.setup()

        # Set Initial Guesses
        p.set_val('external_params.radius', 0.05, units='m')
        p.set_val('external_params.dens', 7.87, units='g/cm**3')

        p.set_val('traj.design_parameters:CD', 0.5)
        p.set_val('traj.design_parameters:CL', 0.0)
        p.set_val('traj.design_parameters:T', 0.0)

        p.set_val('traj.ascent.t_initial', 0.0)
        p.set_val('traj.ascent.t_duration', 10.0)

        p.set_val('traj.ascent.states:r',
                  ascent.interpolate(ys=[0, 100], nodes='state_input'))
        p.set_val('traj.ascent.states:h',
                  ascent.interpolate(ys=[0, 100], nodes='state_input'))
        p.set_val('traj.ascent.states:v',
                  ascent.interpolate(ys=[200, 150], nodes='state_input'))
        p.set_val('traj.ascent.states:gam',
                  ascent.interpolate(ys=[25, 0], nodes='state_input'),
                  units='deg')

        p.set_val('traj.descent.t_initial', 10.0)
        p.set_val('traj.descent.t_duration', 10.0)

        p.set_val('traj.descent.states:r',
                  descent.interpolate(ys=[100, 200], nodes='state_input'))
        p.set_val('traj.descent.states:h',
                  descent.interpolate(ys=[100, 0], nodes='state_input'))
        p.set_val('traj.descent.states:v',
                  descent.interpolate(ys=[150, 200], nodes='state_input'))
        p.set_val('traj.descent.states:gam',
                  descent.interpolate(ys=[0, -45], nodes='state_input'),
                  units='deg')

        dm.run_problem(p)

        assert_near_equal(p.get_val('traj.descent.states:r')[-1],
                          3183.25,
                          tolerance=1.0E-2)

        exp_out = traj.simulate()

        print('optimal radius: {0:6.4f} m '.format(
            p.get_val('external_params.radius', units='m')[0]))
        print('cannonball mass: {0:6.4f} kg '.format(
            p.get_val('size_comp.mass', units='kg')[0]))
        print('launch angle: {0:6.4f} '
              'deg '.format(
                  p.get_val('traj.ascent.timeseries.states:gam',
                            units='deg')[0, 0]))
        print('maximum range: {0:6.4f} '
              'm '.format(
                  p.get_val('traj.descent.timeseries.states:r')[-1, 0]))

        fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(10, 6))

        time_imp = {
            'ascent': p.get_val('traj.ascent.timeseries.time'),
            'descent': p.get_val('traj.descent.timeseries.time')
        }

        time_exp = {
            'ascent': exp_out.get_val('traj.ascent.timeseries.time'),
            'descent': exp_out.get_val('traj.descent.timeseries.time')
        }

        r_imp = {
            'ascent': p.get_val('traj.ascent.timeseries.states:r'),
            'descent': p.get_val('traj.descent.timeseries.states:r')
        }

        r_exp = {
            'ascent': exp_out.get_val('traj.ascent.timeseries.states:r'),
            'descent': exp_out.get_val('traj.descent.timeseries.states:r')
        }

        h_imp = {
            'ascent': p.get_val('traj.ascent.timeseries.states:h'),
            'descent': p.get_val('traj.descent.timeseries.states:h')
        }

        h_exp = {
            'ascent': exp_out.get_val('traj.ascent.timeseries.states:h'),
            'descent': exp_out.get_val('traj.descent.timeseries.states:h')
        }

        axes.plot(r_imp['ascent'], h_imp['ascent'], 'bo')

        axes.plot(r_imp['descent'], h_imp['descent'], 'ro')

        axes.plot(r_exp['ascent'], h_exp['ascent'], 'b--')

        axes.plot(r_exp['descent'], h_exp['descent'], 'r--')

        axes.set_xlabel('range (m)')
        axes.set_ylabel('altitude (m)')

        fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(10, 6))
        states = ['r', 'h', 'v', 'gam']
        for i, state in enumerate(states):
            x_imp = {
                'ascent':
                p.get_val('traj.ascent.timeseries.states:{0}'.format(state)),
                'descent':
                p.get_val('traj.descent.timeseries.states:{0}'.format(state))
            }

            x_exp = {
                'ascent':
                exp_out.get_val(
                    'traj.ascent.timeseries.states:{0}'.format(state)),
                'descent':
                exp_out.get_val(
                    'traj.descent.timeseries.states:{0}'.format(state))
            }

            axes[i].set_ylabel(state)

            axes[i].plot(time_imp['ascent'], x_imp['ascent'], 'bo')
            axes[i].plot(time_imp['descent'], x_imp['descent'], 'ro')
            axes[i].plot(time_exp['ascent'], x_exp['ascent'], 'b--')
            axes[i].plot(time_exp['descent'], x_exp['descent'], 'r--')

        params = ['CL', 'CD', 'T', 'alpha', 'mass', 'S']
        fig, axes = plt.subplots(nrows=6, ncols=1, figsize=(12, 6))
        for i, param in enumerate(params):
            p_imp = {
                'ascent':
                p.get_val('traj.ascent.timeseries.input_parameters:{0}'.format(
                    param)),
                'descent':
                p.get_val(
                    'traj.descent.timeseries.input_parameters:{0}'.format(
                        param))
            }

            p_exp = {
                'ascent':
                exp_out.get_val('traj.ascent.timeseries.'
                                'input_parameters:{0}'.format(param)),
                'descent':
                exp_out.get_val('traj.descent.timeseries.'
                                'input_parameters:{0}'.format(param))
            }

            axes[i].set_ylabel(param)

            axes[i].plot(time_imp['ascent'], p_imp['ascent'], 'bo')
            axes[i].plot(time_imp['descent'], p_imp['descent'], 'ro')
            axes[i].plot(time_exp['ascent'], p_exp['ascent'], 'b--')
            axes[i].plot(time_exp['descent'], p_exp['descent'], 'r--')

        plt.show()
    def test_brachistochrone_undecorated_ode_gl(self):
        import numpy as np
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm

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

        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=dm.GaussLobatto(num_segments=10))

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

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

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

        p.setup()

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

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

        # Solve for the optimal trajectory
        p.run_driver()

        # Test the results
        assert_near_equal(p.get_val('phase0.timeseries.time')[-1],
                          1.8016,
                          tolerance=1.0E-3)
                  'solidity': num_blades * blade_chord / np.pi / prop_rad,  # solidity
                  'omega': 136. / prop_rad,  # angular rotation rate
                  'prop_CD0': 0.012,  # CD0 for prop profile power
                  'k_elec': 0.9,  # electrical and mechanical losses factor
                  'k_ind': 1.2,  # induced-losses factor
                  'nB': num_blades,  # number of blades per propeller
                  'bc': blade_chord,  # representative blade chord
                  'n_props': num_props  # number of propellers
                  }

    p = om.Problem()

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

    phase = dm.Phase(transcription=dm.GaussLobatto(num_segments=10, order=3, solve_segments=False,
                                                   compressed=False),
                     ode_class=DynamicsVectorized,
                     ode_init_kwargs={'input_dict': input_dict})

    traj.add_phase('phase0', phase)

    phase.set_time_options(fix_initial=True, duration_bounds=(5, 60), duration_ref=30)
    phase.add_state('x', fix_initial=True, rate_source='x_dot', ref0=0, ref=900, defect_ref=100)
    phase.add_state('y', fix_initial=True, rate_source='y_dot', ref0=0, ref=300, defect_ref=300)
    phase.add_state('vx', fix_initial=True, rate_source='a_x', ref0=0, ref=10)
    phase.add_state('vy', fix_initial=True, rate_source='a_y', ref0=0, ref=10)
    phase.add_state('energy', fix_initial=True, rate_source='energy_dot', ref0=0, ref=1E7, defect_ref=1E5)

    phase.add_control('power', lower=1e3, upper=311000, ref0=1e3, ref=311000, rate_continuity=False)
    phase.add_control('theta', lower=0., upper=3 * np.pi / 4, ref0=0, ref=3 * np.pi / 4,
                      rate_continuity=False)
Beispiel #9
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.interp('x', [0, 350000.0])
        p['traj.phase0.states:y'] = phase.interp('y', [0, 185000.0])
        p['traj.phase0.states:vx'] = phase.interp('vx', [0, 1627.0])
        p['traj.phase0.states:vy'] = phase.interp('vy', [1.0E-6, 0])
        p['traj.phase0.states:m'] = phase.interp('m', [50000, 50000])
        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()
    def test_finite_burn_orbit_raise(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.finite_burn_orbit_raise.finite_burn_eom import FiniteBurnODE

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

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

        traj = dm.Trajectory()

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

        # First Phase (burn)

        burn1 = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.GaussLobatto(num_segments=5, order=3, compressed=False))

        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', units='DU')
        burn1.add_state('theta', fix_initial=True, fix_final=False, defect_scaler=100.0,
                        rate_source='theta_dot', units='rad')
        burn1.add_state('vr', fix_initial=True, fix_final=False, defect_scaler=100.0,
                        rate_source='vr_dot', units='DU/TU')
        burn1.add_state('vt', fix_initial=True, fix_final=False, defect_scaler=100.0,
                        rate_source='vt_dot', units='DU/TU')
        burn1.add_state('accel', fix_initial=True, fix_final=False,
                        rate_source='at_dot', units='DU/TU**2')
        burn1.add_state('deltav', fix_initial=True, fix_final=False,
                        rate_source='deltav_dot', units='DU/TU')
        burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg',
                          scaler=0.01, rate_continuity_scaler=0.001, rate2_continuity_scaler=0.001,
                          lower=-30, upper=30)
        # Second Phase (Coast)
        coast = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.GaussLobatto(num_segments=5, order=3, compressed=False))

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

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

        # Third Phase (burn)
        burn2 = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.GaussLobatto(num_segments=5, order=3, compressed=False))

        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', units='DU')
        burn2.add_state('theta', fix_initial=False, fix_final=False, defect_scaler=100.0,
                        rate_source='theta_dot', units='rad')
        burn2.add_state('vr', fix_initial=False, fix_final=True, defect_scaler=1000.0,
                        rate_source='vr_dot', units='DU/TU')
        burn2.add_state('vt', fix_initial=False, fix_final=True, defect_scaler=1000.0,
                        rate_source='vt_dot', units='DU/TU')
        burn2.add_state('accel', fix_initial=False, fix_final=False, defect_scaler=1.0,
                        rate_source='at_dot', units='DU/TU**2')
        burn2.add_state('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0,
                        rate_source='deltav_dot', units='DU/TU')

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

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

        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
        traj.link_phases(phases=['burn1', 'coast', 'burn2'],
                         vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav'])

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

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

        # Finish Problem Setup

        # Needed to move the direct solver down into the phases for use with MPI.
        #  - After moving down, used fewer iterations (about 30 less)

        p.driver.add_recorder(om.SqliteRecorder('two_burn_orbit_raise_example.db'))

        p.setup(check=True, mode='fwd')

        # Set Initial Guesses
        p.set_val('traj.parameters:c', value=1.5, units='DU/TU')

        burn1 = p.model.traj.phases.burn1
        burn2 = p.model.traj.phases.burn2
        coast = p.model.traj.phases.coast

        p.set_val('traj.burn1.t_initial', value=0.0)
        p.set_val('traj.burn1.t_duration', value=2.25)
        p.set_val('traj.burn1.states:r', value=burn1.interpolate(ys=[1, 1.5],
                                                                 nodes='state_input'))
        p.set_val('traj.burn1.states:theta', value=burn1.interpolate(ys=[0, 1.7],
                                                                     nodes='state_input'))
        p.set_val('traj.burn1.states:vr', value=burn1.interpolate(ys=[0, 0],
                                                                  nodes='state_input'))
        p.set_val('traj.burn1.states:vt', value=burn1.interpolate(ys=[1, 1],
                                                                  nodes='state_input'))
        p.set_val('traj.burn1.states:accel', value=burn1.interpolate(ys=[0.1, 0],
                                                                     nodes='state_input'))
        p.set_val('traj.burn1.states:deltav', value=burn1.interpolate(ys=[0, 0.1],
                                                                      nodes='state_input'))
        p.set_val('traj.burn1.controls:u1',
                  value=burn1.interpolate(ys=[-3.5, 13.0], nodes='control_input'))

        p.set_val('traj.coast.t_initial', value=2.25)
        p.set_val('traj.coast.t_duration', value=3.0)

        p.set_val('traj.coast.states:r', value=coast.interpolate(ys=[1.3, 1.5],
                                                                 nodes='state_input'))
        p.set_val('traj.coast.states:theta',
                  value=coast.interpolate(ys=[2.1767, 1.7], nodes='state_input'))

        p.set_val('traj.coast.states:vr', value=coast.interpolate(ys=[0.3285, 0],
                                                                  nodes='state_input'))
        p.set_val('traj.coast.states:vt', value=coast.interpolate(ys=[0.97, 1],
                                                                  nodes='state_input'))
        p.set_val('traj.coast.states:accel', value=coast.interpolate(ys=[0, 0],
                                                                     nodes='state_input'))

        p.set_val('traj.burn2.t_initial', value=5.25)
        p.set_val('traj.burn2.t_duration', value=1.75)

        p.set_val('traj.burn2.states:r', value=burn2.interpolate(ys=[1, 3.],
                                                                 nodes='state_input'))
        p.set_val('traj.burn2.states:theta', value=burn2.interpolate(ys=[0, 4.0],
                                                                     nodes='state_input'))
        p.set_val('traj.burn2.states:vr', value=burn2.interpolate(ys=[0, 0],
                                                                  nodes='state_input'))
        p.set_val('traj.burn2.states:vt',
                  value=burn2.interpolate(ys=[1, np.sqrt(1 / 3.)],
                                          nodes='state_input'))
        p.set_val('traj.burn2.states:deltav',
                  value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input'))
        p.set_val('traj.burn2.states:accel', value=burn2.interpolate(ys=[0.1, 0],
                                                                     nodes='state_input'))

        p.set_val('traj.burn2.controls:u1', value=burn2.interpolate(ys=[0, 0],
                                                                    nodes='control_input'))

        dm.run_problem(p)

        assert_near_equal(p.get_val('traj.burn2.states:deltav')[-1], 0.3995,
                          tolerance=2.0E-3)

        #
        # Plot results
        #
        traj = p.model.traj
        exp_out = traj.simulate()

        fig = plt.figure(figsize=(8, 4))
        fig.suptitle('Two Burn Orbit Raise Solution')
        ax_u1 = plt.subplot2grid((2, 2), (0, 0))
        ax_deltav = plt.subplot2grid((2, 2), (1, 0))
        ax_xy = plt.subplot2grid((2, 2), (0, 1), rowspan=2)

        span = np.linspace(0, 2 * np.pi, 100)
        ax_xy.plot(np.cos(span), np.sin(span), 'k--', lw=1)
        ax_xy.plot(3 * np.cos(span), 3 * np.sin(span), 'k--', lw=1)
        ax_xy.set_xlim(-4.5, 4.5)
        ax_xy.set_ylim(-4.5, 4.5)

        ax_xy.set_xlabel('x ($R_e$)')
        ax_xy.set_ylabel('y ($R_e$)')

        ax_u1.set_xlabel('time ($TU$)')
        ax_u1.set_ylabel('$u_1$ ($deg$)')
        ax_u1.grid(True)

        ax_deltav.set_xlabel('time ($TU$)')
        ax_deltav.set_ylabel('${\Delta}v$ ($DU/TU$)')
        ax_deltav.grid(True)

        t_sol = dict((phs, p.get_val('traj.{0}.timeseries.time'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        x_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_x'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        y_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_y'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        dv_sol = dict((phs, p.get_val('traj.{0}.timeseries.states:deltav'.format(phs)))
                      for phs in ['burn1', 'coast', 'burn2'])
        u1_sol = dict((phs, p.get_val('traj.{0}.timeseries.controls:u1'.format(phs), units='deg'))
                      for phs in ['burn1', 'burn2'])

        t_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.time'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        x_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.pos_x'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        y_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.pos_y'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        dv_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.states:deltav'.format(phs)))
                      for phs in ['burn1', 'coast', 'burn2'])
        u1_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.controls:u1'.format(phs),
                                            units='deg'))
                      for phs in ['burn1', 'burn2'])

        for phs in ['burn1', 'coast', 'burn2']:
            try:
                ax_u1.plot(t_exp[phs], u1_exp[phs], '-', marker=None, color='C0')
                ax_u1.plot(t_sol[phs], u1_sol[phs], 'o', mfc='C1', mec='C1', ms=3)
            except KeyError:
                pass

            ax_deltav.plot(t_exp[phs], dv_exp[phs], '-', marker=None, color='C0')
            ax_deltav.plot(t_sol[phs], dv_sol[phs], 'o', mfc='C1', mec='C1', ms=3)

            ax_xy.plot(x_exp[phs], y_exp[phs], '-', marker=None, color='C0', label='explicit')
            ax_xy.plot(x_sol[phs], y_sol[phs], 'o', mfc='C1', mec='C1', ms=3, label='implicit')

        plt.show()
Beispiel #11
0
    def make_prob(self, transcription, num_segments, transcription_order,
                  compressed):

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

        if transcription == 'gauss-lobatto':
            t = dm.GaussLobatto(
                num_segments=num_segments,
                order=transcription_order,
                compressed=compressed,
            )
        elif transcription == 'radau-ps':
            t = dm.Radau(num_segments=num_segments,
                         order=transcription_order,
                         compressed=compressed)
        elif transcription == 'runge-kutta':
            t = dm.RungeKutta(num_segments=num_segments,
                              order=transcription_order,
                              compressed=compressed)
        traj = dm.Trajectory()
        phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t)
        p.model.add_subsystem('traj0', traj)
        traj.add_phase('phase0', phase)

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

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

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

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

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

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

        p.setup(force_alloc_complex=True)

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

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

        return p
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)
    traj = dm.Trajectory()
    phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t)
    traj.add_phase('phase0', phase)

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

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

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

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

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

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

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

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

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

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

    p.final_setup()
    return p
Beispiel #13
0
    def test_run_HS_problem_gl(self):
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.declare_coloring()
        _, optimizer = set_pyoptsparse_opt('SNOPT', fallback=True)
        p.driver.options['optimizer'] = optimizer

        traj = p.model.add_subsystem('traj', dm.Trajectory())
        phase0 = traj.add_phase(
            'phase0',
            dm.Phase(ode_class=HyperSensitiveODE,
                     transcription=dm.GaussLobatto(num_segments=30, order=3)))
        phase0.set_time_options(fix_initial=True, fix_duration=True)
        phase0.add_state('x',
                         fix_initial=True,
                         fix_final=False,
                         rate_source='x_dot',
                         targets=['x'])
        phase0.add_state('xL',
                         fix_initial=True,
                         fix_final=False,
                         rate_source='L',
                         targets=['xL'])
        phase0.add_control('u', opt=True, targets=['u'], rate_continuity=False)

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

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

        phase0.set_refine_options(refine=True)

        p.setup(check=True)

        tf = 100

        p.set_val('traj.phase0.states:x',
                  phase0.interpolate(ys=[1.5, 1], nodes='state_input'))
        p.set_val('traj.phase0.states:xL',
                  phase0.interpolate(ys=[0, 1], nodes='state_input'))
        p.set_val('traj.phase0.t_initial', 0)
        p.set_val('traj.phase0.t_duration', tf)
        p.set_val('traj.phase0.controls:u',
                  phase0.interpolate(ys=[-0.6, 2.4], nodes='control_input'))
        dm.run_problem(p, refine=True)

        sqrt_two = np.sqrt(2)
        val = sqrt_two * tf
        c1 = (1.5 * np.exp(-val) - 1) / (np.exp(-val) - np.exp(val))
        c2 = (1 - 1.5 * np.exp(val)) / (np.exp(-val) - np.exp(val))

        ui = c1 * (1 + sqrt_two) + c2 * (1 - sqrt_two)
        uf = c1 * (1 + sqrt_two) * np.exp(val) + c2 * (1 -
                                                       sqrt_two) * np.exp(-val)
        J = 0.5 * (c1**2 * (1 + sqrt_two) * np.exp(2 * val) + c2**2 *
                   (1 - sqrt_two) * np.exp(-2 * val) - (1 + sqrt_two) * c1**2 -
                   (1 - sqrt_two) * c2**2)

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

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

        assert_rel_error(self,
                         p.get_val('traj.phase0.timeseries.states:xL')[-1],
                         J,
                         tolerance=5e-4)
Beispiel #14
0
    def _make_problem(self,
                      transcription,
                      num_seg,
                      transcription_order=3,
                      input_initial=False,
                      input_duration=False):
        p = om.Problem(model=om.Group())

        p.driver = om.ScipyOptimizeDriver()

        # Compute sparsity/coloring when run_driver is called
        p.driver.declare_coloring()

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

        phase = dm.Phase(ode_class=_BrachistochroneTestODE,
                         transcription=t[transcription])

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

        phase.set_time_options(initial_bounds=(1, 1),
                               duration_bounds=(.5, 10),
                               units='s',
                               time_phase_targets=['time_phase'],
                               t_duration_targets=['t_duration'],
                               t_initial_targets=['t_initial'],
                               targets=['time'],
                               input_initial=input_initial,
                               input_duration=input_duration)

        phase.add_state('x', fix_initial=True, rate_source='xdot', units='m')
        phase.add_state('y', fix_initial=True, rate_source='ydot', units='m')
        phase.add_state('v',
                        fix_initial=True,
                        rate_source='vdot',
                        targets=['v'],
                        units='m/s')

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

        if input_duration:
            p.model.add_design_var('phase0.t_duration',
                                   lower=0,
                                   upper=3,
                                   scaler=1.0)

        p.setup(check=True)

        p['phase0.t_initial'] = 0.5
        p['phase0.t_duration'] = 5.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.5])

        return p
Beispiel #15
0
    def test_static_parameter_connections_gl(self):
        class TrajectoryODE(om.Group):
            def initialize(self):
                self.options.declare('num_nodes', types=int)

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

                self.add_subsystem(
                    'sum',
                    om.ExecComp('m_tot = sum(m)',
                                m={
                                    'value': np.zeros((2, 2)),
                                    'units': 'kg'
                                },
                                m_tot={
                                    'value': np.zeros(nn),
                                    'units': 'kg'
                                }))

                self.add_subsystem('eom', FlightPathEOM2D(num_nodes=nn))

                self.connect('sum.m_tot', 'eom.m')

        optimizer = 'SLSQP'
        num_segments = 1
        transcription_order = 5

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

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

        seg_ends, _ = lgl(num_segments + 1)

        phase = dm.Phase(ode_class=TrajectoryODE,
                         transcription=dm.GaussLobatto(
                             num_segments=num_segments,
                             order=transcription_order,
                             segment_ends=seg_ends))

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

        phase.set_time_options(initial_bounds=(0.0, 100.0),
                               duration_bounds=(0., 100.),
                               units='s')

        phase.add_state('h',
                        fix_initial=True,
                        fix_final=True,
                        lower=0.0,
                        units='m',
                        rate_source='eom.h_dot')
        phase.add_state('v',
                        fix_initial=True,
                        fix_final=False,
                        units='m/s',
                        rate_source='eom.v_dot')

        phase.add_parameter('m',
                            val=[[1, 2], [3, 4]],
                            units='kg',
                            targets='sum.m',
                            dynamic=False)

        p.model.linear_solver = om.DirectSolver()

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

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

        p['phase0.states:h'] = phase.interpolate(ys=[20, 0],
                                                 nodes='state_input')
        p['phase0.states:v'] = phase.interpolate(ys=[0, -5],
                                                 nodes='state_input')

        p.run_model()

        expected = np.array([[1, 2], [3, 4]])
        assert_near_equal(p.get_val('phase0.rhs_disc.sum.m'), expected)
        assert_near_equal(p.get_val('phase0.rhs_col.sum.m'), expected)
Beispiel #16
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),
        'runge-kutta':
        dm.RungeKutta(num_segments=5, 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])

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

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

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

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

        burn2.set_time_options(initial_bounds=(0.5, 50),
                               duration_bounds=(.5, 10),
                               initial_ref=10,
                               units='TU')
        burn2.add_state('r',
                        fix_initial=False,
                        fix_final=True,
                        defect_scaler=100.0,
                        rate_source='r_dot',
                        targets=['r'],
                        units='DU')
        burn2.add_state('theta',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='theta_dot',
                        targets=['theta'],
                        units='rad')
        burn2.add_state('vr',
                        fix_initial=False,
                        fix_final=True,
                        defect_scaler=1000.0,
                        rate_source='vr_dot',
                        targets=['vr'],
                        units='DU/TU')
        burn2.add_state('vt',
                        fix_initial=False,
                        fix_final=True,
                        defect_scaler=1000.0,
                        rate_source='vt_dot',
                        targets=['vt'],
                        units='DU/TU')
        burn2.add_state('accel',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=1.0,
                        rate_source='at_dot',
                        targets=['accel'],
                        units='DU/TU**2')
        burn2.add_state('deltav',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=1.0,
                        rate_source='deltav_dot',
                        units='DU/TU',
                        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', 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 #17
0
    def test_racecar_for_docs(self):
        import numpy as np
        import openmdao.api as om
        import dymos as dm
        import matplotlib.pyplot as plt
        import matplotlib as mpl

        from dymos.examples.racecar.combinedODE import CombinedODE
        from dymos.examples.racecar.spline import (
            get_spline,
            get_track_points,
            get_gate_normals,
            reverse_transform_gates,
            set_gate_displacements,
            transform_gates,
        )
        from dymos.examples.racecar.linewidthhelper import linewidth_from_data_units
        from dymos.examples.racecar.tracks import ovaltrack  # track curvature imports

        # 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 GaussLobatto Transcription
        phase = dm.Phase(ode_class=CombinedODE,
                         transcription=dm.GaussLobatto(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,
                          ref=0.04,
                          rate_continuity=True)  # steering angle
        phase.add_control(name='thrust',
                          units=None,
                          fix_initial=False,
                          fix_final=False,
                          rate_continuity=True)
        # 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
        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['nlp_scaling_method'] = 'none'
        p.driver.opt_settings['print_level'] = 5
        p.driver.opt_settings[
            'nlp_scaling_method'] = 'gradient-based'  # for faster convergence
        p.driver.options['print_results'] = False

        # 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
        # Nonzero velocity to avoid division by zero errors
        p.set_val('traj.phase0.states:V',
                  phase.interp('V', [20, 20]),
                  units='m/s')
        # All other states start at 0
        p.set_val('traj.phase0.states:lambda',
                  phase.interp('lambda', [0.0, 0.0]),
                  units='rad')
        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
        # a small amount of thrust can speed up convergence
        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)

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

        # Get optimized time series
        n = p.get_val('traj.phase0.timeseries.states:n')
        s = p.get_val('traj.phase0.timeseries.time')
        V = p.get_val('traj.phase0.timeseries.states:V')
        thrust = p.get_val('traj.phase0.timeseries.controls:thrust')
        delta = p.get_val('traj.phase0.timeseries.controls:delta')
        power = p.get_val('traj.phase0.timeseries.power', units='W')

        print("Plotting")

        # We know the optimal distance from the centerline (n). To transform this into the racing
        # line we fit a spline to the displaced points. This will let us plot the racing line in
        # x/y coordinates
        normals = get_gate_normals(finespline, slope)
        newgates = []
        newnormals = []
        newn = []
        for i in range(len(n)):
            index = ((s[i] / s_final) * np.array(finespline).shape[1]).astype(
                int)  # interpolation to find the appropriate index
            if index[0] == np.array(finespline).shape[1]:
                index[0] = np.array(finespline).shape[1] - 1
            if i > 0 and s[i] == s[i - 1]:
                continue
            else:
                newgates.append(
                    [finespline[0][index[0]], finespline[1][index[0]]])
                newnormals.append(normals[index[0]])
                newn.append(n[i][0])

        newgates = reverse_transform_gates(newgates)
        displaced_gates = set_gate_displacements(newn, newgates, newnormals)
        displaced_gates = np.array((transform_gates(displaced_gates)))

        npoints = 1000
        # fit the racing line spline to npoints
        displaced_spline, gates, gatesd, curv, slope = get_spline(
            displaced_gates, 1 / npoints, 0)

        plt.rcParams.update({'font.size': 12})

        def plot_track_with_data(state, s):
            # this function plots the track
            state = np.array(state)[:, 0]
            s = np.array(s)[:, 0]
            s_new = np.linspace(0, s_final, npoints)

            # Colormap and norm of the track plot
            cmap = mpl.cm.get_cmap('viridis')
            norm = mpl.colors.Normalize(vmin=np.amin(state),
                                        vmax=np.amax(state))

            fig, ax = plt.subplots(figsize=(15, 6))
            # establishes the figure axis limits needed for plotting the track below
            plt.plot(displaced_spline[0],
                     displaced_spline[1],
                     linewidth=0.1,
                     solid_capstyle="butt")

            plt.axis('equal')
            # the linewidth is set in order to match the width of the track
            plt.plot(finespline[0],
                     finespline[1],
                     'k',
                     linewidth=linewidth_from_data_units(8.5, ax),
                     solid_capstyle="butt")
            plt.plot(finespline[0],
                     finespline[1],
                     'w',
                     linewidth=linewidth_from_data_units(8, ax),
                     solid_capstyle="butt"
                     )  # 8 is the width, and the 8.5 wide line draws 'kerbs'
            plt.xlabel('x (m)')
            plt.ylabel('y (m)')

            # plot spline with color
            for i in range(1, len(displaced_spline[0])):
                s_spline = s_new[i]
                index_greater = np.argwhere(s >= s_spline)[0][0]
                index_less = np.argwhere(s < s_spline)[-1][0]

                x = s_spline
                xp = np.array([s[index_less], s[index_greater]])
                fp = np.array([state[index_less], state[index_greater]])
                interp_state = np.interp(
                    x, xp,
                    fp)  # interpolate the given state to calculate the color

                # calculate the appropriate color
                state_color = norm(interp_state)
                color = cmap(state_color)
                color = mpl.colors.to_hex(color)

                # the track plot consists of thousands of tiny lines:
                point = [displaced_spline[0][i], displaced_spline[1][i]]
                prevpoint = [
                    displaced_spline[0][i - 1], displaced_spline[1][i - 1]
                ]
                if i <= 5 or i == len(displaced_spline[0]) - 1:
                    plt.plot([point[0], prevpoint[0]],
                             [point[1], prevpoint[1]],
                             color,
                             linewidth=linewidth_from_data_units(1.5, ax),
                             solid_capstyle="butt",
                             antialiased=True)
                else:
                    plt.plot([point[0], prevpoint[0]],
                             [point[1], prevpoint[1]],
                             color,
                             linewidth=linewidth_from_data_units(1.5, ax),
                             solid_capstyle="projecting",
                             antialiased=True)

            clb = plt.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap),
                               fraction=0.02,
                               pad=0.04)  # add colorbar

            if np.array_equal(state, V[:, 0]):
                clb.set_label('Velocity (m/s)')
            elif np.array_equal(state, thrust[:, 0]):
                clb.set_label('Thrust')
            elif np.array_equal(state, delta[:, 0]):
                clb.set_label('Delta')

            plt.tight_layout()
            plt.grid()

        # Create the plots
        plot_track_with_data(V, s)
        plot_track_with_data(thrust, s)
        plot_track_with_data(delta, s)

        # Plot the main vehicle telemetry
        fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(15, 8))

        # Velocity vs s
        axes[0].plot(s,
                     p.get_val('traj.phase0.timeseries.states:V'),
                     label='solution')

        axes[0].set_xlabel('s (m)')
        axes[0].set_ylabel('V (m/s)')
        axes[0].grid()
        axes[0].set_xlim(0, s_final)

        # n vs s
        axes[1].plot(s,
                     p.get_val('traj.phase0.timeseries.states:n', units='m'),
                     label='solution')

        axes[1].set_xlabel('s (m)')
        axes[1].set_ylabel('n (m)')
        axes[1].grid()
        axes[1].set_xlim(0, s_final)

        # throttle vs s
        axes[2].plot(s, thrust)

        axes[2].set_xlabel('s (m)')
        axes[2].set_ylabel('thrust')
        axes[2].grid()
        axes[2].set_xlim(0, s_final)

        # delta vs s
        axes[3].plot(s,
                     p.get_val('traj.phase0.timeseries.controls:delta',
                               units=None),
                     label='solution')

        axes[3].set_xlabel('s (m)')
        axes[3].set_ylabel('delta')
        axes[3].grid()
        axes[3].set_xlim(0, s_final)

        plt.tight_layout()

        # Performance constraint plot. Tire friction and power constraints
        fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(15, 4))
        plt.subplots_adjust(right=0.82, bottom=0.14, top=0.97, left=0.07)

        axes.plot(s,
                  p.get_val('traj.phase0.timeseries.c_fl', units=None),
                  label='c_fl')
        axes.plot(s,
                  p.get_val('traj.phase0.timeseries.c_fr', units=None),
                  label='c_fr')
        axes.plot(s,
                  p.get_val('traj.phase0.timeseries.c_rl', units=None),
                  label='c_rl')
        axes.plot(s,
                  p.get_val('traj.phase0.timeseries.c_rr', units=None),
                  label='c_rr')

        axes.plot(s, power / pmax, label='Power')

        axes.legend(bbox_to_anchor=(1.04, 0.5), loc="center left")
        axes.set_xlabel('s (m)')
        axes.set_ylabel('Performance constraints')
        axes.grid()
        axes.set_xlim(0, s_final)
def brachistochrone_min_time(transcription='gauss-lobatto',
                             num_segments=8,
                             transcription_order=3,
                             compressed=True,
                             optimizer='SLSQP',
                             dynamic_simul_derivs=True,
                             force_alloc_complex=False,
                             solve_segments=False,
                             run_driver=True):
    p = om.Problem(model=om.Group())

    if optimizer == 'SNOPT':
        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = optimizer
        p.driver.opt_settings['Major iterations limit'] = 100
        p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6
        p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6
        p.driver.opt_settings['iSumm'] = 6
    else:
        p.driver = om.ScipyOptimizeDriver()

    if dynamic_simul_derivs:
        p.driver.declare_coloring()

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

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

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

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

    # can't fix final position if you're solving the segments

    phase.add_state('pos',
                    fix_initial=True,
                    fix_final=fix_final,
                    solve_segments=solve_segments,
                    ref=[1, 1])
    #
    phase.add_state('v',
                    fix_initial=True,
                    fix_final=False,
                    solve_segments=solve_segments)
    #
    phase.add_control('theta',
                      continuity=True,
                      rate_continuity=True,
                      units='deg',
                      lower=0.01,
                      upper=179.9)

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

    if not fix_final:
        phase.add_boundary_constraint('pos', loc='final', equals=[10, 5])

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

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

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

    pos0 = [0, 10]
    posf = [10, 5]

    p['traj0.phase0.states:pos'] = phase.interp('pos', [pos0, posf])
    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

    p.run_model()
    if run_driver:
        p.run_driver()

    return p
Beispiel #19
0
    def test_brachistochrone_integrated_control_gauss_lobatto(self):
        import numpy as np
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm

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

        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=dm.GaussLobatto(num_segments=10))

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

        phase.set_time_options(initial_bounds=(0, 0),
                               duration_bounds=(.5, 10),
                               units='s')

        phase.add_state('x',
                        fix_initial=True,
                        fix_final=True,
                        rate_source='xdot',
                        units='m')
        phase.add_state('y',
                        fix_initial=True,
                        fix_final=True,
                        rate_source='ydot',
                        units='m')
        phase.add_state('v',
                        fix_initial=True,
                        rate_source='vdot',
                        units='m/s',
                        targets=['v'])
        phase.add_state('theta',
                        targets='theta',
                        fix_initial=False,
                        rate_source='theta_dot',
                        units='rad')

        phase.add_control('theta_dot',
                          units='deg/s',
                          rate_continuity=True,
                          lower=0,
                          upper=60)

        phase.add_design_parameter('g',
                                   units='m/s**2',
                                   opt=False,
                                   val=9.80665,
                                   targets=['g'])

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

        p.model.linear_solver = om.DirectSolver()

        p.setup()

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

        p['phase0.states:x'] = phase.interpolate(ys=[0, 10],
                                                 nodes='state_input')
        p['phase0.states:y'] = phase.interpolate(ys=[10, 5],
                                                 nodes='state_input')
        p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9],
                                                 nodes='state_input')
        p['phase0.states:theta'] = np.radians(
            phase.interpolate(ys=[0.05, 100.0], nodes='state_input'))
        p['phase0.controls:theta_dot'] = phase.interpolate(
            ys=[50, 50], nodes='control_input')

        # Solve for the optimal trajectory
        p.run_driver()

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

        sim_out = phase.simulate(times_per_seg=20)

        x_sol = p.get_val('phase0.timeseries.states:x')
        y_sol = p.get_val('phase0.timeseries.states:y')
        v_sol = p.get_val('phase0.timeseries.states:v')
        theta_sol = p.get_val('phase0.timeseries.states:theta')
        theta_dot_sol = p.get_val('phase0.timeseries.controls:theta_dot')
        time_sol = p.get_val('phase0.timeseries.time')

        x_sim = sim_out.get_val('phase0.timeseries.states:x')
        y_sim = sim_out.get_val('phase0.timeseries.states:y')
        v_sim = sim_out.get_val('phase0.timeseries.states:v')
        theta_sim = sim_out.get_val('phase0.timeseries.states:theta')
        theta_dot_sim = sim_out.get_val('phase0.timeseries.controls:theta_dot')
        time_sim = sim_out.get_val('phase0.timeseries.time')

        x_interp = interp1d(time_sim[:, 0], x_sim[:, 0])
        y_interp = interp1d(time_sim[:, 0], y_sim[:, 0])
        v_interp = interp1d(time_sim[:, 0], v_sim[:, 0])
        theta_interp = interp1d(time_sim[:, 0], theta_sim[:, 0])
        theta_dot_interp = interp1d(time_sim[:, 0], theta_dot_sim[:, 0])

        assert_near_equal(x_interp(time_sol), x_sol, tolerance=1.0E-5)
        assert_near_equal(y_interp(time_sol), y_sol, tolerance=1.0E-5)
        assert_near_equal(v_interp(time_sol), v_sol, tolerance=1.0E-5)
        assert_near_equal(theta_interp(time_sol), theta_sol, tolerance=1.0E-5)
        assert_near_equal(theta_dot_interp(time_sol),
                          theta_dot_sol,
                          tolerance=1.0E-5)
Beispiel #20
0
#p.driver.declare_coloring()

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

# Define a Dymos Phase object with GaussLobatto Transcription
# phase = dm.Phase(ode_class = ODESystem1,
#                 transcription = dm.GaussLobatto(num_segments = 10, order = 3))
#traj.add_phase(name = 'phase0', phase = phase)

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

# 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(
    initial_bounds=(0, 0),  # 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.
    def test_brachistochrone_base_phase_class_gl(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm

        class BrachistochronePhase(dm.Phase):
            def setup(self):

                self.options['ode_class'] = BrachistochroneODE
                self.set_time_options(fix_initial=True,
                                      duration_bounds=(.5, 10),
                                      units='s')
                self.add_state('x', fix_initial=True, rate_source='xdot')
                self.add_state('y', fix_initial=True, rate_source='ydot')
                self.add_state('v',
                               fix_initial=True,
                               rate_source='vdot',
                               targets=['v'])
                self.add_control('theta',
                                 units='deg',
                                 rate_continuity=False,
                                 lower=0.01,
                                 upper=179.9,
                                 targets=['theta'])
                self.add_parameter('g',
                                   units='m/s**2',
                                   opt=False,
                                   val=9.80665,
                                   targets=['g'])

                super(BrachistochronePhase, self).setup()

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

        phase = BrachistochronePhase(
            transcription=dm.GaussLobatto(num_segments=20, order=3))
        p.model.add_subsystem('phase0', phase)

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

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

        p.model.linear_solver = om.DirectSolver()

        p.setup()

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

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

        # Solve for the optimal trajectory
        p.run_driver()

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

        exp_out = phase.simulate()

        assert_near_equal(exp_out.get_val('phase0.timeseries.states:x')[-1],
                          10,
                          tolerance=1.0E-3)
        assert_near_equal(exp_out.get_val('phase0.timeseries.states:y')[-1],
                          5,
                          tolerance=1.0E-3)
    def test_promotes_parameter(self):
        transcription = 'radau-ps'
        optimizer = 'SLSQP'
        num_segments = 10
        transcription_order = 3
        compressed = False

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

        p.driver = om.pyOptSparseDriver()
        OPT, OPTIMIZER = set_pyoptsparse_opt(optimizer, fallback=True)
        p.driver.options['optimizer'] = OPTIMIZER
        p.driver.declare_coloring()

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

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

        traj.add_phase('phase0', phase, promotes_inputs=['t_initial', 't_duration', 'parameters:g'])

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

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

        phase.add_state('x', fix_initial=True, fix_final=False, solve_segments=False,
                        units='m', rate_source='xdot')
        phase.add_state('y', fix_initial=True, fix_final=False, solve_segments=False,
                        units='m', rate_source='ydot')
        phase.add_state('v', fix_initial=True, fix_final=False, solve_segments=False,
                        units='m/s', rate_source='vdot', targets=['v'])

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

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

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

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

        p.set_val('traj.t_initial', 0.0)
        p.set_val('traj.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]))
        p.set_val('traj.parameters:g', 9.80665)

        p.run_driver()

        assert_near_equal(p['traj.t_duration'], 1.8016, tolerance=1.0E-4)
    def test_brachistochrone_quick_start(self):
        import numpy as np
        import openmdao.api as om
        import dymos as dm
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        p.set_val('traj.phase0.controls:theta',
                  phase.interpolate(ys=[90, 90], nodes='control_input'),
                  units='deg')

        # Run the driver to solve the problem
        p.run_driver()

        # Check the validity of our results by using scipy.integrate.solve_ivp to
        # integrate the solution.
        sim_out = traj.simulate()

        # Plot the results
        fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 4.5))

        axes[0].plot(p.get_val('traj.phase0.timeseries.states:x'),
                     p.get_val('traj.phase0.timeseries.states:y'),
                     'ro', label='solution')

        axes[0].plot(sim_out.get_val('traj.phase0.timeseries.states:x'),
                     sim_out.get_val('traj.phase0.timeseries.states:y'),
                     'b-', label='simulation')

        axes[0].set_xlabel('x (m)')
        axes[0].set_ylabel('y (m/s)')
        axes[0].legend()
        axes[0].grid()

        axes[1].plot(p.get_val('traj.phase0.timeseries.time'),
                     p.get_val('traj.phase0.timeseries.controls:theta', units='deg'),
                     'ro', label='solution')

        axes[1].plot(sim_out.get_val('traj.phase0.timeseries.time'),
                     sim_out.get_val('traj.phase0.timeseries.controls:theta', units='deg'),
                     'b-', label='simulation')

        axes[1].set_xlabel('time (s)')
        axes[1].set_ylabel(r'$\theta$ (deg)')
        axes[1].legend()
        axes[1].grid()

        plt.show()
Beispiel #24
0
    def test_brachistochrone_upstream_control(self):
        import numpy as np
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm

        import matplotlib.pyplot as plt
        plt.switch_backend('Agg')

        from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE

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

        # Instantiate the transcription so we can get the number of nodes from it while
        # building the problem.
        tx = dm.GaussLobatto(num_segments=10, order=3)

        # Add an indep var comp to provide the external control values
        ivc = p.model.add_subsystem('control_ivc',
                                    om.IndepVarComp(),
                                    promotes_outputs=['*'])

        # Add the output to provide the values of theta at the control input nodes of the transcription.
        ivc.add_output('theta',
                       shape=(tx.grid_data.subset_num_nodes['control_input']),
                       units='rad')

        # Add this external control as a design variable
        p.model.add_design_var('theta', units='rad', lower=1.0E-5, upper=np.pi)
        # Connect this to controls:theta in the appropriate phase.
        # connect calls are cached, so we can do this before we actually add the trajectory to the problem.
        p.model.connect('theta', 'traj.phase0.controls:theta')

        #
        # 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=tx)

        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,
                        units='m',
                        rate_source='xdot')
        phase.add_state('y',
                        fix_initial=True,
                        fix_final=True,
                        units='m',
                        rate_source='ydot')
        phase.add_state('v',
                        fix_initial=True,
                        fix_final=False,
                        units='m/s',
                        rate_source='vdot',
                        targets=['v'])

        # Define theta as a control.
        # Use opt=False to allow it to be connected to an external source.
        # Arguments lower and upper are no longer valid for an input control.
        phase.add_control(name='theta', targets=['theta'], 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()

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

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

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

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

        p.set_val('traj.phase0.controls:theta',
                  phase.interpolate(ys=[90, 90], nodes='control_input'),
                  units='deg')

        # Run the driver to solve the problem
        p.run_driver()

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

        # Check the validity of our results by using scipy.integrate.solve_ivp to
        # integrate the solution.
        sim_out = traj.simulate()

        # Plot the results
        fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 4.5))

        axes[0].plot(p.get_val('traj.phase0.timeseries.states:x'),
                     p.get_val('traj.phase0.timeseries.states:y'),
                     'ro',
                     label='solution')

        axes[0].plot(sim_out.get_val('traj.phase0.timeseries.states:x'),
                     sim_out.get_val('traj.phase0.timeseries.states:y'),
                     'b-',
                     label='simulation')

        axes[0].set_xlabel('x (m)')
        axes[0].set_ylabel('y (m/s)')
        axes[0].legend()
        axes[0].grid()

        axes[1].plot(p.get_val('traj.phase0.timeseries.time'),
                     p.get_val('traj.phase0.timeseries.controls:theta',
                               units='deg'),
                     'ro',
                     label='solution')

        axes[1].plot(sim_out.get_val('traj.phase0.timeseries.time'),
                     sim_out.get_val('traj.phase0.timeseries.controls:theta',
                                     units='deg'),
                     'b-',
                     label='simulation')

        axes[1].set_xlabel('time (s)')
        axes[1].set_ylabel(r'$\theta$ (deg)')
        axes[1].legend()
        axes[1].grid()

        plt.show()
Beispiel #25
0
def run_takeoff_no_transition(airplane,
                              runway,
                              flap_angle=0.0,
                              wind_speed=0.0):
    p = om.Problem(model=om.Group())

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

    p.model.linear_solver = om.DirectSolver()

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

    # --------------------------------------------- Initial Run --------------------------------------------------------
    initial_run = dm.Phase(ode_class=InitialRunODE,
                           transcription=dm.GaussLobatto(num_segments=20,
                                                         compressed=False),
                           ode_init_kwargs={'airplane': airplane})

    traj.add_phase('initial_run', initial_run)

    initial_run.set_time_options(fix_initial=True,
                                 units='s',
                                 duration_bounds=(10, 100))

    # Initial run states
    initial_run.add_state(name='V',
                          units='m/s',
                          rate_source='initial_run_eom.v_dot',
                          targets=['V'],
                          fix_initial=True,
                          fix_final=False,
                          lower=0)
    initial_run.add_state(name='x',
                          units='m',
                          rate_source='initial_run_eom.x_dot',
                          targets=['mlg_pos.x'],
                          fix_initial=True,
                          fix_final=False,
                          lower=airplane.landing_gear.main.x)
    initial_run.add_state(name='mass',
                          units='kg',
                          rate_source='prop.m_dot',
                          targets=['mass'],
                          fix_initial=False,
                          fix_final=False,
                          lower=0.0,
                          upper=airplane.limits.MTOW)

    # Initial run parameters
    initial_run.add_parameter(name='de',
                              val=0.0,
                              units='deg',
                              desc='Elevator deflection',
                              targets=['aero.de'],
                              opt=False)
    initial_run.add_parameter(
        name='theta',
        val=0.0,
        units='deg',
        desc='Pitch Angle',
        targets=['aero.alpha', 'initial_run_eom.alpha', 'mlg_pos.theta'],
        opt=False)
    initial_run.add_parameter(name='h',
                              val=0.0,
                              units='m',
                              desc='Vertical CG position',
                              targets=['mlg_pos.h'],
                              opt=False)

    # path constraint
    initial_run.add_path_constraint(name='initial_run_eom.f_mg',
                                    lower=0,
                                    units='N')
    initial_run.add_path_constraint(name='initial_run_eom.f_ng',
                                    lower=0,
                                    units='N')

    initial_run.add_boundary_constraint(name='initial_run_eom.f_ng',
                                        loc='final',
                                        units='N',
                                        lower=0.0,
                                        upper=0.5,
                                        shape=(1, ))

    initial_run.add_objective('mass', loc='initial', scaler=-1)

    initial_run.add_timeseries_output('initial_run_eom.f_mg', units='kN')
    initial_run.add_timeseries_output('initial_run_eom.f_ng', units='kN')
    initial_run.add_timeseries_output('aero.CL')
    initial_run.add_timeseries_output('aero.CD')
    initial_run.add_timeseries_output('aero.Cm')
    # --------------------------------------------- Rotation -----------------------------------------------------------
    rotation = dm.Phase(ode_class=RotationODE,
                        transcription=dm.GaussLobatto(num_segments=5,
                                                      compressed=False),
                        ode_init_kwargs={'airplane': airplane})
    traj.add_phase(name='rotation', phase=rotation)

    rotation.set_time_options(fix_initial=False,
                              units='s',
                              duration_bounds=(1, 6))

    # Rotation states
    rotation.add_state(name='V',
                       units='m/s',
                       rate_source='rotation_eom.v_dot',
                       targets=['V'],
                       fix_initial=False,
                       fix_final=False,
                       lower=0)
    rotation.add_state(name='x',
                       units='m',
                       rate_source='rotation_eom.x_dot',
                       targets=['mlg_pos.x'],
                       fix_initial=False,
                       fix_final=False,
                       lower=0)
    rotation.add_state(name='h',
                       units='m',
                       rate_source='rotation_eom.h_dot',
                       targets=['mlg_pos.h'],
                       fix_initial=True,
                       fix_final=False)
    rotation.add_state(name='mass',
                       units='kg',
                       rate_source='prop.m_dot',
                       targets=['mass'],
                       fix_initial=False,
                       fix_final=False,
                       lower=0.0)
    rotation.add_state(
        name='theta',
        units='deg',
        rate_source='rotation_eom.theta_dot',
        targets=['aero.alpha', 'rotation_eom.alpha', 'mlg_pos.theta'],
        fix_initial=True,
        fix_final=False,
        lower=0.0)
    rotation.add_state(name='q',
                       units='deg/s',
                       rate_source='rotation_eom.q_dot',
                       targets=['q'],
                       fix_initial=True,
                       fix_final=False,
                       lower=0.0)

    # Rotation controls
    rotation.add_control(name='de',
                         units='deg',
                         lower=-30.0,
                         upper=30.0,
                         targets=['aero.de'],
                         fix_initial=True,
                         rate_continuity=True)

    # Rotation path constraints
    rotation.add_path_constraint(name='rotation_eom.f_mg', lower=0, units='N')

    # Rotation boundary constraint
    rotation.add_boundary_constraint(name='rotation_eom.f_mg',
                                     loc='final',
                                     units='N',
                                     lower=0.0,
                                     upper=0.5,
                                     shape=(1, ))
    rotation.add_boundary_constraint(name='x',
                                     loc='final',
                                     units='m',
                                     upper=runway.tora,
                                     shape=(1, ))

    rotation.add_timeseries_output('rotation_eom.f_mg', units='kN')
    rotation.add_timeseries_output('aero.CL')
    rotation.add_timeseries_output('aero.CD')
    rotation.add_timeseries_output('aero.Cm')
    # ---------------------------------------- Trajectory Parameters ---------------------------------------------------
    traj.add_parameter(name='dih',
                       val=0.0,
                       units='deg',
                       lower=-5.0,
                       upper=5.0,
                       desc='Horizontal stabilizer angle',
                       targets={
                           'initial_run': ['aero.dih'],
                           'rotation': ['aero.dih'],
                       },
                       opt=True,
                       dynamic=False)
    traj.add_parameter(
        name='Vw',
        val=0.0,
        units='m/s',
        desc='Wind speed along the runway, defined as positive for a headwind',
        targets={
            'initial_run': ['Vw'],
            'rotation': ['Vw'],
        },
        opt=False,
        dynamic=False)
    traj.add_parameter(name='flap_angle',
                       val=0.0,
                       units='deg',
                       desc='Flap defletion',
                       targets={
                           'initial_run': ['aero.flap_angle'],
                           'rotation': ['aero.flap_angle'],
                       },
                       opt=False,
                       dynamic=False)
    traj.add_parameter(name='elevation',
                       val=0.0,
                       units='m',
                       desc='Runway elevation',
                       targets={
                           'initial_run': ['elevation'],
                           'rotation': ['elevation'],
                       },
                       opt=False,
                       dynamic=False)
    traj.add_parameter(name='rw_slope',
                       val=0.0,
                       units='rad',
                       desc='Runway slope',
                       targets={
                           'initial_run': ['initial_run_eom.rw_slope'],
                           'rotation': ['rotation_eom.rw_slope'],
                       },
                       opt=False,
                       dynamic=False)

    # ------------------------------------------------ Link Phases -----------------------------------------------------
    traj.link_phases(phases=['initial_run', 'rotation'],
                     vars=['time', 'V', 'x', 'mass'])

    p.setup(check=True)

    p.set_val('traj.initial_run.t_initial', 0)
    p.set_val('traj.initial_run.t_duration', 60)
    p.set_val('traj.rotation.t_initial', 60)
    p.set_val('traj.rotation.t_duration', 3)

    p.set_val('traj.parameters:elevation', runway.elevation)
    p.set_val('traj.parameters:rw_slope', runway.slope)
    p.set_val('traj.parameters:flap_angle', flap_angle)
    p.set_val('traj.parameters:dih', 0.0)
    p.set_val('traj.parameters:Vw', wind_speed)

    p['traj.initial_run.states:x'] = initial_run.interpolate(
        ys=[airplane.landing_gear.main.x, 0.7 * runway.tora],
        nodes='state_input')
    p['traj.initial_run.states:V'] = initial_run.interpolate(
        ys=[0, 70], nodes='state_input')
    p['traj.initial_run.states:mass'] = initial_run.interpolate(
        ys=[airplane.limits.MTOW, airplane.limits.MTOW - 100],
        nodes='state_input')
    p['traj.initial_run.parameters:h'] = airplane.landing_gear.main.z

    p['traj.rotation.states:x'] = rotation.interpolate(
        ys=[0.7 * runway.tora, 0.8 * runway.tora], nodes='state_input')
    p['traj.rotation.states:V'] = rotation.interpolate(ys=[70, 80],
                                                       nodes='state_input')
    p['traj.rotation.states:mass'] = rotation.interpolate(
        ys=[airplane.limits.MTOW - 100, airplane.limits.MTOW - 200],
        nodes='state_input')
    p['traj.rotation.states:h'] = airplane.landing_gear.main.z
    p['traj.rotation.states:q'] = rotation.interpolate(ys=[0.0, 10.0],
                                                       nodes='state_input')
    p['traj.rotation.states:theta'] = rotation.interpolate(ys=[0.0, 15.0],
                                                           nodes='state_input')
    p['traj.rotation.controls:de'] = rotation.interpolate(
        ys=[0.0, -20.0], nodes='control_input')

    dm.run_problem(p)
    sim_out = traj.simulate()

    print(
        f"RTOW: {p.get_val('traj.initial_run.timeseries.states:mass', units='kg')[0]} kg"
    )
    print(
        f"Rotation speed (VR): {p.get_val('traj.initial_run.timeseries.states:V', units='kn')[-1]} kn"
    )
    print(
        f"Vlof speed (Vlof): {p.get_val('traj.rotation.timeseries.states:V', units='kn')[-1]} kn"
    )
    print(f"Horizontal stabilizer: {p.get_val('traj.parameters:dih')} deg")

    return p, sim_out
Beispiel #26
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 phases
phase0 = dm.Phase(ode_class=DonnerSubODE,
                  transcription=dm.GaussLobatto(num_segments=10,
                                                order=3,
                                                compressed=True,
                                                solve_segments=True))

phase1 = dm.Phase(ode_class=DonnerSubODE,
                  transcription=dm.Radau(num_segments=10,
                                         order=3,
                                         compressed=True,
                                         solve_segments=True))

# Add the phase to the trajectory, and the trajectory to the model
traj.add_phase('phase0', phase=phase0)
traj.add_phase('phase1', phase=phase1)
traj.link_phases(phases=['phase0', 'phase1'], vars=['time', 'x', 'y', 'phi'])
p.model.add_subsystem('traj', traj)

#
    def test_min_time_climb_for_docs_partial_coloring(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal

        import dymos as dm
        from dymos.examples.min_time_climb.doc.min_time_climb_ode_partial_coloring import MinTimeClimbODE

        for fd in (False, True):
            if fd:
                pc_options = (False, True)
            else:
                pc_options = (False, )
            for pc in pc_options:
                with self.subTest(
                        f'Finite Differencing: {fd}  Partial Coloring: {pc}'):
                    print(f'Finite Differencing: {fd}  Partial Coloring: {pc}')

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

                    p.driver = om.pyOptSparseDriver()
                    p.driver.options['optimizer'] = 'IPOPT'
                    p.driver.declare_coloring(tol=1.0E-12)
                    p.driver.opt_settings['max_iter'] = 500
                    p.driver.opt_settings[
                        'alpha_for_y'] = 'safer-min-dual-infeas'

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

                    phase = dm.Phase(
                        ode_class=MinTimeClimbODE,
                        ode_init_kwargs={
                            'fd': fd,
                            'partial_coloring': pc
                        },
                        transcription=dm.GaussLobatto(num_segments=30))

                    traj.add_phase('phase0', phase)

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

                    #
                    # Set the options on the optimization variables
                    #
                    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')

                    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')

                    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')

                    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')

                    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'])

                    #
                    # 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=100.0)

                    p.model.linear_solver = om.DirectSolver()

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

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

                    p['traj.phase0.states:r'] = phase.interpolate(
                        ys=[0.0, 50000.0], nodes='state_input')
                    p['traj.phase0.states:h'] = phase.interpolate(
                        ys=[100.0, 20000.0], nodes='state_input')
                    p['traj.phase0.states:v'] = phase.interpolate(
                        ys=[135.964, 283.159], nodes='state_input')
                    p['traj.phase0.states:gam'] = phase.interpolate(
                        ys=[0.0, 0.0], nodes='state_input')
                    p['traj.phase0.states:m'] = phase.interpolate(
                        ys=[19030.468, 10000.], nodes='state_input')
                    p['traj.phase0.controls:alpha'] = phase.interpolate(
                        ys=[0.0, 0.0], nodes='control_input')

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

                    #
                    # This code is intended to save the coloring plots for the documentation.
                    # In practice, use the command line interface to view these files instead:
                    # `openmdao view_coloring coloring_files/total_coloring.pkl --view`
                    #
                    stfd = '_fd' if fd else ''
                    stpc = '_pc' if pc else ''
                    coloring_dir = f'coloring_files{stfd}{stpc}'
                    if fd or pc:
                        if os.path.exists(coloring_dir):
                            shutil.rmtree(coloring_dir)
                        shutil.move('coloring_files', coloring_dir)

                    _view_coloring(
                        os.path.join(coloring_dir, 'total_coloring.pkl'))

                    #
                    # Test the results
                    #
                    assert_near_equal(p.get_val('traj.phase0.t_duration'),
                                      321.0,
                                      tolerance=1.0E-1)
Beispiel #28
0
def min_time_climb(num_seg=3,
                   transcription_order=3,
                   force_alloc_complex=False):

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

    tx = dm.GaussLobatto(num_segments=num_seg, order=transcription_order)

    traj = dm.Trajectory()

    phase = dm.Phase(ode_class=MinTimeClimbODE, transcription=tx)
    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_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)
    phase.add_path_constraint(name='time', lower=0, upper=400)
    phase.add_path_constraint(name='time_phase', lower=0, upper=400)

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

    p.model.linear_solver = om.DirectSolver()

    p.setup(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])

    return p
Beispiel #29
0
    def test_simulate_array_param(self):
        #
        # Initialize the Problem and the optimization driver
        #
        p = om.Problem(model=om.Group())
        p.driver = om.ScipyOptimizeDriver()
        p.driver.declare_coloring()

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

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

        #
        # Set the variables
        #
        phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(.5, 10))

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

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

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

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

        phase.add_parameter('g', units='m/s**2', val=9.80665)
        phase.add_parameter('array', units=None, shape=(10,), dynamic=False)

        # dummy array of data
        indeps = p.model.add_subsystem('indeps', om.IndepVarComp(), promotes=['*'])
        indeps.add_output('array', np.linspace(1, 10, 10), units=None)
        # add dummy array as a parameter and connect it
        p.model.connect('array', 'traj.phase0.parameters:array')

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

        p.model.linear_solver = om.DirectSolver()

        #
        # Setup the Problem
        #
        p.setup()

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

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

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

        # Test the results
        sol_results = om.CaseReader('dymos_solution.db').get_case('final')
        sim_results = om.CaseReader('dymos_solution.db').get_case('final')

        sol = sol_results.get_val('traj.phase0.timeseries.parameters:array')
        sim = sim_results.get_val('traj.phase0.timeseries.parameters:array')

        assert_near_equal(sol - sim, np.zeros_like(sol))

        # Test that the parameter is available in the solution and simulation files
        sol = sol_results.get_val('traj.phase0.parameters:array')
        sim = sim_results.get_val('traj.phase0.parameters:array')

        assert_near_equal(sol - sim, np.zeros_like(sol))
Beispiel #30
0
def setup_problem(
        trans=dm.GaussLobatto(num_segments=10), polynomial_control=False):
    from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE
    from dymos.transcriptions.runge_kutta.runge_kutta import RungeKutta

    p = om.Problem(model=om.Group())
    if isinstance(trans, RungeKutta):
        p.driver = om.pyOptSparseDriver()
    else:
        p.driver = om.ScipyOptimizeDriver()

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

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

    phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(.5, 10))

    phase.add_state('x',
                    fix_initial=True,
                    fix_final=not isinstance(trans, RungeKutta),
                    rate_source=BrachistochroneODE.states['x']['rate_source'],
                    units=BrachistochroneODE.states['x']['units'])
    phase.add_state('y',
                    fix_initial=True,
                    fix_final=not isinstance(trans, RungeKutta),
                    rate_source=BrachistochroneODE.states['y']['rate_source'],
                    units=BrachistochroneODE.states['y']['units'])
    phase.add_state('v',
                    fix_initial=True,
                    rate_source=BrachistochroneODE.states['v']['rate_source'],
                    units=BrachistochroneODE.states['v']['units'])

    if not polynomial_control:
        phase.add_control('theta',
                          units='deg',
                          rate_continuity=False,
                          lower=0.01,
                          upper=179.9)
    else:
        phase.add_polynomial_control('theta',
                                     order=1,
                                     units='deg',
                                     lower=0.01,
                                     upper=179.9)

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

    if isinstance(trans, RungeKutta):
        phase.add_timeseries_output('check', units='m/s', shape=(1, ))
        phase.add_boundary_constraint('x', loc='final', equals=10)
        phase.add_boundary_constraint('y', loc='final', equals=5)

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

    p.model.linear_solver = om.DirectSolver()

    p.setup()

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

    p['phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input')
    p['phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input')
    p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input')
    if not polynomial_control:
        p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5],
                                                       nodes='control_input')
    else:
        p['phase0.polynomial_controls:theta'][:] = 5.0

    return p