Esempio n. 1
0
    def _make_problem(self,
                      transcription='gauss-lobatto',
                      num_segments=8,
                      transcription_order=3,
                      compressed=True,
                      optimizer='SLSQP',
                      run_driver=True,
                      force_alloc_complex=False,
                      solve_segments=False):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return p
Esempio n. 2
0
        # self.add_subsystem(name='hp_mass',
        #                    subsys=heatPipeMass(num_nodes=nn),
        #                    promotes_inputs=['D_od','D_v','L_heatpipe','t_w','t_wk','cu_density',('fill_wk','epsilon'),'liq_density','fill_liq'],
        #                    promotes_outputs=['mass_heatpipe', 'mass_wick', 'mass_liquid'])

        thermal_link(self, 'evap', 'cond', num_nodes=nn)
        thermal_link(self, 'cond', 'cond2', num_nodes=nn)
        self.connect('evap_bridge.k_wk',
                     ['evap.k_wk', 'cond.k_wk', 'cond2.k_wk'])

        load_inputs('boring.input.assumptions2', self, nn)


if __name__ == "__main__":
    p = om.Problem(model=om.Group())
    nn = 1

    p.model.add_subsystem(name='hp',
                          subsys=HeatPipeRun(num_nodes=nn),
                          promotes_inputs=['*'],
                          promotes_outputs=['*'])

    p.setup(force_alloc_complex=True)

    p['L_eff'] = (0.02 + 0.1) / 2. + 0.03
    p['evap.Rex.T_in'] = 100
    p['cond.Rex.T_in'] = 20
    p['cond2.Rex.T_in'] = 20

    # p.set_val('L_evap',0.01)
Esempio n. 3
0
    def test_rk4_scalar_nonlinearblockgs(self):
        num_seg = 4
        num_stages = 4
        state_options = {'y': {'shape': (1, ), 'units': 'm', 'targets': ['y']}}

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

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

        ivc.add_output('initial_states_per_seg:y',
                       shape=(num_seg, 1),
                       units='m')
        ivc.add_output('h', shape=(num_seg, 1), units='s')
        ivc.add_output('t', shape=(num_seg * num_stages, 1), units='s')

        p.model.add_subsystem(
            'k_iter_group',
            RungeKuttaKIterGroup(num_segments=num_seg,
                                 method='RK4',
                                 state_options=state_options,
                                 time_units='s',
                                 ode_class=TestODE,
                                 ode_init_kwargs={},
                                 solver_class=om.NonlinearBlockGS,
                                 solver_options={'iprint': 2}))

        p.model.connect('t', 'k_iter_group.ode.t')
        p.model.connect('h', 'k_iter_group.h')
        p.model.connect('initial_states_per_seg:y',
                        'k_iter_group.initial_states_per_seg:y')

        src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1))
        p.model.connect('k_iter_group.ode.ydot',
                        'k_iter_group.k_comp.f:y',
                        src_indices=src_idxs,
                        flat_src_indices=True)

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

        p['t'] = np.array([[
            0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, 1.00, 1.25, 1.25,
            1.50, 1.50, 1.75, 1.75, 2.00
        ]]).T

        p['h'] = np.array([[0.5, 0.5, 0.5, 0.5]]).T

        p['initial_states_per_seg:y'] = np.array([[0.50000000],
                                                  [1.425130208333333],
                                                  [2.639602661132812],
                                                  [4.006818970044454]])

        # Start k with a terrible guess
        p['k_iter_group.k_comp.k:y'][...] = 0

        p.run_model()

        # Test that the residuals of k are zero (we started k at the expected converged value)
        outputs = p.model.list_outputs(print_arrays=True,
                                       residuals=True,
                                       out_stream=False)
        op_dict = dict([op for op in outputs])
        assert_almost_equal(op_dict['k_iter_group.k_comp.k:y']['resids'], 0.0)

        # Test the partials
        cpd = p.check_partials(method='cs', out_stream=None)
        assert_check_partials(cpd)
Esempio n. 4
0
    def test_simple_external_code_implicit_comp(self):
        import sys
        import openmdao.api as om

        class MachExternalCodeComp(om.ExternalCodeImplicitComp):
            def initialize(self):
                self.options.declare('super_sonic', types=bool)

            def setup(self):
                self.add_input('area_ratio', val=1.0, units=None)
                self.add_output('mach', val=1., units=None)
                self.declare_partials(of='mach', wrt='area_ratio', method='fd')

                self.input_file = 'mach_input.dat'
                self.output_file = 'mach_output.dat'

                # providing these are optional; the component will verify that any input
                # files exist before execution and that the output files exist after.
                self.options['external_input_files'] = [self.input_file]
                self.options['external_output_files'] = [self.output_file]

                self.options['command_apply'] = [
                    sys.executable,
                    'extcode_mach.py',
                    self.input_file,
                    self.output_file,
                ]
                self.options['command_solve'] = [
                    sys.executable,
                    'extcode_mach.py',
                    self.input_file,
                    self.output_file,
                ]

                # If you want to write your own string command, the code below will also work.
                # self.options['command_apply'] = ('python extcode_mach.py {} {}').format(self.input_file, self.output_file)

            def apply_nonlinear(self, inputs, outputs, residuals):
                with open(self.input_file, 'w') as input_file:
                    input_file.write('residuals\n')
                    input_file.write('{}\n'.format(inputs['area_ratio'][0]))
                    input_file.write('{}\n'.format(outputs['mach'][0]))

                # the parent apply_nonlinear function actually runs the external code
                super(MachExternalCodeComp,
                      self).apply_nonlinear(inputs, outputs, residuals)

                # parse the output file from the external code and set the value of mach
                with open(self.output_file, 'r') as output_file:
                    mach = float(output_file.read())
                residuals['mach'] = mach

            def solve_nonlinear(self, inputs, outputs):
                with open(self.input_file, 'w') as input_file:
                    input_file.write('outputs\n')
                    input_file.write('{}\n'.format(inputs['area_ratio'][0]))
                    input_file.write('{}\n'.format(
                        self.options['super_sonic']))
                # the parent apply_nonlinear function actually runs the external code
                super(MachExternalCodeComp,
                      self).solve_nonlinear(inputs, outputs)

                # parse the output file from the external code and set the value of mach
                with open(self.output_file, 'r') as output_file:
                    mach = float(output_file.read())
                outputs['mach'] = mach

        group = om.Group()
        group.add_subsystem('ar', om.IndepVarComp('area_ratio', 0.5))
        mach_comp = group.add_subsystem('comp',
                                        MachExternalCodeComp(),
                                        promotes=['*'])
        prob = om.Problem(model=group)
        group.nonlinear_solver = om.NewtonSolver()
        group.nonlinear_solver.options['solve_subsystems'] = True
        group.nonlinear_solver.options['iprint'] = 0
        group.nonlinear_solver.options['maxiter'] = 20
        group.linear_solver = om.DirectSolver()

        prob.setup()

        area_ratio = 1.3
        super_sonic = False
        prob['area_ratio'] = area_ratio
        mach_comp.options['super_sonic'] = super_sonic
        prob.run_model()
        assert_near_equal(prob['mach'],
                          mach_solve(area_ratio, super_sonic=super_sonic),
                          1e-8)

        area_ratio = 1.3
        super_sonic = True
        prob['area_ratio'] = area_ratio
        mach_comp.options['super_sonic'] = super_sonic
        prob.run_model()
        assert_near_equal(prob['mach'],
                          mach_solve(area_ratio, super_sonic=super_sonic),
                          1e-8)
Esempio n. 5
0
def brachistochrone_min_time(transcription='gauss-lobatto',
                             num_segments=8,
                             transcription_order=3,
                             compressed=True,
                             optimizer='SLSQP',
                             simul_derivs=True):
    p = om.Problem(model=om.Group())

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

    if simul_derivs:
        p.driver.declare_coloring()

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

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

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

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

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

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

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

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

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

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

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

    p.run_driver()

    return p
Esempio n. 6
0
    def test_continuity_comp_connected_scalar_no_iteration_fwd(self):
        num_seg = 4
        state_options = {
            'y': {
                'shape': (1, ),
                'units': 'm',
                'targets': ['y'],
                'defect_scaler': None,
                'defect_ref': None,
                'lower': None,
                'upper': None,
                'connected_initial': True
            }
        }

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

        ivc = p.model.add_subsystem('ivc',
                                    om.IndepVarComp(),
                                    promotes_outputs=['*'])
        ivc.add_output('initial_states:y', units='m', shape=(1, 1))

        p.model.add_subsystem('continuity_comp',
                              RungeKuttaStateContinuityComp(
                                  num_segments=num_seg,
                                  state_options=state_options),
                              promotes_inputs=['*'],
                              promotes_outputs=['*'])

        p.model.nonlinear_solver = om.NonlinearRunOnce()
        p.model.linear_solver = om.DirectSolver()

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

        p['initial_states:y'] = 0.5

        p['states:y'] = np.array([[0.50000000], [1.425130208333333],
                                  [2.639602661132812], [4.006818970044454],
                                  [5.301605229265987]])

        p['state_integrals:y'] = np.array([[1.0], [1.0], [1.0], [1.0]])

        p.run_model()
        p.model.run_apply_nonlinear()

        # Test that the residuals of the states are the expected values
        outputs = p.model.list_outputs(print_arrays=True,
                                       residuals=True,
                                       out_stream=None)

        y_f = p['states:y'][1:, ...]
        y_i = p['states:y'][:-1, ...]
        dy_given = y_f - y_i
        dy_computed = p['state_integrals:y']

        expected_resids = np.zeros((num_seg + 1, 1))
        expected_resids[1:, ...] = dy_given - dy_computed

        op_dict = dict([op for op in outputs])
        assert_rel_error(self, op_dict['continuity_comp.states:y']['resids'],
                         expected_resids)

        # Test the partials
        cpd = p.check_partials(method='cs')

        J_fwd = cpd['continuity_comp']['states:y',
                                       'state_integrals:y']['J_fwd']
        J_rev = cpd['continuity_comp']['states:y',
                                       'state_integrals:y']['J_rev']
        J_fd = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_fd']
        assert_rel_error(self, J_fwd, J_rev)
        assert_rel_error(self, J_fwd, J_fd)

        J_fwd = cpd['continuity_comp']['states:y', 'states:y']['J_fwd']
        J_rev = cpd['continuity_comp']['states:y', 'states:y']['J_rev']
        J_fd = cpd['continuity_comp']['states:y', 'states:y']['J_fd']

        J_fd[0, 0] = -1.0

        assert_rel_error(self, J_fwd, J_rev)
        assert_rel_error(self, J_fwd, J_fd)
Esempio n. 7
0
    def test_reentry(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_rel_error
        import dymos as dm
        from dymos.examples.shuttle_reentry.shuttle_ode import ShuttleODE
        from dymos.examples.plotting import plot_results

        # Instantiate the problem, add the driver, and allow it to use coloring
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.declare_coloring()
        p.driver.options['optimizer'] = 'SLSQP'

        # Instantiate the trajectory and add a phase to it
        traj = p.model.add_subsystem('traj', dm.Trajectory())
        phase0 = traj.add_phase(
            'phase0',
            dm.Phase(ode_class=ShuttleODE,
                     transcription=dm.Radau(num_segments=15, order=3)))

        phase0.set_time_options(fix_initial=True, units='s', duration_ref=200)
        phase0.add_state('h',
                         fix_initial=True,
                         fix_final=True,
                         units='ft',
                         rate_source='hdot',
                         targets=['h'],
                         lower=0,
                         ref0=75000,
                         ref=300000,
                         defect_ref=1000)
        phase0.add_state('gamma',
                         fix_initial=True,
                         fix_final=True,
                         units='rad',
                         rate_source='gammadot',
                         targets=['gamma'],
                         lower=-89. * np.pi / 180,
                         upper=89. * np.pi / 180)
        phase0.add_state('phi',
                         fix_initial=True,
                         fix_final=False,
                         units='rad',
                         rate_source='phidot',
                         lower=0,
                         upper=89. * np.pi / 180)
        phase0.add_state('psi',
                         fix_initial=True,
                         fix_final=False,
                         units='rad',
                         rate_source='psidot',
                         targets=['psi'],
                         lower=0,
                         upper=90. * np.pi / 180)
        phase0.add_state('theta',
                         fix_initial=True,
                         fix_final=False,
                         units='rad',
                         rate_source='thetadot',
                         targets=['theta'],
                         lower=-89. * np.pi / 180,
                         upper=89. * np.pi / 180)
        phase0.add_state('v',
                         fix_initial=True,
                         fix_final=True,
                         units='ft/s',
                         rate_source='vdot',
                         targets=['v'],
                         lower=0,
                         ref0=2500,
                         ref=25000)
        phase0.add_control('alpha',
                           units='rad',
                           opt=True,
                           lower=-np.pi / 2,
                           upper=np.pi / 2,
                           targets=['alpha'])
        phase0.add_control('beta',
                           units='rad',
                           opt=True,
                           lower=-89 * np.pi / 180,
                           upper=1 * np.pi / 180,
                           targets=['beta'])

        # The original implementation by Betts includes a heating rate path constraint.
        # This will work with the SNOPT optimizer but SLSQP has difficulty converging the solution.
        # phase0.add_path_constraint('q', lower=0, upper=70, units='Btu/ft**2/s', ref=70)
        phase0.add_timeseries_output('q', shape=(1, ), units='Btu/ft**2/s')

        phase0.add_objective('theta', loc='final', ref=-0.01)

        p.setup(check=True)

        p.set_val('traj.phase0.states:h',
                  phase0.interpolate(ys=[260000, 80000], nodes='state_input'),
                  units='ft')
        p.set_val('traj.phase0.states:gamma',
                  phase0.interpolate(ys=[-1, -5], nodes='state_input'),
                  units='deg')
        p.set_val('traj.phase0.states:phi',
                  phase0.interpolate(ys=[0, 75], nodes='state_input'),
                  units='deg')
        p.set_val('traj.phase0.states:psi',
                  phase0.interpolate(ys=[90, 10], nodes='state_input'),
                  units='deg')
        p.set_val('traj.phase0.states:theta',
                  phase0.interpolate(ys=[0, 25], nodes='state_input'),
                  units='deg')
        p.set_val('traj.phase0.states:v',
                  phase0.interpolate(ys=[25600, 2500], nodes='state_input'),
                  units='ft/s')
        p.set_val('traj.phase0.t_initial', 0, units='s')
        p.set_val('traj.phase0.t_duration', 2000, units='s')
        p.set_val('traj.phase0.controls:alpha',
                  phase0.interpolate(ys=[17.4, 17.4], nodes='control_input'),
                  units='deg')
        p.set_val('traj.phase0.controls:beta',
                  phase0.interpolate(ys=[-75, 0], nodes='control_input'),
                  units='deg')

        # Run the driver
        dm.run_problem(p)

        # Check the validity of the solution
        assert_rel_error(self,
                         p.get_val('traj.phase0.timeseries.time')[-1],
                         2008.59,
                         tolerance=1e-3)
        assert_rel_error(self,
                         p.get_val('traj.phase0.timeseries.states:theta',
                                   units='deg')[-1],
                         34.1412,
                         tolerance=1e-3)
        # assert_rel_error(self, p.get_val('traj.phase0.timeseries.time')[-1], 2181.90371131, tolerance=1e-3)
        # assert_rel_error(self, p.get_val('traj.phase0.timeseries.states:theta')[-1], .53440626, tolerance=1e-3)

        # Run the simulation to check if the model is physically valid
        sim_out = traj.simulate()

        # Plot the results

        plot_results([
            ('traj.phase0.timeseries.time',
             'traj.phase0.timeseries.controls:alpha', 'time (s)',
             'alpha (rad)'),
            ('traj.phase0.timeseries.time',
             'traj.phase0.timeseries.controls:beta', 'time (s)', 'beta (rad)'),
            ('traj.phase0.timeseries.time',
             'traj.phase0.timeseries.states:theta', 'time (s)', 'theta (rad)'),
            ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.q',
             'time (s)', 'q (btu/ft/ft/s')
        ],
                     title='Reentry Solution',
                     p_sol=p,
                     p_sim=sim_out)

        plt.show()
Esempio n. 8
0
    def test_brachistochrone_quick_start(self):
        import numpy as np
        import openmdao.api as om
        import dymos as dm
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        plt.show()
    def test_brachistochrone_tandem_phases(self):
        from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE

        import numpy as np
        import matplotlib.pyplot as plt
        plt.switch_backend('Agg')
        import openmdao.api as om
        import dymos as dm

        from openmdao.utils.assert_utils import assert_near_equal

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

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

        # The transcription of the first phase
        tx0 = dm.GaussLobatto(num_segments=10, order=3, compressed=False)

        # The transcription for the second phase (and the secondary timeseries outputs from the first phase)
        tx1 = dm.Radau(num_segments=20, order=9, compressed=False)

        #
        # First Phase: Integrate the standard brachistochrone ODE
        #
        phase0 = dm.Phase(ode_class=BrachistochroneODE, transcription=tx0)

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

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

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

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

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

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

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

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

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

        #
        # Second Phase: Integration of ArcLength
        #
        phase1 = dm.Phase(ode_class=BrachistochroneArclengthODE,
                          transcription=tx1)

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

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

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

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

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

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

        # Minimize arclength at the end of the second phase
        phase1.add_objective('S', loc='final', ref=1)

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

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

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

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

        dm.run_problem(p)

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

        fig, (ax0, ax1) = plt.subplots(2, 1)
        fig.tight_layout()
        ax0.plot(p.get_val('phase0.timeseries.states:x'),
                 p.get_val('phase0.timeseries.states:y'), '.')
        ax0.set_xlabel('x (m)')
        ax0.set_ylabel('y (m)')
        ax1.plot(p.get_val('phase1.timeseries.time'),
                 p.get_val('phase1.timeseries.states:S'), '+')
        ax1.set_xlabel('t (s)')
        ax1.set_ylabel('S (m)')
        plt.show()
Esempio n. 10
0
    def test_double_integrator_for_docs(self):
        import matplotlib.pyplot as plt
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_rel_error
        import dymos as dm
        from dymos.examples.plotting import plot_results
        from dymos.examples.double_integrator.double_integrator_ode import DoubleIntegratorODE

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

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

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

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

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

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

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

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

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

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

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

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

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

        plt.show()
Esempio n. 11
0
def eval_ode_on_grid(phase, transcription):
    """
    Evaluate the ODE from the given phase at all nodes of the given transcription.

    Parameters
    ----------
    phase : Phase
        A Phase object which has been executed and whose ODE is to be run at all nodes
        of the given transcription.
    transcription : Radau or GaussLobatto transcription instance
        The transcription object at which to execute the ODE of the given phase at all nodes.

    Returns
    -------
    dict of (str: ndarray)
        A dictionary of the state values from the phase interpolated to the new transcription.
    dict of (str: ndarray)
        A dictionary of the control values from the phase interpolated to the new transcription.
    dict of (str: ndarray)
        A dictionary of the polynomial control values from the phase interpolated to the new transcription.
    dict of (str: ndarray)
        A dictionary of the state rates computed in the phase's ODE at the new transcription points.
    """
    x = {}
    u = {}
    u_rate = {}
    u_rate2 = {}
    p = {}
    p_rate = {}
    p_rate2 = {}
    param = {}
    f = {}

    # Build the interpolation matrix which interpolates from all nodes on the old grid to
    # all nodes on the new grid.
    grid_data = transcription.grid_data
    L, _ = interpolation_lagrange_matrix(old_grid=phase.options['transcription'].grid_data,
                                         new_grid=grid_data)

    # Create a new problem for the grid_refinement
    # For this test, use the same grid as the original problem.
    p_refine = om.Problem(model=om.Group())
    grid_refinement_system = GridRefinementODESystem(grid_data=grid_data,
                                                     time=phase.time_options,
                                                     states=phase.state_options,
                                                     controls=phase.control_options,
                                                     polynomial_controls=phase.polynomial_control_options,
                                                     parameters=phase.parameter_options,
                                                     ode_class=phase.options['ode_class'],
                                                     ode_init_kwargs=phase.options[
                                                         'ode_init_kwargs'])
    p_refine.model.add_subsystem('grid_refinement_system', grid_refinement_system, promotes=['*'])
    p_refine.setup()

    # Set the values in the refinement problem using the outputs from the first
    ode = p_refine.model.grid_refinement_system.ode

    t_prev = phase.get_val('timeseries.time', units=phase.time_options['units'])
    t_phase_prev = phase.get_val('timeseries.time_phase', units=phase.time_options['units'])
    t_initial = np.repeat(t_prev[0, 0], repeats=transcription.grid_data.num_nodes, axis=0)
    t_duration = np.repeat(t_prev[-1, 0], repeats=transcription.grid_data.num_nodes, axis=0)
    t = np.dot(L, t_prev)
    t_phase = np.dot(L, t_phase_prev)
    targets = get_targets(ode, 'time', phase.time_options['targets'])
    time_phase_targets = get_targets(ode, 'time_phase', phase.time_options['time_phase_targets'])
    t_initial_targets = get_targets(ode, 't_initial', phase.time_options['t_initial_targets'])
    t_duration_targets = get_targets(ode, 't_duration', phase.time_options['t_duration_targets'])
    if targets:
        p_refine.set_val(f'time', t)
    if time_phase_targets:
        p_refine.set_val(f'time_phase', t_phase)
    if t_initial_targets:
        p_refine.set_val(f't_initial', t_initial)
    if t_duration_targets:
        p_refine.set_val(f't_duration', t_duration)

    for name, options in phase.state_options.items():
        x_prev = phase.get_val(f'timeseries.states:{name}', units=options['units'])
        x[name] = np.dot(L, x_prev)
        targets = get_targets(ode, name, options['targets'])
        if targets:
            p_refine.set_val(f'states:{name}', x[name])

    for name, options in phase.control_options.items():
        targets = get_targets(ode, name, options['targets'])
        rate_targets = get_targets(ode, f'{name}_rate', options['rate_targets'])
        rate2_targets = get_targets(ode, f'{name}_rate12', options['rate2_targets'])

        u_prev = phase.get_val(f'timeseries.controls:{name}', units=options['units'])
        u[name] = np.dot(L, u_prev)
        if targets:
            p_refine.set_val(f'controls:{name}', u[name])

        u_rate_prev = phase.get_val(f'timeseries.control_rates:{name}_rate')
        u_rate[name] = np.dot(L, u_rate_prev)
        if rate_targets:
            p_refine.set_val(f'control_rates:{name}_rate', u_rate[name])

        u_rate2_prev = phase.get_val(f'timeseries.control_rates:{name}_rate2')
        u_rate2[name] = np.dot(L, u_rate2_prev)
        if rate2_targets:
            p_refine.set_val(f'control_rates:{name}_rate2', u_rate2[name])

    for name, options in phase.polynomial_control_options.items():
        targets = get_targets(ode, name, options['targets'])
        rate_targets = get_targets(ode, f'{name}_rate', options['rate_targets'])
        rate2_targets = get_targets(ode, f'{name}_rate2', options['rate2_targets'])

        p_prev = phase.get_val(f'timeseries.polynomial_controls:{name}', units=options['units'])
        p[name] = np.dot(L, p_prev)
        if targets:
            p_refine.set_val(f'polynomial_controls:{name}', p[name])

        p_rate_prev = phase.get_val(f'timeseries.polynomial_control_rates:{name}_rate')
        p_rate[name] = np.dot(L, p_rate_prev)
        if rate_targets:
            p_refine.set_val(f'polynomial_control_rates:{name}_rate', p_rate[name])

        p_rate2_prev = phase.get_val(f'timeseries.polynomial_control_rates:{name}_rate2')
        p_rate2[name] = np.dot(L, p_rate2_prev)
        if rate2_targets:
            p_refine.set_val(f'polynomial_control_rates:{name}_rate2', p_rate2[name])

    # Configure the parameters
    for name, options in phase.parameter_options.items():
        targets = get_targets(ode, name, options['targets'])
        # The value of the parameter at one node
        d = phase.get_val(f'timeseries.parameters:{name}', units=options['units'])[0, ...]
        # Duplicate along the first axis by the number of nodes in the new transcription
        param[name] = np.atleast_2d(np.repeat(d, repeats=transcription.grid_data.num_nodes, axis=0))
        if targets:
            p_refine.set_val(f'parameters:{name}', param[name], units=options['units'])

    # Execute the model
    p_refine.run_model()

    # Assign the state rates on the new grid to f
    for name, options in phase.state_options.items():
        rate_units = get_rate_units(options['units'], phase.time_options['units'])
        rate_source = options['rate_source']
        rate_source_class = phase.classify_var(rate_source)
        if rate_source_class in {'time'}:
            src_units = phase.time_options['units']
            f[name] = om.convert_units(t, src_units, rate_units)
        elif rate_source_class in {'time_phase'}:
            src_units = phase.time_options['units']
            f[name] = om.convert_units(t_phase, src_units, rate_units)
        elif rate_source_class in {'state'}:
            src_units = phase.state_options[rate_source]['units']
            f[name] = om.convert_units(x[rate_source], src_units, rate_units)
        elif rate_source_class in {'input_control', 'indep_control'}:
            src_units = phase.control_options[rate_source]['units']
            f[name] = om.convert_units(u[rate_source], src_units, rate_units)
        elif rate_source_class in {'control_rate'}:
            u_name = rate_source[:-5]
            u_units = phase.control_options[u_name]['units']
            src_units = get_rate_units(u_units, phase.time_options['units'], deriv=1)
            f[name] = om.convert_units(u_rate[rate_source], src_units, rate_units)
        elif rate_source_class in {'control_rate2'}:
            u_name = rate_source[:-6]
            u_units = phase.control_options[u_name]['units']
            src_units = get_rate_units(u_units, phase.time_options['units'], deriv=2)
            f[name] = om.convert_units(u_rate2[rate_source], src_units, rate_units)
        elif rate_source_class in {'input_polynomial_control', 'indep_polynomial_control'}:
            src_units = phase.polynomial_control_options[rate_source]['units']
            f[name] = om.convert_units(p[rate_source], src_units, rate_units)
        elif rate_source_class in {'polynomial_control_rate'}:
            pc_name = rate_source[:-5]
            pc_units = phase.polynomial_control_options[pc_name]['units']
            src_units = get_rate_units(pc_units, phase.time_options['units'], deriv=1)
            f[name] = om.convert_units(p_rate[rate_source], src_units, rate_units)
        elif rate_source_class in {'polynomial_control_rate2'}:
            pc_name = rate_source[:-6]
            pc_units = phase.polynomial_control_options[pc_name]['units']
            src_units = get_rate_units(pc_units, phase.time_options['units'], deriv=2)
            f[name] = om.convert_units(p_rate2[rate_source], src_units, rate_units)
        elif rate_source_class in {'parameter'}:
            src_units = phase.parameter_options[rate_source]['units']
            f[name] = om.convert_units(param[rate_source], src_units, rate_units)
        elif rate_source_class in {'ode'}:
            f[name] = np.atleast_2d(p_refine.get_val(f'ode.{rate_source}', units=rate_units))

        if options['shape'] == (1,):
            f[name] = f[name].T

    return x, u, p, f
Esempio n. 12
0
def run_wisdem(fname_wt_input,
               fname_modeling_options,
               fname_opt_options,
               overridden_values=None):
    # Load all yaml inputs and validate (also fills in defaults)
    wt_initial = WindTurbineOntologyPython(fname_wt_input,
                                           fname_modeling_options,
                                           fname_opt_options)
    wt_init, modeling_options, opt_options = wt_initial.get_input_data()

    # Initialize openmdao problem. If running with multiple processors in MPI, use parallel finite differencing equal to the number of cores used.
    # Otherwise, initialize the WindPark system normally. Get the rank number for parallelization. We only print output files using the root processor.
    myopt = PoseOptimization(modeling_options, opt_options)

    if MPI:

        n_DV = myopt.get_number_design_variables()

        # Extract the number of cores available
        max_cores = MPI.COMM_WORLD.Get_size()

        if max_cores / 2.0 != np.round(max_cores / 2.0):
            raise ValueError(
                "ERROR: the parallelization logic only works for an even number of cores available"
            )

        # Define the color map for the parallelization, determining the maximum number of parallel finite difference (FD) evaluations based on the number of design variables (DV).
        n_FD = min([max_cores, n_DV])

        # Define the color map for the cores
        n_FD = max([n_FD, 1])
        comm_map_down, comm_map_up, color_map = map_comm_heirarchical(n_FD, 1)
        rank = MPI.COMM_WORLD.Get_rank()
        color_i = color_map[rank]
        comm_i = MPI.COMM_WORLD.Split(color_i, 1)
    else:
        color_i = 0
        rank = 0

    folder_output = opt_options["general"]["folder_output"]
    if rank == 0 and not os.path.isdir(folder_output):
        os.mkdir(folder_output)

    if color_i == 0:  # the top layer of cores enters
        if MPI:
            # Parallel settings for OpenMDAO
            wt_opt = om.Problem(model=om.Group(num_par_fd=n_FD), comm=comm_i)
            wt_opt.model.add_subsystem("comp",
                                       WindPark(
                                           modeling_options=modeling_options,
                                           opt_options=opt_options),
                                       promotes=["*"])
        else:
            # Sequential finite differencing
            wt_opt = om.Problem(model=WindPark(
                modeling_options=modeling_options, opt_options=opt_options))

        # If at least one of the design variables is active, setup an optimization
        if opt_options["opt_flag"]:
            wt_opt = myopt.set_driver(wt_opt)
            wt_opt = myopt.set_objective(wt_opt)
            wt_opt = myopt.set_design_variables(wt_opt, wt_init)
            wt_opt = myopt.set_constraints(wt_opt)
            wt_opt = myopt.set_recorders(wt_opt)

        # Setup openmdao problem
        wt_opt.setup()

        # Load initial wind turbine data from wt_initial to the openmdao problem
        wt_opt = yaml2openmdao(wt_opt, modeling_options, wt_init, opt_options)
        wt_opt = myopt.set_initial(wt_opt, wt_init)

        # If the user provides values in this dict, they overwrite
        # whatever values have been set by the yaml files.
        # This is useful for performing black-box wrapped optimization without
        # needing to modify the yaml files.
        if overridden_values is not None:
            for key in overridden_values:
                wt_opt[key][:] = overridden_values[key]

        # Place the last design variables from a previous run into the problem.
        # This needs to occur after the above setup() and yaml2openmdao() calls
        # so these values are correctly placed in the problem.
        wt_opt = myopt.set_restart(wt_opt)

        if "check_totals" in opt_options["driver"]:
            if opt_options["driver"]["check_totals"]:
                wt_opt.run_model()
                totals = wt_opt.compute_totals()

        if "check_partials" in opt_options["driver"]:
            if opt_options["driver"]["check_partials"]:
                wt_opt.run_model()
                checks = wt_opt.check_partials(compact_print=True)

        sys.stdout.flush()
        # Run openmdao problem
        if opt_options["opt_flag"]:
            wt_opt.run_driver()
        else:
            wt_opt.run_model()

        if (not MPI) or (MPI and rank == 0):
            # Save data coming from openmdao to an output yaml file
            froot_out = os.path.join(folder_output,
                                     opt_options["general"]["fname_output"])
            wt_initial.write_ontology(wt_opt, froot_out)
            wt_initial.write_options(froot_out)

            # Save data to numpy and matlab arrays
            fileIO.save_data(froot_out, wt_opt)

    if rank == 0:
        return wt_opt, modeling_options, opt_options
    else:
        return [], [], []
Esempio n. 13
0
    def test_control_interp_scalar(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': {
                'units': 'm',
                'shape': (1, ),
                'dynamic': True
            },
            'b': {
                'units': 'm',
                'shape': (1, ),
                'dynamic': True
            }
        }

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

        ivc.add_output('controls:a',
                       val=np.zeros((gd.subset_num_nodes['control_input'], 1)),
                       units='m')

        ivc.add_output('controls:b',
                       val=np.zeros((gd.subset_num_nodes['control_input'], 1)),
                       units='m')

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

        p.model.add_subsystem('control_interp_comp',
                              subsys=ControlInterpComp(
                                  grid_data=gd,
                                  control_options=controls,
                                  time_units='s'),
                              promotes_inputs=['controls:*'])

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

        t = p['time']
        p['controls:a'][:, 0] = f_a(t[gd.subset_node_indices['control_input']])
        p['controls:b'][:, 0] = f_b(t[gd.subset_node_indices['control_input']])

        p.run_model()

        a_value_expected = f_a(t)
        b_value_expected = f_b(t)

        a_rate_expected = f1_a(t)
        b_rate_expected = f1_b(t)

        a_rate2_expected = f2_a(t)
        b_rate2_expected = f2_b(t)

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

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

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

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

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

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

        np.set_printoptions(linewidth=1024)
        cpd = p.check_partials(compact_print=False, method='cs')
        assert_check_partials(cpd)
Esempio n. 14
0
    def test_control_interp_matrix_2x2(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': {'units': 'm', 'shape': (2, 2), 'dynamic': True}}

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

        ivc.add_output('controls:a',
                       val=np.zeros(
                           (gd.subset_num_nodes['control_input'], 2, 2)),
                       units='m')
        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'])

        p.model.add_subsystem('control_interp_comp',
                              subsys=ControlInterpComp(
                                  grid_data=gd,
                                  control_options=controls,
                                  time_units='s'),
                              promotes_inputs=['controls:*'])

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

        t = p['time']
        control_input_idxs = gd.subset_node_indices['control_input']
        p['controls:a'][:, 0, 0] = f_a(t[control_input_idxs])
        p['controls:a'][:, 0, 1] = f_b(t[control_input_idxs])
        p['controls:a'][:, 1, 0] = f_c(t[control_input_idxs])
        p['controls:a'][:, 1, 1] = f_d(t[control_input_idxs])

        p.run_model()

        a0_value_expected = f_a(t)
        a1_value_expected = f_b(t)
        a2_value_expected = f_c(t)
        a3_value_expected = f_d(t)

        a0_rate_expected = f1_a(t)
        a1_rate_expected = f1_b(t)
        a2_rate_expected = f1_c(t)
        a3_rate_expected = f1_d(t)

        a0_rate2_expected = f2_a(t)
        a1_rate2_expected = f2_b(t)
        a2_rate2_expected = f2_c(t)
        a3_rate2_expected = f2_d(t)

        assert_almost_equal(p['control_interp_comp.control_values:a'][:, 0, 0],
                            a0_value_expected)

        assert_almost_equal(p['control_interp_comp.control_values:a'][:, 0, 1],
                            a1_value_expected)

        assert_almost_equal(p['control_interp_comp.control_values:a'][:, 1, 0],
                            a2_value_expected)

        assert_almost_equal(p['control_interp_comp.control_values:a'][:, 1, 1],
                            a3_value_expected)

        assert_almost_equal(
            p['control_interp_comp.control_rates:a_rate'][:, 0, 0],
            a0_rate_expected)

        assert_almost_equal(
            p['control_interp_comp.control_rates:a_rate'][:, 0, 1],
            a1_rate_expected)

        assert_almost_equal(
            p['control_interp_comp.control_rates:a_rate'][:, 1, 0],
            a2_rate_expected)

        assert_almost_equal(
            p['control_interp_comp.control_rates:a_rate'][:, 1, 1],
            a3_rate_expected)

        assert_almost_equal(
            p['control_interp_comp.control_rates:a_rate2'][:, 0, 0],
            a0_rate2_expected)

        assert_almost_equal(
            p['control_interp_comp.control_rates:a_rate2'][:, 0, 1],
            a1_rate2_expected)

        assert_almost_equal(
            p['control_interp_comp.control_rates:a_rate2'][:, 1, 0],
            a2_rate2_expected)

        assert_almost_equal(
            p['control_interp_comp.control_rates:a_rate2'][:, 1, 1],
            a3_rate2_expected)

        with np.printoptions(linewidth=100000, edgeitems=100000):
            cpd = p.check_partials(compact_print=True, method='cs')

        assert_check_partials(cpd)
Esempio n. 15
0
    def test_simulate_array_param(self):
        #
        # Initialize the Problem and the optimization driver
        #
        p = om.Problem(model=om.Group())
        p.driver = om.ScipyOptimizeDriver()
        p.driver.declare_coloring()

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

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

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

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

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

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

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

        #
        # Setup the Problem
        #
        p.setup()

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

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

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

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

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

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

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

        assert_near_equal(sol - sim, np.zeros_like(sol))
Esempio n. 16
0
    def test_doc_ssto_earth(self):
        import matplotlib.pyplot as plt
        import openmdao.api as om
        import dymos as dm

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

        from dymos.examples.ssto.launch_vehicle_ode import LaunchVehicleODE

        #
        # Initialize our Trajectory and Phase
        #
        traj = dm.Trajectory()

        phase = dm.Phase(ode_class=LaunchVehicleODE,
                         ode_init_kwargs={'central_body': 'earth'},
                         transcription=dm.GaussLobatto(num_segments=12, order=3, compressed=False))

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

        #
        # Set the options for the variables
        #
        phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(10, 500))

        phase.add_state('x', fix_initial=True, ref=1.0E5, defect_ref=1.0,
                        rate_source='eom.xdot', units='m')
        phase.add_state('y', fix_initial=True, ref=1.0E5, defect_ref=1.0,
                        rate_source='eom.ydot', targets=['atmos.y'], units='m')
        phase.add_state('vx', fix_initial=True, ref=1.0E3, defect_ref=1.0,
                        rate_source='eom.vxdot', targets=['eom.vx'], units='m/s')
        phase.add_state('vy', fix_initial=True, ref=1.0E3, defect_ref=1.0,
                        rate_source='eom.vydot', targets=['eom.vy'], units='m/s')
        phase.add_state('m', fix_initial=True, ref=1.0E3, defect_ref=1.0,
                        rate_source='eom.mdot', targets=['eom.m'], units='kg')

        phase.add_control('theta', units='rad', lower=-1.57, upper=1.57, targets=['eom.theta'])
        phase.add_parameter('thrust', units='N', opt=False, val=2100000.0, targets=['eom.thrust'])

        #
        # Set the options for our constraints and objective
        #
        phase.add_boundary_constraint('y', loc='final', equals=1.85E5, linear=True)
        phase.add_boundary_constraint('vx', loc='final', equals=7796.6961)
        phase.add_boundary_constraint('vy', loc='final', equals=0)

        phase.add_objective('time', loc='final', scaler=0.01)

        p.model.linear_solver = om.DirectSolver()

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

        p.set_val('traj.phase0.t_initial', 0.0)
        p.set_val('traj.phase0.t_duration', 150.0)
        p.set_val('traj.phase0.states:x', phase.interpolate(ys=[0, 1.15E5], nodes='state_input'))
        p.set_val('traj.phase0.states:y', phase.interpolate(ys=[0, 1.85E5], nodes='state_input'))
        p.set_val('traj.phase0.states:vx', phase.interpolate(ys=[0, 7796.6961], nodes='state_input'))
        p.set_val('traj.phase0.states:vy', phase.interpolate(ys=[1.0E-6, 0], nodes='state_input'))
        p.set_val('traj.phase0.states:m', phase.interpolate(ys=[117000, 1163], nodes='state_input'))
        p.set_val('traj.phase0.controls:theta', phase.interpolate(ys=[1.5, -0.76], nodes='control_input'))
        p.set_val('traj.phase0.parameters:thrust', 2.1, units='MN')

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

        assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1], 143, tolerance=0.05)
        assert_near_equal(p.get_val('traj.phase0.timeseries.states:y')[-1], 1.85E5, 1e-4)
        assert_near_equal(p.get_val('traj.phase0.timeseries.states:vx')[-1], 7796.6961, 1e-4)
        assert_near_equal(p.get_val('traj.phase0.timeseries.states:vy')[-1], 0, 1e-4)
        #
        # Get the explicitly simulated results
        #
        exp_out = traj.simulate()

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

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

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

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

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

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

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

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

        plt.show()
Esempio n. 17
0
    def test_continuity_comp_vector_newton_fwd(self):
        num_seg = 2
        state_options = {
            'y': {
                'shape': (2, ),
                'units': 'm',
                'targets': ['y'],
                'fix_initial': True,
                'fix_final': False,
                'defect_ref': 1,
                'lower': None,
                'upper': None,
                'connected_initial': False
            }
        }

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

        p.model.add_subsystem('continuity_comp',
                              RungeKuttaStateContinuityComp(
                                  num_segments=num_seg,
                                  state_options=state_options),
                              promotes_inputs=['*'],
                              promotes_outputs=['*'])

        p.model.nonlinear_solver = om.NewtonSolver(iprint=2)
        p.model.linear_solver = om.DirectSolver()

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

        p['states:y'] = np.array([[0.50000000, 2.639602661132812],
                                  [1.425130208333333, 4.006818970044454],
                                  [2.639602661132812, 5.301605229265987]])

        p['state_integrals:y'] = np.array([[1.0, 1.0], [1.0, 1.0]])

        p.run_model()

        # Test that the residuals of the states are the expected values
        outputs = p.model.list_outputs(print_arrays=True,
                                       residuals=True,
                                       out_stream=None)
        expected_resids = np.zeros((num_seg + 1, 2))

        op_dict = dict([op for op in outputs])
        assert_rel_error(self, op_dict['continuity_comp.states:y']['resids'],
                         expected_resids)

        # Test the partials
        cpd = p.check_partials(method='cs', out_stream=None)

        J_fwd = cpd['continuity_comp']['states:y',
                                       'state_integrals:y']['J_fwd']
        J_rev = cpd['continuity_comp']['states:y',
                                       'state_integrals:y']['J_rev']
        J_fd = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_fd']
        assert_rel_error(self, J_fwd, J_rev)
        assert_rel_error(self, J_fwd, J_fd)

        J_fwd = cpd['continuity_comp']['states:y', 'states:y']['J_fwd']
        J_rev = cpd['continuity_comp']['states:y', 'states:y']['J_rev']
        J_fd = cpd['continuity_comp']['states:y', 'states:y']['J_fd']

        size = np.prod(state_options['y']['shape'])
        J_fd[:size, :size] = -np.eye(size)

        assert_rel_error(self, J_fwd, J_rev)
        assert_rel_error(self, J_fwd, J_fd)
Esempio n. 18
0
    def test_hyper_sensitive_for_docs(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm
        from dymos.examples.plotting import plot_results
        from dymos.examples.hyper_sensitive.hyper_sensitive_ode import HyperSensitiveODE

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

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

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

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

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

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

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

        p.setup(check=True)

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

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

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

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

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

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

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

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

        plt.show()
Esempio n. 19
0
    def test_simple_list_vars_options(self):
        import openmdao.api as om

        class QuadraticComp(om.ImplicitComponent):
            """
            A Simple Implicit Component representing a Quadratic Equation.

            R(a, b, c, x) = ax^2 + bx + c

            Solution via Quadratic Formula:
            x = (-b + sqrt(b^2 - 4ac)) / 2a
            """
            def setup(self):
                self.add_input('a', val=1., units='ft')
                self.add_input('b', val=1., units='inch')
                self.add_input('c', val=1., units='ft')
                self.add_output('x',
                                val=0.,
                                lower=1.0,
                                upper=100.0,
                                ref=1.1,
                                ref0=2.1,
                                units='inch')

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

            def apply_nonlinear(self, inputs, outputs, residuals):
                a = inputs['a']
                b = inputs['b']
                c = inputs['c']
                x = outputs['x']
                residuals['x'] = a * x**2 + b * x + c

            def solve_nonlinear(self, inputs, outputs):
                a = inputs['a']
                b = inputs['b']
                c = inputs['c']
                outputs['x'] = (-b + (b**2 - 4 * a * c)**0.5) / (2 * a)

        group = om.Group()

        comp1 = group.add_subsystem('comp1', om.IndepVarComp())
        comp1.add_output('a', 1.0, units='ft')
        comp1.add_output('b', 1.0, units='inch')
        comp1.add_output('c', 1.0, units='ft')

        sub = group.add_subsystem('sub', om.Group())
        sub.add_subsystem('comp2', QuadraticComp())
        sub.add_subsystem('comp3', QuadraticComp())

        group.connect('comp1.a', 'sub.comp2.a')
        group.connect('comp1.b', 'sub.comp2.b')
        group.connect('comp1.c', 'sub.comp2.c')

        group.connect('comp1.a', 'sub.comp3.a')
        group.connect('comp1.b', 'sub.comp3.b')
        group.connect('comp1.c', 'sub.comp3.c')

        global prob
        prob = om.Problem(model=group)
        prob.setup()

        prob['comp1.a'] = 1.
        prob['comp1.b'] = -4.
        prob['comp1.c'] = 3.
        prob.run_model()

        # list_inputs test
        stream = cStringIO()
        inputs = prob.model.list_inputs(values=False, out_stream=stream)
        text = stream.getvalue()
        self.assertEqual(sorted(inputs), [
            ('sub.comp2.a', {}),
            ('sub.comp2.b', {}),
            ('sub.comp2.c', {}),
            ('sub.comp3.a', {}),
            ('sub.comp3.b', {}),
            ('sub.comp3.c', {}),
        ])
        self.assertEqual(1, text.count("6 Input(s) in 'model'"))
        self.assertEqual(1, text.count("top"))
        self.assertEqual(1, text.count("  sub"))
        self.assertEqual(1, text.count("    comp2"))
        self.assertEqual(2, text.count("      a"))
        num_non_empty_lines = sum([1 for s in text.splitlines() if s.strip()])
        self.assertEqual(num_non_empty_lines, 14)

        # list_outputs tests
        # list implicit outputs
        outputs = prob.model.list_outputs(explicit=False, out_stream=None)
        text = stream.getvalue()
        self.assertEqual(sorted(outputs), [('sub.comp2.x', {
            'value': [3.]
        }), ('sub.comp3.x', {
            'value': [3.]
        })])
        # list explicit outputs
        stream = cStringIO()
        outputs = prob.model.list_outputs(implicit=False, out_stream=None)
        self.assertEqual(sorted(outputs), [
            ('comp1.a', {
                'value': [1.]
            }),
            ('comp1.b', {
                'value': [-4.]
            }),
            ('comp1.c', {
                'value': [3.]
            }),
        ])
Esempio n. 20
0
    def test_min_time_climb_for_docs_gauss_lobatto(self):
        import matplotlib.pyplot as plt

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

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

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

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

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

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

        traj.add_phase('phase0', phase)

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

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

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

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

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

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

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

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

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

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

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

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

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

        #
        # Test the results
        #
        assert_near_equal(p.get_val('traj.phase0.t_duration'),
                          321.0,
                          tolerance=1.0E-1)

        #
        # Get the explicitly simulated solution and plot the results
        #
        exp_out = traj.simulate()

        plot_results(
            [('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:h',
              'time (s)', 'altitude (m)'),
             ('traj.phase0.timeseries.time',
              'traj.phase0.timeseries.controls:alpha', 'time (s)',
              'alpha (deg)')],
            title='Supersonic Minimum Time-to-Climb Solution',
            p_sol=p,
            p_sim=exp_out)

        plt.show()
Esempio n. 21
0
        rows = np.arange(n_in)
        cols = rows
        self.declare_partials('GLs', 'k', rows=rows, cols=cols)

    def compute(self, inputs, outputs):
        SF = self.options['SF']
        outputs['GLs'] = SF * inputs['k']

    def compute_partials(self, inputs, partials):
        SF = self.options['SF']
        partials['GLs', 'k'] = SF


#for testing
if __name__ == "__main__":
    model = om.Group()
    n = 4
    SF = list(range(1, n))
    comp = om.IndepVarComp()
    comp.add_output('k', shape=n)

    model.add_subsystem('input', comp)
    model.add_subsystem('example', LinearCondComp(SF=SF))

    model.connect('input.k', 'example.k')

    problem = om.Problem(model=model)
    problem.setup()
    problem.run_model()
    totals = problem.compute_totals(['example.GLs'], ['input.k'])
Esempio n. 22
0
    def setup(self):
        surfaces = self.options['surfaces']
        rotational = self.options['rotational']

        coupled = om.Group()

        for surface in surfaces:

            name = surface['name']

            # Connect the output of the loads component with the FEM
            # displacement parameter. This links the coupling within the coupled
            # group that necessitates the subgroup solver.
            coupled.connect(name + '_loads.loads', name + '.loads')

            # Perform the connections with the modified names within the
            # 'aero_states' group.
            coupled.connect(name + '.normals',
                            'aero_states.' + name + '_normals')
            coupled.connect(name + '.def_mesh',
                            'aero_states.' + name + '_def_mesh')

            # Connect the results from 'coupled' to the performance groups
            coupled.connect(name + '.def_mesh', name + '_loads.def_mesh')
            coupled.connect('aero_states.' + name + '_sec_forces',
                            name + '_loads.sec_forces')

            # Connect the results from 'aero_states' to the performance groups
            self.connect('coupled.aero_states.' + name + '_sec_forces',
                         name + '_perf' + '.sec_forces')

            # Connection performance functional variables
            self.connect(name + '_perf.CL', 'total_perf.' + name + '_CL')
            self.connect(name + '_perf.CD', 'total_perf.' + name + '_CD')
            self.connect('coupled.aero_states.' + name + '_sec_forces',
                         'total_perf.' + name + '_sec_forces')
            self.connect('coupled.' + name + '.chords',
                         name + '_perf.aero_funcs.chords')

            # Connect parameters from the 'coupled' group to the performance
            # groups for the individual surfaces.
            self.connect('coupled.' + name + '.disp', name + '_perf.disp')
            self.connect('coupled.' + name + '.S_ref', name + '_perf.S_ref')
            self.connect('coupled.' + name + '.widths', name + '_perf.widths')
            # self.connect('coupled.' + name + '.chords', name + '_perf.chords')
            self.connect('coupled.' + name + '.lengths',
                         name + '_perf.lengths')
            self.connect('coupled.' + name + '.cos_sweep',
                         name + '_perf.cos_sweep')

            # Connect parameters from the 'coupled' group to the total performance group.
            self.connect('coupled.' + name + '.S_ref',
                         'total_perf.' + name + '_S_ref')
            self.connect('coupled.' + name + '.widths',
                         'total_perf.' + name + '_widths')
            self.connect('coupled.' + name + '.chords',
                         'total_perf.' + name + '_chords')
            self.connect('coupled.' + name + '.b_pts',
                         'total_perf.' + name + '_b_pts')

            # Add components to the 'coupled' group for each surface.
            # The 'coupled' group must contain all components and parameters
            # needed to converge the aerostructural system.
            coupled_AS_group = CoupledAS(surface=surface)

            if surface[
                    'distributed_fuel_weight'] or 'n_point_masses' in surface.keys(
                    ) or surface['struct_weight_relief']:
                prom_in = ['load_factor']
            else:
                prom_in = []

            coupled.add_subsystem(name,
                                  coupled_AS_group,
                                  promotes_inputs=prom_in)

        if self.options['compressible'] == True:
            aero_states = CompressibleVLMStates(surfaces=surfaces,
                                                rotational=rotational)
            prom_in = ['v', 'alpha', 'beta', 'rho', 'Mach_number']
        else:
            aero_states = VLMStates(surfaces=surfaces, rotational=rotational)
            prom_in = ['v', 'alpha', 'beta', 'rho']

        # Add a single 'aero_states' component for the whole system within the
        # coupled group.
        coupled.add_subsystem('aero_states',
                              aero_states,
                              promotes_inputs=prom_in)

        # Explicitly connect parameters from each surface's group and the common
        # 'aero_states' group.
        for surface in surfaces:
            name = surface['name']

            # Add a loads component to the coupled group
            coupled.add_subsystem(name + '_loads',
                                  LoadTransfer(surface=surface))
        """
        ### Change the solver settings here ###
        """

        # Set solver properties for the coupled group
        # coupled.linear_solver = ScipyKrylov()
        # coupled.linear_solver.precon = om.LinearRunOnce()

        coupled.nonlinear_solver = om.NonlinearBlockGS(use_aitken=True)
        coupled.nonlinear_solver.options['maxiter'] = 100
        coupled.nonlinear_solver.options['atol'] = 1e-7
        coupled.nonlinear_solver.options['rtol'] = 1e-30
        coupled.nonlinear_solver.options['iprint'] = 2
        coupled.nonlinear_solver.options['err_on_non_converge'] = True

        # coupled.linear_solver = om.DirectSolver()

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

        # coupled.nonlinear_solver = om.NewtonSolver(solve_subsystems=True)
        # coupled.nonlinear_solver.options['maxiter'] = 50
        """
        ### End change of solver settings ###
        """
        prom_in = ['v', 'alpha', 'beta', 'rho']
        if self.options['compressible'] == True:
            prom_in.append('Mach_number')

        # Add the coupled group to the model problem
        self.add_subsystem('coupled', coupled, promotes_inputs=prom_in)

        for surface in surfaces:
            name = surface['name']

            # Add a performance group which evaluates the data after solving
            # the coupled system
            perf_group = CoupledPerformance(surface=surface)

            self.add_subsystem(name + '_perf',
                               perf_group,
                               promotes_inputs=[
                                   'rho', 'v', 'alpha', 'beta', 're',
                                   'Mach_number'
                               ])

        # Add functionals to evaluate performance of the system.
        # Note that only the interesting results are promoted here; not all
        # of the parameters.
        self.add_subsystem(
            'total_perf',
            TotalPerformance(
                surfaces=surfaces,
                user_specified_Sref=self.options['user_specified_Sref'],
                internally_connect_fuelburn=self.
                options['internally_connect_fuelburn']),
            promotes_inputs=[
                'v', 'rho', 'empty_cg', 'total_weight', 'CT', 'speed_of_sound',
                'R', 'Mach_number', 'W0', 'load_factor', 'S_ref_total'
            ],
            promotes_outputs=[
                'L_equals_W', 'fuelburn', 'CL', 'CD', 'CM', 'cg'
            ])
    def test_connect_control_to_parameter(self):
        """ Test that the final value of a control in one phase can be connected as the value
        of a parameter in a subsequent phase. """
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal

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

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

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

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

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

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

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

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

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

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

        # All initial states except flight path angle are fixed
        # Final flight path angle is fixed (we will set it to zero so that the phase ends at apogee)

        ascent.set_time_options(fix_initial=True, duration_bounds=(1, 100), duration_ref=100, units='s')
        ascent.add_state('r', fix_initial=True, fix_final=False, rate_source='r_dot', units='m')
        ascent.add_state('h', fix_initial=True, fix_final=False, units='m', rate_source='h_dot')
        ascent.add_state('gam', fix_initial=False, fix_final=True, units='rad', rate_source='gam_dot')
        ascent.add_state('v', fix_initial=False, fix_final=False, units='m/s', rate_source='v_dot')

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

        ascent.add_control('CD', targets=['CD'], opt=False, val=0.05)

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

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

        traj.add_phase('descent', descent)

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

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

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

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

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

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

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

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

        traj.connect('ascent.timeseries.controls:CD', 'descent.parameters:CD', src_indices=[-1])

        # A linear solver at the top level can improve performance.
        p.model.linear_solver = om.DirectSolver()

        # Finish Problem Setup
        p.setup()

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

        p.set_val('traj.ascent.controls:CD', 0.5)

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

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

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

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

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

        assert_near_equal(p.get_val('traj.descent.states:r')[-1], 3183.25, tolerance=1.0E-2)
        assert_near_equal(p.get_val('traj.ascent.timeseries.controls:CD')[-1],
                          p.get_val('traj.descent.timeseries.parameters:CD')[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', units='V')
        phase0.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V')
        phase0.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A')
        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=True,
                         targets=['SOC'], rate_source='dXdt:SOC')
        phase1.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V')
        phase1.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V')
        phase1.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A')
        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=True,
                               targets=['SOC'], rate_source='dXdt:SOC')
        phase1_bfail.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V')
        phase1_bfail.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V')
        phase1_bfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A')
        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=True,
                               targets=['SOC'], rate_source='dXdt:SOC')
        phase1_mfail.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V')
        phase1_mfail.add_timeseries_output('battery.V_pack', output_name='V_pack', units='V')
        phase1_mfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li', units='A')
        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()
    def test_brachistochrone_polynomial_control_rate_targets_radau(self):
        import matplotlib.pyplot as plt
        plt.switch_backend('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()
        p.driver.declare_coloring()

        phase = dm.Phase(ode_class=BrachistochroneRateTargetODE,
                         transcription=dm.Radau(num_segments=10))

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

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

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

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

        phase.add_state('v',
                        rate_source='vdot',
                        units='m/s',
                        fix_initial=True,
                        fix_final=False,
                        solve_segments=False)

        phase.add_polynomial_control('theta',
                                     order=3,
                                     units='deg*s',
                                     lower=0.01,
                                     upper=179.9,
                                     rate_targets=['theta_rate'],
                                     fix_initial=True)

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

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

        p.model.linear_solver = om.DirectSolver()

        p.setup()

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

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

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

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

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

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

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

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

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

        fig, ax = plt.subplots()

        t_imp = p.get_val('phase0.timeseries.time')
        theta_imp = p.get_val(
            'phase0.timeseries.polynomial_control_rates:theta_rate')
        t_exp = exp_out.get_val('phase0.timeseries.time')
        theta_exp = exp_out.get_val(
            'phase0.timeseries.polynomial_control_rates:theta_rate')

        ax.plot(t_imp, theta_imp, 'ro', label='solution')
        ax.plot(t_exp, theta_exp, 'b-', label='simulated')

        ax.set_xlabel('time (s)')
        ax.set_ylabel(r'$\theta$ (deg)')
        ax.grid(True)
        ax.legend(loc='upper right')

        plt.show()
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_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.parameters:g'] = 9.80665

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

    return p
Esempio n. 27
0
    def test_rk4_scalar_no_iteration(self):
        num_seg = 4
        num_stages = 4
        state_options = {'y': {'shape': (1, ), 'units': 'm', 'targets': ['y']}}

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

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

        ivc.add_output('initial_states_per_seg:y',
                       shape=(num_seg, 1),
                       units='m')
        ivc.add_output('h', shape=(num_seg, 1), units='s')
        ivc.add_output('t', shape=(num_seg * num_stages, 1), units='s')

        p.model.add_subsystem(
            'k_iter_group',
            RungeKuttaKIterGroup(num_segments=num_seg,
                                 method='RK4',
                                 state_options=state_options,
                                 time_units='s',
                                 ode_class=TestODE,
                                 ode_init_kwargs={},
                                 solver_class=om.NonlinearRunOnce))

        p.model.connect('t', 'k_iter_group.ode.t')
        p.model.connect('h', 'k_iter_group.h')
        p.model.connect('initial_states_per_seg:y',
                        'k_iter_group.initial_states_per_seg:y')

        src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1))
        p.model.connect('k_iter_group.ode.ydot',
                        'k_iter_group.k_comp.f:y',
                        src_indices=src_idxs,
                        flat_src_indices=True)

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

        p['t'] = np.array([[
            0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, 1.00, 1.25, 1.25,
            1.50, 1.50, 1.75, 1.75, 2.00
        ]]).T

        p['h'] = np.array([[0.5, 0.5, 0.5, 0.5]]).T

        p['initial_states_per_seg:y'] = np.array([[0.50000000],
                                                  [1.425130208333333],
                                                  [2.639602661132812],
                                                  [4.006818970044454]])

        p['k_iter_group.k_comp.k:y'] = np.array([[[0.75000000], [0.90625000],
                                                  [0.94531250], [1.09765625]],
                                                 [[1.087565104166667],
                                                  [1.203206380208333],
                                                  [1.232116699218750],
                                                  [1.328623453776042]],
                                                 [[1.319801330566406],
                                                  [1.368501663208008],
                                                  [1.380676746368408],
                                                  [1.385139703750610]],
                                                 [[1.378409485022227],
                                                  [1.316761856277783],
                                                  [1.301349949091673],
                                                  [1.154084459568063]]])

        p.run_model()

        # Test that the residuals of k are zero (we started k at the expected converged value)
        outputs = p.model.list_outputs(print_arrays=True,
                                       residuals=True,
                                       out_stream=False)
        op_dict = dict([op for op in outputs])
        assert_almost_equal(op_dict['k_iter_group.k_comp.k:y']['resids'], 0.0)

        # Test the partials
        cpd = p.check_partials(method='cs', out_stream=None)
        assert_check_partials(cpd)
Esempio n. 28
0
    def test_run_HS_problem_radau(self):
        p = om.Problem(model=om.Group())
        p.driver = om.pyOptSparseDriver()
        p.driver.declare_coloring()
        p.driver.options['optimizer'] = optimizer

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

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

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

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

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

        p.setup(check=True)

        tf = np.float128(20)

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

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

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

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

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

        assert_near_equal(p.get_val('traj.phase0.timeseries.states:xL')[-1],
                          J,
                          tolerance=5e-4)
Esempio n. 29
0
def setup_problem(
        trans=dm.GaussLobatto(num_segments=10), polynomial_control=False):
    from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE
    from dymos.transcriptions.runge_kutta.runge_kutta import RungeKutta

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

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

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

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

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

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

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

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

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

    p.model.linear_solver = om.DirectSolver()

    # Recording
    rec = om.SqliteRecorder('brachistochrone_solution.db')
    p.driver.recording_options['record_desvars'] = True
    p.driver.recording_options['record_responses'] = True
    p.driver.recording_options['record_objectives'] = True
    p.driver.recording_options['record_constraints'] = True
    p.model.recording_options['record_metadata'] = True
    p.model.add_recorder(rec)

    p.setup()

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

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

    return p
Esempio n. 30
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),
                               units='s',
                               time_phase_targets=['time_phase'],
                               t_duration_targets=['t_duration'],
                               t_initial_targets=['t_initial'],
                               targets=['time'])

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

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

        phase.add_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(check=True)

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

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

        return p