Пример #1
0
    def test_brachistochrone_forward_shooting_path_constrained_time(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal
        import dymos as dm
        from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE

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

        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=dm.RungeKutta(num_segments=20))

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

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

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

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

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

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

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

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

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

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

        p.model.linear_solver = om.DirectSolver()

        p.setup(check=True)

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

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

        # Solve for the optimal trajectory
        p.run_driver()

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

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

        assert_near_equal(exp_out.get_val('phase0.timeseries.states:x')[-1, 0],
                          10,
                          tolerance=1.0E-3)
        assert_near_equal(exp_out.get_val('phase0.timeseries.states:y')[-1, 0],
                          5,
                          tolerance=1.0E-3)
Пример #2
0
    def test_list_inputs_outputs(self):
        prob = om.Problem()
        model = prob.model

        indep = model.add_subsystem('indep', om.IndepVarComp())
        indep.add_discrete_output('x', 11)

        model.add_subsystem('expl', ModCompEx(3))
        model.add_subsystem('impl', ModCompIm(3))

        model.connect('indep.x', ['expl.x', 'impl.x'])

        prob.setup()
        prob.run_model()

        #
        # list inputs, not hierarchical
        #
        stream = StringIO()
        prob.model.list_inputs(values=True,
                               hierarchical=False,
                               out_stream=stream)
        text = stream.getvalue()

        self.assertEqual(1, text.count("3 Input(s) in 'model'"))

        # make sure they are in the correct order
        self.assertTrue(
            text.find('expl.a') < text.find('expl.x') < text.find('impl.x'))

        #
        # list inputs, hierarchical
        #
        stream = StringIO()
        prob.model.list_inputs(values=True,
                               hierarchical=True,
                               out_stream=stream)
        text = stream.getvalue()

        self.assertEqual(1, text.count("3 Input(s) in 'model'"))
        self.assertEqual(1, text.count('top'))
        self.assertEqual(1, text.count('  expl'))
        self.assertEqual(1, text.count('    a'))
        self.assertEqual(1, text.count('  impl'))
        self.assertEqual(2, text.count('    x'))  # both implicit & explicit

        #
        # list outputs, not hierarchical
        #
        stream = StringIO()
        prob.model.list_outputs(values=True,
                                residuals=True,
                                hierarchical=False,
                                out_stream=stream)
        text = stream.getvalue()

        self.assertEqual(text.count('3 Explicit Output'), 1)
        self.assertEqual(text.count('1 Implicit Output'), 1)

        # make sure they are in the correct order
        self.assertTrue(
            text.find('indep.x') < text.find('expl.b') < text.find('expl.y') <
            text.find('impl.y'))

        #
        # list outputs, hierarchical
        #
        stream = StringIO()
        prob.model.list_outputs(values=True,
                                residuals=True,
                                hierarchical=True,
                                out_stream=stream)
        text = stream.getvalue()

        self.assertEqual(text.count('top'), 2)  # both implicit & explicit
        self.assertEqual(text.count('  indep'), 1)
        self.assertEqual(text.count('    x'), 1)
        self.assertEqual(text.count('  expl'), 1)
        self.assertEqual(text.count('    b'), 1)
        self.assertEqual(text.count('  impl'), 1)
        self.assertEqual(text.count('    y'), 2)  # both implicit & explicit
    def make_problem(self,
                     transcription='radau-ps',
                     num_segments=5,
                     transcription_order=3,
                     compressed=True):

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

        p.driver = om.ScipyOptimizeDriver()
        p.driver.declare_coloring()

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

        phase.set_refine_options(refine=True, tol=1.0E-6)

        traj.add_phase('phase0', phase)

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

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

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

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

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

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

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

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

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

        return p
    def test_static_params(self):
        prob = om.Problem(model=om.Group())

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

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

        P_DEMAND = 2.0

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

        # Second phase: normal operation.

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

        # Second phase, but with battery failure.

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

        # Second phase, but with motor failure.

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

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

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

        prob.setup()
        prob.final_setup()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            plt.show()
Пример #5
0
        ar = np.arange(nn, dtype=int)
        self.declare_partials(of='y_dot', wrt='vy', rows=ar, cols=ar, val=1.0)

    def compute(self,
                inputs,
                outputs,
                discrete_inputs=None,
                discrete_outputs=None):
        vy = inputs['vy']
        outputs['y_dot'] = vy
        outputs['vy_dot'] = -9.80665


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

prob.driver = om.ScipyOptimizeDriver()
prob.driver.add_recorder(om.SqliteRecorder('collocation_figures.db'))
prob.driver.recording_options['includes'] = [
    '*dstau*', '*rhs_col*', '*staterate*', '*timeseries*', '*timeseries2*',
    '*rhs_disc*'
]

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

# Instantiate a Phase and add it to the Trajectory.
phase = dm.Phase(ode_class=FallEOM,
                 transcription=dm.GaussLobatto(num_segments=NUM_SEG,
Пример #6
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_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
Пример #7
0
    def test_ccblade_loads(self):
        prob = om.Problem()
        
        # Load in airfoil and blade shape inputs for NREL 5MW
        npzfile = np.load(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + 'smaller_dataset.npz', allow_pickle=True)
        
        n_span = npzfile['r'].size
        n_aoa = npzfile['aoa'].size
        n_Re = npzfile['Re'].size
            
        modeling_options = {}
        modeling_options['blade'] = {}
        modeling_options['blade']['n_span'] = n_span
        modeling_options['blade']['n_aoa'] = n_aoa
        modeling_options['blade']['n_Re'] = n_Re
        modeling_options['blade']['n_tab'] = 1
    
        n_span, n_aoa, n_Re, n_tab = np.moveaxis(npzfile['cl'][:,:,:,np.newaxis], 0, 1).shape
        modeling_options['airfoils'] = {}
        modeling_options['airfoils']['n_aoa'] = n_aoa
        modeling_options['airfoils']['n_Re'] = n_Re
        modeling_options['airfoils']['n_tab'] = n_tab
    
        comp = CCBladeLoads(modeling_options=modeling_options)
        prob.model.add_subsystem('comp', comp, promotes=['*'])
    
        prob.setup(force_alloc_complex=True)
        
        # Add some arbitrary inputs        
        prob.set_val('airfoils_aoa', npzfile['aoa'], units='deg')
        prob.set_val('airfoils_Re', npzfile['Re'])
        prob.set_val('airfoils_cl', np.moveaxis(npzfile['cl'][:,:,:,np.newaxis], 0, 1))
        prob.set_val('airfoils_cd', np.moveaxis(npzfile['cd'][:,:,:,np.newaxis], 0, 1))
        prob.set_val('airfoils_cm', np.moveaxis(npzfile['cm'][:,:,:,np.newaxis], 0, 1))
        prob.set_val('r', npzfile['r'], units='m')
        prob.set_val('chord', npzfile['chord'], units='m')
        prob.set_val('theta', npzfile['theta'], units='deg')
    

    
        # parameters
        prob.set_val('V_load', 12., units='m/s')
        prob.set_val('Omega_load', 7.0, units='rpm')
        prob.set_val('pitch_load', 2.0, units='deg')
        prob.set_val('azimuth_load', 3.0, units='deg')
    
        prob.set_val('Rhub', 1., units='m')
        prob.set_val('Rtip', 70., units='m')
        prob.set_val('hub_height', 100., units='m')
        prob.set_val('precone', 0., units='deg')
        prob.set_val('tilt', 0., units='deg')
        prob.set_val('yaw', 0., units='deg')
        prob.set_val('precurve', np.zeros(n_span), units='m')
        prob.set_val('precurveTip', 0., units='m')
    
        prob.set_val('rho', 1.225, units='kg/m**3')
        prob.set_val('mu', 1.81206e-5, units='kg/(m*s)')
        prob.set_val('shearExp', 0.25)
        prob.set_val('nBlades', 3)
        prob.set_val('nSector', 4)
        prob.set_val('tiploss', True)
        prob.set_val('hubloss', True)
        prob.set_val('wakerotation', True)
        prob.set_val('usecd', True)
    
        prob.run_model()
    
        check = prob.check_partials(out_stream=None, compact_print=True)
    
        # Manually filter some entries out of the assert_check_partials call.
        # Will want to add this functionality to OpenMDAO itself at some point.
        new_check = {}
        for comp_name in check:
            new_check[comp_name] = {}
            for (output_name, input_name) in check[comp_name]:
                if 'airfoil' not in input_name and 'rho' not in input_name and 'mu' not in input_name and 'shearExp' not in input_name:
                    new_check[comp_name][(output_name, input_name)] = check[comp_name][(output_name, input_name)]
    
        assert_check_partials(new_check, rtol=5e-5, atol=1e-4)
Пример #8
0
        n_xsecs = degen_obj.surf.num_secs

        points = np.empty((npts * n_xsecs, 3))
        points[:, 0] = list(itertools.chain.from_iterable(degen_obj.surf.x))
        points[:, 1] = list(itertools.chain.from_iterable(degen_obj.surf.y))
        points[:, 2] = list(itertools.chain.from_iterable(degen_obj.surf.z))

        return points


if __name__ == "__main__":
    from openmdao.api import DirectSolver, NewtonSolver, BoundsEnforceLS

    vsp_comp = VSPeCRM(horiz_tail_name="Tail", vert_tail_name="VerticalTail", wing_name="Wing")

    p = om.Problem()

    model = p.model
    #newton = model.nonlinear_solver = NewtonSolver()
    #newton.options['iprint'] = 2
    #newton.options['maxiter'] = 100
    #newton.options['solve_subsystems'] = True
    #newton.options['atol'] = 1e-7
    #newton.options['rtol'] = 1e-15
    #newton.options['err_on_non_converge'] = True

    #model.linear_solver = DirectSolver()
    #ls = newton.linesearch = BoundsEnforceLS()
    #ls.options['iprint'] = 2
    #ls.options['print_bound_enforce'] = True
    #ls.options['bound_enforcement'] = 'scalar'
Пример #9
0
    def test_two_phase_cannonball_for_docs(self):
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        traj.add_phase('descent', descent)

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

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

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

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

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

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

        # Link Phases (link time and all state variables)
        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')

        # 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.parameters:CD', 0.5)
        p.set_val('traj.parameters:CL', 0.0)
        p.set_val('traj.parameters:T', 0.0)

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

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

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

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

        dm.run_problem(p)

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

        exp_out = traj.simulate()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            axes[i].set_ylabel(state)

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

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

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

            axes[i].set_ylabel(param)

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

        plt.show()
    def test_finite_burn_orbit_raise(self):
        import numpy as np
        import matplotlib.pyplot as plt
        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_near_equal

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

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

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

        traj = dm.Trajectory()

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

        # First Phase (burn)

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

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

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

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

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

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

        traj.add_phase('coast', coast)
        traj.add_phase('burn2', burn2)

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

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

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

        burn1.add_timeseries_output('pos_x')
        coast.add_timeseries_output('pos_x')
        burn2.add_timeseries_output('pos_x')

        burn1.add_timeseries_output('pos_y')
        coast.add_timeseries_output('pos_y')
        burn2.add_timeseries_output('pos_y')

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

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

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

        # Finish Problem Setup

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

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

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

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

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

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

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

        p.set_val('traj.coast.states:r', value=coast.interp('r', [1.3, 1.5]))
        p.set_val('traj.coast.states:theta', value=coast.interp('theta', [2.1767, 1.7]))
        p.set_val('traj.coast.states:vr', value=coast.interp('vr', [0.3285, 0]))
        p.set_val('traj.coast.states:vt', value=coast.interp('vt', [0.97, 1]))
        p.set_val('traj.coast.states:accel', value=coast.interp('accel', [0, 0]))

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

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

        p.set_val('traj.burn2.controls:u1', value=burn2.interp('u1', [0, 0]))

        dm.run_problem(p)

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

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

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

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

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

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

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

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

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

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

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

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

        plt.show()
    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',
                             static_target=True)
        ascent.add_parameter('mass',
                             targets=['m'],
                             units='kg',
                             static_target=True)

        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',
                              static_target=True)
        descent.add_parameter('mass',
                              targets=['m'],
                              units='kg',
                              static_target=True)
        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'
                           },
                           static_target=True)

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

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

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

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

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

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

        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])
Пример #12
0
    def test_partial_deriv_plot(self):

        class ArrayComp2D(om.ExplicitComponent):
            """
            A fairly simple array component with an intentional error in compute_partials.
            """
            def setup(self):
                self.JJ = np.array([[1.0, 0.0, 0.0, 7.0],
                                    [0.0, 2.5, 0.0, 0.0],
                                    [-1.0, 0.0, 8.0, 0.0],
                                    [0.0, 4.0, 0.0, 6.0]])
                # Params
                self.add_input('x1', np.zeros([4]))
                # Unknowns
                self.add_output('y1', np.zeros([4]))
                self.declare_partials(of='*', wrt='*')
            def compute(self, inputs, outputs):
                """
                Execution.
                """
                outputs['y1'] = self.JJ.dot(inputs['x1'])
            def compute_partials(self, inputs, partials):
                """
                Analytical derivatives.
                """
                # create some error to force the diff plot to show something
                error = np.zeros((4,4))
                err = 1e-7
                error[0][3] = err
                error[1][2] = - 2.0 * err
                partials[('y1', 'x1')] = self.JJ + error

        prob = om.Problem()
        model = prob.model
        model.add_subsystem('x_param1', om.IndepVarComp('x1', np.ones((4))), promotes=['x1'])
        model.add_subsystem('mycomp', ArrayComp2D(), promotes=['x1', 'y1'])
        prob.setup(check=False, mode='fwd')
        check_partials_data = prob.check_partials(out_stream=None)

        # plot with defaults
        fig, ax = om.partial_deriv_plot('y1', 'x1', check_partials_data, title="Defaults")
        # Instead of seeing if the images created by matplotlib match what we expect, which
        # is a fragile thing to do in testing, check a data structure inside matplotlib's
        # objects. We will assume matplotlib draws the correct thing.
        expected_array = np.array([[1., 0., 0., 1.],
                                   [0., 1., 0., 0.],
                                   [1., 0., 1., 0.],
                                   [0., 1., 0., 1.]])
        actual_array = ax[0].images[0]._A.data
        assert_near_equal(expected_array, actual_array, 1e-8)
        expected_array = np.array([[ 1.,  0.,  0.,  1.],
                                   [ 0.,  1.,  1.,  0.],
                                   [ 1.,  0.,  1.,  0.],
                                   [ 0.,  1.,  0.,  1.]])
        actual_array = ax[1].images[0]._A.data
        assert_near_equal(expected_array, actual_array, 1e-8)
        expected_array = np.array([[  9.31322575e-10,   0.0,   0.0, 1.0e-07],
                                   [  0.0,   0.0,  -2.0e-07, 0.0],
                                   [  0.0,   0.0,   9.31322575e-10, 0.0],
                                   [  0.0,   0.0,   0.0, 1.86264515e-09]])
        actual_array = ax[2].images[0]._A.data
        assert_near_equal(expected_array, actual_array, 1e-8)

        # plot with specified jac_method
        fig, ax = om.partial_deriv_plot('y1', 'x1', check_partials_data, jac_method = "J_rev",
                                        title="specified jac_method")
        expected_array = np.array([[1., 0., 0., 1.],
                                   [0., 1., 0., 0.],
                                   [1., 0., 1., 0.],
                                   [0., 1., 0., 1.]])
        actual_array = ax[0].images[0]._A.data
        assert_near_equal(expected_array, actual_array, 1e-8)
        expected_array = np.array([[ 1.,  0.,  0.,  1.],
                                   [ 0.,  1.,  1.,  0.],
                                   [ 1.,  0.,  1.,  0.],
                                   [ 0.,  1.,  0.,  1.]])
        actual_array = ax[1].images[0]._A.data
        assert_near_equal(expected_array, actual_array, 1e-8)
        expected_array = np.array([[  9.31322575e-10,   0.0,   0.0, 1.0e-07],
                                   [  0.0,   0.0,  -2.0e-07, 0.0],
                                   [  0.0,   0.0,   9.31322575e-10, 0.0],
                                   [  0.0,   0.0,   0.0, 1.86264515e-09]])
        actual_array = ax[2].images[0]._A.data
        assert_near_equal(expected_array, actual_array, 1e-8)

        # plot in non-binary mode
        fig, ax = om.partial_deriv_plot('y1', 'x1', check_partials_data, binary = False,
                                        title="non-binary")
        expected_array = np.array([[ 1. ,  0. ,  0. ,  7. ],
                                   [ 0. ,  2.5,  0. ,  0. ],
                                   [-1. ,  0. ,  8. ,  0. ],
                                   [ 0. ,  4. ,  0. ,  6. ]])
        actual_array = ax[0].images[0]._A.data
        assert_near_equal(expected_array, actual_array, 1e-8)
        expected_array = np.array([[  1.0e+00,   0.0,   0.0, 7.00000010e+00],
                                   [  0.0,   2.5e+00,  -2.0e-07, 0.0],
                                   [ -1.0e+00,   0.0,   8.0e+00, 0.0],
                                   [  0.0,   4.0e+00,   0.0, 6.0e+00]])
        actual_array = ax[1].images[0]._A.data
        assert_near_equal(expected_array, actual_array, 1e-8)
        expected_array = np.array([[  9.31322575e-10,   0.0,   0.0, 1.0e-07],
                                   [  0.0,   0.0,  -2.0e-07, 0.0],
                                   [  0.0,   0.0,   9.31322575e-10, 0.0],
                                   [  0.0,   0.0,   0.0, 1.86264515e-09]])
        actual_array = ax[2].images[0]._A.data
        assert_near_equal(expected_array, actual_array, 1e-8)

        # plot with different tol values
        # Not obvious how to test this other than image matching
        om.partial_deriv_plot('y1', 'x1', check_partials_data, tol=1e-5,
                              title="tol greater than err")
        om.partial_deriv_plot('y1', 'x1', check_partials_data, tol=1e-10,
                              title="tol less than err")
Пример #13
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(tol=1.0E-12)

        from dymos.examples.ssto.launch_vehicle_ode import LaunchVehicleODE

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

        phase = dm.Phase(ode_class=LaunchVehicleODE,
                         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(fix_initial=True, duration_bounds=(10, 500))

        phase.add_state('x',
                        fix_initial=True,
                        ref=1.0E5,
                        defect_ref=10000.0,
                        rate_source='xdot')
        phase.add_state('y',
                        fix_initial=True,
                        ref=1.0E5,
                        defect_ref=10000.0,
                        rate_source='ydot')
        phase.add_state('vx',
                        fix_initial=True,
                        ref=1.0E3,
                        defect_ref=1000.0,
                        rate_source='vxdot')
        phase.add_state('vy',
                        fix_initial=True,
                        ref=1.0E3,
                        defect_ref=1000.0,
                        rate_source='vydot')
        phase.add_state('m',
                        fix_initial=True,
                        ref=1.0E3,
                        defect_ref=100.0,
                        rate_source='mdot')

        phase.add_control('theta',
                          units='rad',
                          lower=-1.57,
                          upper=1.57,
                          targets=['theta'])
        phase.add_parameter('thrust',
                            units='N',
                            opt=False,
                            val=2100000.0,
                            targets=['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.interp('x', [0, 1.15E5]))
        p.set_val('traj.phase0.states:y', phase.interp('y', [0, 1.85E5]))
        p.set_val('traj.phase0.states:vy', phase.interp('vx', [1.0E-6, 0]))
        p.set_val('traj.phase0.states:m', phase.interp('vy', [117000, 1163]))
        p.set_val('traj.phase0.controls:theta',
                  phase.interp('theta', [1.5, -0.76]))
        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()
    def test_brachistochrone_external_control(self):
        import numpy as np
        import openmdao.api as om
        import dymos as dm
        from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt

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

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

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

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

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

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

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

        #
        # Define a Dymos Phase object with GaussLobatto Transcription
        #
        phase = dm.Phase(ode_class=BrachistochroneODE,
                         transcription=tx)

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

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

        #
        # Set the time options
        # Initial values of positions and velocity are all fixed.
        # The final value of position are fixed, but the final velocity is a free variable.
        # The equations of motion are not functions of position, so 'x' and 'y' have no targets.
        # The rate source points to the output in the ODE which provides the time derivative of the
        # given state.
        phase.add_state('x', fix_initial=True, fix_final=True, 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.
        # Use opt=False to allow it to be connected to an external source.
        # Arguments lower and upper are no longer valid for an input control.
        phase.add_control(name='theta', units='rad', targets=['theta'], opt=False)

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

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

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

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

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

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

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

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

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

        # 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()
Пример #15
0
    def test_units_with_scaling(self):
        prob = om.Problem()
        model = prob.model

        ivc = om.IndepVarComp()
        ivc.add_output('x', 35.0, units='degF')

        model.add_subsystem('p', ivc, promotes=['x'])
        model.add_subsystem('comp1',
                            om.ExecComp('y1 = 2.0*x',
                                        x={
                                            'value': 2.0,
                                            'units': 'degF'
                                        },
                                        y1={
                                            'value': 2.0,
                                            'units': 'degF'
                                        }),
                            promotes=['x', 'y1'])

        model.add_subsystem('comp2',
                            om.ExecComp('y2 = 3.0*x',
                                        x={
                                            'value': 2.0,
                                            'units': 'degF'
                                        },
                                        y2={
                                            'value': 2.0,
                                            'units': 'degF'
                                        }),
                            promotes=['x', 'y2'])

        model.add_design_var('x',
                             units='degC',
                             lower=0.0,
                             upper=100.0,
                             scaler=3.5,
                             adder=77.0)
        model.add_constraint('y1',
                             units='degC',
                             lower=0.0,
                             upper=100.0,
                             scaler=3.5,
                             adder=77.0)
        model.add_objective('y2', units='degC', scaler=3.5, adder=77.0)

        recorder = om.SqliteRecorder('cases.sql')
        prob.driver.add_recorder(recorder)

        prob.driver.recording_options['record_objectives'] = True
        prob.driver.recording_options['record_constraints'] = True
        prob.driver.recording_options['record_desvars'] = True

        prob.setup()

        prob.run_driver()

        dv = prob.driver.get_design_var_values()
        assert_near_equal(dv['p.x'][0], ((3.0 * 5 / 9) + 77.0) * 3.5, 1e-8)

        obj = prob.driver.get_objective_values(driver_scaling=True)
        assert_near_equal(obj['comp2.y2'][0], ((73.0 * 5 / 9) + 77.0) * 3.5,
                          1e-8)

        con = prob.driver.get_constraint_values(driver_scaling=True)
        assert_near_equal(con['comp1.y1'][0], ((38.0 * 5 / 9) + 77.0) * 3.5,
                          1e-8)

        meta = model.get_design_vars()
        assert_near_equal(meta['p.x']['lower'], ((0.0) + 77.0) * 3.5, 1e-7)
        assert_near_equal(meta['p.x']['upper'], ((100.0) + 77.0) * 3.5, 1e-7)

        meta = model.get_constraints()
        assert_near_equal(meta['comp1.y1']['lower'], ((0.0) + 77.0) * 3.5,
                          1e-7)
        assert_near_equal(meta['comp1.y1']['upper'], ((100.0) + 77.0) * 3.5,
                          1e-7)

        stdout = sys.stdout
        strout = StringIO()
        sys.stdout = strout
        try:
            prob.list_problem_vars(desvar_opts=['units'],
                                   objs_opts=['units'],
                                   cons_opts=['units'])
        finally:
            sys.stdout = stdout
        output = strout.getvalue().split('\n')

        self.assertTrue('275.33' in output[5])
        self.assertTrue('343.3888' in output[12])
        self.assertTrue('411.444' in output[19])
        self.assertTrue('degC' in output[5])
        self.assertTrue('degC' in output[12])
        self.assertTrue('degC' in output[19])

        totals = prob.check_totals(out_stream=None, driver_scaling=True)

        for key, val in totals.items():
            assert_near_equal(val['rel error'][0], 0.0, 1e-6)

        cr = om.CaseReader("cases.sql")
        cases = cr.list_cases('driver')
        case = cr.get_case(cases[0])

        dv = case.get_design_vars()
        assert_near_equal(dv['p.x'][0], ((3.0 * 5 / 9) + 77.0) * 3.5, 1e-8)

        obj = case.get_objectives()
        assert_near_equal(obj['comp2.y2'][0], ((73.0 * 5 / 9) + 77.0) * 3.5,
                          1e-8)

        con = case.get_constraints()
        assert_near_equal(con['comp1.y1'][0], ((38.0 * 5 / 9) + 77.0) * 3.5,
                          1e-8)
    def test_steady_aircraft_for_docs(self):
        import matplotlib.pyplot as plt

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

        import dymos as dm

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        p.setup()

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

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

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

        dm.run_problem(p)

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

        exp_out = traj.simulate()

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

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

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

        plt.show()
Пример #17
0
    def test_units_error_messages(self):
        prob = om.Problem()
        model = prob.model

        ivc = om.IndepVarComp()
        ivc.add_output('x', 35.0, units='degF')

        model.add_subsystem('p', ivc, promotes=['x'])
        model.add_subsystem('comp1',
                            om.ExecComp('y1 = 2.0*x',
                                        x={
                                            'value': 2.0,
                                            'units': 'degF'
                                        },
                                        y1={
                                            'value': 2.0,
                                            'units': 'degF'
                                        }),
                            promotes=['x', 'y1'])

        model.add_design_var('x',
                             units='ft',
                             lower=0.0,
                             upper=100.0,
                             scaler=3.5,
                             adder=77.0)
        prob.setup()

        with self.assertRaises(RuntimeError) as context:
            prob.final_setup()

        msg = "<model> <class Group>: Target for design variable x has 'degF' units, but 'ft' units were specified."
        self.assertEqual(str(context.exception), msg)

        prob = om.Problem()
        model = prob.model

        ivc = om.IndepVarComp()
        ivc.add_output('x', 35.0, units='degF')

        model.add_subsystem('p', ivc, promotes=['x'])
        model.add_subsystem('comp1',
                            om.ExecComp('y1 = 2.0*x',
                                        x={
                                            'value': 2.0,
                                            'units': 'degF'
                                        },
                                        y1={
                                            'value': 2.0,
                                            'units': 'degF'
                                        }),
                            promotes=['x', 'y1'])

        model.add_constraint('x', units='ft', lower=0.0, upper=100.0)
        prob.setup()

        with self.assertRaises(RuntimeError) as context:
            prob.final_setup()

        msg = "<model> <class Group>: Target for constraint x has 'degF' units, but 'ft' units were specified."
        self.assertEqual(str(context.exception), msg)

        prob = om.Problem()
        model = prob.model

        ivc = om.IndepVarComp()
        ivc.add_output('x', 35.0, units=None)

        model.add_subsystem('p', ivc, promotes=['x'])
        model.add_subsystem('comp1',
                            om.ExecComp('y1 = 2.0*x',
                                        x={'value': 2.0},
                                        y1={
                                            'value': 2.0,
                                            'units': 'degF'
                                        }),
                            promotes=['x', 'y1'])

        model.add_design_var('x',
                             units='ft',
                             lower=0.0,
                             upper=100.0,
                             scaler=3.5,
                             adder=77.0)
        prob.setup()

        with self.assertRaises(RuntimeError) as context:
            prob.final_setup()

        msg = "<model> <class Group>: Target for design variable x has no units, but 'ft' units were specified."
        self.assertEqual(str(context.exception), msg)

        prob = om.Problem()
        model = prob.model

        ivc = om.IndepVarComp()
        ivc.add_output('x', 35.0, units=None)

        model.add_subsystem('p', ivc, promotes=['x'])
        model.add_subsystem('comp1',
                            om.ExecComp('y1 = 2.0*x',
                                        x={'value': 2.0},
                                        y1={
                                            'value': 2.0,
                                            'units': 'degF'
                                        }),
                            promotes=['x', 'y1'])

        model.add_constraint('x', units='ft', lower=0.0, upper=100.0)
        prob.setup()

        with self.assertRaises(RuntimeError) as context:
            prob.final_setup()

        msg = "<model> <class Group>: Target for constraint x has no units, but 'ft' units were specified."
        self.assertEqual(str(context.exception), msg)
Пример #18
0
    def test_zero_shape(self):
        raise unittest.SkipTest("zero shapes not fully supported yet")

        class MultComp(ExplicitComponent):
            def __init__(self, mult):
                self.mult = mult
                super().__init__()

            def setup(self):
                if self.comm.rank == 0:
                    self.add_input('x', shape=1)
                    self.add_output('y', shape=1)
                else:
                    self.add_input('x', shape=0)
                    self.add_output('y', shape=0)

            def compute(self, inputs, outputs):
                outputs['y'] = inputs['x'] * self.mult

            def compute_partials(self, inputs, partials):
                partials['y', 'x'] = np.array([self.mult])

        prob = om.Problem()

        model = prob.model
        model.add_subsystem('iv', om.IndepVarComp('x', 1.0))
        model.add_subsystem('c1', MultComp(3.0))

        model.sub = model.add_subsystem('sub', om.ParallelGroup())
        model.sub.add_subsystem('c2', MultComp(-2.0))
        model.sub.add_subsystem('c3', MultComp(5.0))

        model.add_subsystem('c2', MultComp(1.0))
        model.add_subsystem('c3', MultComp(1.0))

        model.connect('iv.x', 'c1.x')

        model.connect('c1.y', 'sub.c2.x')
        model.connect('c1.y', 'sub.c3.x')

        model.connect('sub.c2.y', 'c2.x')
        model.connect('sub.c3.y', 'c3.x')

        of = ['c2.y', "c3.y"]
        wrt = ['iv.x']

        prob.setup(check=False, mode='fwd')
        prob.set_solver_print(level=0)
        prob.run_model()

        J = prob.compute_totals(of=['c2.y', "c3.y"], wrt=['iv.x'])

        assert_near_equal(J['c2.y', 'iv.x'][0][0], -6.0, 1e-6)
        assert_near_equal(J['c3.y', 'iv.x'][0][0], 15.0, 1e-6)

        assert_near_equal(prob['c2.y'], -6.0, 1e-6)
        assert_near_equal(prob['c3.y'], 15.0, 1e-6)

        prob.setup(check=False, mode='rev')
        prob.run_model()

        J = prob.compute_totals(of=['c2.y', "c3.y"], wrt=['iv.x'])

        assert_near_equal(J['c2.y', 'iv.x'][0][0], -6.0, 1e-6)
        assert_near_equal(J['c3.y', 'iv.x'][0][0], 15.0, 1e-6)

        assert_near_equal(prob['c2.y'], -6.0, 1e-6)
        assert_near_equal(prob['c3.y'], 15.0, 1e-6)
Пример #19
0
 def test_ccblade_twist(self):
     """
     Right now this just compares fd to fd so it is not a meaningful test.
     However, it ensures that we have the derivatives set up in the component
     to actually be finite differenced.
     """
     prob = om.Problem()
 
     # Add some arbitrary inputs        
     # Load in airfoil and blade shape inputs for NREL 5MW
     npzfile = np.load(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + 'smaller_dataset.npz', allow_pickle=True)
     n_span = npzfile['r'].size
     n_aoa = npzfile['aoa'].size
     n_Re = npzfile['Re'].size
     
     
 
     modeling_options = {}
     modeling_options['blade'] = {}
     modeling_options['blade']['n_span'] = n_span
     modeling_options['blade']['n_aoa'] = n_aoa
     modeling_options['blade']['n_Re'] = n_Re
     modeling_options['blade']['n_tab'] = 1
 
     modeling_options['assembly'] = {}
     modeling_options['assembly']['number_of_blades'] = 3
 
     n_span, n_aoa, n_Re, n_tab = np.moveaxis(npzfile['cl'][:,:,:,np.newaxis], 0, 1).shape
     modeling_options['airfoils'] = {}
     modeling_options['airfoils']['n_aoa'] = n_aoa
     modeling_options['airfoils']['n_Re'] = n_Re
     modeling_options['airfoils']['n_tab'] = n_tab
 
     opt_options = {}
     opt_options['optimization_variables'] = {}
     opt_options['optimization_variables']['blade'] = {}
     opt_options['optimization_variables']['blade']['aero_shape'] = {}
     opt_options['optimization_variables']['blade']['aero_shape']['chord'] = {}
     opt_options['optimization_variables']['blade']['aero_shape']['chord']['n_opt'] = 8
     opt_options['optimization_variables']['blade']['aero_shape']['twist'] = {}
     opt_options['optimization_variables']['blade']['aero_shape']['twist']['n_opt'] = 8
     opt_options['optimization_variables']['blade']['aero_shape']['twist']['inverse'] = False
     opt_options['constraints'] = {}
     opt_options['constraints']['blade'] = {}
     opt_options['constraints']['blade']['stall'] = {}
     opt_options['constraints']['blade']['stall']['margin'] =  0.05233        
 
     comp = CCBladeTwist(modeling_options=modeling_options, opt_options=opt_options)
     prob.model.add_subsystem('comp', comp, promotes=['*'])
 
     prob.setup(force_alloc_complex=True)
     
     prob.set_val('airfoils_aoa', npzfile['aoa'], units='deg')
     prob.set_val('airfoils_Re', npzfile['Re'])
     prob.set_val('airfoils_cl', np.moveaxis(npzfile['cl'][:,:,:,np.newaxis], 0, 1))
     prob.set_val('airfoils_cd', np.moveaxis(npzfile['cd'][:,:,:,np.newaxis], 0, 1))
     prob.set_val('airfoils_cm', np.moveaxis(npzfile['cm'][:,:,:,np.newaxis], 0, 1))
     prob.set_val('r', npzfile['r'], units='m')
     prob.set_val('chord', npzfile['chord'], units='m')
 
     prob.set_val('Rhub', 1., units='m')
     prob.set_val('Rtip', 70., units='m')
     prob.set_val('hub_height', 100., units='m')
     prob.set_val('precone', 0., units='deg')
     prob.set_val('tilt', 0., units='deg')
     prob.set_val('yaw', 0., units='deg')
     prob.set_val('precurve', np.zeros(n_span), units='m')
     prob.set_val('precurveTip', 0., units='m')
 
     prob.set_val('rho', 1.225, units='kg/m**3')
     prob.set_val('mu', 1.81206e-5, units='kg/(m*s)')
     prob.set_val('shearExp', 0.25)
     prob.set_val('nBlades', 3)
     prob.set_val('nSector', 4)
     prob.set_val('tiploss', True)
     prob.set_val('hubloss', True)
     prob.set_val('wakerotation', True)
     prob.set_val('usecd', True)
 
     prob.run_model()
 
     check = prob.check_partials(out_stream=None, compact_print=True)
 
     # Manually filter some entries out of the assert_check_partials call.
     # Will want to add this functionality to OpenMDAO itself at some point.
     new_check = {}
     for comp_name in check:
         new_check[comp_name] = {}
         for (output_name, input_name) in check[comp_name]:
             if 'airfoil' not in input_name and 'rho' not in input_name and 'mu' not in input_name and 'shearExp' not in input_name:
                 new_check[comp_name][(output_name, input_name)] = check[comp_name][(output_name, input_name)]
 
     assert_check_partials(new_check)  #, rtol=5e-5, atol=1e-4)
Пример #20
0
def _make_tree_model():
    p = om.Problem()
    model = p.model

    units1 = units2 = 'ft'

    val = 1.0

    g1 = model.add_subsystem("G1", om.Group(), promotes_inputs=['x'])

    g2 = g1.add_subsystem("G2", om.Group(), promotes_inputs=['x'])
    g2.add_subsystem("C1",
                     om.ExecComp("y = 2. * x",
                                 x={
                                     'val': val,
                                     'units': units2
                                 },
                                 y={
                                     'val': 1.0,
                                     'units': units2
                                 }),
                     promotes_inputs=['x'])
    g2.add_subsystem("C2",
                     om.ExecComp("y = 3. * x",
                                 x={
                                     'val': val,
                                     'units': units1
                                 },
                                 y={
                                     'val': 1.0,
                                     'units': units1
                                 }),
                     promotes_inputs=['x'])

    g3 = model.add_subsystem("G3", om.Group(), promotes_inputs=['x'])
    g3.add_subsystem("C3",
                     om.ExecComp("y = 4. * x",
                                 x={
                                     'val': val,
                                     'units': units1
                                 },
                                 y={
                                     'val': 1.0,
                                     'units': units1
                                 }),
                     promotes_inputs=['x'])
    g3.add_subsystem("C4",
                     om.ExecComp("y = 5. * x",
                                 x={
                                     'val': val,
                                     'units': units2
                                 },
                                 y={
                                     'val': 1.0,
                                     'units': units2
                                 }),
                     promotes_inputs=['x'])

    par = model.add_subsystem("par", om.ParallelGroup(), promotes_inputs=['x'])

    g4 = par.add_subsystem("G4", om.Group(), promotes_inputs=['x'])
    g4.add_subsystem("C5",
                     om.ExecComp("y = 6. * x",
                                 x={
                                     'val': val,
                                     'units': units2
                                 },
                                 y={
                                     'val': 1.0,
                                     'units': units2
                                 }),
                     promotes_inputs=['x'])
    g4.add_subsystem("C6",
                     om.ExecComp("y = 7. * x",
                                 x={
                                     'val': val,
                                     'units': units1
                                 },
                                 y={
                                     'val': 1.0,
                                     'units': units1
                                 }),
                     promotes_inputs=['x'])

    g5 = par.add_subsystem("G5", om.Group(), promotes_inputs=['x'])
    g5.add_subsystem("C7",
                     om.ExecComp("y = 8. * x",
                                 x={
                                     'val': val,
                                     'units': units1
                                 },
                                 y={
                                     'val': 1.0,
                                     'units': units1
                                 }),
                     promotes_inputs=['x'])
    g5.add_subsystem("C8",
                     om.ExecComp("y = 9. * x",
                                 x={
                                     'val': val,
                                     'units': units2
                                 },
                                 y={
                                     'val': 1.0,
                                     'units': units2
                                 }),
                     promotes_inputs=['x'])

    model.add_subsystem("C9",
                        om.ExecComp("y = 10. * x",
                                    x={
                                        'val': val,
                                        'units': units2
                                    },
                                    y={
                                        'val': 1.0,
                                        'units': units2
                                    }),
                        promotes_inputs=['x'])

    return p
    def test_length_constrained_brachistochrone(self):
        import openmdao.api as om
        import dymos as dm
        import matplotlib.pyplot as plt
        from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE
        from dymos.examples.length_constrained_brachistochrone.arc_length_comp import ArcLengthComp

        MAX_ARCLENGTH = 11.9
        OPTIMIZER = 'SLSQP'

        p = om.Problem(model=om.Group())
        p.add_recorder(om.SqliteRecorder('length_constrained_brach_sol.db'))

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

        p.driver.declare_coloring()

        # Create the transcription so we can get the number of nodes for the downstream analysis
        tx = dm.Radau(num_segments=20, order=3, compressed=False)

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

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

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

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

        phase.add_control('theta', units='deg', lower=0.01, upper=179.9,
                          continuity=True, rate_continuity=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=1)

        # p.model.options['assembled_jac_type'] = top_level_jacobian.lower()
        # p.model.linear_solver = DirectSolver(assemble_jac=True)

        # Add the arc length component
        p.model.add_subsystem('arc_length_comp',
                              subsys=ArcLengthComp(num_nodes=tx.grid_data.num_nodes))

        p.model.connect('traj.phase0.timeseries.controls:theta', 'arc_length_comp.theta')
        p.model.connect('traj.phase0.timeseries.states:x', 'arc_length_comp.x')

        p.model.add_constraint('arc_length_comp.S', upper=MAX_ARCLENGTH, ref=1)

        p.setup(check=True)

        p.set_val('traj.phase0.t_initial', 0.0)
        p.set_val('traj.phase0.t_duration', 2.0)

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

        p.run_driver()

        p.record(case_name='final')

        # Plot results
        if SHOW_PLOTS:
            # Generate the explicitly simulated trajectory
            exp_out = traj.simulate()

            # Extract the timeseries from the implicit solution and the explicit simulation
            x = p.get_val('traj.phase0.timeseries.states:x')
            y = p.get_val('traj.phase0.timeseries.states:y')
            t = p.get_val('traj.phase0.timeseries.time')
            theta = p.get_val('traj.phase0.timeseries.controls:theta')

            x_exp = exp_out.get_val('traj.phase0.timeseries.states:x')
            y_exp = exp_out.get_val('traj.phase0.timeseries.states:y')
            t_exp = exp_out.get_val('traj.phase0.timeseries.time')
            theta_exp = exp_out.get_val('traj.phase0.timeseries.controls:theta')

            fig, axes = plt.subplots(nrows=2, ncols=1)

            axes[0].plot(x, y, 'o')
            axes[0].plot(x_exp, y_exp, '-')
            axes[0].set_xlabel('x (m)')
            axes[0].set_ylabel('y (m)')

            axes[1].plot(t, theta, 'o')
            axes[1].plot(t_exp, theta_exp, '-')
            axes[1].set_xlabel('time (s)')
            axes[1].set_ylabel(r'$\theta$ (deg)')

            plt.show()

        return p
Пример #22
0
def run_opt(layout_number, wec_method_number, wake_model, opt_alg_number,
            max_wec, nsteps):
    OPENMDAO_REQUIRE_MPI = False
    run_number = layout_number
    model = wake_model
    # set model
    MODELS = ['FLORIS', 'BPA', 'JENSEN', 'LARSEN']
    print(MODELS[model])

    # select optimization approach/method
    opt_algs = ['snopt', 'ga', 'ps']
    opt_algorithm = opt_algs[opt_alg_number]

    # select wec method
    wec_methods = ['none', 'diam', 'angle', 'hybrid']
    wec_method = wec_methods[wec_method_number]

    # pop_size = 760

    # save and show options
    show_start = False
    show_end = False
    save_start = False
    save_end = False

    save_locations = True
    save_aep = True
    save_time = True
    rec_func_calls = True

    input_directory = "../../../input_files/"

    # set options for BPA
    print_ti = False
    sort_turbs = True

    # turbine_type = 'NREL5MW'            #can be 'V80' or 'NREL5MW'
    turbine_type = 'V80'  # can be 'V80' or 'NREL5MW'

    wake_model_version = 2016

    WECH = 0
    if wec_method == 'diam':
        output_directory = "../output_files/%s_wec_diam_max_wec_%i_nsteps_%.3f/" % (
            opt_algorithm, max_wec, nsteps)
        relax = True
        # expansion_factors = np.array([3, 2.75, 2.5, 2.25, 2.0, 1.75, 1.5, 1.25, 1.0, 1.0])
        expansion_factors = np.linspace(1.0, max_wec, nsteps)
        expansion_factors = np.append(np.flip(expansion_factors), 1.0)
        conv_tols = np.array([9E-3, 9E-3, 9E-3, 9E-3, 9E-3, 9E-3, 1E-3])
    elif wec_method == 'angle':
        output_directory = "../output_files/%s_wec_angle_max_wec_%i_nsteps_%.3f/" % (
            opt_algorithm, max_wec, nsteps)
        relax = True
        # expansion_factors = np.array([50, 40, 30, 20, 10, 0.0, 0.0])
        expansion_factors = np.linspace(0.0, max_wec, nsteps)
        expansion_factors = np.append(np.flip(expansion_factors), 0.0)
    elif wec_method == 'hybrid':
        expansion_factors = np.linspace(1.0, max_wec, nsteps)
        expansion_factors = np.append(np.flip(expansion_factors), 1.0)
        output_directory = "../output_files/%s_wec_hybrid_max_wec_%i_nsteps_%.3f/" % (
            opt_algorithm, max_wec, nsteps)
        relax = True
        WECH = 1
    elif wec_method == 'none':
        relax = False
        if opt_algorithm == "ps":
            expansion_factors = np.array([1.0])
            conv_tols = np.array([1E-4])
        else:
            expansion_factors = np.array([1.0, 1.0])
            conv_tols = np.array([9E-3, 1E-3])
        output_directory = "../output_files/%s/" % opt_algorithm
    else:
        raise ValueError('wec_method must be diam, angle, hybrid, or none')

    # create output directory if it does not exist yet
    import distutils.dir_util
    distutils.dir_util.mkpath(output_directory)

    differentiable = True

    # for expansion_factor in np.array([5., 4., 3., 2.75, 2.5, 2.25, 2.0, 1.75, 1.5, 1.25, 1.0]):
    # for expansion_factor in np.array([20., 15., 10., 5., 4., 3., 2.5, 1.25, 1.0]):
    # expansion_factors = np.array([20., 10., 5., 2.5, 1.25, 1.0])

    wake_combination_method = 1  # can be [0:Linear freestreem superposition,
    #  1:Linear upstream velocity superposition,
    #  2:Sum of squares freestream superposition,
    #  3:Sum of squares upstream velocity superposition]

    ti_calculation_method = 4  # can be [0:No added TI calculations,
    # 1:TI by Niayifar and Porte Agel altered by Annoni and Thomas,
    # 2:TI by Niayifar and Porte Agel 2016,
    # 3:TI by Niayifar and Porte Agel 2016 with added soft max function,
    # 4:TI by Niayifar and Porte Agel 2016 using area overlap ratio,
    # 5:TI by Niayifar and Porte Agel 2016 using area overlap ratio and SM function]

    if wec_method_number > 0:
        ti_opt_method = 0  # can be [0:No added TI calculations,
        # 1:TI by Niayifar and Porte Agel altered by Annoni and Thomas,
        # 2:TI by Niayifar and Porte Agel 2016,
        # 3:TI by Niayifar and Porte Agel 2016 with added soft max function,
        # 4:TI by Niayifar and Porte Agel 2016 using area overlap ratio,
        # 5:TI by Niayifar and Porte Agel 2016 using area overlap ratio and SM function]

    else:
        ti_opt_method = 0
    final_ti_opt_method = 5

    if opt_algorithm == 'ps':
        ti_opt_method = ti_calculation_method

    sm_smoothing = 700.

    if ti_calculation_method == 0:
        calc_k_star_calc = False
    else:
        calc_k_star_calc = True

    if ti_opt_method == 0:
        calc_k_star_opt = False
    else:
        calc_k_star_opt = True

    nRotorPoints = 1

    wind_rose_file = 'nantucket'  # can be one of: 'amalia', 'nantucket', 'directional

    TI = 0.108
    k_calc = 0.3837 * TI + 0.003678
    # k_calc = 0.022
    # k_opt = 0.04

    shear_exp = 0.31

    # air_density = 1.1716  # kg/m^3
    air_density = 1.225  # kg/m^3 (from Jen)

    if turbine_type == 'V80':

        # define turbine size
        rotor_diameter = 80.  # (m)
        hub_height = 70.0

        z_ref = 80.0  # m
        z_0 = 0.0

        # load performance characteristics
        cut_in_speed = 4.  # m/s
        cut_out_speed = 25.  # m/s
        rated_wind_speed = 16.  # m/s
        rated_power = 2000.  # kW
        generator_efficiency = 0.944

        ct_curve_data = np.loadtxt(input_directory +
                                   'mfg_ct_vestas_v80_niayifar2016.txt',
                                   delimiter=",")
        ct_curve_wind_speed = ct_curve_data[:, 0]
        ct_curve_ct = ct_curve_data[:, 1]

        # air_density = 1.1716  # kg/m^3
        Ar = 0.25 * np.pi * rotor_diameter**2
        # cp_curve_wind_speed = ct_curve[:, 0]
        power_data = np.loadtxt(input_directory +
                                'niayifar_vestas_v80_power_curve_observed.txt',
                                delimiter=',')
        # cp_curve_cp = niayifar_power_model(cp_curve_wind_speed)/(0.5*air_density*cp_curve_wind_speed**3*Ar)
        cp_curve_cp = power_data[:, 1] * (1E6) / (0.5 * air_density *
                                                  power_data[:, 0]**3 * Ar)
        cp_curve_wind_speed = power_data[:, 0]
        cp_curve_spline = UnivariateSpline(cp_curve_wind_speed,
                                           cp_curve_cp,
                                           ext='const')
        cp_curve_spline.set_smoothing_factor(.0001)

    elif turbine_type == 'NREL5MW':

        # define turbine size
        rotor_diameter = 126.4  # (m)
        hub_height = 90.0

        z_ref = 80.0  # m
        z_0 = 0.0

        # load performance characteristics
        cut_in_speed = 3.  # m/s
        cut_out_speed = 25.  # m/s
        rated_wind_speed = 11.4  # m/s
        rated_power = 5000.  # kW
        generator_efficiency = 0.944

        filename = input_directory + "NREL5MWCPCT_dict.p"
        # filename = "../input_files/NREL5MWCPCT_smooth_dict.p"
        import pickle

        data = pickle.load(open(filename, "rb"), encoding='latin1')
        ct_curve = np.zeros([data['wind_speed'].size, 2])
        ct_curve_wind_speed = data['wind_speed']
        ct_curve_ct = data['CT']

        # cp_curve_cp = data['CP']
        # cp_curve_wind_speed = data['wind_speed']

        loc0 = np.where(data['wind_speed'] < 11.55)
        loc1 = np.where(data['wind_speed'] > 11.7)

        cp_curve_cp = np.hstack([data['CP'][loc0], data['CP'][loc1]])
        cp_curve_wind_speed = np.hstack(
            [data['wind_speed'][loc0], data['wind_speed'][loc1]])
        cp_curve_spline = UnivariateSpline(cp_curve_wind_speed,
                                           cp_curve_cp,
                                           ext='const')
        cp_curve_spline.set_smoothing_factor(.000001)
    else:
        raise ValueError("Turbine type is undefined.")

    # load starting locations
    layout_directory = input_directory

    layout_data = np.loadtxt(
        layout_directory +
        "layouts/round_38turbs/nTurbs38_spacing5_layout_%i.txt" %
        layout_number)
    # layout_data = np.loadtxt(layout_directory + "layouts/grid_16turbs/nTurbs16_spacing5_layout_%i.txt" % layout_number)
    # layout_data = np.loadtxt(layout_directory+"layouts/nTurbs9_spacing5_layout_%i.txt" % layout_number)

    turbineX = layout_data[:, 0] * rotor_diameter + rotor_diameter / 2.
    turbineY = layout_data[:, 1] * rotor_diameter + rotor_diameter / 2.

    turbineX_init = np.copy(turbineX)
    turbineY_init = np.copy(turbineY)

    nTurbines = turbineX.size

    # create boundary specifications
    boundary_radius = 0.5 * (rotor_diameter * 4000. / 126.4 - rotor_diameter
                             )  # 1936.8
    center = np.array([boundary_radius, boundary_radius]) + rotor_diameter / 2.
    start_min_spacing = 5.
    nVertices = 1
    boundary_center_x = center[0]
    boundary_center_y = center[1]
    xmax = np.max(turbineX)
    ymax = np.max(turbineY)
    xmin = np.min(turbineX)
    ymin = np.min(turbineY)
    boundary_radius_plot = boundary_radius + 0.5 * rotor_diameter

    plot_round_farm(turbineX,
                    turbineY,
                    rotor_diameter, [boundary_center_x, boundary_center_y],
                    boundary_radius,
                    show_start=show_start)
    # quit()
    # initialize input variable arrays
    nTurbs = nTurbines
    rotorDiameter = np.zeros(nTurbs)
    hubHeight = np.zeros(nTurbs)
    axialInduction = np.zeros(nTurbs)
    Ct = np.zeros(nTurbs)
    Cp = np.zeros(nTurbs)
    generatorEfficiency = np.zeros(nTurbs)
    yaw = np.zeros(nTurbs)
    minSpacing = 2.  # number of rotor diameters

    # define initial values
    for turbI in range(0, nTurbs):
        rotorDiameter[turbI] = rotor_diameter  # m
        hubHeight[turbI] = hub_height  # m
        axialInduction[turbI] = 1.0 / 3.0
        Ct[turbI] = 4.0 * axialInduction[turbI] * (1.0 - axialInduction[turbI])
        # print(Ct)
        Cp[turbI] = 4.0 * 1.0 / 3.0 * np.power((1 - 1.0 / 3.0), 2)
        generatorEfficiency[turbI] = generator_efficiency
        yaw[turbI] = 0.  # deg.

    # Define flow properties
    if wind_rose_file == 'nantucket':
        windRose = np.loadtxt(input_directory +
                              'nantucket_windrose_ave_speeds.txt')
        # windRose = np.loadtxt(input_directory + 'nantucket_wind_rose_for_LES.txt')
        windDirections = windRose[:, 0]
        windSpeeds = windRose[:, 1]
        windFrequencies = windRose[:, 2]
        size = np.size(windDirections)
    elif wind_rose_file == 'amalia':
        windRose = np.loadtxt(
            input_directory +
            'windrose_amalia_directionally_averaged_speeds.txt')
        windDirections = windRose[:, 0]
        windSpeeds = windRose[:, 1]
        windFrequencies = windRose[:, 2]
        size = np.size(windDirections)
    elif wind_rose_file == 'directional':
        windRose = np.loadtxt(input_directory + 'directional_windrose.txt')
        windDirections = windRose[:, 0]
        windSpeeds = windRose[:, 1]
        windFrequencies = windRose[:, 2]
        size = np.size(windDirections)
    elif wind_rose_file == '1d':
        windDirections = np.array([270.])
        windSpeeds = np.array([8.0])
        windFrequencies = np.array([1.0])
        size = np.size(windDirections)
    else:
        size = 20
        windDirections = np.linspace(0, 270, size)
        windFrequencies = np.ones(size) / size

    wake_model_options = {
        'nSamples': 0,
        'nRotorPoints': nRotorPoints,
        'use_ct_curve': True,
        'ct_curve_ct': ct_curve_ct,
        'ct_curve_wind_speed': ct_curve_wind_speed,
        'interp_type': 1,
        'use_rotor_components': False,
        'differentiable': differentiable,
        'verbose': False
    }

    if MODELS[model] == 'BPA':
        # initialize problem
        prob = om.Problem(
            model=OptAEP(nTurbines=nTurbs,
                         nDirections=windDirections.size,
                         nVertices=nVertices,
                         minSpacing=minSpacing,
                         differentiable=differentiable,
                         use_rotor_components=False,
                         wake_model=gauss_wrapper,
                         params_IdepVar_func=add_gauss_params_IndepVarComps,
                         params_IdepVar_args={'nRotorPoints': nRotorPoints},
                         wake_model_options=wake_model_options,
                         cp_points=cp_curve_cp.size,
                         cp_curve_spline=cp_curve_spline,
                         record_function_calls=True,
                         runparallel=False))
    elif MODELS[model] == 'FLORIS':
        # initialize problem
        prob = om.Problem(
            model=OptAEP(nTurbines=nTurbs,
                         nDirections=windDirections.size,
                         nVertices=nVertices,
                         minSpacing=minSpacing,
                         differentiable=differentiable,
                         use_rotor_components=False,
                         wake_model=floris_wrapper,
                         params_IdepVar_func=add_floris_params_IndepVarComps,
                         params_IdepVar_args={},
                         record_function_calls=True))
    # elif MODELS[model] == 'JENSEN':
    #     initialize problem
    # prob = om.Problem(model=OptAEP(nTurbines=nTurbs, nDirections=windDirections.size, nVertices=nVertices,
    #                                       minSpacing=minSpacing, differentiable=False, use_rotor_components=False,
    #                                       wake_model=jensen_wrapper,
    #                                       params_IdepVar_func=add_jensen_params_IndepVarComps,
    #                                       params_IdepVar_args={},
    #                                               record_function_calls=True))
    else:
        ValueError(
            'The %s model is not currently available. Please select BPA or FLORIS'
            % (MODELS[model]))
    # prob.model.deriv_options['type'] = 'fd'
    # prob.model.deriv_options['form'] = 'central'
    # prob.model.deriv_options['step_size'] = 1.0e-8
    # prob.model.linear_solver = om.LinearBlockGS()
    # prob.model.linear_solver.options['iprint'] = 0
    # prob.model.linear_solver.options['maxiter'] = 5
    #
    # prob.model.nonlinear_solver = om.NonlinearBlockGS()
    # prob.model.nonlinear_solver.options['iprint'] = 0

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

    prob.driver = om.pyOptSparseDriver()

    if opt_algorithm == 'snopt':
        # set up optimizer
        prob.driver.options['optimizer'] = 'SNOPT'
        # prob.driver.options['gradient method'] = 'snopt_fd'

        # set optimizer options
        prob.driver.opt_settings['Verify level'] = -1
        # set optimizer options
        prob.driver.opt_settings['Major optimality tolerance'] = np.float(1e-3)

        prob.driver.opt_settings[
            'Print file'] = output_directory + 'SNOPT_print_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % (
                nTurbs, wind_rose_file, size, MODELS[model], run_number)
        prob.driver.opt_settings[
            'Summary file'] = output_directory + 'SNOPT_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % (
                nTurbs, wind_rose_file, size, MODELS[model], run_number)

        prob.model.add_constraint('sc',
                                  lower=np.zeros(
                                      int(((nTurbs - 1.) * nTurbs / 2.))),
                                  scaler=1E-4)  # ,
        # active_tol=(2. * rotor_diameter) ** 2)
        prob.model.add_constraint('boundaryDistances',
                                  lower=(np.zeros(1 * turbineX.size)),
                                  scaler=1E-4)  # ,
        # active_tol=2. * rotor_diameter)

        prob.driver.options['dynamic_derivs_sparsity'] = True

    elif opt_algorithm == 'ga':

        prob.driver.options['optimizer'] = 'NSGA2'

        prob.driver.opt_settings['PrintOut'] = 1

        prob.driver.opt_settings['maxGen'] = 50000

        prob.driver.opt_settings['PopSize'] = 10 * nTurbines * 2

        # prob.driver.opt_settings['pMut_real'] = 0.001

        prob.driver.opt_settings['xinit'] = 1

        prob.driver.opt_settings['rtol'] = 1E-4

        prob.driver.opt_settings['atol'] = 1E-4

        prob.driver.opt_settings['min_tol_gens'] = 200

        prob.driver.opt_settings['file_number'] = run_number

        prob.model.add_constraint('sc',
                                  lower=np.zeros(
                                      int(((nTurbs - 1.) * nTurbs / 2.))),
                                  scaler=1E-4)
        prob.model.add_constraint('boundaryDistances',
                                  lower=(np.zeros(1 * turbineX.size)),
                                  scaler=1E-4)

    elif opt_algorithm == 'ps':

        prob.driver.options['optimizer'] = 'ALPSO'

        prob.driver.opt_settings['fileout'] = 1

        prob.driver.opt_settings[
            'filename'] = output_directory + 'ALPSO_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % (
                nTurbs, wind_rose_file, size, MODELS[model], run_number)

        prob.driver.opt_settings['maxOuterIter'] = 10000

        prob.driver.opt_settings['SwarmSize'] = 25

        prob.driver.opt_settings[
            'xinit'] = 1  # Initial Position Flag (0 - no position, 1 - position given)

        prob.driver.opt_settings[
            'Scaling'] = 1  # Design Variables Scaling Flag (0 - no scaling, 1 - scaling between [-1, 1])

        # prob.driver.opt_settings['rtol'] = 1E-3  # Relative Tolerance for Lagrange Multipliers
        #
        # prob.driver.opt_settings['atol'] = 1E-2  # Absolute Tolerance for Lagrange Function
        #
        prob.driver.opt_settings[
            'dtol'] = 0.01  # Relative Tolerance in Distance of All Particles to Terminate (GCPSO)
        #
        # prob.driver.opt_settings['itol'] = 1E-3  # Absolute Tolerance for Inequality constraints
        #
        # prob.driver.opt_settings['dynInnerIter'] = 1  # Dynamic Number of Inner Iterations Flag

        prob.model.add_constraint('sc',
                                  lower=np.zeros(
                                      int(((nTurbs - 1.) * nTurbs / 2.))),
                                  scaler=1E-4)
        prob.model.add_constraint('boundaryDistances',
                                  lower=(np.zeros(1 * turbineX.size)),
                                  scaler=1E-4)

        # prob.driver.add_objective('obj', scaler=1E0)
    prob.model.add_objective('obj', scaler=1E-4)

    # select design variables
    prob.model.add_design_var('turbineX',
                              scaler=1E0,
                              lower=np.zeros(nTurbines),
                              upper=np.ones(nTurbines) * 3. * boundary_radius)
    prob.model.add_design_var('turbineY',
                              scaler=1E0,
                              lower=np.zeros(nTurbines),
                              upper=np.ones(nTurbines) * 3. * boundary_radius)

    # prob.model.ln_solver.options['single_voi_relevance_reduction'] = True
    # prob.model.ln_solver.options['mode'] = 'rev'

    # if run_number == 0:
    #     # set up recorder
    #     recorder = SqliteRecorder(output_directory+'recorder_database_run%i' % run_number)
    #     recorder.options['record_params'] = True
    #     recorder.options['record_metadata'] = False
    #     recorder.options['record_unknowns'] = True
    #     recorder.options['record_derivs'] = False
    #     recorder.options['includes'] = ['turbineX', 'turbineY', 'AEP']
    #     prob.driver.add_recorder(recorder)

    driver_recorder = om.SqliteRecorder(output_directory +
                                        'recorded_data_driver_%s.sql' %
                                        (run_number))
    # model_recorder = om.SqliteRecorder(output_directory + 'recorded_data_model_%s.sql' %(run_number))
    prob.driver.add_recorder(driver_recorder)
    # prob.model.add_recorder(model_recorder)
    prob.driver.recording_options['record_constraints'] = False
    prob.driver.recording_options['record_derivatives'] = False
    prob.driver.recording_options['record_desvars'] = True
    prob.driver.recording_options['record_inputs'] = False
    prob.driver.recording_options['record_model_metadata'] = True
    prob.driver.recording_options['record_objectives'] = True
    prob.driver.recording_options['includes'] = ['AEP']
    prob.driver.recording_options['record_responses'] = False
    #
    # prob_recorder = om.SqliteRecorder(output_directory + 'recorded_data_prob_%s.sql' %(run_number))
    # prob.add_recorder(prob_recorder)
    # prob.recording_options['includes'] = []
    # prob.recording_options['record_objectives'] = True

    # set up profiling
    # from plantenergy.GeneralWindFarmComponents import WindFarmAEP
    # methods = [
    #     ('*', (WindFarmAEP,))
    # ]
    #
    # iprofile.setup(methods=methods)

    print("almost time for setup")
    tic = time.time()
    print("entering setup at time = ", tic)
    prob.setup(check=True)
    toc = time.time()
    print("setup complete at time = ", toc)

    # print the results
    print(('Problem setup took %.03f sec.' % (toc - tic)))

    # assign initial values to design variables
    prob['turbineX'] = np.copy(turbineX)
    prob['turbineY'] = np.copy(turbineY)
    for direction_id in range(0, windDirections.size):
        prob['yaw%i' % direction_id] = yaw

    # assign values to constant inputs (not design variables)
    prob['rotorDiameter'] = rotorDiameter
    prob['hubHeight'] = hubHeight
    prob['axialInduction'] = axialInduction
    prob['generatorEfficiency'] = generatorEfficiency
    prob['windSpeeds'] = windSpeeds
    prob['air_density'] = air_density
    prob['windDirections'] = windDirections
    prob['windFrequencies'] = windFrequencies
    prob['Ct_in'] = Ct
    prob['Cp_in'] = Cp
    prob['cp_curve_cp'] = cp_curve_cp
    prob['cp_curve_wind_speed'] = cp_curve_wind_speed
    cutInSpeeds = np.ones(nTurbines) * cut_in_speed
    prob['cut_in_speed'] = cutInSpeeds
    ratedPowers = np.ones(nTurbines) * rated_power
    prob['rated_power'] = ratedPowers

    # assign values to turbine states
    prob['cut_in_speed'] = np.ones(nTurbines) * cut_in_speed
    prob['cut_out_speed'] = np.ones(nTurbines) * cut_out_speed
    prob['rated_power'] = np.ones(nTurbines) * rated_power
    prob['rated_wind_speed'] = np.ones(nTurbines) * rated_wind_speed
    prob['use_power_curve_definition'] = True

    # assign boundary values
    prob['boundary_center'] = np.array([boundary_center_x, boundary_center_y])
    prob['boundary_radius'] = boundary_radius

    if MODELS[model] == 'BPA':
        prob['model_params:wake_combination_method'] = np.copy(
            wake_combination_method)
        prob['model_params:ti_calculation_method'] = np.copy(
            ti_calculation_method)
        prob['model_params:wake_model_version'] = np.copy(wake_model_version)
        prob['model_params:wec_factor'] = 1.0
        prob['model_params:wec_spreading_angle'] = 0.0
        prob['model_params:calc_k_star'] = np.copy(calc_k_star_calc)
        prob['model_params:sort'] = np.copy(sort_turbs)
        prob['model_params:z_ref'] = np.copy(z_ref)
        prob['model_params:z_0'] = np.copy(z_0)
        prob['model_params:ky'] = np.copy(k_calc)
        prob['model_params:kz'] = np.copy(k_calc)
        prob['model_params:print_ti'] = np.copy(print_ti)
        prob['model_params:shear_exp'] = np.copy(shear_exp)
        prob['model_params:I'] = np.copy(TI)
        prob['model_params:sm_smoothing'] = np.copy(sm_smoothing)
        prob['model_params:WECH'] = WECH
        if nRotorPoints > 1:
            prob['model_params:RotorPointsY'], prob[
                'model_params:RotorPointsZ'] = sunflower_points(nRotorPoints)

    modelruns = 0
    prob.run_model(case_prefix='ModelRun%i' % modelruns)
    AEP_init_calc = np.copy(prob['AEP'])
    print(AEP_init_calc * 1E-6)

    if MODELS[model] == 'BPA':
        prob['model_params:ti_calculation_method'] = np.copy(ti_opt_method)
        prob['model_params:calc_k_star'] = np.copy(calc_k_star_opt)

    modelruns += 1
    prob.run_model(case_prefix='ModelRun%i' % modelruns)
    AEP_init_opt = np.copy(prob['AEP'])
    AEP_run_opt = np.copy(AEP_init_opt)
    print(AEP_init_opt * 1E-6)

    config.obj_func_calls_array[:] = 0.0
    config.sens_func_calls_array[:] = 0.0

    expansion_factor_last = 0.0
    driverruns = 0
    tict = time.time()
    if relax:
        for expansion_factor, i in zip(
                expansion_factors,
                np.arange(0, expansion_factors.size)):  # best so far
            # print("func calls: ", config.obj_func_calls_array, np.sum(config.obj_func_calls_array))
            # print("grad func calls: ", config.sens_func_calls_array, np.sum(config.sens_func_calls_array))
            # AEP_init_run_opt = prob['AEP']

            if expansion_factor_last == expansion_factor:
                ti_opt_method = np.copy(final_ti_opt_method)
                calc_k_star_opt = True

            print("starting run with exp. fac = ", expansion_factor)

            if opt_algorithm == 'snopt':
                prob.driver.opt_settings['Major optimality tolerance'] = float(
                    conv_tols[i])
                prob.driver.opt_settings['Print file'] = output_directory + \
                                                         'SNOPT_print_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_EF%.3f_TItype%i.out' % (
                                                             nTurbs, wind_rose_file, size, MODELS[model], run_number,
                                                             expansion_factor, ti_opt_method)

                prob.driver.opt_settings['Summary file'] = output_directory + \
                                                           'SNOPT_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_EF%.3f_TItype%i.out' % (
                                                               nTurbs, wind_rose_file, size, MODELS[model], run_number,
                                                               expansion_factor, ti_opt_method)
            elif opt_algorithm == 'ps':
                prob.driver.opt_settings[
                    'filename'] = output_directory + 'ALPSO_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % (
                        nTurbs, wind_rose_file, size, MODELS[model],
                        run_number)

            turbineX = np.copy(prob['turbineX'])
            turbineY = np.copy(prob['turbineY'])
            prob['turbineX'] = np.copy(turbineX)
            prob['turbineY'] = np.copy(turbineY)

            if MODELS[model] == 'BPA':
                prob['model_params:ti_calculation_method'] = np.copy(
                    ti_opt_method)
                prob['model_params:calc_k_star'] = np.copy(calc_k_star_opt)
                if wec_method == 'diam':
                    prob['model_params:wec_factor'] = np.copy(expansion_factor)
                elif wec_method == "hybrid":
                    prob['model_params:wec_factor'] = np.copy(expansion_factor)
                elif wec_method == 'angle':
                    prob['model_params:wec_spreading_angle'] = np.copy(
                        expansion_factor)

            # run the problem
            print('start %s run' % (MODELS[model]))
            tic = time.time()
            # iprofile.start()
            config.obj_func_calls_array[prob.comm.rank] = 0.0
            config.sens_func_calls_array[prob.comm.rank] = 0.0
            prob.run_driver(case_prefix='DriverRun%i' % driverruns)
            driverruns += 1
            # quit()
            toc = time.time()
            obj_calls = np.copy(config.obj_func_calls_array[0])
            sens_calls = np.copy(config.sens_func_calls_array[0])
            # iprofile.stop()
            toc = time.time()
            # print(np.sum(config.obj_func_calls_array))
            # print(np.sum(config.sens_func_calls_array))
            print('end %s run' % (MODELS[model]))

            run_time = toc - tic
            # print(run_time, expansion_factor)

            AEP_run_opt = np.copy(prob['AEP'])
            # print("AEP improvement = ", AEP_run_opt / AEP_init_opt)

            if MODELS[model] == 'BPA':
                prob['model_params:wec_factor'] = 1.0
                prob['model_params:wec_spreading_angle'] = 0.0
                prob['model_params:ti_calculation_method'] = np.copy(
                    ti_calculation_method)
                prob['model_params:calc_k_star'] = np.copy(calc_k_star_calc)

            modelruns += 1
            prob.run_model(case_prefix='ModelRun%i' % modelruns)
            AEP_run_calc = np.copy(prob['AEP'])
            # print("compare: ", aep_run, prob['AEP'])
            print("AEP calc improvement = ", AEP_run_calc / AEP_init_calc)

            if prob.model.comm.rank == 0:
                # if save_aep:
                #     np.savetxt(output_directory + '%s_multistart_aep_results_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_EF%.3f.txt' % (
                #         opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, expansion_factor),
                #                np.c_[AEP_init, prob['AEP']],
                #                header="Initial AEP, Final AEP")
                if save_locations:
                    np.savetxt(
                        output_directory +
                        '%s_multistart_locations_%iturbs_%sWindRose_%idirs_%s_run%i_EF%.3f_TItype%i.txt'
                        % (opt_algorithm, nTurbs, wind_rose_file, size,
                           MODELS[model], run_number, expansion_factor,
                           ti_opt_method),
                        np.c_[turbineX_init, turbineY_init, prob['turbineX'],
                              prob['turbineY']],
                        header=
                        "initial turbineX, initial turbineY, final turbineX, final turbineY"
                    )
                # if save_time:
                #     np.savetxt(output_directory + '%s_multistart_time_%iturbs_%sWindRose_%idirs_%s_run%i_EF%.3f.txt' % (
                #         opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, expansion_factor),
                #                np.c_[run_time],
                #                header="run time")
                if save_time and save_aep and rec_func_calls:
                    output_file = output_directory + '%s_multistart_rundata_%iturbs_%sWindRose_%idirs_%s_run%i.txt' \
                                  % (opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number)
                    f = open(output_file, "a")

                    if i == 0:
                        header = "run number, exp fac, ti calc, ti opt, aep init calc (kW), aep init opt (kW), " \
                                 "aep run calc (kW), aep run opt (kW), run time (s), obj func calls, sens func calls"
                    else:
                        header = ''

                    np.savetxt(f,
                               np.c_[run_number, expansion_factor,
                                     ti_calculation_method, ti_opt_method,
                                     AEP_init_calc, AEP_init_opt, AEP_run_calc,
                                     AEP_run_opt, run_time, obj_calls,
                                     sens_calls],
                               header=header)
                    f.close()
            expansion_factor_last = expansion_factor
    else:
        for expansion_factor, i in zip(
                expansion_factors,
                np.arange(0, expansion_factors.size)):  # best so far
            # print("func calls: ", config.obj_func_calls_array, np.sum(config.obj_func_calls_array))
            # print("grad func calls: ", config.sens_func_calls_array, np.sum(config.sens_func_calls_array))
            # AEP_init_run_opt = prob['AEP']

            if expansion_factor_last == expansion_factor:
                ti_opt_method = np.copy(final_ti_opt_method)
                calc_k_star_opt = True

            if opt_algorithm == 'snopt':
                prob.driver.opt_settings['Major optimality tolerance'] = float(
                    conv_tols[i])
                prob.driver.opt_settings['Print file'] = output_directory + \
                                                         'SNOPT_print_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_TItype%i.out' % (
                                                             nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method)

                prob.driver.opt_settings['Summary file'] = output_directory + \
                                                           'SNOPT_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_TItype%i.out' % (
                                                               nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method)

            print("starting run with exp. fac = ", expansion_factor)
            # run the problem
            print('start %s run' % (MODELS[model]))
            # cProfile.run('prob.run_driver()')
            if MODELS[model] == 'BPA':
                # prob['model_params:wec_factor'] = 1.
                prob['model_params:ti_calculation_method'] = np.copy(
                    ti_opt_method)
                prob['model_params:calc_k_star'] = np.copy(calc_k_star_opt)
            tic = time.time()
            # cProfile.run('prob.run_driver()')
            config.obj_func_calls_array[prob.comm.rank] = 0.0
            config.sens_func_calls_array[prob.comm.rank] = 0.0
            prob.run_driver(case_prefix='DriverRun%i' % driverruns)
            driverruns += 1
            # quit()
            toc = time.time()
            obj_calls = np.copy(config.obj_func_calls_array[0])
            sens_calls = np.copy(config.sens_func_calls_array[0])

            run_time = toc - tic

            AEP_run_opt = np.copy(prob['AEP'])
            # print("AEP improvement = ", AEP_run_calc / AEP_init_calc)

            if MODELS[model] == 'BPA':
                prob['model_params:wec_factor'] = 1.0
                prob['model_params:wec_spreading_angle'] = 0.0
                prob['model_params:ti_calculation_method'] = np.copy(
                    ti_calculation_method)
                prob['model_params:calc_k_star'] = np.copy(calc_k_star_calc)

            modelruns += 1
            prob.run_model(case_prefix='ModelRun%i' % modelruns)
            AEP_run_calc = np.copy(prob['AEP'])

            if prob.model.comm.rank == 0:

                if save_locations:
                    np.savetxt(
                        output_directory +
                        '%s_multistart_locations_%iturbs_%sWindRose_%idirs_%s_run%i_TItype%i.txt'
                        % (opt_algorithm, nTurbs, wind_rose_file, size,
                           MODELS[model], run_number, ti_opt_method),
                        np.c_[turbineX_init, turbineY_init, prob['turbineX'],
                              prob['turbineY']],
                        header=
                        "initial turbineX, initial turbineY, final turbineX, final turbineY"
                    )

                if save_time and save_aep and rec_func_calls:
                    output_file = output_directory + '%s_multistart_rundata_%iturbs_%sWindRose_%idirs_%s_run%i_TItype%i.txt' \
                                  % (opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method)
                    f = open(output_file, "a")

                    header = "run number, ti calc, ti opt, aep init calc (kW), aep init opt (kW), " \
                             "aep run calc (kW), aep run opt (kW), run time (s), obj func calls, sens func calls"

                    np.savetxt(f,
                               np.c_[run_number, ti_calculation_method,
                                     ti_opt_method, AEP_init_calc,
                                     AEP_init_opt, AEP_run_calc, AEP_run_opt,
                                     run_time, obj_calls, sens_calls],
                               header=header)
                    f.close()
            expansion_factor_last = expansion_factor

    turbineX_end = np.copy(prob['turbineX'])
    turbineY_end = np.copy(prob['turbineY'])

    toct = time.time()
    total_time = toct - tict

    if prob.model.comm.rank == 0:

        # print the results
        print(('Opt. calculation took %.03f sec.' % (toct - tict)))

        for direction_id in range(0, windDirections.size):
            print('yaw%i (deg) = ' % direction_id,
                  prob['yaw%i' % direction_id])

        print('turbine X positions in wind frame (m): %s' % prob['turbineX'])
        print('turbine Y positions in wind frame (m): %s' % prob['turbineY'])
        print('wind farm power in each direction (kW): %s' % prob['dirPowers'])
        print('Initial AEP (kWh): %s' % AEP_init_opt)
        print('Final AEP (kWh): %s' % AEP_run_calc)
        print('AEP improvement: %s' % (AEP_run_calc / AEP_init_calc))

    if show_end:
        plot_square_farm(turbineX_end,
                         turbineY_end,
                         rotor_diameter,
                         boundary_x,
                         boundary_y,
                         boundary_x[1] - boundary_x[0],
                         show_start=show_start)

    prob.cleanup()

    if MODELS[model] == 'BPA':
        prob['model_params:wec_factor'] = 1.0
        prob['model_params:wec_spreading_angle'] = 0.0
        prob['model_params:ti_calculation_method'] = 4
        prob['model_params:calc_k_star'] = True

    cr = om.CaseReader(output_directory +
                       'recorded_data_driver_%s.sql' % run_number)

    driver_cases = cr.list_cases('driver')
    nits = len(driver_cases)
    objectives = np.zeros(nits)
    AEPopt = np.zeros(nits)
    AEPcalc = np.zeros(nits)
    calls = np.zeros(nits)
    for i in np.arange(0, nits):
        case = cr.get_case(driver_cases[i])
        # print(case)
        AEPopt[i] = case['AEP']
        objectives[i] = case.get_objectives()['obj']

        prob['turbineX'] = np.copy(case['turbineX'])
        prob['turbineY'] = np.copy(case['turbineY'])
        if opt_algorithm == "snopt":
            prob.run_model(case_prefix='ProcessingRun')
            AEPcalc[i] = np.copy(prob['AEP'])
        else:
            AEPcalc[i] = case['AEP']

        calls[i] = i
Пример #23
0
        # Compute the stall margins
        self.add_subsystem('stall_margins',
                           StallCalcs(),
                           promotes_inputs=[('PR_actual', 'PRmap'),
                                            ('Wc_actual', 'WcMap')],
                           promotes_outputs=['SMN', 'SMW'])
        self.connect('SMN_map.PRmap', 'stall_margins.PR_SMN')
        self.connect('SMW_map.PRmap', 'stall_margins.PR_SMW')
        self.connect('SMN_map.WcMap', 'stall_margins.Wc_SMN')


if __name__ == "__main__":
    from pycycle.maps.ncp01 import NCP01

    p1 = om.Problem()
    ivc = p1.model.add_subsystem('ivc', om.IndepVarComp(), promotes=['*'])
    # Design variables
    ivc.add_output('alphaMap', 0.0)
    ivc.add_output('PR', 2.0)
    ivc.add_output('Nc', 1000.0, units='rpm')
    ivc.add_output('eff', .9)
    ivc.add_output('Wc', 3000., units='lbm/s')

    # Off-design variables
    # ivc.add_output('alphaMap', 0.0)
    # ivc.add_output('Nc', 1000.0, units='rpm')
    # ivc.add_output('Wc', 3000., units='lbm/s')
    # ivc.add_output('s_Nc', 1.0)
    # ivc.add_output('s_Wc', 1.0)
    # ivc.add_output('s_PR', 1.0)
Пример #24
0
    def test_debug_print_desvar_physical_with_indices(self):
        prob = om.Problem()
        model = prob.model

        size = 3
        model.add_subsystem('p1', om.IndepVarComp('x',
                                                  np.array([50.0] * size)))
        model.add_subsystem('p2', om.IndepVarComp('y',
                                                  np.array([50.0] * size)))
        model.add_subsystem(
            'comp',
            om.ExecComp('f_xy = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0',
                        x=np.zeros(size),
                        y=np.zeros(size),
                        f_xy=np.zeros(size)))
        model.add_subsystem(
            'con',
            om.ExecComp('c = - x + y',
                        c=np.zeros(size),
                        x=np.zeros(size),
                        y=np.zeros(size)))

        model.connect('p1.x', 'comp.x')
        model.connect('p2.y', 'comp.y')
        model.connect('p1.x', 'con.x')
        model.connect('p2.y', 'con.y')

        prob.set_solver_print(level=0)

        prob.driver = om.ScipyOptimizeDriver()
        prob.driver.options['optimizer'] = 'SLSQP'
        prob.driver.options['tol'] = 1e-9
        prob.driver.options['disp'] = False

        model.add_design_var('p1.x',
                             indices=[1],
                             lower=-50.0,
                             upper=50.0,
                             ref=[
                                 5.0,
                             ])
        model.add_design_var('p2.y', indices=[1], lower=-50.0, upper=50.0)
        model.add_objective('comp.f_xy', index=1)
        model.add_constraint('con.c', indices=[1], upper=-15.0)

        prob.setup()

        prob.driver.options['debug_print'] = [
            'desvars',
        ]
        stdout = sys.stdout
        strout = StringIO()
        sys.stdout = strout

        try:
            # formatting has changed in numpy 1.14 and beyond.
            if LooseVersion(np.__version__) >= LooseVersion("1.14"):
                with printoptions(precision=2, legacy="1.13"):
                    prob.run_driver()
            else:
                with printoptions(precision=2):
                    prob.run_driver()
        finally:
            sys.stdout = stdout
        output = strout.getvalue().split('\n')
        # should see unscaled (physical) and the full arrays, not just what is indicated by indices
        self.assertEqual(
            output[3],
            "{'p1.x': array([ 50.,  50.,  50.]), 'p2.y': array([ 50.,  50.,  50.])}"
        )
    def test(self):
        """
        This is an opt problem that tests the wingbox model with wave drag and the fuel vol constraint
        """

        # Create a dictionary to store options about the surface
        mesh_dict = {'num_y' : 7,
                     'num_x' : 2,
                     'wing_type' : 'CRM',
                     'symmetry' : True,
                     'num_twist_cp' : 6,
                     'chord_cos_spacing' : 0,
                     'span_cos_spacing' : 0,
                     }

        mesh, twist_cp = generate_mesh(mesh_dict)

        surf_dict = {
                    # Wing definition
                    'name' : 'wing',        # name of the surface
                    'symmetry' : True,     # if true, model one half of wing
                                            # reflected across the plane y = 0
                    'S_ref_type' : 'wetted', # how we compute the wing area,
                                             # can be 'wetted' or 'projected'
                    'fem_model_type' : 'wingbox',

                    'spar_thickness_cp' : np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m]
                    'skin_thickness_cp' : np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]),
                    'twist_cp' : np.array([4., 5., 8., 8., 8., 9.]),
                    'mesh' : mesh,

                    'data_x_upper' : upper_x,
                    'data_x_lower' : lower_x,
                    'data_y_upper' : upper_y,
                    'data_y_lower' : lower_y,
                    'strength_factor_for_upper_skin' : 1.,

                    # Aerodynamic performance of the lifting surface at
                    # an angle of attack of 0 (alpha=0).
                    # These CL0 and CD0 values are added to the CL and CD
                    # obtained from aerodynamic analysis of the surface to get
                    # the total CL and CD.
                    # These CL0 and CD0 values do not vary wrt alpha.
                    'CL0' : 0.0,            # CL of the surface at alpha=0
                    'CD0' : 0.0078,            # CD of the surface at alpha=0

                    # Airfoil properties for viscous drag calculation
                    'k_lam' : 0.05,         # percentage of chord with laminar
                                            # flow, used for viscous drag
                    't_over_c_cp' : np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]),
                    'original_wingbox_airfoil_t_over_c' : 0.12,
                    'c_max_t' : .38,       # chordwise location of maximum thickness
                    'with_viscous' : True,
                    'with_wave' : True,     # if true, compute wave drag

                    # Structural values are based on aluminum 7075
                    'E' : 73.1e9,              # [Pa] Young's modulus
                    'G' : (73.1e9/2/1.33),     # [Pa] shear modulus (calculated using E and the Poisson's ratio here)
                    'yield' : (420.e6 / 1.5),  # [Pa] allowable yield stress
                    'mrho' : 2.78e3,           # [kg/m^3] material density
                    'strength_factor_for_upper_skin' : 1.0, # the yield stress is multiplied by this factor for the upper skin
                    # 'fem_origin' : 0.35,    # normalized chordwise location of the spar
                    'wing_weight_ratio' : 1.25,
                    'struct_weight_relief' : True,
                    'distributed_fuel_weight' : False,
                    # Constraints
                    'exact_failure_constraint' : False, # if false, use KS function
                    'fuel_density' : 803.,      # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used)
                    'Wf_reserve' :15000.,       # [kg] reserve fuel mass
                    }

        surfaces = [surf_dict]

        # Create the problem and assign the model group
        prob = om.Problem()

        # Add problem information as an independent variables component
        indep_var_comp = om.IndepVarComp()
        indep_var_comp.add_output('v', val=.85 * 295.07, units='m/s')
        indep_var_comp.add_output('alpha', val=0., units='deg')
        indep_var_comp.add_output('Mach_number', val=0.85)
        indep_var_comp.add_output('re', val=0.348*295.07*.85*1./(1.43*1e-5), units='1/m')
        indep_var_comp.add_output('rho', val=0.348, units='kg/m**3')
        indep_var_comp.add_output('CT', val=0.53/3600, units='1/s')
        indep_var_comp.add_output('R', val=14.307e6, units='m')
        indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'],  units='kg')
        indep_var_comp.add_output('speed_of_sound', val=295.07, units='m/s')
        indep_var_comp.add_output('load_factor', val=1.)
        indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m')

        prob.model.add_subsystem('prob_vars',
             indep_var_comp,
             promotes=['*'])

        # Loop over each surface in the surfaces list
        for surface in surfaces:

            # Get the surface name and create a group to contain components
            # only for this surface
            name = surface['name']

            aerostruct_group = AerostructGeometry(surface=surface)

            # Add tmp_group to the problem with the name of the surface.
            prob.model.add_subsystem(name, aerostruct_group)

        # Loop through and add a certain number of aero points
        for i in range(1):

            point_name = 'AS_point_{}'.format(i)
            # Connect the parameters within the model for each aero point

            # Create the aero point group and add it to the model
            AS_point = AerostructPoint(surfaces=surfaces)

            prob.model.add_subsystem(point_name, AS_point)

            # Connect flow properties to the analysis point
            prob.model.connect('v', point_name + '.v')
            prob.model.connect('alpha', point_name + '.alpha')
            prob.model.connect('Mach_number', point_name + '.Mach_number')
            prob.model.connect('re', point_name + '.re')
            prob.model.connect('rho', point_name + '.rho')
            prob.model.connect('CT', point_name + '.CT')
            prob.model.connect('R', point_name + '.R')
            prob.model.connect('W0', point_name + '.W0')
            prob.model.connect('speed_of_sound', point_name + '.speed_of_sound')
            prob.model.connect('empty_cg', point_name + '.empty_cg')
            prob.model.connect('load_factor', point_name + '.load_factor')

            for surface in surfaces:

                com_name = point_name + '.' + name + '_perf.'
                prob.model.connect(name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed')
                prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes')

                # Connect aerodyamic mesh to coupled group mesh
                prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh')
                prob.model.connect(name + '.element_mass', point_name + '.coupled.' + name + '.element_mass')

                # Connect performance calculation variables
                prob.model.connect(name + '.nodes', com_name + 'nodes')
                prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location')
                prob.model.connect(name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass')

                # Connect wingbox properties to von Mises stress calcs
                prob.model.connect(name + '.Qz', com_name + 'Qz')
                prob.model.connect(name + '.J', com_name + 'J')
                prob.model.connect(name + '.A_enc', com_name + 'A_enc')
                prob.model.connect(name + '.htop', com_name + 'htop')
                prob.model.connect(name + '.hbottom', com_name + 'hbottom')
                prob.model.connect(name + '.hfront', com_name + 'hfront')
                prob.model.connect(name + '.hrear', com_name + 'hrear')

                prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness')
                prob.model.connect(name + '.t_over_c', com_name + 't_over_c')

            #=======================================================================================
            # Here we add the fuel volume constraint componenet to the model
            #=======================================================================================
            prob.model.add_subsystem('fuel_vol_delta', WingboxFuelVolDelta(surface=surface))
            prob.model.connect('AS_point_0.fuelburn', 'fuel_vol_delta.fuelburn')
            prob.model.connect('wing.struct_setup.fuel_vols', 'fuel_vol_delta.fuel_vols')
            #=======================================================================================
            #=======================================================================================

        prob.driver = om.ScipyOptimizeDriver()
        prob.driver.options['tol'] = 1e-9

        # prob.driver = om.pyOptSparseDriver()
        # prob.driver.add_recorder(om.SqliteRecorder("cases.sql"))
        # prob.driver.options['optimizer'] = "SNOPT"
        # prob.driver.opt_settings['Major optimality tolerance'] = 1e-6
        # prob.driver.opt_settings['Major feasibility tolerance'] = 1e-8
        # prob.driver.opt_settings['Major iterations limit'] = 200

        prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5)

        prob.model.add_design_var('wing.twist_cp', lower=-15., upper=15., scaler=0.1)
        prob.model.add_design_var('wing.spar_thickness_cp', lower=0.003, upper=0.1, scaler=1e2)
        prob.model.add_design_var('wing.skin_thickness_cp', lower=0.003, upper=0.1, scaler=1e2)
        prob.model.add_design_var('wing.geometry.t_over_c_cp', lower=0.07, upper=0.2, scaler=10.)

        prob.model.add_constraint('AS_point_0.CL', equals=0.5)
        prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.)

        #=======================================================================================
        # Here we add the fuel volume constraint
        #=======================================================================================
        prob.model.add_constraint('fuel_vol_delta.fuel_vol_delta', lower=0.)
        #=======================================================================================
        #=======================================================================================

        # Set up the problem
        prob.setup()

        # om.view_model(prob)

        prob.run_driver()

        # prob.check_partials(form='central', compact_print=True)

        # print(prob['AS_point_0.fuelburn'][0])
        # print(prob['wing.structural_mass'][0]/1.25)

        assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 85029.7479699, 1e-5)
        assert_rel_error(self, prob['wing.structural_mass'][0]/1.25, 18927.5387802, 1e-5)
Пример #26
0
 def test_driver_recording_options_deprecated(self):
     prob = om.Problem()
     msg = "The recording option, record_model_metadata, on Driver is deprecated. " \
           "Recording of model metadata will always be done"
     with assert_warning(DeprecationWarning, msg):
         prob.driver.recording_options['record_model_metadata'] = True
Пример #27
0
    def test_obj_pass(self):
        prob = om.Problem()
        model = prob.model

        indep = model.add_subsystem('indep',
                                    om.IndepVarComp(),
                                    promotes_outputs=['x'])
        indep.add_discrete_output('x', _DiscreteVal(19))

        G = model.add_subsystem('G', om.ParallelGroup(), promotes_inputs=['x'])

        G1 = G.add_subsystem('G1',
                             om.Group(),
                             promotes_inputs=['x'],
                             promotes_outputs=['y'])
        G1.add_subsystem('C1_1',
                         ObjAdderCompEx(_DiscreteVal(5)),
                         promotes_inputs=['x'])
        G1.add_subsystem('C1_2',
                         ObjAdderCompEx(_DiscreteVal(7)),
                         promotes_outputs=['y'])
        G1.connect('C1_1.y', 'C1_2.x')

        G2 = G.add_subsystem('G2', om.Group(), promotes_inputs=['x'])
        G2.add_subsystem('C2_1',
                         ObjAdderCompEx(_DiscreteVal(1)),
                         promotes_inputs=['x'])
        G2.add_subsystem('C2_2',
                         ObjAdderCompEx(_DiscreteVal(11)),
                         promotes_outputs=['y'])
        G2.connect('C2_1.y', 'C2_2.x')

        model.add_subsystem('C3', ObjAdderCompEx(_DiscreteVal(9)))
        model.add_subsystem('C4', ObjAdderCompEx(_DiscreteVal(21)))

        model.connect('G.y', 'C3.x')
        model.connect('G.G2.y', 'C4.x')

        prob.setup()
        prob.run_model()

        self.assertEqual(prob['C3.y'].getval(), 40)
        self.assertEqual(prob['C4.y'].getval(), 52)

        def _var_iter(obj):
            name = obj['name']
            if 'children' in obj:
                for c in obj['children']:
                    for vname in _var_iter(c):
                        if name:
                            yield '.'.join((name, vname))
                        else:
                            yield vname
            else:
                yield name

        # add a test to see if discrete vars show up in n2
        data = _get_viewer_data(prob)
        findvars = [
            'indep.x',
            'G.G1.C1_1.x',
            'G.G1.C1_1.y',
            'G.G1.C1_2.x',
            'G.G1.C1_2.y',
            'G.G2.C2_1.x',
            'G.G2.C2_1.y',
            'G.G2.C2_2.x',
            'G.G2.C2_2.y',
            'C3.x',
            'C3.y',
            'C4.x',
            'C4.y',
        ]
        vnames = list(_var_iter(data['tree']))
        self.assertTrue(sorted(findvars), sorted(vnames))
Пример #28
0
    def test_units_basic(self):
        prob = om.Problem()
        model = prob.model

        ivc = om.IndepVarComp()
        ivc.add_output('x', 35.0, units='degF')

        model.add_subsystem('p', ivc, promotes=['x'])
        model.add_subsystem('comp1',
                            om.ExecComp('y1 = 2.0*x',
                                        x={
                                            'value': 2.0,
                                            'units': 'degF'
                                        },
                                        y1={
                                            'value': 2.0,
                                            'units': 'degF'
                                        }),
                            promotes=['x', 'y1'])

        model.add_subsystem('comp2',
                            om.ExecComp('y2 = 3.0*x',
                                        x={
                                            'value': 2.0,
                                            'units': 'degF'
                                        },
                                        y2={
                                            'value': 2.0,
                                            'units': 'degF'
                                        }),
                            promotes=['x', 'y2'])

        model.add_design_var('x', units='degC', lower=0.0, upper=100.0)
        model.add_constraint('y1', units='degC', lower=0.0, upper=100.0)
        model.add_objective('y2', units='degC')

        prob.setup()

        prob.run_driver()

        dv = prob.driver.get_design_var_values()
        assert_near_equal(dv['p.x'][0], 3.0 * 5 / 9, 1e-8)

        obj = prob.driver.get_objective_values(driver_scaling=True)
        assert_near_equal(obj['comp2.y2'][0], 73.0 * 5 / 9, 1e-8)

        con = prob.driver.get_constraint_values(driver_scaling=True)
        assert_near_equal(con['comp1.y1'][0], 38.0 * 5 / 9, 1e-8)

        meta = model.get_design_vars()
        assert_near_equal(meta['p.x']['lower'], 0.0, 1e-7)
        assert_near_equal(meta['p.x']['upper'], 100.0, 1e-7)

        meta = model.get_constraints()
        assert_near_equal(meta['comp1.y1']['lower'], 0.0, 1e-7)
        assert_near_equal(meta['comp1.y1']['upper'], 100.0, 1e-7)

        stdout = sys.stdout
        strout = StringIO()
        sys.stdout = strout
        try:
            prob.list_problem_vars(desvar_opts=['units'],
                                   objs_opts=['units'],
                                   cons_opts=['units'])
        finally:
            sys.stdout = stdout
        output = strout.getvalue().split('\n')

        self.assertTrue('1.666' in output[5])
        self.assertTrue('21.111' in output[12])
        self.assertTrue('40.555' in output[19])
        self.assertTrue('degC' in output[5])
        self.assertTrue('degC' in output[12])
        self.assertTrue('degC' in output[19])
Пример #29
0
import openmdao.api as om
import dymos as dm

from donner_sub_ode import DonnerSubODE

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

# Add the trajectory (optional for single phase problems)
traj = dm.Trajectory()

# Create the phase
phase = dm.Phase(ode_class=DonnerSubODE,
                 transcription=dm.GaussLobatto(num_segments=20,
                                               order=3,
                                               compressed=False))

# Add the phase to the trajectory, and the trajectory to the model
traj.add_phase('phase0', phase=phase)
p.model.add_subsystem('traj', traj)

#
# Configure the phase
#
phase.set_time_options(units=None,
                       targets=['threat_comp.time'],
                       fix_initial=True,
                       duration_bounds=(0.1, 100))
phase.add_state('x',
                rate_source='eom_comp.dx_dt',
                targets=['nav_comp.x'],
Пример #30
0
    def testRunAll(self):

        opt = {}
        opt["floating"] = {}
        opt["WISDEM"] = {}
        opt["WISDEM"]["FloatingSE"] = {}
        opt["floating"]["members"] = {}
        opt["floating"]["members"]["n_members"] = n_member = 6
        opt["floating"]["members"]["n_height"] = [2]
        opt["floating"]["members"]["n_bulkheads"] = [4]
        opt["floating"]["members"]["n_layers"] = [1]
        opt["floating"]["members"]["n_ballasts"] = [0]
        opt["floating"]["members"]["n_axial_joints"] = [1]
        opt["floating"]["tower"] = {}
        opt["floating"]["tower"]["n_height"] = [3]
        opt["floating"]["tower"]["n_bulkheads"] = [0]
        opt["floating"]["tower"]["n_layers"] = [1]
        opt["floating"]["tower"]["n_ballasts"] = [0]
        opt["floating"]["tower"]["n_axial_joints"] = [0]
        opt["WISDEM"]["FloatingSE"]["frame3dd"] = {}
        opt["WISDEM"]["FloatingSE"]["frame3dd"]["shear"] = True
        opt["WISDEM"]["FloatingSE"]["frame3dd"]["geom"] = True
        opt["WISDEM"]["FloatingSE"]["frame3dd"]["tol"] = 1e-7
        opt["WISDEM"]["FloatingSE"]["frame3dd"]["modal"] = False  # True
        opt["WISDEM"]["FloatingSE"]["gamma_f"] = 1.35  # Safety factor on loads
        opt["WISDEM"]["FloatingSE"]["gamma_m"] = 1.3  # Safety factor on materials
        opt["WISDEM"]["FloatingSE"]["gamma_n"] = 1.0  # Safety factor on consequence of failure
        opt["WISDEM"]["FloatingSE"]["gamma_b"] = 1.1  # Safety factor on buckling
        opt["WISDEM"]["FloatingSE"]["gamma_fatigue"] = 1.755  # Not used
        opt["mooring"] = {}
        opt["mooring"]["n_attach"] = 3
        opt["mooring"]["n_anchors"] = 3

        opt["materials"] = {}
        opt["materials"]["n_mat"] = 2

        prob = om.Problem()
        prob.model = frame.FloatingFrame(modeling_options=opt)
        prob.setup()

        # Material properties
        prob["rho_mat"] = np.array([7850.0, 5000.0])  # Steel, ballast slurry [kg/m^3]
        prob["E_mat"] = 200e9 * np.ones((2, 3))  # Young's modulus [N/m^2]
        prob["G_mat"] = 79.3e9 * np.ones((2, 3))  # Shear modulus [N/m^2]
        prob["sigma_y_mat"] = 3.45e8 * np.ones(2)  # Elastic yield stress [N/m^2]
        prob["unit_cost_mat"] = np.array([2.0, 1.0])
        prob["material_names"] = ["steel", "slurry"]

        # Mass and cost scaling factors
        prob["labor_cost_rate"] = 1.0  # Cost factor for labor time [$/min]
        prob["painting_cost_rate"] = 14.4  # Cost factor for column surface finishing [$/m^2]

        prob["member0:nodes_xyz"][:2, :] = np.array([[0, 0, 0], [1, 0, 0]])
        prob["member1:nodes_xyz"][:2, :] = np.array([[1, 0, 0], [0.5, 1, 0]])
        prob["member2:nodes_xyz"][:2, :] = np.array([[0.5, 1, 0], [0, 0, 0]])
        prob["member3:nodes_xyz"][:2, :] = np.array([[0, 0, 0], [0, 0, 1]])
        prob["member4:nodes_xyz"][:2, :] = np.array([[1, 0, 0], [0, 0, 1]])
        prob["member5:nodes_xyz"][:2, :] = np.array([[0.5, 1, 0], [0, 0, 1]])
        for k in range(n_member):
            L = np.sqrt(np.sum(np.diff(prob["member" + str(k) + ":nodes_xyz"][:, 2], axis=0) ** 2))
            prob["member" + str(k) + ":nodes_r"][:2] = 0.1 * k * np.ones(2)
            prob["member" + str(k) + ":section_D"][:1] = 2.0
            prob["member" + str(k) + ":section_t"][:1] = 0.1
            prob["member" + str(k) + ":section_A"][:1] = 0.5 * k * np.ones(1) + 1
            prob["member" + str(k) + ":section_Asx"][:1] = 0.5 * k * np.ones(1) + 1
            prob["member" + str(k) + ":section_Asy"][:1] = 0.5 * k * np.ones(1) + 1
            prob["member" + str(k) + ":section_Ixx"][:1] = 2 * k * np.ones(1) + 1
            prob["member" + str(k) + ":section_Iyy"][:1] = 2 * k * np.ones(1) + 1
            prob["member" + str(k) + ":section_Izz"][:1] = 2 * k * np.ones(1) + 1
            prob["member" + str(k) + ":section_rho"][:1] = 1e3 / (0.5 * k * np.ones(1) + 1) / L
            prob["member" + str(k) + ":section_E"][:1] = 3 * k * np.ones(1) + 1
            prob["member" + str(k) + ":section_G"][:1] = 4 * k * np.ones(1) + 1
            prob["member" + str(k) + ":idx_cb"] = 0
            prob["member" + str(k) + ":buoyancy_force"] = 1e2
            prob["member" + str(k) + ":displacement"] = 1e1
            prob["member" + str(k) + ":center_of_buoyancy"] = prob["member" + str(k) + ":nodes_xyz"][:2, :].mean(axis=0)
            prob["member" + str(k) + ":center_of_mass"] = prob["member" + str(k) + ":nodes_xyz"][:2, :].mean(axis=0)
            prob["member" + str(k) + ":total_mass"] = 1e3
            prob["member" + str(k) + ":total_cost"] = 2e3
            prob["member" + str(k) + ":Awater"] = 5.0
            prob["member" + str(k) + ":Iwater"] = 15.0
            prob["member" + str(k) + ":added_mass"] = np.arange(6)

        # Set environment to that used in OC3 testing campaign
        # prob["rho_air"] = 1.226  # Density of air [kg/m^3]
        # prob["mu_air"] = 1.78e-5  # Viscosity of air [kg/m/s]
        prob["rho_water"] = 1025.0  # Density of water [kg/m^3]
        # prob["mu_water"] = 1.08e-3  # Viscosity of water [kg/m/s]
        # prob["water_depth"] = 320.0  # Distance to sea floor [m]
        # prob["Hsig_wave"] = 0.0  # Significant wave height [m]
        # prob["Tsig_wave"] = 1e3  # Wave period [s]
        # prob["shearExp"] = 0.11  # Shear exponent in wind power law
        # prob["cm"] = 2.0  # Added mass coefficient
        # prob["Uc"] = 0.0  # Mean current speed
        # prob["yaw"] = 0.0  # Turbine yaw angle
        # prob["beta_wind"] = prob["beta_wave"] = 0.0
        # prob["cd_usr"] = -1.0  # Compute drag coefficient
        # prob["Uref"] = 10.0
        # prob["zref"] = 100.0

        # Porperties of turbine tower
        nTower = prob.model.options["modeling_options"]["floating"]["tower"]["n_height"][0]
        prob["hub_height"] = 85.0
        prob["distance_tt_hub"] = 5.0
        prob["tower.s"] = np.linspace(0.0, 1.0, nTower)
        prob["tower.outer_diameter_in"] = np.linspace(6.5, 3.87, nTower)
        prob["tower.layer_thickness"] = np.linspace(0.027, 0.019, nTower).reshape((1, nTower))
        prob["tower.layer_materials"] = ["steel"]
        prob["tower.outfitting_factor"] = 1.07

        prob["mooring_neutral_load"] = np.zeros((3, 3))
        prob["mooring_neutral_load"][:, 0] = [200, -100.0, -100]
        prob["mooring_neutral_load"][:, 1] = [0.0, 50, -50]
        prob["mooring_neutral_load"][:, 2] = -1e3
        prob["mooring_fairlead_joints"] = np.array([[0.0, 0.0, 0.0], [0.5, 1.0, 0.0], [1.0, 0.0, 0.0]])
        prob["rna_mass"] = 1e4
        prob["rna_cg"] = np.ones(3)
        prob["rna_I"] = 1e4 * np.arange(6)
        prob["rna_F"] = np.array([1e2, 1e1, 0.0])
        prob["rna_M"] = np.array([2e1, 2e2, 0.0])
        prob["transition_piece_mass"] = 1e3
        prob["transition_node"] = prob["member4:nodes_xyz"][0, :]

        prob.run_model()
        self.assertTrue(True)