Example #1
0
def gauss_lobatto_subsets_and_nodes(n, seg_idx, compressed=False):
    """
    Returns the subset dictionary corresponding to the Gauss-Lobatto transcription.

    Parameters
    ----------
    n : int
        The total number of nodes in the Gauss-Lobatto segment.  Must be
        an odd number.
    seg_idx : int
        The index of this segment within its phase.
    compressed : bool
        True if the subset requested is for a phase with compressed transcription.

    Returns
    -------
    dict
        A dictionary with the following keys:
        'disc' gives the indices of the state discretization nodes (deprecated)
        'state_disc' gives the indices of the state discretization nodes
        'state_input' gives the indices of the state input nodes
        'control_disc' gives the indices of the control discretization nodes
        'control_input' gives the indices of the control input nodes
        'segment_ends' gives the indices of the nodes at the start (even) and end (odd) of a segment
        'col' gives the indices of the collocation nodes
        'all' gives all node indices.

    Notes
    -----
    Subset 'state_input' is the same as subset 'state_disc' if `compressed == False` or
    `first_seg == True`.  The same is true of subsets 'control_input' and 'control_disc'.
    """
    if n % 2 == 0:
        raise ValueError(
            'A Gauss-Lobatto scheme must use an odd number of points')

    subsets = {
        'disc':
        np.arange(0, n, 2, dtype=int),
        'state_disc':
        np.arange(0, n, 2, dtype=int),
        'state_input':
        np.arange(0, n, 2, dtype=int)
        if not compressed or seg_idx == 0 else np.arange(2, n, 2, dtype=int),
        'control_disc':
        np.arange(n, dtype=int),
        'control_input':
        np.arange(n, dtype=int)
        if not compressed or seg_idx == 0 else np.arange(1, n, dtype=int),
        'segment_ends':
        np.array([0, n - 1], dtype=int),
        'col':
        np.arange(1, n, 2, dtype=int),
        'all':
        np.arange(n, dtype=int),
        'solution':
        np.arange(n, dtype=int),
    }

    return subsets, lgl(n)[0]
    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)
    def test_solver_defects_single_phase_reverse_propagation(self):
        prob = Problem()

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

        # First phase: normal operation.

        transcription = Radau(num_segments=5,
                              order=5,
                              segment_ends=seg_ends,
                              compressed=True)
        phase0 = 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.set_state_options('state_of_charge',
                                  fix_initial=True,
                                  fix_final=False,
                                  solve_segments=True)

        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_rel_error(self, soc0[-1], 1.0, 1e-6)
Example #4
0
    def test_static_input_parameter_connections_gl(self):

        class TrajectoryODE(om.Group):
            def initialize(self):
                self.options.declare('num_nodes', types=int)

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

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

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

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

        optimizer = 'SLSQP'
        num_segments = 1
        transcription_order = 5

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

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

        seg_ends, _ = lgl(num_segments + 1)

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

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

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

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

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

        p.run_model()

        expected = np.array([[1, 2], [3, 4]])
        assert_rel_error(self, p.get_val('phase0.rhs_disc.sum.m'), expected)
        assert_rel_error(self, p.get_val('phase0.rhs_col.sum.m'), expected)
    def test_solver_defects_reverse_propagation(self):
        prob = om.Problem()

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

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

        # First phase: normal operation.
        transcription = dm.Radau(num_segments=5,
                                 order=5,
                                 segment_ends=seg_ends,
                                 compressed=True)
        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,
                          solve_segments=True,
                          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,
                          solve_segments=True,
                          targets=['SOC'],
                          rate_source='dXdt:SOC')
        traj_p1.add_objective('time', loc='final')

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

        prob.setup()

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

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

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

        soc1 = prob['traj.phase1.states:state_of_charge']
        assert_near_equal(soc1[-1], 1.0, 1e-6)
Example #6
0
def explicit_subsets_and_nodes(n, seg_idx, compressed=False, shooting='single'):
    """
    Returns the subset dictionary corresponding to the Runge-Kutta transcription.

    Parameters
    ----------
    n : int
        The total number of control discretization nodes in the Runge-Kutta segment.
    seg_idx : int
        The index of this segment within its phase.
    compressed : bool
        True if the subset requested is for a phase with compressed transcription.
    shooting : str
        One of the shooting method types for explicit phases ('single', 'hybrid', or 'multiple')

    Returns
    -------
    subsets : dict of {str: np.ndarray}
        'state_disc' gives the indices of the state discretization nodes
        'state_input' gives the indices of the state input nodes
        'control_disc' gives the indices of the control discretization nodes
        'control_input' gives the indices of the control input nodes
        'segment_ends' gives the indices of the nodes at the start (even) and end (odd) of a segment
        'step' gives the indices of the nodes at step boundaries
        'all' gives all node indices
    nodes : np.ndarray
        The location of all nodes on the interval -1, 1.

    Notes
    -----
    (subsets, nodes)
    Subset 'state_input' is the same as subset 'state_disc'.

    """
    subsets = {
        'disc': np.arange(0, n, 2, dtype=int),
        'state_disc': np.zeros((1,), dtype=int) if seg_idx == 0 or shooting == 'multiple'
        else np.empty((0,), dtype=int),
        'state_input': np.zeros((1,), dtype=int) if seg_idx == 0 or shooting == 'multiple'
        else np.empty((0,), dtype=int),
        'control_disc': np.arange(n, dtype=int),
        'control_input': np.arange(n, dtype=int) if not compressed or seg_idx == 0
        else np.arange(1, n, dtype=int),
        'segment_ends': np.array([0, n-1], dtype=int),
        'col': np.arange(1, n, 2, dtype=int),
        'all': np.arange(n, dtype=int),
        'solution': np.arange(n, dtype=int),
    }

    return subsets, lgl(n)[0]
Example #7
0
    def test_polynomial_control(self):
        tx = dm.GaussLobatto(num_segments=8, order=5, compressed=True)
        phase = dm.Phase(ode_class=BrachistochroneODE, transcription=tx)
        phase.add_polynomial_control('u',
                                     fix_initial=True,
                                     fix_final=True,
                                     order=3)
        xs = np.linspace(-10, 10, 100)
        ys = xs**3

        input_nodes, _ = lgl(4)
        expected = np.atleast_2d((10 * input_nodes)**3).T

        assert_near_equal(phase.interp('u', ys=ys, xs=xs, kind='cubic'),
                          expected)
    def test_basic(self):
        import matplotlib.pyplot as plt

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

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

        prob = om.Problem()

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

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

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

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

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

        # Second phase: normal operation.

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

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

        # Second phase, but with battery failure.

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

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

        # Second phase, but with motor failure.

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

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

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

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

        prob.setup()

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

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

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

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

        prob.set_solver_print(level=0)
        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.
        print('State of Charge after 1 hour')
        assert_near_equal(soc0[-1], 0.63464982, 1e-6)
        print('State of Charge after 2 hours')
        assert_near_equal(soc1[-1], 0.23794217, 1e-6)
        print('State of Charge after 2 hours, battery fails at 1 hour')
        assert_near_equal(soc1b[-1], 0.0281523, 1e-6)
        print('State of Charge after 2 hours, motor fails at 1 hour')
        assert_near_equal(soc1m[-1], 0.18625395, 1e-6)

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

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

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

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

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

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

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

        import dymos as dm

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

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

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

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

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

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

        phase.set_time_options(fix_initial=True,
                               duration_bounds=(300, 10000),
                               duration_ref=5600)

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

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

        phase.add_state('alt',
                        units='kft',
                        rate_source='climb_rate',
                        fix_initial=True,
                        fix_final=True,
                        lower=0.0,
                        upper=60,
                        ref=1e-3,
                        defect_ref=1e-3)

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

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

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

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

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

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

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

        phase.add_timeseries_output('aero.CL')
        phase.add_timeseries_output('aero.CD')

        p.setup()

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

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

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

        dm.run_problem(p)

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

        exp_out = traj.simulate()

        assert_near_equal(p.get_val('traj.phase0.timeseries.CL')[0],
                          exp_out.get_val('traj.phase0.timeseries.CL')[0],
                          tolerance=1.0E-9)

        assert_near_equal(p.get_val('traj.phase0.timeseries.CD')[0],
                          exp_out.get_val('traj.phase0.timeseries.CD')[0],
                          tolerance=1.0E-9)

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

        plt.show()
    def test_optimizer_segments_direct_connections(self):
        prob = Problem()

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

            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 = ScipyOptimizeDriver()
            opt.options['dynamic_simul_derivs'] = True

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

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

        # First phase: normal operation.
        transcription = Radau(num_segments=5,
                              order=5,
                              segment_ends=seg_ends,
                              compressed=True)
        phase0 = 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.set_state_options('state_of_charge',
                                  fix_initial=True,
                                  fix_final=False)

        # Second phase: normal operation.

        phase1 = 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.set_state_options('state_of_charge',
                                  fix_initial=False,
                                  fix_final=False)
        traj_p1.add_objective('time', loc='final')

        # Second phase, but with battery failure.
        phase1_bfail = 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.set_state_options('state_of_charge',
                                        fix_initial=False,
                                        fix_final=False)

        # Second phase, but with motor failure.

        phase1_mfail = 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.set_state_options('state_of_charge',
                                        fix_initial=False,
                                        fix_final=False)

        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 = DirectSolver(assemble_jac=True)

        prob.setup()

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

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

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

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

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

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

        # Final value for State of Chrage in each segment should be a good test.
        assert_rel_error(self, soc0[-1], 0.63464982, 1e-6)
        assert_rel_error(self, soc1[-1], 0.23794217, 1e-6)
        assert_rel_error(self, soc1b[-1], 0.0281523, 1e-6)
        assert_rel_error(self, soc1m[-1], 0.18625395, 1e-6)
    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_solver_defects(self):
        prob = om.Problem()

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

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

        # First phase: normal operation.

        transcription = dm.Radau(num_segments=5,
                                 order=5,
                                 segment_ends=seg_ends,
                                 compressed=True)
        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,
                          solve_segments=True,
                          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,
                          solve_segments=True,
                          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,
                                solve_segments=True,
                                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,
                                solve_segments=True,
                                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.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['traj.phase0.states:state_of_charge'][:] = 1.0

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

        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 Charge in each segment should be a good test.
        assert_near_equal(soc0[-1], 0.63464982, 1e-6)
        assert_near_equal(soc1[-1], 0.23794217, 1e-6)
        assert_near_equal(soc1b[-1], 0.0281523, 1e-6)
        assert_near_equal(soc1m[-1], 0.18625395, 1e-6)
Example #13
0
                 scale=.25)

    if i == 0:
        plt.savefig('lgl_animation_1.png')

    # Plot the interpolating polynomials
    t_dense = np.linspace(time[0], time[-1], 100)
    A_i, B_i, A_d, B_d = hermite_matrices(time[state_disc_idxs], t_dense)
    y_dense = (A_i.dot(y[state_disc_idxs]) + B_i.dot(ydot[state_disc_idxs]))
    vy_dense = A_i.dot(vy[state_disc_idxs]) + B_i.dot(vydot[state_disc_idxs])

    axes[0].plot(t_dense, y_dense, ms=None, ls=':')
    axes[1].plot(t_dense, vy_dense, ms=None, ls=':')

    # Plot the values and rates at the collocation nodes
    tau_s, _ = lgl(3)
    tau_disc = tau_s[0::2]
    tau_col = tau_s[1::2]
    A_i, B_i, A_d, B_d = hermite_matrices(tau_disc, tau_col)

    y_col = B_i.dot(ydot[state_disc_idxs]) * dt_dstau[col_idxs] + A_i.dot(
        y[state_disc_idxs])
    vy_col = B_i.dot(vydot[state_disc_idxs]) * dt_dstau[col_idxs] + A_i.dot(
        vy[state_disc_idxs])

    yprime_col = A_d.dot(y[state_disc_idxs]) / dt_dstau + B_d.dot(
        ydot[state_disc_idxs])
    vyprime_col = A_d.dot(vy[state_disc_idxs]) / dt_dstau + B_d.dot(
        vydot[state_disc_idxs])

    axes[0].plot(time[col_idxs], y_col, marker=(3, 0, 0), ms=8)
Example #14
0
 def test_nodes_and_weights_2(self):
     x_2, w_2 = lgl(2)
     assert_almost_equal(x_2, x_i[2], decimal=6)
     assert_almost_equal(w_2, w_i[2], decimal=6)
Example #15
0
def ex_aircraft_steady_flight(optimizer='SLSQP',
                              transcription='gauss-lobatto'):
    p = Problem(model=Group())
    p.driver = pyOptSparseDriver()
    p.driver.options['optimizer'] = optimizer
    p.driver.options['dynamic_simul_derivs'] = True
    if optimizer == 'SNOPT':
        p.driver.opt_settings['Major iterations limit'] = 1000
        p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6
        p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6
        p.driver.opt_settings["Linesearch tolerance"] = 0.10
        p.driver.opt_settings['iSumm'] = 6

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

    phase = Phase(transcription,
                  ode_class=AircraftODE,
                  num_segments=num_seg,
                  segment_ends=seg_ends,
                  transcription_order=5,
                  compressed=False)

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

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

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

    phase.set_state_options('range',
                            units='NM',
                            fix_initial=True,
                            fix_final=False,
                            scaler=0.001,
                            defect_scaler=1.0E-2)
    phase.set_state_options('mass_fuel',
                            units='lbm',
                            fix_initial=True,
                            fix_final=True,
                            upper=1.5E5,
                            lower=0.0,
                            scaler=1.0E-5,
                            defect_scaler=1.0E-1)

    phase.add_control('alt',
                      units='kft',
                      opt=True,
                      lower=0.0,
                      upper=50.0,
                      rate_param='climb_rate',
                      rate_continuity=True,
                      rate_continuity_scaler=1.0,
                      rate2_continuity=True,
                      rate2_continuity_scaler=1.0,
                      ref=1.0,
                      fix_initial=True,
                      fix_final=True)

    phase.add_control('mach', units=None, opt=False)

    phase.add_input_parameter('S', units='m**2')
    phase.add_input_parameter('mass_empty', units='kg')
    phase.add_input_parameter('mass_payload', units='kg')

    phase.add_path_constraint('propulsion.tau', lower=0.01, upper=1.0)
    phase.add_path_constraint('alt_rate',
                              units='ft/min',
                              lower=-3000,
                              upper=3000,
                              ref=3000)

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

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

    p.model.linear_solver = DirectSolver(assemble_jac=True)

    p.setup()

    p['phase0.t_initial'] = 0.0
    p['phase0.t_duration'] = 3600.0
    p['phase0.states:range'] = phase.interpolate(ys=(0, 1000.0),
                                                 nodes='state_input')
    p['phase0.states:mass_fuel'] = phase.interpolate(ys=(30000, 0),
                                                     nodes='state_input')

    p['phase0.controls:mach'][:] = 0.8
    p['phase0.controls:alt'][:] = 10.0

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

    p.run_driver()

    exp_out = phase.simulate(
        times=np.linspace(0, p['phase0.t_duration'], 500),
        record=True,
        record_file='test_ex_aircraft_steady_flight_rec.db')

    plt.plot(phase.get_values('time', nodes='all'),
             phase.get_values('alt', nodes='all'), 'ro')
    plt.plot(exp_out.get_values('time'), exp_out.get_values('alt'), 'b-')
    plt.suptitle('altitude vs time')
    plt.figure()
    plt.plot(phase.get_values('time', nodes='all'),
             phase.get_values('alt_rate', nodes='all', units='ft/min'), 'ro')
    plt.plot(exp_out.get_values('time'),
             exp_out.get_values('alt_rate', units='ft/min'), 'b-')
    plt.suptitle('altitude rate vs time')
    plt.figure()
    plt.plot(phase.get_values('time', nodes='all'),
             phase.get_values('mass_fuel', nodes='all'), 'ro')
    plt.plot(exp_out.get_values('time'), exp_out.get_values('mass_fuel'), 'b-')
    plt.suptitle('fuel mass vs time')
    plt.figure()
    plt.plot(phase.get_values('time', nodes='all'),
             phase.get_values('propulsion.dXdt:mass_fuel', nodes='all'), 'ro')
    plt.plot(exp_out.get_values('time'),
             exp_out.get_values('propulsion.dXdt:mass_fuel'), 'b-')
    plt.suptitle('fuel mass flow rate vs time')
    plt.figure()
    plt.plot(phase.get_values('time', nodes='all'),
             phase.get_values('mach', nodes='all'), 'ro')
    plt.plot(exp_out.get_values('time'), exp_out.get_values('mach'), 'b-')
    plt.suptitle('mach vs time')
    plt.figure()
    plt.plot(phase.get_values('time', nodes='all'),
             phase.get_values('mach_rate', nodes='all'), 'ro')
    plt.plot(exp_out.get_values('time'), exp_out.get_values('mach_rate'), 'b-')
    plt.suptitle('mach rate vs time')

    print('time')
    print(phase.get_values('time', nodes='all').T)

    print('alt')
    print(phase.get_values('alt', nodes='all').T)

    print('alt_rate')
    print(phase.get_values('alt_rate', nodes='all').T)

    print('alt_rate2')
    print(phase.get_values('alt_rate2', nodes='all').T)

    print('range')
    print(phase.get_values('range', nodes='all').T)

    print('flight path angle')
    print(phase.get_values('gam_comp.gam').T)

    print('true airspeed')
    print(phase.get_values('tas_comp.TAS', units='m/s').T)

    print('coef of lift')
    print(phase.get_values('aero.CL').T)

    print('coef of drag')
    print(phase.get_values('aero.CD').T)

    print('atmos density')
    print(phase.get_values('atmos.rho').T)

    print('alpha')
    print(phase.get_values('flight_equilibrium.alpha', units='rad').T)

    print('coef of thrust')
    print(phase.get_values('flight_equilibrium.CT').T)

    print('fuel flow rate')
    print(phase.get_values('propulsion.dXdt:mass_fuel').T)

    print('max_thrust')
    print(phase.get_values('propulsion.max_thrust', units='N').T)

    print('tau')
    print(phase.get_values('propulsion.tau').T)

    print('dynamic pressure')
    print(phase.get_values('q_comp.q', units='Pa').T)

    print('S')
    print(phase.get_values('S', units='m**2').T)

    plt.show()

    return p
Example #16
0
    def test_polynomial_control_group_scalar_gl(self):
        transcription = 'gauss-lobatto'
        compressed = True

        segends = np.array([0.0, 3.0, 10.0])

        gd = GridData(num_segments=2,
                      transcription_order=5,
                      segment_ends=segends,
                      transcription=transcription,
                      compressed=compressed)

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

        controls = {
            'a': PolynomialControlOptionsDictionary(),
            'b': PolynomialControlOptionsDictionary()
        }

        controls['a']['units'] = 'm'
        controls['a']['order'] = 3
        controls['a']['shape'] = (1, )
        controls['a']['opt'] = True

        controls['b']['units'] = 'm'
        controls['b']['order'] = 3
        controls['b']['shape'] = (1, )
        controls['b']['opt'] = True

        ivc = om.IndepVarComp()
        p.model.add_subsystem('ivc', ivc, promotes_outputs=['*'])

        ivc.add_output('t_initial', val=0.0, units='s')
        ivc.add_output('t_duration', val=10.0, units='s')

        p.model.add_subsystem('time_comp',
                              subsys=TimeComp(
                                  num_nodes=gd.num_nodes,
                                  node_ptau=gd.node_ptau,
                                  node_dptau_dstau=gd.node_dptau_dstau,
                                  units='s'),
                              promotes_inputs=['t_initial', 't_duration'],
                              promotes_outputs=['time', 'dt_dstau'])

        polynomial_control_group = PolynomialControlGroup(
            grid_data=gd, polynomial_control_options=controls, time_units='s')

        p.model.add_subsystem('polynomial_control_group',
                              subsys=polynomial_control_group,
                              promotes_inputs=['*'],
                              promotes_outputs=['*'])

        p.setup(force_alloc_complex=True)

        p['t_initial'] = 0.0
        p['t_duration'] = 3.0

        p.run_model()

        control_nodes_ptau, _ = lgl(controls['a']['order'] + 1)

        t_control_input = p['t_initial'] + 0.5 * (control_nodes_ptau +
                                                  1) * p['t_duration']
        t_all = p['time']

        p['polynomial_controls:a'][:, 0] = f_a(t_control_input)
        p['polynomial_controls:b'][:, 0] = f_b(t_control_input)

        p.run_model()

        a_value_expected = f_a(t_all)
        b_value_expected = f_b(t_all)

        a_rate_expected = f1_a(t_all)
        b_rate_expected = f1_b(t_all)

        a_rate2_expected = f2_a(t_all)
        b_rate2_expected = f2_b(t_all)

        assert_almost_equal(p['polynomial_control_values:a'],
                            np.atleast_2d(a_value_expected).T)

        assert_almost_equal(p['polynomial_control_values:b'],
                            np.atleast_2d(b_value_expected).T)

        assert_almost_equal(p['polynomial_control_rates:a_rate'],
                            np.atleast_2d(a_rate_expected).T)

        assert_almost_equal(p['polynomial_control_rates:b_rate'],
                            np.atleast_2d(b_rate_expected).T)

        assert_almost_equal(p['polynomial_control_rates:a_rate2'],
                            np.atleast_2d(a_rate2_expected).T)

        assert_almost_equal(p['polynomial_control_rates:b_rate2'],
                            np.atleast_2d(b_rate2_expected).T)

        np.set_printoptions(linewidth=1024)
        cpd = p.check_partials(compact_print=False,
                               out_stream=None,
                               method='cs')
        assert_check_partials(cpd)
Example #17
0
 def test_nodes_and_weights_3(self):
     x_3, w_3 = lgl(3)
     assert_almost_equal(x_3, x_i[3], decimal=6)
     assert_almost_equal(w_3, w_i[3], decimal=6)
Example #18
0
    def test_polynomial_control_group_matrix_rungekutta(self):
        transcription = 'runge-kutta'
        compressed = True

        segends = np.array([0.0, 3.0, 10.0])

        gd = GridData(num_segments=2,
                      transcription_order='RK4',
                      segment_ends=segends,
                      transcription=transcription,
                      compressed=compressed)

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

        controls = {'a': PolynomialControlOptionsDictionary()}

        controls['a']['units'] = 'm'
        controls['a']['order'] = 3
        controls['a']['opt'] = True
        controls['a']['shape'] = (3, 1)

        ivc = om.IndepVarComp()
        p.model.add_subsystem('ivc', ivc, promotes_outputs=['*'])

        ivc.add_output('t_initial', val=0.0, units='s')
        ivc.add_output('t_duration', val=10.0, units='s')

        p.model.add_subsystem('time_comp',
                              subsys=TimeComp(num_nodes=gd.num_nodes, node_ptau=gd.node_ptau,
                                              node_dptau_dstau=gd.node_dptau_dstau, units='s'),
                              promotes_inputs=['t_initial', 't_duration'],
                              promotes_outputs=['time', 'dt_dstau'])

        polynomial_control_group = PolynomialControlGroup(grid_data=gd,
                                                          polynomial_control_options=controls,
                                                          time_units='s')

        p.model.add_subsystem('polynomial_control_group',
                              subsys=polynomial_control_group,
                              promotes_inputs=['*'],
                              promotes_outputs=['*'])

        # p.model.connect('dt_dstau', 'control_interp_comp.dt_dstau')

        p.setup(force_alloc_complex=True)

        p['t_initial'] = 0.0
        p['t_duration'] = 3.0

        p.run_model()

        control_nodes_ptau, _ = lgl(controls['a']['order'] + 1)

        t_control_input = p['t_initial'] + 0.5 * (control_nodes_ptau + 1) * p['t_duration']
        t_all = p['time']

        p['polynomial_controls:a'][:, 0, 0] = f_a(t_control_input)
        p['polynomial_controls:a'][:, 1, 0] = f_b(t_control_input)
        p['polynomial_controls:a'][:, 2, 0] = f_c(t_control_input)

        p.run_model()

        a0_value_expected = f_a(t_all)
        a1_value_expected = f_b(t_all)
        a2_value_expected = f_c(t_all)

        a0_rate_expected = f1_a(t_all)
        a1_rate_expected = f1_b(t_all)
        a2_rate_expected = f1_c(t_all)

        a0_rate2_expected = f2_a(t_all)
        a1_rate2_expected = f2_b(t_all)
        a2_rate2_expected = f2_c(t_all)

        assert_almost_equal(p['polynomial_control_values:a'][:, 0, 0],
                            a0_value_expected)

        assert_almost_equal(p['polynomial_control_values:a'][:, 1, 0],
                            a1_value_expected)

        assert_almost_equal(p['polynomial_control_values:a'][:, 2, 0],
                            a2_value_expected)

        assert_almost_equal(p['polynomial_control_rates:a_rate'][:, 0, 0],
                            a0_rate_expected)

        assert_almost_equal(p['polynomial_control_rates:a_rate'][:, 1, 0],
                            a1_rate_expected)

        assert_almost_equal(p['polynomial_control_rates:a_rate'][:, 2, 0],
                            a2_rate_expected)

        assert_almost_equal(p['polynomial_control_rates:a_rate2'][:, 0, 0],
                            a0_rate2_expected)

        assert_almost_equal(p['polynomial_control_rates:a_rate2'][:, 1, 0],
                            a1_rate2_expected)

        assert_almost_equal(p['polynomial_control_rates:a_rate2'][:, 2, 0],
                            a2_rate2_expected)

        np.set_printoptions(linewidth=1024)
        cpd = p.check_partials(method='cs', out_stream=None)

        assert_check_partials(cpd)
Example #19
0
def main():
    prob = om.Problem()
    model = prob.model

    num_seg = 15
    seg_ends, _ = lgl(num_seg + 1)
    traj = model.add_subsystem('traj', dm.Trajectory())
    phase = traj.add_phase('phase0',
                           dm.Phase(ode_class=AircraftODE,
                                    transcription=dm.Radau(num_segments=num_seg,
                                                           segment_ends=seg_ends,
                                                           order=3, compressed=False)))

    assumptions = model.add_subsystem('assumptions', om.IndepVarComp())
    assumptions.add_output('S', val=427.8, units='m**2')
    assumptions.add_output('mass_empty', val=1.0, units='kg')
    assumptions.add_output('mass_payload', val=1.0, units='kg')

    prob.driver = om.pyOptSparseDriver()
    prob.driver.options['optimizer'] = 'SNOPT'

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

    phase.set_state_options('range', units='NM', fix_initial=True,
                            fix_final=False, lower=0, upper=2000)
    phase.set_state_options('mass_fuel', units='lbm', fix_initial=True, fix_final=True,
                            upper=1.5E5, lower=0.0)
    phase.set_state_options('alt', units='kft', fix_initial=True, fix_final=True,
                            lower=0.0, upper=60)

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

    phase.add_control('mach', units=None, opt=False)

    phase.add_input_parameter('S', units='m**2')
    phase.add_input_parameter('mass_empty', units='kg')
    phase.add_input_parameter('mass_payload', units='kg')

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

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

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

    prob.setup()

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

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

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

    with open('total_jac_info.pickle', 'rb') as file:
        jac = pickle.load(file)
    with open('lower_bounds_info.pickle', 'rb') as file:
        lbs = pickle.load(file)
    with open('upper_bounds_info.pickle', 'rb') as file:
        ubs = pickle.load(file)

    # sc = None
    # sc = IsoScaler(jac, lbs, ubs)
    sc = PJRNScaler(jac, lbs, ubs)

    autoscale(prob, autoscaler=sc)

    prob.run_driver()

    return prob
Example #20
0
 def test_nodes_and_weights_6(self):
     x_6, w_6 = lgl(6)
     assert_almost_equal(x_6, x_i[6], decimal=6)
     assert_almost_equal(w_6, w_i[6], decimal=6)
Example #21
0
 def test_nodes_and_weights_5(self):
     x_5, w_5 = lgl(5)
     assert_almost_equal(x_5, x_i[5], decimal=6)
     assert_almost_equal(w_5, w_i[5], decimal=6)
Example #22
0
 def test_nodes_and_weights_4(self):
     x_4, w_4 = lgl(4)
     assert_almost_equal(x_4, x_i[4], decimal=6)
     assert_almost_equal(w_4, w_i[4], decimal=6)
Example #23
0
    def test_overlapping_phases_make_plot(self):

        prob = om.Problem()

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

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

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

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

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

        # Second phase: normal operation.

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

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

        # Second phase, but with battery failure.

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

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

        # Second phase, but with motor failure.

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

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

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

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

        prob.setup()

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

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

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

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

        prob.set_solver_print(level=0)
        dm.run_problem(prob, simulate=True, make_plots=False,
                       simulation_record_file='simulation_record_file.db')

        timeseries_plots('dymos_solution.db', simulation_record_file='simulation_record_file.db')

        self.assertTrue(os.path.exists('plots/time_phase.png'))
        self.assertTrue(os.path.exists('plots/states_state_of_charge.png'))
        self.assertTrue(os.path.exists('plots/state_rates_state_of_charge.png'))
    0.0, 0.0, 0.0, 0.0, 457.0, 1744.0, 1744.0, 457.0, 457.0, 457.0, 457.0,
    457.0
])
h_seg += 690.0  # add ground level

# Create the problem
prob = om.Problem()

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

# Set up the segments based on the type of mission
num_seg = 11

seg_ends, _ = lgl(num_seg + 1)
traj = prob.model.add_subsystem('traj', dm.Trajectory())
'''
Set the values of the design parameters
'''
# Geometric parameters
# --------------------
traj.add_design_parameter('x',
                          val=10e-3,
                          lower=1e-3,
                          upper=80e-3,
                          units='m',
                          opt=True,
                          dynamic=False)
# targets={'traj_p1':'x', 'traj_p2':'x', 'traj_p3':'x',
#                                    'traj_p4':'x', 'traj_p5':'x', 'traj_p6':'x',
def ex_aircraft_steady_flight(optimizer='SLSQP',
                              solve_segments=False,
                              use_boundary_constraints=False,
                              compressed=False):
    p = om.Problem(model=om.Group())
    p.driver = om.pyOptSparseDriver()
    p.driver.options['optimizer'] = optimizer
    p.driver.declare_coloring()
    if optimizer == 'SNOPT':
        p.driver.opt_settings['Major iterations limit'] = 20
        p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6
        p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6
        p.driver.opt_settings["Linesearch tolerance"] = 0.10
        p.driver.opt_settings['iSumm'] = 6
    if optimizer == 'SLSQP':
        p.driver.opt_settings['MAXIT'] = 50

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

    phase = dm.Phase(ode_class=AircraftODE,
                     transcription=dm.Radau(num_segments=num_seg,
                                            segment_ends=seg_ends,
                                            order=3,
                                            compressed=compressed,
                                            solve_segments=solve_segments))

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

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

    phase.set_time_options(fix_initial=True,
                           duration_bounds=(300, 10000),
                           duration_ref=5600)

    fix_final = True
    if use_boundary_constraints:
        fix_final = False
        phase.add_boundary_constraint('mass_fuel',
                                      loc='final',
                                      equals=1e-3,
                                      linear=False)
        phase.add_boundary_constraint('alt',
                                      loc='final',
                                      equals=10.0,
                                      linear=False)

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

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

    phase.add_state('alt',
                    units='kft',
                    rate_source='climb_rate',
                    fix_initial=True,
                    fix_final=fix_final,
                    lower=0.0,
                    upper=60,
                    ref=1e-3,
                    defect_ref=1e-3)

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

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

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

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

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

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

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

    p.setup()

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

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

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

    dm.run_problem(p)

    return p
    def test_steady_aircraft_for_docs(self):
        import numpy as np
        import matplotlib.pyplot as plt

        from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver, IndepVarComp
        from openmdao.utils.assert_utils import assert_rel_error

        from dymos import Phase

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

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

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

        phase = Phase('gauss-lobatto',
                      ode_class=AircraftODE,
                      num_segments=num_seg,
                      segment_ends=seg_ends,
                      transcription_order=5,
                      compressed=False)

        # Pass design parameters in externally from an external source
        assumptions = p.model.add_subsystem('assumptions', IndepVarComp())
        assumptions.add_output('mach', val=0.8, units=None)
        assumptions.add_output('S', val=427.8, units='m**2')
        assumptions.add_output('mass_empty', val=1.0, units='kg')
        assumptions.add_output('mass_payload', val=1.0, units='kg')

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

        phase.set_time_options(fix_initial=True,
                               duration_bounds=(300, 10000),
                               duration_ref=3600)

        phase.set_state_options('range', units='NM', fix_initial=True, fix_final=False,
                                scaler=0.001,
                                defect_scaler=1.0E-2)

        phase.set_state_options('mass_fuel', units='lbm', fix_initial=True, fix_final=True,
                                upper=1.5E5, lower=0.0, scaler=1.0E-5, defect_scaler=1.0E-1)

        phase.add_control('alt', units='kft', opt=True, lower=0.0, upper=50.0,
                          rate_param='climb_rate',
                          rate_continuity=True, rate_continuity_scaler=1.0,
                          rate2_continuity=True, rate2_continuity_scaler=1.0, ref=1.0,
                          fix_initial=True, fix_final=True)

        phase.add_input_parameter('mach', units=None)
        phase.add_input_parameter('S', units='m**2')
        phase.add_input_parameter('mass_empty', units='kg')
        phase.add_input_parameter('mass_payload', units='kg')

        phase.add_path_constraint('propulsion.tau', lower=0.01, upper=1.0)
        phase.add_path_constraint('alt_rate', units='ft/min', lower=-3000, upper=3000, ref=3000)

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

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

        p.model.linear_solver = DirectSolver(assemble_jac=True)

        p.setup()

        p['phase0.t_initial'] = 0.0
        p['phase0.t_duration'] = 3600.0
        p['phase0.states:range'] = phase.interpolate(ys=(0, 1000.0), nodes='state_input')
        p['phase0.states:mass_fuel'] = phase.interpolate(ys=(30000, 0), nodes='state_input')

        p['phase0.controls:alt'][:] = 10.0

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

        p.run_driver()

        exp_out = phase.simulate(times=np.linspace(0, p['phase0.t_duration'], 500), record=True,
                                 record_file='test_doc_aircraft_steady_flight_rec.db')

        assert_rel_error(self, phase.get_values('range', units='NM')[-1], 726.7, tolerance=1.0E-2)

        plt.figure()

        plt.plot(phase.get_values('time', nodes='all'),
                 phase.get_values('alt', nodes='all', units='ft'),
                 'ro')

        plt.plot(exp_out.get_values('time'),
                 exp_out.get_values('alt', units='ft'),
                 'b-')

        plt.suptitle('Altitude vs Time')
        plt.xlabel('Time (s)')
        plt.ylabel('Altitude (ft)')

        plt.figure()
        plt.plot(phase.get_values('time', nodes='all'),
                 phase.get_values('alt_rate', nodes='all', units='ft/min'),
                 'ro')
        plt.plot(exp_out.get_values('time'),
                 exp_out.get_values('alt_rate', units='ft/min'),
                 'b-')

        plt.suptitle('Climb Rate vs Time')
        plt.xlabel('Time (s)')
        plt.ylabel('Climb Rate (ft/min)')

        plt.figure()
        plt.plot(phase.get_values('time', nodes='all'),
                 phase.get_values('mass_fuel', nodes='all', units='lbm'),
                 'ro')

        plt.plot(exp_out.get_values('time'),
                 exp_out.get_values('mass_fuel', units='lbm'),
                 'b-')

        plt.suptitle('Fuel Mass vs Time')
        plt.xlabel('Time (s)')
        plt.ylabel('Fuel Mass (lbm)')

        plt.show()