Beispiel #1
0
    def test_simple_integration_forward_connected_initial(self):

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

        traj = p.model.add_subsystem('traj', subsys=dm.Trajectory())
        phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4'))
        traj.add_phase('phase0', phase)

        phase.set_time_options(fix_initial=True, fix_duration=True, targets=['t'])
        phase.add_state('y', fix_initial=False, connected_initial=True, targets=['y'], rate_source='ydot', units='m')

        phase.add_timeseries_output('ydot', output_name='state_rate:y', units='m/s')

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

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

        # The initial guess of states at the segment boundaries
        p['traj.phase0.states:y'] = 0.0

        # The initial value of the states from which the integration proceeds
        p['traj.phase0.initial_states:y'] = 0.5

        p.run_model()

        expected = _test_ode_solution(p['traj.phase0.ode.y'], p['traj.phase0.ode.t'])
        assert_near_equal(p['traj.phase0.ode.y'], expected, tolerance=1.0E-3)
    def test_simple_integration_backward_connected_initial(self):

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

        phase = dm.Phase(ode_class=TestODE,
                         transcription=dm.RungeKutta(num_segments=200,
                                                     method='RK4'))
        p.model.add_subsystem('phase0', subsys=phase)

        phase.set_time_options(fix_initial=True, fix_duration=True)
        phase.add_state('y', connected_initial=True)

        phase.add_timeseries_output('ydot',
                                    output_name='state_rate:y',
                                    units='m/s')

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

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

        # The initial guess of state values at the segment boundaries
        p['phase0.states:y'] = 0

        # The initial value of the states from which the integration proceeds
        p['phase0.initial_states:y'] = 5.305471950534675

        p.run_model()

        expected = np.atleast_2d(
            _test_ode_solution(p['phase0.ode.y'], p['phase0.timeseries.time']))
        assert_rel_error(self,
                         p['phase0.timeseries.states:y'],
                         expected,
                         tolerance=1.0E-3)
Beispiel #3
0
    def test_simple_integration_forward_connected_initial_fixed_initial(self):

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

        phase = dm.Phase(ode_class=TestODE,
                         transcription=dm.RungeKutta(num_segments=200,
                                                     method='RK4'))
        p.model.add_subsystem('phase0', subsys=phase)

        phase.set_time_options(fix_initial=True,
                               fix_duration=True,
                               targets=['t'])
        phase.add_state('y',
                        fix_initial=True,
                        connected_initial=True,
                        targets=['y'],
                        rate_source='ydot',
                        units='m')

        phase.add_timeseries_output('ydot',
                                    output_name='state_rate:y',
                                    units='m/s')

        with self.assertRaises(ValueError) as e:
            p.setup(check=True, force_alloc_complex=True)
        expected = "Cannot specify 'fix_initial=True' and specify 'connected_initial=True' for " \
                   "state y in phase phase0."
        self.assertEqual(str(e.exception), expected)
Beispiel #4
0
    def test_load_case_rk4_to_lgl(self):
        import openmdao.api as om
        import dymos as dm
        from openmdao.utils.assert_utils import assert_near_equal

        p = setup_problem(dm.RungeKutta(num_segments=50))

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

        # Load the solution
        case = om.CaseReader('dymos_solution.db').get_case('final')

        # create a problem with a different transcription with a different number of variables
        q = setup_problem(dm.GaussLobatto(num_segments=10))

        # Load the values from the previous solution
        dm.load_case(q, case)

        # Run the model to ensure we find the same output values as those that we recorded
        q.run_driver()

        outputs = dict([
            (o[0], o[1])
            for o in case.list_outputs(units=True, shape=True, out_stream=None)
        ])

        time_val = outputs['phase0.timeseries.time']['value']
        theta_val = outputs['phase0.timeseries.controls:theta']['value']

        assert_near_equal(q['phase0.timeseries.controls:theta'],
                          q.model.phase0.interpolate(xs=time_val,
                                                     ys=theta_val,
                                                     nodes='all'),
                          tolerance=1.0E-1)
    def test_single_phase_reverse_propagation_rk(self):
        prob = om.Problem()

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

        # First phase: normal operation.
        transcription = dm.RungeKutta(num_segments=num_seg)
        phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription)
        traj_p0 = prob.model.add_subsystem('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')

        prob.setup()

        prob['phase0.t_initial'] = 0
        prob['phase0.t_duration'] = -1.0 * 3600
        prob['phase0.states:state_of_charge'][:] = 0.63464982

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

        soc0 = prob['phase0.states:state_of_charge']
        assert_near_equal(soc0[-1], 1.0, 1e-6)
Beispiel #6
0
    def test_simple_integration_forward(self):

        p = om.Problem(model=om.Group())
        phase = dm.Phase(ode_class=TestODE,
                         transcription=dm.RungeKutta(num_segments=200,
                                                     method='RK4'))
        p.model.add_subsystem('phase0', subsys=phase)

        phase.set_time_options(fix_initial=True,
                               fix_duration=True,
                               targets=['t'])
        phase.add_state('y',
                        fix_initial=True,
                        targets=['y'],
                        rate_source='ydot',
                        units='m')

        phase.add_timeseries_output('ydot',
                                    output_name='state_rate:y',
                                    units='m/s')

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

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

        p['phase0.states:y'] = 0.5

        p.run_model()

        expected = _test_ode_solution(p['phase0.ode.y'], p['phase0.ode.t'])
        assert_near_equal(p['phase0.ode.y'], expected, tolerance=1.0E-3)
Beispiel #7
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),
            'runge-kutta':
            dm.RungeKutta(num_segments=num_seg)
        }

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

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

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

        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',
                          units='deg',
                          rate_continuity=True,
                          lower=0.01,
                          upper=179.9)

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

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

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

        p.model.linear_solver = om.DirectSolver()

        p.setup()

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

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

        return p
Beispiel #8
0
    def test_double_integrator_rk4(self, compressed=True):

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

        t = dm.RungeKutta(num_segments=30, order=3, compressed=compressed)

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

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

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

        phase.add_state('v',
                        fix_initial=True,
                        fix_final=False,
                        rate_source='u',
                        shape=(1, ),
                        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)

        phase.add_boundary_constraint(name='v',
                                      loc='final',
                                      equals=0,
                                      units='m/s')

        # 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['traj.phase0.t_initial'] = 0.0
        p['traj.phase0.t_duration'] = 1.0

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

        p.run_driver()

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

    # if optimizer == 'SNOPT':
    p.driver = pyOptSparseDriver()
    p.driver.options['optimizer'] = optimizer
    p.driver.options['dynamic_simul_derivs'] = simul_derivs

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

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

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

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

    phase.set_state_options('x', fix_initial=True, fix_final=False, solve_segments=False)
    phase.set_state_options('y', fix_initial=True, fix_final=False, solve_segments=False)
    phase.set_state_options('v', fix_initial=True, fix_final=False, solve_segments=False)

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

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

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

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

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

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

    p.run_driver()

    return p
Beispiel #10
0
    def test_load_case_lgl_to_rk4(self):
        import openmdao.api as om
        import dymos as dm
        from openmdao.utils.assert_utils import assert_rel_error
        from scipy.interpolate import interp1d
        import numpy as np

        p = setup_problem(dm.GaussLobatto(num_segments=20))

        # Solve for the optimal trajectory
        p.run_driver()

        # Load the solution
        cr = om.CaseReader('brachistochrone_solution.db')
        system_cases = cr.list_cases('root')
        case = cr.get_case(system_cases[-1])

        # create a problem with a different transcription with a different number of variables
        q = setup_problem(dm.RungeKutta(num_segments=50))

        # Load the values from the previous solution
        dm.load_case(q, case)

        # Run the model to ensure we find the same output values as those that we recorded
        q.run_driver()

        outputs = dict([
            (o[0], o[1])
            for o in case.list_outputs(units=True, shape=True, out_stream=None)
        ])

        time_val = outputs['phase0.timeseries.time']['value'][:, 0]
        theta_val = outputs['phase0.timeseries.controls:theta']['value'][:, 0]
        nodup = np.insert(time_val[1:] != time_val[:-1], 0,
                          True)  # remove duplicate times
        time_val = time_val[nodup]
        theta_val = theta_val[nodup]

        q_time = q['phase0.timeseries.time'][:, 0]
        q_theta = q['phase0.timeseries.controls:theta'][:, 0]
        nodup = np.insert(q_time[1:] != q_time[:-1], 0,
                          True)  # remove duplicate times
        q_time = q_time[nodup]
        q_theta = q_theta[nodup]
        fq_theta = interp1d(q_time,
                            q_theta,
                            kind='cubic',
                            bounds_error=False,
                            fill_value='extrapolate')

        assert_rel_error(self, fq_theta(time_val), theta_val, tolerance=1.0E-2)
    def test_brachistochrone_undecorated_ode_rk(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.RungeKutta(num_segments=20))

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

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

        phase.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=False, lower=0.01, upper=179.9, targets=['theta'])

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

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

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

        p.model.linear_solver = 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)
Beispiel #12
0
def make_brachistochrone_phase(transcription='gauss-lobatto', num_segments=8, transcription_order=3,
                               compressed=True):

    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)

    return phase
Beispiel #13
0
    def test_ex_brachistochrone_vs_rungekutta_compressed(self):
        import openmdao.api as om
        import dymos as dm
        from dymos.examples.brachistochrone.brachistochrone_vector_states_ode import \
            BrachistochroneVectorStatesODE

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

        p.driver = om.ScipyOptimizeDriver()

        p.driver.declare_coloring()

        phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE,
                         transcription=dm.RungeKutta(num_segments=20,
                                                     compressed=True))

        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=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', lower=[10, 5])

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

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

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

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

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

        p.run_driver()

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

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

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

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

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

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

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

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

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

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

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

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

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

    p.final_setup()
    return p
Beispiel #15
0
    def test_brachistochrone_vector_state_path_constraints_rk_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.RungeKutta(num_segments=50))

        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=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=True,
            lower=0.01,
            upper=179.9)

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

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

        phase.add_timeseries_output('pos_dot', shape=(2, ), units='m/s')

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

        p.model.linear_solver = 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.parameters:g'] = 9.80665

        p.run_driver()

        assert_near_equal(np.min(
            p.get_val('phase0.timeseries.states:pos')[:, 1]),
                          5.0,
                          tolerance=1.0E-3)

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

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

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

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

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

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

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

            t_imp = p.get_val('phase0.timeseries.time')
            t_exp = exp_out.get_val('phase0.timeseries.time')

            xdot_imp = p.get_val('phase0.timeseries.pos_dot')[:, 0]
            ydot_imp = p.get_val('phase0.timeseries.pos_dot')[:, 1]

            xdot_exp = exp_out.get_val('phase0.timeseries.pos_dot')[:, 0]
            ydot_exp = exp_out.get_val('phase0.timeseries.pos_dot')[:, 1]

            ax.plot(t_imp, xdot_imp, 'bo', label='implicit')
            ax.plot(t_exp, xdot_exp, 'b-', label='explicit')

            ax.plot(t_imp, ydot_imp, 'ro', label='implicit')
            ax.plot(t_exp, ydot_exp, 'r-', label='explicit')

            ax.set_xlabel('t (s)')
            ax.set_ylabel('v (m/s)')
            ax.grid(True)
            ax.legend(loc='upper right')

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

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

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

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

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

            plt.show()

        return p
Beispiel #16
0
    def _run_transcription(self, transcription):
        p = om.Problem(model=om.Group())

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

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

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

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

        elif transcription == 'runge-kutta':
            tx0 = dm.RungeKutta(num_segments=20, compressed=compressed)
            tx1 = dm.RungeKutta(num_segments=20 * 4, compressed=compressed)

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

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

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

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

        phase0.add_input_parameter(
            'g',
            targets=BrachistochroneODE.parameters['g']['targets'],
            units=BrachistochroneODE.parameters['g']['units'],
            val=9.80665)

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

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

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

        #
        # Second Phase: Integration of ArcLength
        #

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

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

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

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

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

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

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

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

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

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

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

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

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

        p.run_driver()

        expected = np.sqrt((10 - 0)**2 + (10 - 5)**2)
        assert_rel_error(self,
                         p['phase1.timeseries.states:S'][-1],
                         expected,
                         tolerance=1.0E-3)
Beispiel #17
0
    def test_brachistochrone_for_docs_runge_kutta_polynomial_controls(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.ScipyOptimizeDriver()
        p.driver.declare_coloring()

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

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

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

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

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

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

        phase.add_polynomial_control(
            'theta',
            order=1,
            targets=BrachistochroneODE.parameters['theta']['targets'],
            units='deg',
            lower=0.01,
            upper=179.9)

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

        #
        # Final state values are not optimization variables, so we must enforce final values
        # with boundary constraints, not simple bounds.
        #
        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['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.polynomial_controls:theta'][:] = 5.0

        #
        # 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.polynomial_controls:theta', 'time (s)',
              'theta (deg)')],
            title=
            'Brachistochrone Solution\nRK4 Shooting and Polynomial Controls',
            p_sol=p,
            p_sim=exp_out)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    dm.run_problem(p, run_driver=run_driver)

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

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

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

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

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

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

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

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

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

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

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

        plt.show()

    return p
def 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_parameter('c',
                       opt=False,
                       val=1.5,
                       units='DU/TU',
                       targets={
                           'burn1': ['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_parameter('u1', opt=False, val=0.0, units='deg', targets=['u1'])
    coast.add_parameter('c', val=0.0, units='DU/TU', targets=['c'])

    # 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,
                          lower=-180,
                          upper=180,
                          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
    def test_promotes_parameter(self):
        transcription = 'radau-ps'
        optimizer = 'SNOPT'
        num_segments = 10
        transcription_order = 3
        compressed = False

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

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

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

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

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

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

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

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

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

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

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

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

        p['traj.t_initial'] = 0.0
        p['traj.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], nodes='control_input')
        p['traj.parameters:g'] = 9.80665

        p.run_driver()

        assert_near_equal(p['traj.t_duration'], 1.8016, tolerance=1.0E-4)
Beispiel #21
0
    def test_static_ode_output_runge_kutta(self):

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

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

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

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

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

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

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

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

        phase.add_timeseries_output('*')

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

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

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

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

        # Setup the problem
        with warnings.catch_warnings(record=True) as ctx:
            warnings.simplefilter('always')
            p.setup(check=True)
            expected_warning = "Cannot add ODE output foo to the timeseries output. It is sized " \
                               "such that its first dimension != num_nodes."
            self.assertIn(expected_warning, [str(w.message) for w in ctx])

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

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

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

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

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

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

        # Run the driver to solve the problem
        with warnings.catch_warnings(record=True) as ctx:
            warnings.simplefilter('always')
            dm.run_problem(p, simulate=True, make_plots=False)
            expected_warning = "Cannot add ODE output foo to the timeseries output. It is sized " \
                               "such that its first dimension != num_nodes."
            self.assertIn(expected_warning, [str(w.message) for w in ctx])

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

        with self.assertRaises(expected_exception=KeyError) as e:
            sol.get_val('traj.phase0.timeseries.foo')
        self.assertEqual(str(e.exception), "'Variable name \"traj.phase0.timeseries.foo\" not found.'")

        with self.assertRaises(expected_exception=KeyError) as e:
            sim.get_val('traj.phase0.timeseries.foo')
        self.assertEqual(str(e.exception), "'Variable name \"traj.phase0.timeseries.foo\" not found.'")
def brachistochrone_min_time(transcription='gauss-lobatto',
                             num_segments=8,
                             transcription_order=3,
                             compressed=True,
                             optimizer='SLSQP',
                             dynamic_simul_derivs=True,
                             force_alloc_complex=False,
                             solve_segments=False,
                             run_driver=True):
    p = om.Problem(model=om.Group())

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

    if dynamic_simul_derivs:
        p.driver.declare_coloring()

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

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

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

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

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

    phase.add_state(
        'pos',
        rate_source=BrachistochroneVectorStatesODE.states['pos']
        ['rate_source'],
        units=BrachistochroneVectorStatesODE.states['pos']['units'],
        shape=BrachistochroneVectorStatesODE.states['pos']['shape'],
        fix_initial=True,
        fix_final=fix_final,
        solve_segments=solve_segments)
    #
    phase.add_state(
        'v',
        rate_source=BrachistochroneVectorStatesODE.states['v']['rate_source'],
        targets=BrachistochroneVectorStatesODE.states['v']['targets'],
        units=BrachistochroneVectorStatesODE.states['v']['units'],
        fix_initial=True,
        fix_final=False,
        solve_segments=solve_segments)
    #
    phase.add_control(
        'theta',
        targets=BrachistochroneVectorStatesODE.parameters['theta']['targets'],
        continuity=True,
        rate_continuity=True,
        units='deg',
        lower=0.01,
        upper=179.9)

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

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

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

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

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

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

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

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

    return p
    def test_brachistochrone_forward_shooting(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()
        p.driver.declare_coloring()

        with warnings.catch_warnings(record=True) as w:
            # Cause all warnings to always be triggered.
            warnings.simplefilter("always")
            # Trigger a warning.
            phase = dm.Phase(ode_class=BrachistochroneODE,
                             transcription=dm.RungeKutta(num_segments=20))
            assert issubclass(w[-1].category, DeprecationWarning)
            expected_msg = 'The RungeKutta transcription is deprecated and ' \
                           'will be removed in Dymos v1.0.0.\nFor equivalent behavior, users ' \
                           'should switch to GaussLobatto(order=3, solve_segments=True)'

            self.assertEqual(str(w[-1].message), expected_msg)

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

        phase.set_time_options(initial_bounds=(0, 0),
                               duration_bounds=(0.5, 2.0))

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

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

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

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

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

        # Final state values can't be controlled with simple bounds in ExplicitPhase,
        # so use nonlinear boundary constraints instead.
        phase.add_boundary_constraint('x', loc='final', equals=10)
        phase.add_boundary_constraint('y', loc='final', equals=5)

        # 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'] = 0
        p['phase0.states:y'] = 10
        p['phase0.states:v'] = 0
        p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5],
                                                       nodes='control_input')

        # Solve for the optimal trajectory
        p.run_driver()

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

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

        assert_near_equal(exp_out.get_val('phase0.timeseries.states:x')[-1, 0],
                          10,
                          tolerance=1.0E-3)
        assert_near_equal(exp_out.get_val('phase0.timeseries.states:y')[-1, 0],
                          5,
                          tolerance=1.0E-3)
    def test_connected_linkages_rk(self):
        prob = om.Problem()

        if optimizer == 'SNOPT':
            opt = prob.driver = om.pyOptSparseDriver()
            opt.options['optimizer'] = optimizer
            opt.declare_coloring()

            opt.opt_settings['Major iterations limit'] = 1000
            opt.opt_settings['Major feasibility tolerance'] = 1.0E-6
            opt.opt_settings['Major optimality tolerance'] = 1.0E-6
            opt.opt_settings["Linesearch tolerance"] = 0.10
            opt.opt_settings['iSumm'] = 6

        else:
            opt = prob.driver = om.ScipyOptimizeDriver()
            opt.declare_coloring()

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

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

        # First phase: normal operation.

        transcription = dm.RungeKutta(num_segments=num_seg)
        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'],
                         connected=True)
        traj.link_phases(phases=['phase0', 'phase1_bfail'],
                         vars=['state_of_charge', 'time'],
                         connected=True)
        traj.link_phases(phases=['phase0', 'phase1_mfail'],
                         vars=['state_of_charge', 'time'],
                         connected=True)

        prob.model.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)
        dm.run_problem(prob)

        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.
        assert_near_equal(soc0[-1], 0.63464982, 5e-5)
        assert_near_equal(soc1[-1], 0.23794217, 5e-5)
        assert_near_equal(soc1b[-1], 0.0281523, 5e-5)
        assert_near_equal(soc1m[-1], 0.18625395, 5e-5)
    def test_brachistochrone_forward_shooting_path_constrained_time(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.RungeKutta(num_segments=20))

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

        phase.set_time_options(initial_bounds=(0, 0),
                               duration_bounds=(0.5, 2.0))

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

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

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

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

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

        # Final state values can't be controlled with simple bounds in ExplicitPhase,
        # so use nonlinear boundary constraints instead.
        phase.add_boundary_constraint('x', loc='final', equals=10)
        phase.add_boundary_constraint('y', loc='final', equals=5)

        phase.add_path_constraint('time', lower=0.0, upper=2.0)
        phase.add_path_constraint('time_phase', lower=0.0, upper=2.0)

        # 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'] = 0
        p['phase0.states:y'] = 10
        p['phase0.states:v'] = 0
        p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5],
                                                       nodes='control_input')

        # Solve for the optimal trajectory
        p.run_driver()

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

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

        assert_near_equal(exp_out.get_val('phase0.timeseries.states:x')[-1, 0],
                          10,
                          tolerance=1.0E-3)
        assert_near_equal(exp_out.get_val('phase0.timeseries.states:y')[-1, 0],
                          5,
                          tolerance=1.0E-3)
Beispiel #26
0
    def test_two_burn_orbit_raise_gl_rk_gl_constrained(self):
        import numpy as np

        import matplotlib.pyplot as plt

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

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

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

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

        p.driver.declare_coloring()

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

        # First Phase (burn)

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

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

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

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

        traj.add_phase('coast', coast)

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

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

        # Third Phase (burn)

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

        traj.add_phase('burn2', burn2)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        p.run_driver()

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

        # Plot results
        exp_out = traj.simulate()

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

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

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

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

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

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

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

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

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

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

        plt.show()
Beispiel #27
0
    def test_static_params(self):
        prob = om.Problem(model=om.Group())

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

        # First phase: normal operation.
        # NOTE: using RK4 integration here

        P_DEMAND = 2.0

        phase0 = dm.Phase(ode_class=BatteryODE,
                          transcription=dm.RungeKutta(num_segments=200))
        phase0.set_time_options(fix_initial=True, fix_duration=True)
        phase0.add_state('state_of_charge',
                         fix_initial=True,
                         fix_final=False,
                         targets=['SOC'],
                         rate_source='dXdt:SOC')
        phase0.add_timeseries_output('battery.V_oc', output_name='V_oc')
        phase0.add_timeseries_output('battery.V_pack', output_name='V_pack')
        phase0.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li')
        traj.add_phase('phase0', phase0)

        # Second phase: normal operation.

        transcription = dm.Radau(num_segments=5, order=5, compressed=True)
        phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription)
        phase1.set_time_options(fix_initial=False, fix_duration=True)
        phase1.add_state('state_of_charge',
                         fix_initial=False,
                         fix_final=False,
                         solve_segments='forward',
                         targets=['SOC'],
                         rate_source='dXdt:SOC')
        phase1.add_timeseries_output('battery.V_oc', output_name='V_oc')
        phase1.add_timeseries_output('battery.V_pack', output_name='V_pack')
        phase1.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li')
        traj.add_phase('phase1', phase1)

        # Second phase, but with battery failure.

        phase1_bfail = dm.Phase(ode_class=BatteryODE,
                                ode_init_kwargs={'num_battery': 2},
                                transcription=transcription)
        phase1_bfail.set_time_options(fix_initial=False, fix_duration=True)
        phase1_bfail.add_state('state_of_charge',
                               fix_initial=False,
                               fix_final=False,
                               solve_segments='forward',
                               targets=['SOC'],
                               rate_source='dXdt:SOC')
        phase1_bfail.add_timeseries_output('battery.V_oc', output_name='V_oc')
        phase1_bfail.add_timeseries_output('battery.V_pack',
                                           output_name='V_pack')
        phase1_bfail.add_timeseries_output('pwr_balance.I_Li',
                                           output_name='I_Li')
        traj.add_phase('phase1_bfail', phase1_bfail)

        # Second phase, but with motor failure.

        phase1_mfail = dm.Phase(ode_class=BatteryODE,
                                ode_init_kwargs={'num_motor': 2},
                                transcription=transcription)
        phase1_mfail.set_time_options(fix_initial=False, fix_duration=True)
        phase1_mfail.add_state('state_of_charge',
                               fix_initial=False,
                               fix_final=False,
                               solve_segments='forward',
                               targets=['SOC'],
                               rate_source='dXdt:SOC')
        phase1_mfail.add_timeseries_output('battery.V_oc', output_name='V_oc')
        phase1_mfail.add_timeseries_output('battery.V_pack',
                                           output_name='V_pack')
        phase1_mfail.add_timeseries_output('pwr_balance.I_Li',
                                           output_name='I_Li')
        traj.add_phase('phase1_mfail', phase1_mfail)

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

        # prob.model.linear_solver = om.DirectSolver(assemble_jac=True)

        prob.setup()
        prob.final_setup()

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

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

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

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

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

        plot = True
        if plot:
            import matplotlib
            matplotlib.use('Agg')
            import matplotlib.pyplot as plt

            t0 = prob['traj.phase0.timeseries.time']
            t1 = prob['traj.phase1.timeseries.time']
            t1b = prob['traj.phase1_bfail.timeseries.time']
            t1m = prob['traj.phase1_mfail.timeseries.time']
            soc0 = prob['traj.phase0.timeseries.states:state_of_charge']
            soc1 = prob['traj.phase1.timeseries.states:state_of_charge']
            soc1b = prob['traj.phase1_bfail.timeseries.states:state_of_charge']
            soc1m = prob['traj.phase1_mfail.timeseries.states:state_of_charge']

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

            V_oc0 = prob['traj.phase0.timeseries.V_oc']
            V_oc1 = prob['traj.phase1.timeseries.V_oc']
            V_oc1b = prob['traj.phase1_bfail.timeseries.V_oc']
            V_oc1m = prob['traj.phase1_mfail.timeseries.V_oc']

            plt.subplot(2, 2, 2)
            plt.plot(t0, V_oc0, 'b')
            plt.plot(t1, V_oc1, 'b')
            plt.plot(t1b, V_oc1b, 'r')
            plt.plot(t1m, V_oc1m, 'c')
            plt.xlabel('Time (hour)')
            plt.ylabel('Open Circuit Voltage (V)')

            V_pack0 = prob['traj.phase0.timeseries.V_pack']
            V_pack1 = prob['traj.phase1.timeseries.V_pack']
            V_pack1b = prob['traj.phase1_bfail.timeseries.V_pack']
            V_pack1m = prob['traj.phase1_mfail.timeseries.V_pack']

            plt.subplot(2, 2, 3)
            plt.plot(t0, V_pack0, 'b')
            plt.plot(t1, V_pack1, 'b')
            plt.plot(t1b, V_pack1b, 'r')
            plt.plot(t1m, V_pack1m, 'c')
            plt.xlabel('Time (hour)')
            plt.ylabel('Terminal Voltage (V)')

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

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

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

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

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

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

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

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

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

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

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

        p.setup(force_alloc_complex=True)

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

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

        return p
Beispiel #29
0
def vanderpol(transcription='gauss-lobatto', num_segments=8, transcription_order=3,
              compressed=True, optimizer='SLSQP', use_pyoptsparse=False, delay=None):
    """Dymos problem definition for optimal control of a Van der Pol oscillator"""

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

    if not use_pyoptsparse:
        p.driver = om.ScipyOptimizeDriver()
    else:
        p.driver = om.pyOptSparseDriver()
    p.driver.options['optimizer'] = optimizer
    if use_pyoptsparse and optimizer == 'SNOPT':
        p.driver.opt_settings['iSumm'] = 6  # show detailed SNOPT output
    p.driver.declare_coloring()

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

    # define a Transcription
    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)

    # define a Phase as specified above and add to Phase
    if not delay:
        phase = dm.Phase(ode_class=vanderpol_ode, transcription=t)
    else:
        phase = dm.Phase(ode_class=vanderpol_ode_group, transcription=t)  # distributed component group
    traj.add_phase(name='phase0', phase=phase)

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

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

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

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

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

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

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

    # TODO - Dymos API will soon provide a way to specify this.
    # the linear solver used to compute derivatives is not working on MPI, so switch to LinearRunOnce
    for phase in traj._phases.values():
        phase.linear_solver = om.LinearRunOnce()

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

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

    p.final_setup()

    # debugging helpers:
    # om.n2(p)       # show n2 diagram
    #
    # with np.printoptions(linewidth=1024):  # display partials for manual checking
    #     p.check_partials(compact_print=True)

    return p
Beispiel #30
0
def min_time_climb(optimizer='SLSQP',
                   num_seg=3,
                   transcription='gauss-lobatto',
                   transcription_order=3):

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

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

    p.driver.add_recorder(
        om.SqliteRecorder(f'min_time_climb_solution_{transcription}.sql'))
    p.driver.recording_options['includes'] = ['*']
    p.driver.recording_options['record_objectives'] = True
    p.driver.recording_options['record_constraints'] = True
    p.driver.recording_options['record_desvars'] = True

    if optimizer == 'SNOPT':
        p.driver.opt_settings['Major iterations limit'] = 1000
        p.driver.opt_settings['iSumm'] = 6
        p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6
        p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6
        p.driver.opt_settings['Function precision'] = 1.0E-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),
        'runge-kutta':
        dm.RungeKutta(num_segments=num_seg)
    }

    traj = dm.Trajectory()

    phase = dm.Phase(ode_class=MinTimeClimbODE, 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_design_parameter('S',
                               val=49.2386,
                               units='m**2',
                               opt=False,
                               targets=['S'])
    phase.add_design_parameter('Isp',
                               val=1600.0,
                               units='s',
                               opt=False,
                               targets=['Isp'])
    phase.add_design_parameter('throttle',
                               val=1.0,
                               opt=False,
                               targets=['throttle'])

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

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

    phase.add_timeseries('timeseries2',
                         transcription=dm.GaussLobatto(num_segments=50,
                                                       order=3))

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

    p.model.linear_solver = om.DirectSolver()

    p.setup()

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

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

    p.run_driver()

    traj.simulate(record_file=f'min_time_climb_simulation_{transcription}.sql')

    return p