예제 #1
0
    def test_brachistochrone_for_docs_radau(self):
        from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver, SqliteRecorder
        from openmdao.utils.assert_utils import assert_rel_error
        import dymos as dm
        from dymos.examples.plotting import plot_results
        from dymos.examples.brachistochrone import BrachistochroneODE

        #
        # Initialize the Problem and the optimization driver
        #
        p = Problem(model=Group())
        p.driver = ScipyOptimizeDriver()
        p.driver.options['dynamic_simul_derivs'] = True

        #
        # 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.Radau(num_segments=10)))

        #
        # Set the variables
        #
        phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(.5, 10))
        phase.set_state_options('x', fix_initial=True, fix_final=True)
        phase.set_state_options('y', fix_initial=True, fix_final=True)
        phase.set_state_options('v', fix_initial=True)
        phase.add_control('theta', units='deg', lower=0.01, upper=179.9)
        phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665)

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

        p.model.linear_solver = DirectSolver()

        #
        # 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
        #
        p.run_driver()

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

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

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

        plt.show()
예제 #2
0
def flying_robot_direct_collocation(transcription='gauss-lobatto',
                                    compressed=True):

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

    if transcription == 'gauss-lobatto':
        t = dm.GaussLobatto(num_segments=8, order=5, compressed=compressed)
    elif transcription == "radau-ps":
        t = dm.Radau(num_segments=8, order=5, compressed=compressed)
    else:
        raise ValueError('invalid transcription')

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

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

    phase.set_time_options(fix_initial=True,
                           fix_duration=False,
                           duration_bounds=(0.1, 1E4),
                           units='s')

    phase.add_state('x',
                    shape=(2, ),
                    fix_initial=True,
                    fix_final=True,
                    rate_source='v',
                    units='m')
    phase.add_state('v',
                    shape=(2, ),
                    fix_initial=True,
                    fix_final=True,
                    rate_source='u',
                    units='m/s')
    phase.add_state('J',
                    fix_initial=True,
                    fix_final=False,
                    rate_source='u_mag2',
                    units='m**2/s**3')

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

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

    p.model.linear_solver = om.DirectSolver()

    p.setup(check=True)

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

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

    p.run_driver()

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

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

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

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

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

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

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

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

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

        #
        # Setup the Problem
        #
        p.setup()

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

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

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

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

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

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

        plt.show()
    def test_brachistochrone_vector_boundary_constraints_radau_partial_indices(
            self):

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

        phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE,
                         transcription=dm.Radau(num_segments=20, order=3))

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

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

        phase.add_state(
            'pos',
            shape=(2, ),
            rate_source=BrachistochroneVectorStatesODE.states['pos']
            ['rate_source'],
            units=BrachistochroneVectorStatesODE.states['pos']['units'],
            fix_initial=True,
            fix_final=[True, False])
        phase.add_state(
            'v',
            rate_source=BrachistochroneVectorStatesODE.states['v']
            ['rate_source'],
            targets=BrachistochroneVectorStatesODE.states['v']['targets'],
            units=BrachistochroneVectorStatesODE.states['v']['units'],
            fix_initial=True,
            fix_final=False)

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

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

        phase.add_boundary_constraint('pos',
                                      loc='final',
                                      equals=5,
                                      indices=[1])

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

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

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

        p['phase0.states:pos'] = phase.interpolate(ys=[pos0, posf],
                                                   nodes='state_input')
        p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9],
                                                 nodes='state_input')
        p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100],
                                                       nodes='control_input')
        p['phase0.design_parameters:g'] = 9.80665

        p.run_driver()

        assert_rel_error(self,
                         p.get_val('phase0.time')[-1],
                         1.8016,
                         tolerance=1.0E-3)

        # Plot results
        if SHOW_PLOTS:
            p.run_driver()
            exp_out = phase.simulate(times_per_seg=20)

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

            x_imp = p.get_val('phase0.timeseries.states:pos')[:, 0]
            y_imp = p.get_val('phase0.timeseries.states:pos')[:, 1]

            x_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 0]
            y_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 1]

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

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

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

            x_imp = p.get_val('phase0.timeseries.time')
            y_imp = p.get_val('phase0.timeseries.control_rates:theta_rate2')

            x_exp = exp_out.get_val('phase0.timeseries.time')
            y_exp = exp_out.get_val(
                'phase0.timeseries.control_rates:theta_rate2')

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

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

            plt.show()

        return p
예제 #5
0
    def test_brachistochrone_integrated_parameter_radau_ps(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.Radau(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')
        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=1.0E-3,
                                     num_points=10)
        assert_timeseries_near_equal(t_sol,
                                     y_sol,
                                     t_sim,
                                     y_sim,
                                     tolerance=1.0E-3,
                                     num_points=10)
        assert_timeseries_near_equal(t_sol,
                                     v_sol,
                                     t_sim,
                                     v_sim,
                                     tolerance=1.0E-3,
                                     num_points=10)
        assert_timeseries_near_equal(t_sol,
                                     theta_sol,
                                     t_sim,
                                     theta_sim,
                                     tolerance=1.0E-3,
                                     num_points=10)
예제 #6
0
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=False))

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

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

#
# Configure the first phase
#
phase0.set_time_options(units=None, targets=['threat_comp.time'], fix_initial=True, duration_bounds=(0.1, 100))
phase0.add_state('x', rate_source='eom_comp.dx_dt', targets=['nav_comp.x'], fix_initial=True, fix_final=False)
phase0.add_state('y', rate_source='eom_comp.dy_dt', targets=['nav_comp.y'], fix_initial=True, fix_final=False)

# phase0.add_input_parameter('v', targets=['eom_comp.v'])
예제 #7
0
    def test_objective_parameter_radau(self):
        p = om.Problem(model=om.Group())

        p.driver = om.ScipyOptimizeDriver()

        p.driver.declare_coloring()

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

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

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

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

        phase.add_state(
            'y',
            rate_source=BrachistochroneODE.states['y']['rate_source'],
            units=BrachistochroneODE.states['y']['units'],
            fix_initial=True,
            fix_final=True,
            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',
            continuity=True,
            rate_continuity=True,
            opt=True,
            targets=BrachistochroneODE.parameters['theta']['targets'],
            units='deg',
            lower=0.01,
            upper=179.9,
            ref=1,
            ref0=0)

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

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

        p.model.options['assembled_jac_type'] = 'csc'
        p.model.linear_solver = om.DirectSolver()
        p.setup(check=True)

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

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

        p.run_driver()

        assert_near_equal(p['phase0.t_duration'], 10, tolerance=1.0E-3)
n_nodes = 60
seed_perturbation = np.zeros(n_nodes)
# seed_perturbation[2] = 1.e-6

# Add an indep_var_comp that will talk to external calls from pyStatReduce
random_perturbations = p.model.add_subsystem('random_perturbations', IndepVarComp())
random_perturbations.add_output('rho_pert', val=seed_perturbation, units='kg/m**3',
                                desc="perturbations introduced into the density data")

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

phase = dm.Phase(ode_class=MinTimeClimbODE,
                 transcription=dm.Radau(num_segments=15, compressed=True))

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.set_state_options('r', fix_initial=True, lower=0, upper=1.0E6,
                        ref=1.0E3, defect_ref=1.0E3, units='m')

phase.set_state_options('h', fix_initial=True, lower=0, upper=20000.0,
예제 #9
0
    def test_results(self):
        # begin code for paper
        import numpy as np
        from scipy.interpolate import interp1d
        import matplotlib.pyplot as plt

        import openmdao.api as om

        import dymos as dm
        from dymos.models.atmosphere.atmos_1976 import USatm1976Data as USatm1976Data

        # CREATE an atmosphere interpolant
        english_to_metric_rho = om.unit_conversion('slug/ft**3', 'kg/m**3')[0]
        english_to_metric_alt = om.unit_conversion('ft', 'm')[0]
        rho_interp = interp1d(np.array(USatm1976Data.alt * english_to_metric_alt, dtype=complex),
                              np.array(USatm1976Data.rho * english_to_metric_rho, dtype=complex),
                              kind='linear')


        class CannonballSize(om.ExplicitComponent):
            """
            Static calculations performed before the dynamic model
            """

            def setup(self):
                self.add_input(name='radius', val=1.0,
                               desc='cannonball radius', units='m')
                self.add_input(name='density', val=7870.,
                               desc='cannonball density', units='kg/m**3')

                self.add_output(name='mass', shape=(1,),
                                desc='cannonball mass', units='kg')
                self.add_output(name='area', shape=(1,),
                                desc='aerodynamic reference area', units='m**2')

                self.declare_partials(of='*', wrt='*', method='cs')

            def compute(self, inputs, outputs):
                radius = inputs['radius']
                rho = inputs['density']

                outputs['mass'] = (4 / 3.) * rho * np.pi * radius ** 3
                outputs['area'] = np.pi * radius ** 2


        class CannonballODE(om.ExplicitComponent):
            """
            Cannonball ODE assuming flat earth and accounting for air resistance
            """

            def initialize(self):
                self.options.declare('num_nodes', types=int)

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

                # static parameters
                self.add_input('mass', units='kg')
                self.add_input('area', units='m**2')

                # time varying inputs
                self.add_input('alt', units='m', shape=nn)
                self.add_input('v', units='m/s', shape=nn)
                self.add_input('gam', units='rad', shape=nn)

                # state rates
                self.add_output('v_dot', shape=nn, units='m/s**2')
                self.add_output('gam_dot', shape=nn, units='rad/s')
                self.add_output('h_dot', shape=nn, units='m/s')
                self.add_output('r_dot', shape=nn, units='m/s')
                self.add_output('ke', shape=nn, units='J')

                # Ask OpenMDAO to compute the partial derivatives using complex-step
                # with a partial coloring algorithm for improved performance
                self.declare_partials('*', '*', method='cs')
                self.declare_coloring(wrt='*', method='cs')

            def compute(self, inputs, outputs):

                gam = inputs['gam']
                v = inputs['v']
                alt = inputs['alt']
                m = inputs['mass']
                S = inputs['area']

                CD = 0.5  # good assumption for a sphere
                GRAVITY = 9.80665  # m/s**2

                # handle complex-step gracefully from the interpolant
                if np.iscomplexobj(alt):
                    rho = rho_interp(inputs['alt'])
                else:
                    rho = rho_interp(inputs['alt']).real

                q = 0.5 * rho * inputs['v'] ** 2
                qS = q * S
                D = qS * CD
                cgam = np.cos(gam)
                sgam = np.sin(gam)
                outputs['v_dot'] = - D / m - GRAVITY * sgam
                outputs['gam_dot'] = -(GRAVITY / v) * cgam
                outputs['h_dot'] = v * sgam
                outputs['r_dot'] = v * cgam
                outputs['ke'] = 0.5 * m * v ** 2

        p = om.Problem()

        ###################################
        # Co-design part of the model,
        # static analysis outside of Dymos
        ###################################
        static_calcs = p.model.add_subsystem('static_calcs', CannonballSize())
        static_calcs.add_design_var('radius', lower=0.01, upper=0.10,
                                    ref0=0.01, ref=0.10)

        p.model.connect('static_calcs.mass', 'traj.parameters:mass')
        p.model.connect('static_calcs.area', 'traj.parameters:area')

        traj = p.model.add_subsystem('traj', dm.Trajectory())
        # Declare parameters that will be constant across
        # the two phases of the trajectory, so we can connect to it only once
        traj.add_parameter('mass', units='kg', val=0.01, static_target=True)
        traj.add_parameter('area', units='m**2', static_target=True)

        tx = dm.Radau(num_segments=5, order=3, compressed=True)
        ascent = dm.Phase(transcription=tx, ode_class=CannonballODE)
        traj.add_phase('ascent', ascent)

        ###################################
        # first phase: ascent
        ###################################
        # All initial states except flight path angle are fixed
        ascent.add_state('r', units='m', rate_source='r_dot',
                         fix_initial=True, fix_final=False)
        ascent.add_state('h', units='m', rate_source='h_dot',
                         fix_initial=True, fix_final=False)
        ascent.add_state('v', units='m/s', rate_source='v_dot',
                         fix_initial=False, fix_final=False)
        # Final flight path angle is fixed (
        #     we will set it to zero so that the phase ends at apogee)
        ascent.add_state('gam', units='rad', rate_source='gam_dot',
                         fix_initial=False, fix_final=True)
        ascent.set_time_options(fix_initial=True, duration_bounds=(1, 100),
                                duration_ref=100, units='s')

        ascent.add_parameter('mass', units='kg', val=0.01, static_target=True)
        ascent.add_parameter('area', units='m**2', static_target=True)

        # Limit the initial muzzle energy to create a well posed problem
        # with respect to cannonball size and initial velocity
        ascent.add_boundary_constraint('ke', loc='initial', units='J',
                                       upper=400000, lower=0, ref=100000)

        ###################################
        # second phase: descent
        ###################################
        tx = dm.GaussLobatto(num_segments=5, order=3, compressed=True)
        descent = dm.Phase(transcription=tx, ode_class=CannonballODE)
        traj.add_phase('descent', descent)

        # All initial states and time are free so their
        #    values can be linked to the final ascent values
        # Final altitude is fixed to 0 to ensure final impact on the ground
        descent.add_state('r', units='m', rate_source='r_dot',
                          fix_initial=False, fix_final=False)
        descent.add_state('h', units='m', rate_source='h_dot',
                          fix_initial=False, fix_final=True)
        descent.add_state('gam', units='rad', rate_source='gam_dot',
                          fix_initial=False, fix_final=False)
        descent.add_state('v', units='m/s', rate_source='v_dot',
                          fix_initial=False, fix_final=False)
        descent.set_time_options(initial_bounds=(.5, 100), duration_bounds=(.5, 100),
                                 duration_ref=100, units='s')

        descent.add_parameter('mass', units='kg', val=0.01, static_target=True)
        descent.add_parameter('area', units='m**2', static_target=True)

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

        # maximize range
        descent.add_objective('r', loc='final', ref=-1.0)

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

        # Finish Problem Setup
        p.setup()

        # Set Initial guesses for static dvs and ascent
        p.set_val('static_calcs.radius', 0.05, units='m')
        p.set_val('traj.ascent.t_duration', 10.0)

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

        # more intitial guesses for descent
        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.interp('r', [100, 200]))
        p.set_val('traj.descent.states:h', descent.interp('h', [100, 0]))
        p.set_val('traj.descent.states:v', descent.interp('v', [150, 200]))
        p.set_val('traj.descent.states:gam', descent.interp('gam', [0, -45]), units='deg')

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

        fig, ax = plt.subplots()
        x0 = p.get_val('traj.ascent.timeseries.states:r', units='m')
        y0 = p.get_val('traj.ascent.timeseries.states:h', units='m')
        x1 = p.get_val('traj.descent.timeseries.states:r', units='m')
        y1 = p.get_val('traj.descent.timeseries.states:h', units='m')
        tab20 = plt.cm.get_cmap('tab20').colors
        ax.plot(x0, y0, marker='o', label='ascent', color=tab20[0])
        ax.plot(x1, y1, marker='o', label='descent', color=tab20[1])
        ax.legend(loc='best')
        ax.set_xlabel('range (m)')
        ax.set_ylabel('height (m)')
        fig.savefig('cannonball_hr.png', bbox_inches='tight')
        # End code for paper

        assert_near_equal(x1[-1], 3064, tolerance=1.0E-4)
예제 #10
0
    def test_ex_double_integrator_input_times_compressed(self):
        """
        Tests that externally connected t_initial and t_duration function as expected.
        """
        compressed = True
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.declare_coloring()

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

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

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

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

        p.setup(check=True)

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

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

        p.run_driver()

        assert_near_equal(p.get_val('phase0.timeseries.states:x')[-1, ...],
                          [0.25],
                          tolerance=1.0E-8)
예제 #11
0

        
예제 #12
0
    def _make_problem(self, transcription, num_seg, transcription_order=3):
        p = om.Problem(model=om.Group())

        p.driver = om.ScipyOptimizeDriver()

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

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

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

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

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

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

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

        p.setup(check=True)

        p['phase0.t_initial'] = 1.0
        p['phase0.t_duration'] = 3.0

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

        return p
예제 #13
0

        
예제 #14
0

        
예제 #15
0
    def test_link_bounded_times_final_to_initial(self):
        """ Test that linking phases with times that are fixed at the linkage point raises an exception. """

        import openmdao.api as om

        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(initial_bounds=(0, 0),
                                duration_bounds=(10, 10),
                                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_parameter('S', targets=['aero.S'], units='m**2')
        ascent.add_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=(10, 10),
                                 duration_bounds=(10, 10),
                                 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_parameter('S', targets=['aero.S'], units='m**2')
        descent.add_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_parameter('CD',
                           targets={
                               'ascent': ['aero.CD'],
                               'descent': ['aero.CD']
                           },
                           val=0.5,
                           units=None,
                           opt=False)
        traj.add_parameter('CL',
                           targets={
                               'ascent': ['aero.CL'],
                               'descent': ['aero.CL']
                           },
                           val=0.0,
                           units=None,
                           opt=False)
        traj.add_parameter('T',
                           targets={
                               'ascent': ['eom.T'],
                               'descent': ['eom.T']
                           },
                           val=0.0,
                           units='N',
                           opt=False)
        traj.add_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_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_parameter('S', units='m**2', val=0.005)

        # Link Phases (link time and all state variables)
        # Note velocity is not included here.  Doing so is equivalent to linking kinetic energy,
        # and causes a duplicate row in the constraint jacobian.
        traj.link_phases(phases=['ascent', 'descent'],
                         vars=['time', 'r', 'h', 'gam'],
                         connected=False)

        traj.add_linkage_constraint('ascent',
                                    'descent',
                                    'kinetic_energy.ke',
                                    'kinetic_energy.ke',
                                    ref=100000,
                                    connected=False)

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

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

        with self.assertRaises(ValueError) as e:
            p.setup()

        self.assertEqual(
            str(e.exception),
            'Invalid linkage in Trajectory traj: Cannot link final '
            'value of "time" in ascent to initial value of "time" in '
            'descent.  Values on both sides of the linkage are fixed.')
예제 #16
0
def brachistochrone_min_time(transcription='gauss-lobatto',
                             num_segments=8,
                             transcription_order=3,
                             compressed=True,
                             optimizer='SLSQP',
                             simul_derivs=True):
    p = om.Problem(model=om.Group())

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

    if simul_derivs:
        p.driver.declare_coloring()

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

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

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

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

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

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

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

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

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

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

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

    p.run_driver()

    return p
    def test_two_burn_orbit_raise_radau_wildcard_add_timeseries_output(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('IPOPT', fallback=True)
        p.driver.options['optimizer'] = optimizer

        p.driver.declare_coloring()

        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.Radau(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')

        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,
                        units='rad', rate_source='theta_dot', targets=['theta'])
        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_parameter('u1', targets=['u1'], opt=False, val=0.0, units='deg')

        # Third Phase (burn)
        burn2 = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.Radau(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)

        # demonstrate adding multiple variables at once using wildcard in add_timeseries_output
        burn1.add_timeseries_output('pos_*')  # match partial variable in ODE outputs (Radau)
        coast.add_timeseries_output('pos_*')  # match partial variable in ODE outputs (Runge Kutta)
        burn2.add_timeseries_output('*')      # add all ODE outputs

        # Link Phases
        traj.link_phases(phases=['burn1', 'coast', 'burn2'],
                         vars=['time', 'r', '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.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.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)

        # test ODE output wildcard matching in solve_ivp
        exp_out = traj.simulate()

        for prob in (p, exp_out):
            # check timeseries: pos_x = r * cos(theta) and pos_y = r * sin(theta)
            for phs in ['burn1', 'coast', 'burn2']:
                x = np.array(prob.get_val('traj.{0}.timeseries.pos_x'.format(phs))).flatten()
                y = np.array(prob.get_val('traj.{0}.timeseries.pos_y'.format(phs))).flatten()
                t = np.array(prob.get_val('traj.{0}.timeseries.states:theta'.format(phs))).flatten()
                r = np.array(prob.get_val('traj.{0}.timeseries.states:r'.format(phs))).flatten()

                xerr = x - r * np.cos(t)
                yerr = y - r * np.sin(t)

                assert_near_equal(np.sqrt(np.mean(xerr*xerr)), 0.0)
                assert_near_equal(np.sqrt(np.mean(yerr*yerr)), 0.0)
예제 #18
0

        
예제 #19
0
ORDER = 5
NUM_FRAMES = 20
ORDER = 3

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

# We need an optimization driver.  To solve this simple problem ScipyOptimizerDriver will work.
prob.driver = om.ScipyOptimizeDriver()

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

# Instantiate a Phase and add it to the Trajectory.
phase = dm.Phase(ode_class=OscillatorODE, transcription=dm.Radau(num_segments=NUM_SEG, order=ORDER, compressed=False))
traj.add_phase('phase0', phase)

# Tell Dymos that the duration of the phase is bounded.
phase.set_time_options(fix_initial=True, fix_duration=True)

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

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

# secondary "dense" timeseries
    def test_ssto_simulate_root_trajectory(self):
        """
        Tests that we can properly simulate a trajectory even if the trajectory is the root
        group of the model.  In this case the name of the trajectory in the output will
        be 'sim_traj'.
        """
        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

        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 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', om.ExecComp('theta=arctan(tan_theta)',
                                                           theta={'value': np.ones(nn),
                                                                  'units': 'rad'},
                                                           tan_theta={'value': np.ones(nn)}))

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

                self.connect('guidance.theta', 'eom.theta')

        #
        # Setup and solve the optimal control problem
        #
        traj = dm.Trajectory()

        p = om.Problem(model=traj)

        phase = dm.Phase(ode_class=LaunchVehicleLinearTangentODE,
                         transcription=dm.Radau(num_segments=20, order=3, compressed=False))
        traj.add_phase('phase0', phase)

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

        #
        # Set the state options.  We include rate_source, units, and targets here since the ODE
        # is not decorated with their default values.
        #
        phase.add_state('x', fix_initial=True, lower=0, rate_source='eom.xdot')
        phase.add_state('y', fix_initial=True, lower=0, rate_source='eom.ydot')
        phase.add_state('vx', fix_initial=True, lower=0, rate_source='eom.vxdot',
                        units='m/s', targets=['eom.vx'])
        phase.add_state('vy', fix_initial=True, rate_source='eom.vydot',
                        units='m/s', targets=['eom.vy'])
        phase.add_state('m', fix_initial=True, rate_source='eom.mdot',
                        units='kg', targets=['eom.m'])

        #
        # The tangent of theta is modeled as a linear polynomial over the duration of the phase.
        #
        phase.add_polynomial_control('tan_theta', order=1, units=None, opt=True,
                                     targets=['guidance.tan_theta'])

        #
        # Parameters values for thrust and specific impulse are design parameters. They are
        # provided by an IndepVarComp in the phase, but with opt=False their values are not
        # design variables in the optimization problem.
        #
        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'])

        #
        # Set the boundary constraints.  These are all states which could also be handled
        # by setting fix_final=True and including the correct final value in the initial guess.
        #
        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_objective('time', index=-1, scaler=0.01)

        #
        # Add theta as a timeseries output since it's not included by default.
        #
        phase.add_timeseries_output('guidance.theta', units='deg')

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

        #
        # We don't strictly need to define a linear solver here since our problem is entirely
        # feed-forward with no iterative loops.  It's good practice to add one, however, since
        # failing to do so can cause incorrect derivatives if iterative processes are ever
        # introduced to the system.
        #
        p.model.linear_solver = om.DirectSolver()

        p.setup(check=True)

        #
        # Assign initial guesses for the independent variables in the problem.
        #
        p['phase0.t_initial'] = 0.0
        p['phase0.t_duration'] = 500.0
        p['phase0.states:x'] = phase.interpolate(ys=[0, 350000.0], nodes='state_input')
        p['phase0.states:y'] = phase.interpolate(ys=[0, 185000.0], nodes='state_input')
        p['phase0.states:vx'] = phase.interpolate(ys=[0, 1627.0], nodes='state_input')
        p['phase0.states:vy'] = phase.interpolate(ys=[1.0E-6, 0], nodes='state_input')
        p['phase0.states:m'] = phase.interpolate(ys=[50000, 50000], nodes='state_input')
        p['phase0.polynomial_controls:tan_theta'] = [[0.5 * np.pi], [0.0]]

        #
        # Solve the problem.
        #
        p.run_driver()

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

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

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

        axes[0].plot(p.get_val('phase0.timeseries.states:x'),
                     p.get_val('phase0.timeseries.states:y'),
                     marker='o',
                     ms=4,
                     linestyle='None',
                     label='solution')

        axes[0].plot(exp_out.get_val('sim_traj.phase0.timeseries.states:x'),
                     exp_out.get_val('sim_traj.phase0.timeseries.states:y'),
                     marker=None,
                     linestyle='-',
                     label='simulation')

        axes[0].set_xlabel('range (m)')
        axes[0].set_ylabel('altitude (m)')
        axes[0].set_aspect('equal')

        axes[1].plot(p.get_val('phase0.timeseries.time'),
                     p.get_val('phase0.timeseries.theta'),
                     marker='o',
                     ms=4,
                     linestyle='None')

        axes[1].plot(exp_out.get_val('sim_traj.phase0.timeseries.time'),
                     exp_out.get_val('sim_traj.phase0.timeseries.theta'),
                     linestyle='-',
                     marker=None)

        axes[1].set_xlabel('time (s)')
        axes[1].set_ylabel('theta (deg)')

        plt.suptitle('Single Stage to Orbit Solution Using Polynomial Controls')
        fig.legend(loc='lower center', ncol=2)

        plt.show()
    def test_brachistochrone_undecorated_ode_radau(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.Radau(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',
                        targets=['v'],
                        units='m/s')

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

        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)
예제 #22
0
    def test_two_phase_cannonball_ode_output_linkage(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_ode import CannonballODE

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

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

        p.model.add_subsystem('size_comp',
                              CannonballSizeComp(),
                              promotes_inputs=['radius', 'dens'])
        p.model.set_input_defaults('dens', val=7.87, units='g/cm**3')
        p.model.add_design_var('radius',
                               lower=0.01,
                               upper=0.10,
                               ref0=0.01,
                               ref=0.10,
                               units='m')

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

        transcription = dm.Radau(num_segments=5, order=3, compressed=True)
        ascent = dm.Phase(ode_class=CannonballODE, transcription=transcription)

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

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

        ascent.add_parameter('S', targets=['S'], units='m**2', dynamic=False)
        ascent.add_parameter('mass', targets=['m'], units='kg', dynamic=False)

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

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

        traj.add_phase('descent', descent)

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

        descent.add_parameter('S', targets=['S'], units='m**2', dynamic=False)
        descent.add_parameter('mass', targets=['m'], units='kg', dynamic=False)

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

        # Add internally-managed design parameters to the trajectory.
        traj.add_parameter('CD',
                           targets={
                               'ascent': ['CD'],
                               'descent': ['CD']
                           },
                           val=0.5,
                           units=None,
                           opt=False,
                           dynamic=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_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_parameter('S', units='m**2', val=0.005)

        # Link Phases (link time and all state variables)
        # Note velocity is not included here.  Doing so is equivalent to linking kinetic energy,
        # and causes a duplicate row in the constraint jacobian.
        traj.link_phases(phases=['ascent', 'descent'],
                         vars=['time', 'r', 'h', 'gam'],
                         connected=True)

        traj.add_linkage_constraint('ascent',
                                    'descent',
                                    'ke',
                                    'ke',
                                    ref=100000,
                                    connected=False)

        p.model.connect('size_comp.mass', 'traj.parameters:m')
        p.model.connect('size_comp.S', 'traj.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('radius', 0.05, units='m')
        p.set_val('dens', 7.87, units='g/cm**3')

        p.set_val('traj.parameters:CD', 0.5)

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

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

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

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

        dm.run_problem(p)

        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('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 = ['CD', 'mass', 'S']
        fig, axes = plt.subplots(nrows=3, ncols=1, figsize=(12, 6))
        for i, param in enumerate(params):
            p_imp = {
                'ascent':
                p.get_val(
                    'traj.ascent.timeseries.parameters:{0}'.format(param)),
                'descent':
                p.get_val(
                    'traj.descent.timeseries.parameters:{0}'.format(param))
            }

            p_exp = {
                'ascent':
                exp_out.get_val('traj.ascent.timeseries.'
                                'parameters:{0}'.format(param)),
                'descent':
                exp_out.get_val('traj.descent.timeseries.'
                                '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()
예제 #23
0
    def test_control_rate2_path_constraint_radau(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm
        from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE

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

        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=dm.Radau(num_segments=10,
                                                compressed=False))

        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=True,
            rate_source=BrachistochroneODE.states['x']['rate_source'])
        phase.add_state(
            'y',
            fix_initial=True,
            fix_final=True,
            rate_source=BrachistochroneODE.states['y']['rate_source'])
        phase.add_state(
            'v',
            fix_initial=True,
            rate_source=BrachistochroneODE.states['v']['rate_source'])

        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)

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

        phase.add_path_constraint('theta_rate2',
                                  lower=-200,
                                  upper=200,
                                  units='rad/s**2')

        p.model.linear_solver = om.DirectSolver()
        p.model.options['assembled_jac_type'] = 'csc'

        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)
예제 #24
0
    def test_traj_param_target_none(self):
        # Tests a bug where you couldn't specify None as a target for a specific phase.
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal

        import dymos as dm
        from dymos.examples.cannonball.size_comp import CannonballSizeComp
        from dymos.examples.cannonball.cannonball_ode import CannonballODE

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

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

        p.model.add_subsystem('size_comp',
                              CannonballSizeComp(),
                              promotes_inputs=['radius', 'dens'])
        p.model.set_input_defaults('dens', val=7.87, units='g/cm**3')
        p.model.add_design_var('radius',
                               lower=0.01,
                               upper=0.10,
                               ref0=0.01,
                               ref=0.10,
                               units='m')

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

        transcription = dm.Radau(num_segments=5, order=3, compressed=True)
        ascent = dm.Phase(ode_class=CannonballODE, transcription=transcription)

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

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

        ascent.add_parameter('S', targets=['S'], units='m**2', dynamic=False)
        ascent.add_parameter('mass', targets=['m'], units='kg', dynamic=False)

        # Limit the muzzle energy
        ascent.add_boundary_constraint('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 = dm.Phase(ode_class=CannonballODE,
                           transcription=transcription)

        traj.add_phase('descent', descent)

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

        descent.add_parameter('S', targets=['S'], units='m**2', dynamic=False)
        descent.add_parameter('mass', targets=['m'], units='kg', dynamic=False)

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

        # Add internally-managed design parameters to the trajectory.
        traj.add_parameter('CD',
                           targets={
                               'ascent': ['CD'],
                               'descent': ['CD']
                           },
                           val=0.5,
                           units=None,
                           opt=False,
                           dynamic=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_parameter('m',
                           units='kg',
                           val=1.0,
                           targets={
                               'ascent': 'mass',
                               'descent': 'mass'
                           },
                           dynamic=False)

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

        # Link Phases (link time and all state variables)
        # Note velocity is not included here.  Doing so is equivalent to linking kinetic energy,
        # and causes a duplicate row in the constraint jacobian.
        traj.link_phases(phases=['ascent', 'descent'],
                         vars=['time', 'r', 'h', 'gam'],
                         connected=True)

        traj.add_linkage_constraint('ascent',
                                    'descent',
                                    'ke',
                                    'ke',
                                    ref=100000,
                                    connected=False)

        p.model.connect('size_comp.mass', 'traj.parameters:m')
        p.model.connect('size_comp.S', 'traj.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('radius', 0.05, units='m')
        p.set_val('dens', 7.87, units='g/cm**3')

        p.set_val('traj.parameters:CD', 0.5)

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

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

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

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

        dm.run_problem(p)

        assert_near_equal(p.get_val('traj.descent.states:r')[-1],
                          3183.25,
                          tolerance=1.0E-2)
예제 #25
0
    def test_run_HS_problem_radau(self):
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.declare_coloring()
        p.driver.options['optimizer'] = optimizer

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

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

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

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

        phase0.set_refine_options(refine=True, tol=1e-6)

        p.setup(check=True)

        tf = np.float128(20)

        p.set_val('traj.phase0.states:x', phase0.interp('x', [1.5, 1]))
        p.set_val('traj.phase0.states:xL', phase0.interp('xL', [0, 1]))
        p.set_val('traj.phase0.t_initial', 0)
        p.set_val('traj.phase0.t_duration', tf)
        p.set_val('traj.phase0.controls:u', phase0.interp('u', [-0.6, 2.4]))
        dm.run_problem(p, refine_method='hp', refine_iteration_limit=10)

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

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

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

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

        assert_near_equal(p.get_val('traj.phase0.timeseries.states:xL')[-1],
                          J,
                          tolerance=5e-4)
    def test_basic(self):
        import matplotlib.pyplot as plt

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

        import dymos as dm
        from dymos.examples.battery_multibranch.battery_multibranch_ode import BatteryODE
        from dymos.utils.lgl import lgl

        prob = om.Problem()

        opt = prob.driver = om.ScipyOptimizeDriver()
        opt.declare_coloring()
        opt.options['optimizer'] = 'SLSQP'

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

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

        # First phase: normal operation.
        transcription = dm.Radau(num_segments=num_seg, order=5, segment_ends=seg_ends, compressed=False)
        phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription)
        traj_p0 = traj.add_phase('phase0', phase0)

        traj_p0.set_time_options(fix_initial=True, fix_duration=True)
        traj_p0.add_state('state_of_charge', fix_initial=True, fix_final=False,
                          targets=['SOC'], rate_source='dXdt:SOC')

        # Second phase: normal operation.

        phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription)
        traj_p1 = traj.add_phase('phase1', phase1)

        traj_p1.set_time_options(fix_initial=False, fix_duration=True)
        traj_p1.add_state('state_of_charge', fix_initial=False, fix_final=False,
                          targets=['SOC'], rate_source='dXdt:SOC')
        traj_p1.add_objective('time', loc='final')

        # Second phase, but with battery failure.

        phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2},
                                transcription=transcription)
        traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail)

        traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True)
        traj_p1_bfail.add_state('state_of_charge', fix_initial=False, fix_final=False,
                                targets=['SOC'], rate_source='dXdt:SOC')

        # Second phase, but with motor failure.

        phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2},
                                transcription=transcription)
        traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail)

        traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True)
        traj_p1_mfail.add_state('state_of_charge', fix_initial=False, fix_final=False,
                                targets=['SOC'], rate_source='dXdt:SOC')

        traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'])
        traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'])
        traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'])

        prob.model.options['assembled_jac_type'] = 'csc'
        prob.model.linear_solver = om.DirectSolver(assemble_jac=True)

        prob.setup()

        prob['traj.phase0.t_initial'] = 0
        prob['traj.phase0.t_duration'] = 1.0*3600

        prob['traj.phase1.t_initial'] = 1.0*3600
        prob['traj.phase1.t_duration'] = 1.0*3600

        prob['traj.phase1_bfail.t_initial'] = 1.0*3600
        prob['traj.phase1_bfail.t_duration'] = 1.0*3600

        prob['traj.phase1_mfail.t_initial'] = 1.0*3600
        prob['traj.phase1_mfail.t_duration'] = 1.0*3600

        prob.set_solver_print(level=0)
        prob.run_driver()

        soc0 = prob['traj.phase0.states:state_of_charge']
        soc1 = prob['traj.phase1.states:state_of_charge']
        soc1b = prob['traj.phase1_bfail.states:state_of_charge']
        soc1m = prob['traj.phase1_mfail.states:state_of_charge']

        # Final value for State of Chrage in each segment should be a good test.
        print('State of Charge after 1 hour')
        assert_rel_error(self, soc0[-1], 0.63464982, 1e-6)
        print('State of Charge after 2 hours')
        assert_rel_error(self, soc1[-1], 0.23794217, 1e-6)
        print('State of Charge after 2 hours, battery fails at 1 hour')
        assert_rel_error(self, soc1b[-1], 0.0281523, 1e-6)
        print('State of Charge after 2 hours, motor fails at 1 hour')
        assert_rel_error(self, soc1m[-1], 0.18625395, 1e-6)

        # Plot Results
        t0 = prob['traj.phases.phase0.time.time']/3600
        t1 = prob['traj.phases.phase1.time.time']/3600
        t1b = prob['traj.phases.phase1_bfail.time.time']/3600
        t1m = prob['traj.phases.phase1_mfail.time.time']/3600

        plt.subplot(2, 1, 1)
        plt.plot(t0, soc0, 'b')
        plt.plot(t1, soc1, 'b')
        plt.plot(t1b, soc1b, 'r')
        plt.plot(t1m, soc1m, 'c')
        plt.xlabel('Time (hour)')
        plt.ylabel('State of Charge (percent)')

        I_Li0 = prob['traj.phases.phase0.rhs_all.pwr_balance.I_Li']
        I_Li1 = prob['traj.phases.phase1.rhs_all.pwr_balance.I_Li']
        I_Li1b = prob['traj.phases.phase1_bfail.rhs_all.pwr_balance.I_Li']
        I_Li1m = prob['traj.phases.phase1_mfail.rhs_all.pwr_balance.I_Li']

        plt.subplot(2, 1, 2)
        plt.plot(t0, I_Li0, 'b')
        plt.plot(t1, I_Li1, 'b')
        plt.plot(t1b, I_Li1b, 'r')
        plt.plot(t1m, I_Li1m, 'c')
        plt.xlabel('Time (hour)')
        plt.ylabel('Line Current (A)')

        plt.legend(['Phase 1', 'Phase 2', 'Phase 2 Battery Fail', 'Phase 2 Motor Fail'], loc=2)

        plt.show()
예제 #27
0
def min_time_climb(optimizer='SLSQP',
                   num_seg=3,
                   transcription='gauss-lobatto',
                   transcription_order=3,
                   force_alloc_complex=False):

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

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

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

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

    traj = dm.Trajectory()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    phase.set_refine_options(max_order=5)

    p.model.linear_solver = om.DirectSolver()

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

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

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

    dm.run_problem(p, refine_iteration_limit=1)

    return p
예제 #28
0
        jacobian['xdot', 'theta'] = v * cos_theta

        jacobian['ydot', 'v'] = -cos_theta
        jacobian['ydot', 'theta'] = v * sin_theta


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

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

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

# Set the time options
phase.set_time_options(fix_initial=True,
                       duration_bounds=(0.5, 10.0))

# Set the state options
phase.add_state('x', rate_source='xdot',
                fix_initial=True, fix_final=True)
phase.add_state('y', rate_source='ydot',
                fix_initial=True, fix_final=True)
phase.add_state('v', rate_source='vdot',
                fix_initial=True, fix_final=False)

# Define theta as a control.
예제 #29
0
    def test_ivp_driver_10_segs(self):
        import openmdao.api as om
        import dymos as dm
        import matplotlib.pyplot as plt
        plt.switch_backend('Agg')  # disable plotting to the screen

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

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

        # We need an optimization driver.  To solve this simple problem ScipyOptimizerDriver will work.
        prob.driver = om.ScipyOptimizeDriver()

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

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

        # Tell Dymos that the duration of the phase is bounded.
        phase.set_time_options(fix_initial=True, fix_duration=True)

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

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

        # Since we're using an optimization driver, an objective is required.  We'll minimize
        # the final time in this case.
        phase.add_objective('time', loc='final')

        # Setup the OpenMDAO problem
        prob.setup()

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

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

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

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

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

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

        states = ['x', 'v']
        fig, axes = plt.subplots(len(states), 1)
        for i, state in enumerate(states):
            sol = axes[i].plot(
                t_sol, prob.get_val(f'traj.phase0.timeseries.states:{state}'),
                'o')
            sim = axes[i].plot(
                t_sim,
                sim_out.get_val(f'traj.phase0.timeseries.states:{state}'), '-')
            axes[i].set_ylabel(state)
        axes[-1].set_xlabel('time (s)')
        fig.legend((sol[0], sim[0]), ('solution', 'simulation'),
                   'lower right',
                   ncol=2)
        plt.tight_layout()
        plt.show()
예제 #30
0
def make_traj(transcription='gauss-lobatto', transcription_order=3, compressed=False,
              connected=False):

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

    traj = dm.Trajectory()

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

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

    coast.add_design_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')

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

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

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

    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