Exemple #1
0
    def test_simul_coloring_example(self):

        from openmdao.api import Problem, IndepVarComp, ExecComp, ScipyOptimizeDriver
        import numpy as np

        # note: size must be an even number
        SIZE = 10
        p = Problem()

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

        # the following were randomly generated using np.random.random(10)*2-1 to randomly
        # disperse them within a unit circle centered at the origin.
        indeps.add_output('x', np.array([ 0.55994437, -0.95923447,  0.21798656, -0.02158783,  0.62183717,
                                          0.04007379,  0.46044942, -0.10129622,  0.27720413, -0.37107886]))
        indeps.add_output('y', np.array([ 0.52577864,  0.30894559,  0.8420792 ,  0.35039912, -0.67290778,
                                          -0.86236787, -0.97500023,  0.47739414,  0.51174103,  0.10052582]))
        indeps.add_output('r', .7)

        p.model.add_subsystem('circle', ExecComp('area=pi*r**2'))

        p.model.add_subsystem('r_con', ExecComp('g=x**2 + y**2 - r',
                                                g=np.ones(SIZE), x=np.ones(SIZE), y=np.ones(SIZE)))

        thetas = np.linspace(0, np.pi/4, SIZE)
        p.model.add_subsystem('theta_con', ExecComp('g=arctan(y/x) - theta',
                                                    g=np.ones(SIZE), x=np.ones(SIZE), y=np.ones(SIZE),
                                                    theta=thetas))
        p.model.add_subsystem('delta_theta_con', ExecComp('g = arctan(y/x)[::2]-arctan(y/x)[1::2]',
                                                          g=np.ones(SIZE//2), x=np.ones(SIZE),
                                                          y=np.ones(SIZE)))

        thetas = np.linspace(0, np.pi/4, SIZE)

        p.model.add_subsystem('l_conx', ExecComp('g=x-1', g=np.ones(SIZE), x=np.ones(SIZE)))

        p.model.connect('r', ('circle.r', 'r_con.r'))
        p.model.connect('x', ['r_con.x', 'theta_con.x', 'delta_theta_con.x'])

        p.model.connect('x', 'l_conx.x')

        p.model.connect('y', ['r_con.y', 'theta_con.y', 'delta_theta_con.y'])

        p.driver = ScipyOptimizeDriver()
        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.options['disp'] = False

        p.model.add_design_var('x')
        p.model.add_design_var('y')
        p.model.add_design_var('r', lower=.5, upper=10)

        # nonlinear constraints
        p.model.add_constraint('r_con.g', equals=0)

        IND = np.arange(SIZE, dtype=int)
        ODD_IND = IND[0::2]  # all odd indices
        p.model.add_constraint('theta_con.g', lower=-1e-5, upper=1e-5, indices=ODD_IND)
        p.model.add_constraint('delta_theta_con.g', lower=-1e-5, upper=1e-5)

        # this constrains x[0] to be 1 (see definition of l_conx)
        p.model.add_constraint('l_conx.g', equals=0, linear=False, indices=[0,])

        # linear constraint
        p.model.add_constraint('y', equals=0, indices=[0,], linear=True)

        p.model.add_objective('circle.area', ref=-1)

        # setup coloring
        color_info = ([
           [20],   # uncolored column list
           [0, 2, 4, 6, 8],   # color 1
           [1, 3, 5, 7, 9],   # color 2
           [10, 12, 14, 16, 18],   # color 3
           [11, 13, 15, 17, 19],   # color 4
        ],
        [
           [1, 11, 16, 21],   # column 0
           [2, 16],   # column 1
           [3, 12, 17],   # column 2
           [4, 17],   # column 3
           [5, 13, 18],   # column 4
           [6, 18],   # column 5
           [7, 14, 19],   # column 6
           [8, 19],   # column 7
           [9, 15, 20],   # column 8
           [10, 20],   # column 9
           [1, 11, 16],   # column 10
           [2, 16],   # column 11
           [3, 12, 17],   # column 12
           [4, 17],   # column 13
           [5, 13, 18],   # column 14
           [6, 18],   # column 15
           [7, 14, 19],   # column 16
           [8, 19],   # column 17
           [9, 15, 20],   # column 18
           [10, 20],   # column 19
           None,   # column 20
        ], None)

        p.driver.set_simul_deriv_color(color_info)

        p.setup(mode='fwd')
        p.run_driver()

        assert_almost_equal(p['circle.area'], np.pi, decimal=7)
Exemple #2
0
    def test_dv_at_apogee(self):
        from openmdao.api import Problem, Group, IndepVarComp, ExecComp, ScipyOptimizeDriver
        from openmdao.test_suite.test_examples.test_hohmann_transfer import VCircComp, TransferOrbitComp, DeltaVComp

        prob = Problem(model=Group())

        model = prob.model

        ivc = model.add_subsystem('ivc',
                                  IndepVarComp(),
                                  promotes_outputs=['*'])
        ivc.add_output('mu', val=0.0, units='km**3/s**2')
        ivc.add_output('r1', val=0.0, units='km')
        ivc.add_output('r2', val=0.0, units='km')
        ivc.add_output('dinc1', val=0.0, units='deg')
        ivc.add_output('dinc2', val=0.0, units='deg')

        model.add_subsystem('leo', subsys=VCircComp())
        model.add_subsystem('geo', subsys=VCircComp())

        model.add_subsystem('transfer', subsys=TransferOrbitComp())

        model.connect('r1', ['leo.r', 'transfer.rp'])
        model.connect('r2', ['geo.r', 'transfer.ra'])

        model.connect('mu', ['leo.mu', 'geo.mu', 'transfer.mu'])

        model.add_subsystem('dv1', subsys=DeltaVComp())

        model.connect('leo.vcirc', 'dv1.v1')
        model.connect('transfer.vp', 'dv1.v2')
        model.connect('dinc1', 'dv1.dinc')

        model.add_subsystem('dv2', subsys=DeltaVComp())

        model.connect('transfer.va', 'dv2.v1')
        model.connect('geo.vcirc', 'dv2.v2')
        model.connect('dinc2', 'dv2.dinc')

        model.add_subsystem('dv_total',
                            subsys=ExecComp('delta_v=dv1+dv2',
                                            delta_v={'units': 'km/s'},
                                            dv1={'units': 'km/s'},
                                            dv2={'units': 'km/s'}),
                            promotes=['delta_v'])

        model.connect('dv1.delta_v', 'dv_total.dv1')
        model.connect('dv2.delta_v', 'dv_total.dv2')

        model.add_subsystem('dinc_total',
                            subsys=ExecComp('dinc=dinc1+dinc2',
                                            dinc={'units': 'deg'},
                                            dinc1={'units': 'deg'},
                                            dinc2={'units': 'deg'}),
                            promotes=['dinc'])

        model.connect('dinc1', 'dinc_total.dinc1')
        model.connect('dinc2', 'dinc_total.dinc2')

        prob.driver = ScipyOptimizeDriver()

        model.add_design_var('dinc1', lower=0, upper=28.5)
        model.add_design_var('dinc2', lower=0, upper=28.5)
        model.add_constraint('dinc', lower=28.5, upper=28.5, scaler=1.0)
        model.add_objective('delta_v', scaler=1.0)

        # Setup the problem

        prob.setup()

        prob['mu'] = 398600.4418
        prob['r1'] = 6778.137
        prob['r2'] = 42164.0

        prob['dinc1'] = 0
        prob['dinc2'] = 28.5

        # Execute the model with the given inputs
        prob.run_model()

        print('Delta-V (km/s):', prob['delta_v'][0])
        print('Inclination change split (deg):', prob['dinc1'][0],
              prob['dinc2'][0])

        prob.run_driver()

        print('Optimized Delta-V (km/s):', prob['delta_v'][0])
        print('Inclination change split (deg):', prob['dinc1'][0],
              prob['dinc2'][0])
Exemple #3
0
    def test(self):
        """
        This is an opt problem that tests the fuel volume constraint with the wingbox model
        """

        # 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':
            False,  # 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 = Problem()

        # Add problem information as an independent variables component
        indep_var_comp = 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')
            #=======================================================================================
            #=======================================================================================

        from openmdao.api import ScipyOptimizeDriver
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['tol'] = 1e-9

        # from openmdao.api import pyOptSparseDriver
        # prob.driver = pyOptSparseDriver()
        # # prob.driver.add_recorder(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()

        # from openmdao.api import view_model
        # 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], 83619.581901,
                         1e-5)
        assert_rel_error(self, prob['wing.structural_mass'][0] / 1.25,
                         13768.9206457, 1e-5)
        assert_rel_error(self, prob['fuel_vol_delta.fuel_vol_delta'][0],
                         39.6491222105, 1e-4)
Exemple #4
0
    def test_feature_vectorized_derivs(self):
        import numpy as np
        from openmdao.api import ExplicitComponent, IndepVarComp, Problem, ScipyOptimizeDriver

        SIZE = 5

        class ExpensiveAnalysis(ExplicitComponent):
            def setup(self):

                self.add_input('x', val=np.ones(SIZE))
                self.add_input('y', val=np.ones(SIZE))

                self.add_output('f', shape=1)

                self.declare_partials('f', 'x')
                self.declare_partials('f', 'y')

            def compute(self, inputs, outputs):

                outputs['f'] = np.sum(inputs['x']**inputs['y'])

            def compute_partials(self, inputs, J):

                J['f', 'x'] = inputs['y'] * inputs['x']**(inputs['y'] - 1)
                J['f', 'y'] = (inputs['x']**inputs['y']) * np.log(inputs['x'])

        class CheapConstraint(ExplicitComponent):
            def setup(self):

                self.add_input('y', val=np.ones(SIZE))
                self.add_output('g', shape=SIZE)

                row_col = np.arange(SIZE, dtype=int)
                self.declare_partials('g', 'y', rows=row_col, cols=row_col)

                self.limit = 2 * np.arange(SIZE)

            def compute(self, inputs, outputs):

                outputs['g'] = inputs['y']**2 - self.limit

            def compute_partials(self, inputs, J):

                J['g', 'y'] = 2 * inputs['y']

        p = Problem()

        dvs = p.model.add_subsystem('des_vars', IndepVarComp(), promotes=['*'])
        dvs.add_output('x', 2 * np.ones(SIZE))
        dvs.add_output('y', 2 * np.ones(SIZE))

        p.model.add_subsystem('obj',
                              ExpensiveAnalysis(),
                              promotes=['x', 'y', 'f'])
        p.model.add_subsystem('constraint',
                              CheapConstraint(),
                              promotes=['y', 'g'])

        p.model.add_design_var('x', lower=.1, upper=10000)
        p.model.add_design_var('y', lower=-1000, upper=10000)
        p.model.add_constraint('g', upper=0, vectorize_derivs=True)
        p.model.add_objective('f')

        p.setup(mode='rev')

        p.run_model()

        p.driver = ScipyOptimizeDriver()
        p.run_driver()

        assert_rel_error(self, p['x'], [0.10000691, 0.1, 0.1, 0.1, 0.1], 1e-5)
        assert_rel_error(self, p['y'], [0, 1.41421, 2.0, 2.44948, 2.82842],
                         1e-5)
    def test(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 5,
            'num_x': 3,
            'wing_type': 'rect',
            'symmetry': True,
            'span': 10.,
            'chord': 1,
            'span_cos_spacing': 0.
        }

        mesh = generate_mesh(mesh_dict)

        surf_dict = {
            # Wing definition
            'name': 'wing',  # name of the surface
            'type': 'aero',
            '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': 'tube',
            'twist_cp': np.zeros(5),
            'mesh': mesh,
            'num_x': mesh.shape[0],
            'num_y': mesh.shape[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.0,  # 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.15]),  # thickness over chord ratio (NACA0015)
            'c_max_t': .303,  # chordwise location of maximum (NACA0015)
            # thickness
            'with_viscous': False,  # if true, compute viscous drag
            'with_wave': False,  # if true, compute wave drag
        }

        surfaces = [surf_dict]

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

        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=5., units='deg')
        indep_var_comp.add_output('M', val=0.84)
        indep_var_comp.add_output('re', val=1.e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('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:

            geom_group = Geometry(surface=surface)

            # Add tmp_group to the problem as the name of the surface.
            # Note that is a group and performance group for each
            # individual surface.
            prob.model.add_subsystem(surface['name'], geom_group)

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

            # Create the aero point group and add it to the model
            aero_group = AeroPoint(surfaces=surfaces)
            point_name = 'aero_point_{}'.format(i)
            prob.model.add_subsystem(point_name, aero_group)

            # Connect flow properties to the analysis point
            prob.model.connect('v', point_name + '.v')
            prob.model.connect('alpha', point_name + '.alpha')
            prob.model.connect('M', point_name + '.M')
            prob.model.connect('re', point_name + '.re')
            prob.model.connect('rho', point_name + '.rho')
            prob.model.connect('cg', point_name + '.cg')

            # Connect the parameters within the model for each aero point
            for surface in surfaces:

                name = surface['name']

                # Connect the mesh from the geometry component to the analysis point
                prob.model.connect(name + '.mesh',
                                   point_name + '.' + name + '.def_mesh')

                # Perform the connections with the modified names within the
                # 'aero_states' group.
                prob.model.connect(
                    name + '.mesh',
                    point_name + '.aero_states.' + name + '_def_mesh')

                prob.model.connect(
                    name + '.t_over_c',
                    point_name + '.' + name + '_perf.' + 't_over_c')

        from openmdao.api import ScipyOptimizeDriver
        prob.driver = ScipyOptimizeDriver()

        # # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.)
        prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5)
        prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4)

        # Set up the problem
        prob.setup()

        prob.run_model()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0],
                         .46173591841167, 1e-6)
        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0],
                         .005524603647, 1e-6)
Exemple #6
0
    def test_recording_remote_voi(self):
        # Create a parallel model
        model = Group()

        model.add_subsystem('par', ParallelGroup())
        model.par.add_subsystem('G1', Mygroup())
        model.par.add_subsystem('G2', Mygroup())
        model.connect('par.G1.y', 'Obj.y1')
        model.connect('par.G2.y', 'Obj.y2')

        model.add_subsystem('Obj', ExecComp('obj=y1+y2'))
        model.add_objective('Obj.obj')

        # Configure driver to record VOIs on both procs
        driver = ScipyOptimizeDriver(disp=False)

        driver.recording_options['record_desvars'] = True
        driver.recording_options['record_objectives'] = True
        driver.recording_options['record_constraints'] = True
        driver.recording_options['includes'] = ['par.G1.y', 'par.G2.y']

        driver.add_recorder(self.recorder)

        # Create problem and run driver
        prob = Problem(model, driver)
        prob.add_recorder(self.recorder)
        prob.setup(mode='fwd')

        t0, t1 = run_driver(prob)
        prob.record('final')
        t2 = time()

        prob.cleanup()

        # Since the test will compare the last case recorded, just check the
        # current values in the problem. This next section is about getting those values

        # These involve collective gathers so all ranks need to run this
        expected_outputs = driver.get_design_var_values()
        expected_outputs.update(driver.get_objective_values())
        expected_outputs.update(driver.get_constraint_values())

        # includes for outputs are specified as promoted names but we need absolute names
        prom2abs = model._var_allprocs_prom2abs_list['output']
        abs_includes = [
            prom2abs[n][0] for n in prob.driver.recording_options['includes']
        ]

        # Absolute path names of includes on this rank
        rrank = model.comm.rank
        rowned = model._owning_rank
        local_includes = [n for n in abs_includes if rrank == rowned[n]]

        # Get values for all vars on this rank
        inputs, outputs, residuals = model.get_nonlinear_vectors()

        # Get values for includes on this rank
        local_vars = {n: outputs[n] for n in local_includes}

        # Gather values for includes on all ranks
        all_vars = model.comm.gather(local_vars, root=0)

        if prob.comm.rank == 0:
            # Only on rank 0 do we have all the values. The all_vars variable is a list of
            # dicts from all ranks 0,1,... In this case, just ranks 0 and 1
            dct = {}
            for d in all_vars:
                dct.update(d)

            expected_includes = {
                'par.G1.Cy.y': dct['par.G1.Cy.y'],
                'par.G2.Cy.y': dct['par.G2.Cy.y'],
            }

            expected_outputs.update(expected_includes)

            coordinate = [0, 'ScipyOptimize_SLSQP', (driver.iter_count - 1, )]

            expected_data = ((coordinate, (t0, t1), expected_outputs, None,
                              None), )
            assertDriverIterDataRecorded(self, expected_data, self.eps)

            expected_data = (('final', (t1, t2), expected_outputs), )
            assertProblemDataRecorded(self, expected_data, self.eps)
Exemple #7
0
def fctOptim(mrhoi, skin, spar, span, toverc):

    # Starting time
    starttime = time.time()

    # Materials
    #sandw1=material(66.35,4.25e9,1.63e9,58.7e6/1.5,34.7,"sandw1")
    #sandw2=material(174.5,14.15e9,5.44e9,195.6e6/1.5,43.4,"sandw2")
    #sandw3=material(483,42.5e9,16.3e9,586e6/1.5,46.8,"sandw3")
    sandw4 = material(504.5, 42.5e9, 16.3e9, 586e6 / 1.5, 44.9, "sandw4")
    #sandw5=material(574.5,42.5e9,16.3e9,586e6/1.5,39.3,"sandw5")
    sandw5 = material(560.5, 42.5e9, 16.3e9, 586e6 / 1.5, 40.3, "sandw5")
    sandw6 = material(529, 42.5e9, 16.3e9, 237e6 / 1.5, 42.75, "sandw6")
    al7075 = material(2.80e3, 72.5e9, 27e9, 444.5e6 / 1.5,
                      13.15 * (1 - 0.426) + 2.61 * 0.426,
                      "al7075")  #from EDUPACK
    #al7075oas=material(2.78e3,73.1e9,73.1e9/2/1.33,444.5e6/1.5,13.15*(1-0.426)+2.61*0.426,"al7075") #from OAS example
    qiCFRP = material(1565, 54.9e9, 21e9, 670e6 / 1.5, 48.1, "qiCFRP")
    steel = material(7750, 200e9, 78.5e9, 562e6 / 1.5,
                     4.55 * (1 - 0.374) + 1.15 * 0.374, "steel")
    gfrp = material(1860, 21.4e9, 8.14e9, 255e6, 6.18,
                    "gfrp")  #epoxy-Eglass,woven,QI
    #nomat=material(1370,0.01,0.01,0.01,60,"noMaterial")
    nomat = material(50, 1e8, 1e4, 1e5, 6000, "noMaterial")
    #nomat=material(50,1e8,1e4,1e5,60,"noMaterial")
    fakemat = material((2.80e3 + 7750) / 2, (72.5e9 + 200e9) / 2,
                       (27e9 + 78.5e9) / 2, (444.5e6 / 1.5 + 562e6 / 1.5) / 2,
                       (13.15 * (1 - 0.426) + 2.61 * 0.426 + 4.55 *
                        (1 - 0.374) + 1.15 * 0.374) / 2, "fakemat")
    nomatEnd = material(10000, 5e9, 2e9, 20e6 / 1.5, 60, "nomatEnd")

    materials = [
        al7075, qiCFRP, steel, gfrp, nomat, fakemat, nomatEnd, sandw4, sandw5,
        sandw6
    ]
    #    materials=[al7075, qiCFRP, steel, gfrp, nomat, fakemat, nomatEnd, sandw3, sandw4, sandw5, sandw6]
    #    materials=[al7075, qiCFRP, steel, gfrp, nomat, fakemat, nomatEnd,sandw1,sandw2,sandw3]
    #    materials=[sandw4, sandw5, nomat, nomatEnd]

    # Provide coordinates for a portion of an airfoil for the wingbox cross-section as an nparray with dtype=complex (to work with the complex-step approximation for derivatives).
    # These should be for an airfoil with the chord scaled to 1.
    # We use the 10% to 60% portion of the NACA 63412 airfoil for this case
    # We use the coordinates available from airfoiltools.com. Using such a large number of coordinates is not necessary.
    # The first and last x-coordinates of the upper and lower surfaces must be the same
    upper_x = np.array([
        0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21,
        0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33,
        0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45,
        0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57,
        0.58, 0.59, 0.6
    ],
                       dtype='complex128')
    lower_x = np.array([
        0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21,
        0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33,
        0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45,
        0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57,
        0.58, 0.59, 0.6
    ],
                       dtype='complex128')
    upper_y = np.array([
        0.0513, 0.0537, 0.0559, 0.0580, 0.0600, 0.0619, 0.0636, 0.0652, 0.0668,
        0.0682, 0.0696, 0.0709, 0.0721, 0.0732, 0.0742, 0.0752, 0.0761, 0.0769,
        0.0776, 0.0782, 0.0788, 0.0793, 0.0797, 0.0801, 0.0804, 0.0806, 0.0808,
        0.0808, 0.0808, 0.0807, 0.0806, 0.0804, 0.0801, 0.0798, 0.0794, 0.0789,
        0.0784, 0.0778, 0.0771, 0.0764, 0.0757, 0.0749, 0.0740, 0.0732, 0.0723,
        0.0713, 0.0703, 0.0692, 0.0681, 0.0669, 0.0657
    ],
                       dtype='complex128')
    lower_y = np.array([
        -0.0296, -0.0307, -0.0317, -0.0326, -0.0335, -0.0343, -0.0350, -0.0357,
        -0.0363, -0.0368, -0.0373, -0.0378, -0.0382, -0.0386, -0.0389, -0.0391,
        -0.0394, -0.0395, -0.0397, -0.0398, -0.0398, -0.0398, -0.0398, -0.0397,
        -0.0396, -0.0394, -0.0392, -0.0389, -0.0386, -0.0382, -0.0378, -0.0374,
        -0.0369, -0.0363, -0.0358, -0.0352, -0.0345, -0.0338, -0.0331, -0.0324,
        -0.0316, -0.0308, -0.0300, -0.0292, -0.0283, -0.0274, -0.0265, -0.0256,
        -0.0246, -0.0237, -0.0227
    ],
                       dtype='complex128')

    Rcurv = RadiusCurvature(upper_x, lower_x, upper_y, lower_y)

    # Create a dictionary to store options about the surface
    mesh_dict = {
        'num_y': 15,
        'num_x': 3,
        'wing_type': 'rect',
        'symmetry': True,
        'chord_cos_spacing': 0,
        'span_cos_spacing': 0,
        'num_twist_cp': 4
    }

    mesh = generate_mesh(mesh_dict)

    # Batteries and solar panels
    densityPV = 0.23  #kg/m^2
    energeticDensityBattery = 435 * 0.995 * 0.95 * 0.875 * 0.97  #Wh/kg 0.995=battery controller efficiency, 0.95=end of life capacity loss of 5%, 0.97=min battery SOC of 3%, 0.875=packaging efficiency
    emissionBat = 0.104 / 0.995 / 0.95 / 0.875 / 0.97  #[kgCO2/Wh]
    night_hours = 13  #h
    productivityPV = 350.0 * 0.97 * 0.95  #[W/m^2] 350 from Zephyr power figure, 0.97=MPPT efficiency, 0.95=battery round trip efficiency
    emissionPV = 0.05 / 0.97 / 0.95  #[kgCO2/W] emissions of the needed PV surface to produce 1W
    emissionsPerW = emissionPV + emissionBat * night_hours  #[kgCO2/W]

    # Dictionary for the lifting surface
    surf_dict = {
        # Wing definition
        'name':
        'wing',  # give the surface some name
        'symmetry':
        True,  # if True, model only one half of the lifting surface
        'S_ref_type':
        'projected',  # how we compute the wing area,
        # can be 'wetted' or 'projected'
        'mesh':
        mesh,
        'fem_model_type':
        'wingbox',  # 'wingbox' or 'tube'
        'data_x_upper':
        upper_x,
        'data_x_lower':
        lower_x,
        'data_y_upper':
        upper_y,
        'data_y_lower':
        lower_y,
        'airfoil_radius_curvature':
        Rcurv,
        'twist_cp':
        np.array([10., 20., 20., 20.]),  # [deg]
        'chord_cp': [1.5],  # [m]
        'span':
        span,  #[m]
        'taper':
        0.3,
        'spar_thickness_cp':
        np.array([spar, spar, spar, spar]),  # [m]
        'skin_thickness_cp':
        np.array([skin / 2, skin, skin * 1.5, 2 * skin]),  # [m]
        't_over_c_cp':
        np.array([0.75 * toverc, toverc, toverc, 1.25 * toverc]),  #TODELETE
        'original_wingbox_airfoil_t_over_c':
        0.12,

        # Aerodynamic deltas.
        # 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.
        # They can be used to account for things that are not included, such as contributions from the fuselage, camber, etc.
        'CL0':
        0.0,  # CL delta
        'CD0':
        0.0078,  # CD delta
        'with_viscous':
        True,  # if true, compute viscous drag
        'with_wave':
        True,  # if true, compute wave drag

        # Airfoil properties for viscous drag calculation
        'k_lam':
        0.80,
        #'k_lam' : 0.05,         # fraction of chord with laminar
        # flow, used for viscous drag
        'c_max_t':
        .349,  # chordwise location of maximum thickness

        # Materials
        'materlist':
        materials,
        'puissanceMM':
        1,  #power used in muli-material function

        # Structural values
        'strength_factor_for_upper_skin':
        1.0,  # the yield stress is multiplied by this factor for the upper skin
        'wing_weight_ratio':
        1.,
        'exact_failure_constraint':
        False,  # if false, use KS function
        'struct_weight_relief':
        True,

        # Engines
        'n_point_masses':
        1,  # number of point masses in the system; in this case, the engine (omit option if no point masses)

        # Power
        'productivityPV':
        productivityPV,  #[W/m^2]
        'densityPV':
        densityPV + productivityPV / energeticDensityBattery *
        night_hours,  #[kg/m^2] the weight of the batteries is counted here
        'payload_power':
        125.5,  #[W] payload=150 + avionics=211
        'motor_propeller_efficiency':
        0.84,  #thrusting power/electrical power used by propulsion
        'co2PV':
        emissionsPerW * productivityPV /
        (densityPV + productivityPV / energeticDensityBattery *
         night_hours),  #[kgCO2/kg] #co2 burden of PV cells and battery
        'prop_density':
        0.0058,  #[kg/W]
        'mppt_density':
        0.00045,  #[kg/W]
    }

    surfaces = [surf_dict]

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

    # Add problem information as an independent variables component data for altitude=23240 m and 0 m
    speed = 15.56  #m/s
    speed_dive = 1.4 * speed  #m/s
    gust_speed = 3.4  #m/s
    rho_air = 0.089  #kg/m**3
    speed_sound = 295.1  #m/s
    #n_gust = 1 + 0.5*rho_air*speed_dive*gust_speed*2*pi/3000

    indep_var_comp = IndepVarComp()
    indep_var_comp.add_output('Mach_number',
                              val=np.array([
                                  speed / speed_sound,
                                  (speed_dive**2 + gust_speed**2)**0.5 /
                                  speed_sound, 0
                              ]))
    indep_var_comp.add_output(
        'v',
        val=np.array([speed, (speed_dive**2 + gust_speed**2)**0.5, 0]),
        units='m/s')
    indep_var_comp.add_output('re',val=np.array([rho_air*speed*1./(1.4*1e-5), \
                              rho_air*speed_dive*1./(1.4*1e-5), 0]),  units='1/m') #L=10m,
    indep_var_comp.add_output('rho',
                              val=np.array([rho_air, rho_air, 1.225]),
                              units='kg/m**3')
    indep_var_comp.add_output('speed_of_sound',
                              val=np.array([speed_sound, speed_sound, 340]),
                              units='m/s')

    indep_var_comp.add_output('W0_without_point_masses', val=8, units='kg')

    indep_var_comp.add_output('load_factor', val=np.array([1., 1.1, 0.]))
    indep_var_comp.add_output('alpha', val=0., units='deg')
    indep_var_comp.add_output('alpha_gust',
                              val=atan(gust_speed / speed_dive) * 180 / pi,
                              units='deg')

    indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m')

    indep_var_comp.add_output('mrho',
                              val=np.array([mrhoi, mrhoi]),
                              units='kg/m**3')

    indep_var_comp.add_output('engine_location', val=-0.3)  #VMGM

    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 groups to the problem with the name of the surface.
        prob.model.add_subsystem(name, aerostruct_group)

    prob.model.add_subsystem('YoungMM',
                             YoungMM(surface=surface),
                             promotes_inputs=['mrho'],
                             promotes_outputs=['young'])  #VMGM
    prob.model.add_subsystem('ShearMM',
                             ShearMM(surface=surface),
                             promotes_inputs=['mrho'],
                             promotes_outputs=['shear'])  #VMGM
    prob.model.add_subsystem('YieldMM',
                             YieldMM(surface=surface),
                             promotes_inputs=['mrho'],
                             promotes_outputs=['yield'])  #VMGM
    prob.model.add_subsystem('CO2MM',
                             CO2MM(surface=surface),
                             promotes_inputs=['mrho'],
                             promotes_outputs=['co2'])  #VMGM
    prob.model.add_subsystem(
        'PointMassLocations',
        PointMassLocations(surface=surface),
        promotes_inputs=['engine_location', 'span', 'nodes'],
        promotes_outputs=['point_mass_locations'])  #VMGM
    prob.model.add_subsystem('PointMasses',
                             PointMasses(surface=surface),
                             promotes_inputs=['PV_surface'],
                             promotes_outputs=['point_masses'])  #VMGM

    prob.model.add_subsystem(
        'W0_comp',
        ExecComp('W0 = W0_without_point_masses + 2*sum(point_masses)',
                 units='kg'),
        promotes=['*'])

    prob.model.connect('mrho',
                       name + '.struct_setup.structural_mass.mrho')  #ED
    prob.model.connect('young', name +
                       '.struct_setup.assembly.local_stiff.young')  #VMGM
    prob.model.connect('shear', name +
                       '.struct_setup.assembly.local_stiff.shear')  #VMGM
    prob.model.connect('wing.span', 'span')  #VMGM
    prob.model.connect('AS_point_0.total_perf.PV_surface', 'PV_surface')  #VMGM
    prob.model.connect(name + '.nodes', 'nodes')  #VMGM

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

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

        # Create the aerostruct 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', src_indices=[i])
        prob.model.connect('Mach_number',
                           point_name + '.Mach_number',
                           src_indices=[i])
        prob.model.connect('re', point_name + '.re', src_indices=[i])
        prob.model.connect('rho', point_name + '.rho', src_indices=[i])
        prob.model.connect('W0', point_name + '.W0')
        prob.model.connect('speed_of_sound',
                           point_name + '.speed_of_sound',
                           src_indices=[i])
        prob.model.connect('empty_cg', point_name + '.empty_cg')
        prob.model.connect('load_factor',
                           point_name + '.load_factor',
                           src_indices=[i])

        for surface in surfaces:

            name = surface['name']

            prob.model.connect('load_factor',
                               point_name + '.coupled.load_factor',
                               src_indices=[i])  #for PV distributed weight

            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')
            prob.model.connect('young',
                               com_name + 'struct_funcs.vonmises.young')
            prob.model.connect('shear',
                               com_name + 'struct_funcs.vonmises.shear')
            prob.model.connect('yield',
                               com_name + 'struct_funcs.failure.yield')  #VMGM
            prob.model.connect('young',
                               com_name + 'struct_funcs.buckling.young')  #VMGM
            prob.model.connect('shear',
                               com_name + 'struct_funcs.buckling.shear')  #VMGM
            prob.model.connect(name + '.t_over_c', com_name +
                               'struct_funcs.buckling.t_over_c')  #VMGM

            # Connect aerodyamic mesh to coupled group mesh
            prob.model.connect(name + '.mesh',
                               point_name + '.coupled.' + name + '.mesh')
            if surf_dict['struct_weight_relief']:
                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 + '.Qx', com_name + 'Qx')

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

            coupled_name = point_name + '.coupled.' + name
            prob.model.connect('point_masses', coupled_name + '.point_masses')
            prob.model.connect('point_mass_locations',
                               coupled_name + '.point_mass_locations')

    prob.model.connect('alpha', 'AS_point_0' + '.alpha')
    prob.model.connect('alpha_gust', 'AS_point_1' + '.alpha')
    prob.model.connect('alpha', 'AS_point_2' + '.alpha')  #VMGM

    # Here we add the co2 objective componenet to the model
    prob.model.add_subsystem('emittedco2',
                             structureCO2(surfaces=surfaces),
                             promotes_inputs=['co2'],
                             promotes_outputs=['emitted_co2'])  #VMGM
    prob.model.connect('wing.structural_mass', 'emittedco2.mass')
    prob.model.connect('AS_point_0.total_perf.PV_mass', 'emittedco2.PV_mass')
    prob.model.connect('wing.spars_mass', 'emittedco2.spars_mass')  #VMGM

    #Here we add the thickness constraint to the model
    prob.model.add_subsystem('acceptableThickness',
                             checkThickness(surface=surface),
                             promotes_outputs=['acceptableThickness'])
    prob.model.connect('wing.geometry.t_over_c_cp',
                       'acceptableThickness.t_over_c')
    prob.model.connect('wing.chord_cp', 'acceptableThickness.chordroot')
    prob.model.connect('wing.skin_thickness_cp',
                       'acceptableThickness.skinThickness')
    prob.model.connect('wing.taper', 'acceptableThickness.taper')

    prob.model.connect('wing.struct_setup.PV_areas',
                       'AS_point_0.coupled.wing.struct_states.PV_areas')
    prob.model.connect('AS_point_0.total_perf.PV_mass',
                       'AS_point_0.coupled.wing.struct_states.PV_mass')
    prob.model.connect('wing.struct_setup.PV_areas',
                       'AS_point_1.coupled.wing.struct_states.PV_areas')
    prob.model.connect('AS_point_0.total_perf.PV_mass',
                       'AS_point_1.coupled.wing.struct_states.PV_mass')
    prob.model.connect('wing.chord_cp',
                       'AS_point_1.wing_perf.struct_funcs.chord')
    prob.model.connect('wing.taper', 'AS_point_1.wing_perf.struct_funcs.taper')
    prob.model.connect('wing.struct_setup.PV_areas',
                       'AS_point_2.coupled.wing.struct_states.PV_areas')  #VMGM
    prob.model.connect('AS_point_0.total_perf.PV_mass',
                       'AS_point_2.coupled.wing.struct_states.PV_mass')  #VMGM
    prob.model.connect('wing.chord_cp',
                       'AS_point_2.wing_perf.struct_funcs.chord')  #VMGM
    prob.model.connect('wing.taper',
                       'AS_point_2.wing_perf.struct_funcs.taper')  #VMGM

    # Objective function
    prob.model.add_objective('emitted_co2', scaler=1e-4)

    # Design variables
    prob.model.add_design_var('wing.twist_cp',
                              lower=-20.,
                              upper=20.,
                              scaler=0.1)  #VMGM
    prob.model.add_design_var('wing.spar_thickness_cp',
                              lower=0.0001,
                              upper=0.1,
                              scaler=1e4)
    prob.model.add_design_var('wing.skin_thickness_cp',
                              lower=0.0001,
                              upper=0.1,
                              scaler=1e3)
    prob.model.add_design_var('wing.span', lower=1., upper=1000., scaler=0.1)
    prob.model.add_design_var('wing.chord_cp', lower=1.4, upper=500., scaler=1)
    ##prob.model.add_design_var('wing.span', lower=1., upper=50., scaler=0.1)
    ##prob.model.add_design_var('wing.chord_cp', lower=1., upper=500., scaler=1)
    prob.model.add_design_var('wing.taper', lower=0.3, upper=0.99, scaler=10)
    prob.model.add_design_var('wing.geometry.t_over_c_cp',
                              lower=0.01,
                              upper=0.4,
                              scaler=10.)
    prob.model.add_design_var('mrho', lower=504.5, upper=504.5,
                              scaler=0.001)  #ED
    #prob.model.add_design_var('mrho', lower=500, upper=8000, scaler=0.001) #ED
    prob.model.add_design_var('engine_location', lower=-1, upper=0,
                              scaler=10.)  #VMGM

    # Constraints
    prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.)
    prob.model.add_constraint(
        'AS_point_0.enough_power', upper=0.
    )  #Make sure needed power stays below the solar power producible by the wing
    prob.model.add_constraint(
        'acceptableThickness', upper=0.
    )  #Make sure skin thickness fits in the wing (to avoid negative spar mass)
    #prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.)  #VMGM
    #prob.model.add_constraint('AS_point_0.wing_perf.buckling', upper=0.)  #VMGM
    prob.model.add_constraint('AS_point_1.wing_perf.failure', upper=0.)
    prob.model.add_constraint('AS_point_1.wing_perf.buckling', upper=0.)
    prob.model.add_constraint('AS_point_2.wing_perf.failure', upper=0.)  #VMGM
    prob.model.add_constraint('AS_point_2.wing_perf.buckling', upper=0.)  #VMGM
    prob.model.add_constraint(
        'AS_point_0.coupled.wing.S_ref',
        upper=200.)  # Surface constarint to avoid snowball effect

    #prob.model.approx_totals(method='fd', step=5e-7, form='forward', step_calc='rel')
    #prob.model.nonlinear_solver = newton = NewtonSolver()

    prob.driver = ScipyOptimizeDriver()
    prob.driver.options['optimizer'] = 'SLSQP'
    prob.driver.options['tol'] = 1e-6
    prob.driver.options['maxiter'] = 250
    #prob.driver.options['debug_print'] = ['desvars','ln_cons','nl_cons','totals']

    recorder = SqliteRecorder("aerostructMrhoi" + str(mrhoi) + "sk" +
                              str(skin) + "sr" + str(spar) + "sn" + str(span) +
                              "tc" + str(toverc) + ".db")
    prob.driver.add_recorder(recorder)

    # We could also just use prob.driver.recording_options['includes']=['*'] here, but for large meshes the database file becomes extremely large. So we just select the variables we need.
    prob.driver.recording_options['includes'] = [
        'alpha',
        'rho',
        'v',
        'cg',
        'alpha_gust',  #
        'AS_point_1.cg',
        'AS_point_0.cg',  #
        'AS_point_0.cg',  #ED
        'AS_point_0.coupled.wing_loads.loads',
        'AS_point_1.coupled.wing_loads.loads',  #
        'AS_point_2.coupled.wing_loads.loads',  #
        'AS_point_0.coupled.wing.normals',
        'AS_point_1.coupled.wing.normals',  #
        'AS_point_0.coupled.wing.widths',
        'AS_point_1.coupled.wing.widths',  #
        'AS_point_0.coupled.aero_states.wing_sec_forces',
        'AS_point_1.coupled.aero_states.wing_sec_forces',  #
        'AS_point_2.coupled.aero_states.wing_sec_forces',  #
        'AS_point_0.wing_perf.CL1',
        'AS_point_1.wing_perf.CL1',  #
        'AS_point_0.coupled.wing.S_ref',
        'AS_point_1.coupled.wing.S_ref',  #
        'wing.geometry.twist',
        'wing.geometry.mesh.taper.taper',
        'wing.geometry.mesh.stretch.span',
        'wing.geometry.mesh.scale_x.chord',
        'wing.mesh',
        'wing.skin_thickness',
        'wing.spar_thickness',
        'wing.t_over_c',
        'wing.structural_mass',
        'AS_point_0.wing_perf.vonmises',
        'AS_point_1.wing_perf.vonmises',  #
        'AS_point_0.coupled.wing.def_mesh',
        'AS_point_1.coupled.wing.def_mesh',  #
        'AS_point_0.total_perf.PV_mass',
        'AS_point_0.total_perf.total_weight',
        'AS_point_0.CL',
        'AS_point_0.CD',
        'yield',
        'point_masses',  #VMGM
        'point_mass_locations',  #VMGM
        'engine_location',  #VMGM
    ]

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

    # Set up the problem
    prob.setup()

    ##prob.run_model() #ED2
    ##data = prob.check_partials(out_stream=None, compact_print=True, method='cs') #ED2
    ##print(data)  #ED2

    prob.run_driver()
    ##print (prob.model.list_outputs(values=False, implicit=False))  #VMGM
    print('The wingbox mass (including the wing_weight_ratio) is',
          prob['wing.structural_mass'][0], '[kg]')
    endtime = time.time()
    totaltime = endtime - starttime
    print('computing time is', totaltime)
    print('co2 emissions are', prob['emitted_co2'][0])
    print('The wing surface is', prob['AS_point_0.coupled.wing.S_ref'][0],
          '[m2]')  #VMGM

    return prob['wing.structural_mass'][0], totaltime, prob['mrho'][0], prob[
        'emitted_co2'][0]
    def test_brachistochrone_vector_ode_path_constraints_rk_partial_indices(
            self):

        p = Problem(model=Group())

        p.driver = ScipyOptimizeDriver()
        p.driver.options['dynamic_simul_derivs'] = True

        phase = Phase(ode_class=BrachistochroneVectorStatesODE,
                      transcription=RungeKutta(num_segments=20))

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

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

        phase.set_state_options('pos', fix_initial=True, fix_final=False)
        phase.set_state_options('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_design_parameter('g', units='m/s**2', opt=False, val=9.80665)

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

        phase.add_path_constraint('pos_dot',
                                  shape=(2, ),
                                  units='m/s',
                                  indices=[1],
                                  lower=-4,
                                  upper=4)

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

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

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

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

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

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

        p.run_driver()

        assert_rel_error(self,
                         np.min(p.get_val('phase0.timeseries.pos_dot')[:, -1]),
                         -4,
                         tolerance=1.0E-2)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            plt.show()

        return p
Exemple #9
0
    def test(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 5,
            'num_x': 3,
            'wing_type': 'rect',
            'symmetry': True,
            'span_cos_spacing': 1.,
            'span': 10,
            'chord': 1
        }

        mesh = generate_mesh(mesh_dict)

        surf_dict = {
            # Wing definition
            'name': 'wing',  # name of the surface
            'type': 'structural',
            'symmetry': True,  # if true, model one half of wing
            # reflected across the plane y = 0
            'fem_model_type': 'tube',
            'mesh': mesh,
            'num_x': mesh.shape[0],
            'num_y': mesh.shape[1],

            # Structural values are based on aluminum 7075
            'E': 70.e9,  # [Pa] Young's modulus of the spar
            'G': 30.e9,  # [Pa] shear modulus of the spar
            'yield':
            500.e6 / 2.5,  # [Pa] yield stress divided by 2.5 for limiting case
            'mrho': 3.e3,  # [kg/m^3] material density
            'fem_origin': 0.35,  # normalized chordwise location of the spar
            't_over_c_cp': np.array([0.15]),  # maximum airfoil thickness
            'thickness_cp': np.ones((3)) * .0075,
            'wing_weight_ratio': 1.,
            'exact_failure_constraint': False,
        }

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

        ny = surf_dict['num_y']

        loads = np.zeros((ny, 6))
        loads[0, 2] = 1e4
        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('loads', val=loads, units='N')
        indep_var_comp.add_output('load_factor', val=1.)

        struct_group = SpatialBeamAlone(surface=surf_dict)

        # Add indep_vars to the structural group
        struct_group.add_subsystem('indep_vars',
                                   indep_var_comp,
                                   promotes=['*'])

        prob.model.add_subsystem(surf_dict['name'], struct_group)

        from openmdao.api import ScipyOptimizeDriver
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['disp'] = True

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.thickness_cp',
                                  lower=0.001,
                                  upper=0.25,
                                  scaler=1e2)
        prob.model.add_constraint('wing.failure', upper=0.)
        prob.model.add_constraint('wing.thickness_intersects', upper=0.)

        # Add design variables, constraisnt, and objective on the problem
        prob.model.add_objective('wing.structural_weight', scaler=1e-5)

        # Set up the problem
        prob.setup()

        # from openmdao.api import view_model
        # view_model(prob)

        prob.run_driver()

        assert_rel_error(self, prob['wing.structural_weight'][0],
                         1144.8503583047038, 1e-4)
    def test_cruise_results(self):
        p = Problem(model=Group())
        if optimizer == 'SNOPT':
            p.driver = pyOptSparseDriver()
            p.driver.options['optimizer'] = optimizer
            p.driver.options['dynamic_simul_derivs'] = True
            p.driver.opt_settings['Major iterations limit'] = 100
            p.driver.opt_settings['Major step limit'] = 0.05
            p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6
            p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6
            p.driver.opt_settings["Linesearch tolerance"] = 0.10
            p.driver.opt_settings['iSumm'] = 6
            p.driver.opt_settings['Verify level'] = 3
        else:
            p.driver = ScipyOptimizeDriver()
            p.driver.options['dynamic_simul_derivs'] = True

        phase = Phase('gauss-lobatto',
                      ode_class=AircraftODE,
                      num_segments=1,
                      transcription_order=13)

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

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

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

        phase.set_state_options('range',
                                units='km',
                                fix_initial=True,
                                fix_final=False,
                                scaler=0.01,
                                defect_scaler=0.01)
        phase.set_state_options('mass_fuel',
                                fix_final=True,
                                upper=20000.0,
                                lower=0.0,
                                scaler=1.0E-4,
                                defect_scaler=1.0E-2)

        phase.add_control('alt',
                          units='km',
                          opt=False,
                          rate_param='climb_rate')

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

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

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

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

        phase.add_objective('time', loc='final', ref=3600)

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

        p.setup()

        p['phase0.t_initial'] = 0.0
        p['phase0.t_duration'] = 1.515132 * 3600.0
        p['phase0.states:range'] = phase.interpolate(ys=(0, 1296.4),
                                                     nodes='state_input')
        p['phase0.states:mass_fuel'] = phase.interpolate(ys=(12236.594555, 0),
                                                         nodes='state_input')
        p['phase0.controls:mach'] = 0.8
        p['phase0.controls:alt'] = 5.0

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

        p.run_driver()

        tas = phase.get_values('tas_comp.TAS', units='m/s')
        time = phase.get_values('time', units='s')
        range = phase.get_values('range', units='m')

        assert_rel_error(self, range, tas * time, tolerance=1.0E-9)
    def test(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 7,
            'wing_type': 'uCRM_based',
            'symmetry': True,
            'num_twist_cp': 5
        }

        mesh, twist_cp = generate_mesh(mesh_dict)

        surf_dict = {
            # Wing definition
            'name':
            'wing',  # name of the surface
            # 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',
            'symmetry':
            True,
            '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':
            False,
            'distributed_fuel_weight':
            True,
            # Constraints
            'exact_failure_constraint':
            True,  # 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
        }

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

        ny = surf_dict['mesh'].shape[1]

        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('loads',
                                  val=np.ones((ny, 6)) * 2e5,
                                  units='N')
        indep_var_comp.add_output('load_factor', val=1.)
        indep_var_comp.add_output('fuel_mass', val=10000., units='kg')
        struct_group = SpatialBeamAlone(surface=surf_dict)
        # Add indep_vars to the structural group
        struct_group.add_subsystem('indep_vars',
                                   indep_var_comp,
                                   promotes=['*'])
        prob.model.add_subsystem(surf_dict['name'], struct_group)
        if surf_dict['distributed_fuel_weight']:
            prob.model.connect('wing.fuel_mass',
                               'wing.struct_states.fuel_mass')
            prob.model.connect('wing.struct_setup.fuel_vols',
                               'wing.struct_states.fuel_vols')

        from openmdao.api import ScipyOptimizeDriver
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['tol'] = 1e-9

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.spar_thickness_cp',
                                  lower=0.01,
                                  upper=0.5,
                                  ref=1e-1)
        prob.model.add_design_var('wing.skin_thickness_cp',
                                  lower=0.01,
                                  upper=0.5,
                                  ref=1e-1)
        prob.model.add_constraint('wing.failure', upper=0.)
        #prob.model.add_constraint('wing.thickness_intersects', upper=0.)

        # Add design variables, constraisnt, and objective on the problem
        prob.model.add_objective('wing.structural_mass', scaler=1e-5)

        # Set up the problem
        prob.setup(force_alloc_complex=False)

        prob.run_model()
        data = prob.check_partials(compact_print=True,
                                   out_stream=None,
                                   method='fd')
        assert_check_partials(data, atol=1e20, rtol=1e-6)

        prob.run_driver()
        assert_rel_error(self, prob['wing.structural_mass'], 16704.07393593,
                         1e-6)
Exemple #12
0
    def driver(self):
        # type: () -> Driver
        """Method to return a preconfigured driver.

        Returns
        -------
            Driver
                A preconfigured driver element to be used for the Problem instance.

        Raises
        ------
            ValueError
                Value error are raised if unsupported settings are encountered.
        """
        if self.driver_type == 'optimizer':
            # Find optimizer element in CMDOWS file
            opt_uid = self.driver_uid
            opt_elem = get_element_by_uid(self.elem_cmdows, opt_uid)
            # Load settings from CMDOWS file
            opt_package = get_opt_setting_safe(opt_elem, 'package', 'SciPy')
            opt_algo = get_opt_setting_safe(opt_elem, 'algorithm', 'SLSQP')
            opt_maxiter = get_opt_setting_safe(opt_elem,
                                               'maximumIterations',
                                               50,
                                               expected_type='int')
            opt_convtol = get_opt_setting_safe(opt_elem,
                                               'convergenceTolerance',
                                               1e-6,
                                               expected_type='float')

            # Apply settings to the driver
            # driver
            if opt_package == 'SciPy':
                driver = ScipyOptimizeDriver()
            elif opt_package == 'pyOptSparse':
                try:
                    from openmdao.api import pyOptSparseDriver
                except ImportError:
                    raise PyOptSparseImportError()
                driver = pyOptSparseDriver()
            else:
                raise ValueError(
                    'Unsupported package {} encountered in CMDOWS file for "{}".'
                    .format(opt_package, opt_uid))

            # optimization algorithm
            if opt_algo == 'SLSQP':
                driver.options['optimizer'] = 'SLSQP'
            elif opt_algo == 'COBYLA':
                driver.options['optimizer'] = 'COBYLA'
            elif opt_algo == 'L-BFGS-B':
                driver.options['optimizer'] = 'L-BFGS-B'
            else:
                raise ValueError(
                    'Unsupported algorithm {} encountered in CMDOWS file for "{}".'
                    .format(opt_algo, opt_uid))

            # maximum iterations and tolerance
            if isinstance(driver, ScipyOptimizeDriver):
                driver.options['maxiter'] = opt_maxiter
                driver.options['tol'] = opt_convtol
            elif isinstance(driver, pyOptSparseDriver):
                driver.opt_settings['MAXIT'] = opt_maxiter
                driver.opt_settings['ACC'] = opt_convtol

            # Set default display and output settings
            if isinstance(driver, ScipyOptimizeDriver):
                driver.options['disp'] = False  # Print the result
            return driver
        elif self.driver_type == 'doe':
            # Find DOE element in CMDOWS file
            doe_uid = self.driver_uid
            doe_elem = get_element_by_uid(self.elem_cmdows, doe_uid)
            # Load settings from CMDOWS file
            doe_method = get_doe_setting_safe(doe_elem, 'method',
                                              'Uniform design')  # type: str
            doe_runs = get_doe_setting_safe(doe_elem,
                                            'runs',
                                            5,
                                            expected_type='int',
                                            doe_method=doe_method,
                                            required_for_doe_methods=[
                                                'Latin hypercube design',
                                                'Uniform design',
                                                'Monte Carlo design'
                                            ])
            doe_center_runs = get_doe_setting_safe(
                doe_elem,
                'centerRuns',
                2,
                expected_type='int',
                doe_method=doe_method,
                required_for_doe_methods=['Box-Behnken design'])
            doe_seed = get_doe_setting_safe(doe_elem,
                                            'seed',
                                            None,
                                            expected_type='int',
                                            doe_method=doe_method,
                                            required_for_doe_methods=[
                                                'Latin hypercube design',
                                                'Uniform design',
                                                'Monte Carlo design'
                                            ])
            doe_levels = get_doe_setting_safe(
                doe_elem,
                'levels',
                2,
                expected_type='int',
                doe_method=doe_method,
                required_for_doe_methods=['Full factorial design'])

            # table
            doe_data = []
            if isinstance(doe_elem.find('settings/table'), _Element):
                doe_table = doe_elem.find('settings/table')
                doe_table_rows = [row for row in doe_table.iterchildren()]
                n_samples = len(
                    [exp for exp in doe_table_rows[0].iterchildren()])
                for idx in range(n_samples):
                    data_sample = []
                    for row_elem in doe_table_rows:
                        value = float(
                            row_elem.find(
                                'tableElement[@experimentID="{}"]'.format(
                                    idx)).text)
                        data_sample.append(
                            [row_elem.attrib['relatedParameterUID'], value])
                    doe_data.append(data_sample)
            else:
                if doe_method in ['Custom design table']:
                    raise ValueError(
                        'Table element with data for custom design table missing in '
                        'CMDOWS file.')

            # Apply settings to the driver
            # define driver
            driver = DOEDriver()

            # define generator
            if doe_method in ['Uniform design', 'Monte Carlo design']:
                driver.options['generator'] = UniformGenerator(
                    num_samples=doe_runs, seed=doe_seed)
            elif doe_method == 'Full factorial design':
                driver.options['generator'] = FullFactorialGenerator(
                    levels=doe_levels)
            elif doe_method == 'Box-Behnken design':
                driver.options['generator'] = BoxBehnkenGenerator(
                    center=doe_center_runs)
            elif doe_method == 'Latin hypercube design':
                driver.options['generator'] = LatinHypercubeGenerator(
                    samples=doe_runs, criterion='maximin', seed=doe_seed)
            elif doe_method == 'Custom design table':
                driver.options['generator'] = ListGenerator(data=doe_data)
            else:
                raise ValueError(
                    'Could not match the doe_method {} with methods from OpenMDAO.'
                    .format(doe_method))
            return driver
        else:
            return Driver()
    def test(self):

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

        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
            'S_ref_type':
            'wetted',  # how we compute the wing area,
            # can be 'wetted' or 'projected'
            'mesh':
            mesh,
            'twist_cp':
            np.array([4., 5., 8., 8., 8., 9.]),
            'fem_model_type':
            'wingbox',
            'data_x_upper':
            upper_x,
            'data_x_lower':
            lower_x,
            'data_y_upper':
            upper_y,
            'data_y_lower':
            lower_y,
            '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]),
            'original_wingbox_airfoil_t_over_c':
            0.12,

            # Aerodynamic deltas.
            # 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.
            # They can be used to account for things that are not included, such as contributions from the fuselage, nacelles, tail surfaces, etc.
            'CL0':
            0.0,
            'CD0':
            0.0078,
            'with_viscous':
            True,  # if true, compute viscous drag
            'with_wave':
            True,  # if true, compute wave drag

            # Airfoil properties for viscous drag calculation
            'k_lam':
            0.05,  # percentage of chord with laminar
            # flow, used for viscous drag
            'c_max_t':
            .38,  # chordwise location of maximum thickness
            't_over_c_cp':
            np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]),

            # 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
            'wing_weight_ratio':
            1.25,
            'exact_failure_constraint':
            False,  # if false, use KS function
            'struct_weight_relief':
            True,
            'distributed_fuel_weight':
            True,
            '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 = Problem()

        # Add problem information as an independent variables component
        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('v',
                                  val=np.array([.85 * 295.07, .64 * 340.294]),
                                  units='m/s')
        indep_var_comp.add_output('alpha', val=0., units='deg')
        indep_var_comp.add_output('alpha_maneuver', val=0., units='deg')
        indep_var_comp.add_output('Mach_number', val=np.array([0.85, 0.64]))
        indep_var_comp.add_output('re',val=np.array([0.348*295.07*.85*1./(1.43*1e-5), \
                                  1.225*340.294*.64*1./(1.81206*1e-5)]),  units='1/m')
        indep_var_comp.add_output('rho',
                                  val=np.array([0.348, 1.225]),
                                  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=np.array([295.07, 340.294]),
                                  units='m/s')
        indep_var_comp.add_output('load_factor', val=np.array([1., 2.5]))
        indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m')
        indep_var_comp.add_output('fuel_mass', val=10000., units='kg')

        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 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 aerostruct points
        for i in range(2):

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

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

            prob.model.add_subsystem(point_name, AS_point)

            # Connect flow properties to the analysis point
            prob.model.connect('v', point_name + '.v', src_indices=[i])
            prob.model.connect('Mach_number',
                               point_name + '.Mach_number',
                               src_indices=[i])
            prob.model.connect('re', point_name + '.re', src_indices=[i])
            prob.model.connect('rho', point_name + '.rho', src_indices=[i])
            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',
                               src_indices=[i])
            prob.model.connect('empty_cg', point_name + '.empty_cg')
            prob.model.connect('load_factor',
                               point_name + '.load_factor',
                               src_indices=[i])
            prob.model.connect('fuel_mass',
                               point_name + '.total_perf.L_equals_W.fuelburn')
            prob.model.connect('fuel_mass',
                               point_name + '.total_perf.CG.fuelburn')

            for surface in surfaces:

                name = surface['name']

                if surf_dict['distributed_fuel_weight']:
                    prob.model.connect('load_factor',
                                       point_name + '.coupled.load_factor',
                                       src_indices=[i])

                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')
                if surf_dict['struct_weight_relief']:
                    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')

        prob.model.connect('alpha', 'AS_point_0' + '.alpha')
        prob.model.connect('alpha_maneuver', 'AS_point_1' + '.alpha')

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

        if surf_dict['distributed_fuel_weight']:
            prob.model.connect(
                'wing.struct_setup.fuel_vols',
                'AS_point_0.coupled.wing.struct_states.fuel_vols')
            prob.model.connect(
                'fuel_mass', 'AS_point_0.coupled.wing.struct_states.fuel_mass')

            prob.model.connect(
                'wing.struct_setup.fuel_vols',
                'AS_point_1.coupled.wing.struct_states.fuel_vols')
            prob.model.connect(
                'fuel_mass', 'AS_point_1.coupled.wing.struct_states.fuel_mass')

        comp = ExecComp('fuel_diff = (fuel_mass - fuelburn) / fuelburn')
        prob.model.add_subsystem('fuel_diff',
                                 comp,
                                 promotes_inputs=['fuel_mass'],
                                 promotes_outputs=['fuel_diff'])
        prob.model.connect('AS_point_0.fuelburn', 'fuel_diff.fuelburn')

        ## Use these settings if you do not have pyOptSparse or SNOPT
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['optimizer'] = 'SLSQP'
        prob.driver.options['tol'] = 1e-8

        recorder = SqliteRecorder("unit_test.db")
        prob.driver.add_recorder(recorder)

        # We could also just use prob.driver.recording_options['includes']=['*'] here, but for large meshes the database file becomes extremely large. So we just select the variables we need.
        prob.driver.recording_options['includes'] = [
            'alpha',
            'rho',
            'v',
            'cg',
            'AS_point_1.cg',
            'AS_point_0.cg',
            'AS_point_0.coupled.wing_loads.loads',
            'AS_point_1.coupled.wing_loads.loads',
            'AS_point_0.coupled.wing.normals',
            'AS_point_1.coupled.wing.normals',
            'AS_point_0.coupled.wing.widths',
            'AS_point_1.coupled.wing.widths',
            'AS_point_0.coupled.aero_states.wing_sec_forces',
            'AS_point_1.coupled.aero_states.wing_sec_forces',
            'AS_point_0.wing_perf.CL1',
            'AS_point_1.wing_perf.CL1',
            'AS_point_0.coupled.wing.S_ref',
            'AS_point_1.coupled.wing.S_ref',
            'wing.geometry.twist',
            'wing.mesh',
            'wing.skin_thickness',
            'wing.spar_thickness',
            'wing.t_over_c',
            'wing.structural_mass',
            'AS_point_0.wing_perf.vonmises',
            'AS_point_1.wing_perf.vonmises',
            'AS_point_0.coupled.wing.def_mesh',
            'AS_point_1.coupled.wing.def_mesh',
        ]

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

        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_design_var('fuel_mass',
                                  lower=0.,
                                  upper=2e5,
                                  scaler=1e-5)
        prob.model.add_design_var('alpha_maneuver', lower=-15., upper=15)

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

        prob.model.add_constraint('fuel_vol_delta.fuel_vol_delta', lower=0.)
        prob.model.add_constraint('fuel_diff', equals=0.)

        # Set up the problem
        prob.setup()

        prob.run_driver()

        # print(prob['AS_point_0.fuelburn'][0])
        # print(prob['wing.structural_mass'][0]/surf_dict['wing_weight_ratio'])
        # print(prob['wing.geometry.t_over_c_cp'])

        assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 101937.827384,
                         1e-5)
        assert_rel_error(
            self,
            prob['wing.structural_mass'][0] / surf_dict['wing_weight_ratio'],
            36539.6437566, 1e-5)
        assert_rel_error(
            self, prob['wing.geometry.t_over_c_cp'],
            np.array([
                0.10247881, 0.08207636, 0.11114547, 0.13114547, 0.10207636,
                0.09365598
            ]), 1e-5)
    def test_brachistochrone_recording_for_docs(self):
        import numpy as np
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt
        from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver, \
            SqliteRecorder, CaseReader
        from openmdao.utils.assert_utils import assert_rel_error
        from dymos import Phase
        from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE

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

        phase = Phase('gauss-lobatto',
                      ode_class=BrachistochroneODE,
                      num_segments=10)

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

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

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

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

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

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

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

        # Recording
        rec = SqliteRecorder('brachistochrone_solution.db')

        p.driver.recording_options['record_desvars'] = True
        p.driver.recording_options['record_responses'] = True
        p.driver.recording_options['record_objectives'] = True
        p.driver.recording_options['record_constraints'] = True

        p.model.recording_options['record_metadata'] = True

        p.driver.add_recorder(rec)
        p.model.add_recorder(rec)
        phase.add_recorder(rec)

        p.setup()

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

        p['phase0.states:x'] = phase.interpolate(ys=[0, 10],
                                                 nodes='state_input')
        p['phase0.states:y'] = phase.interpolate(ys=[10, 5],
                                                 nodes='state_input')
        p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9],
                                                 nodes='state_input')
        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_rel_error(self,
                         phase.get_values('time')[-1],
                         1.8016,
                         tolerance=1.0E-3)

        cr = CaseReader('brachistochrone_solution.db')

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

        assert_rel_error(
            self, p['phase0.controls:theta'],
            outputs['phase0.indep_controls.controls:theta']['value'])

        phase0_options = cr.system_metadata['phase0']['component_options']

        num_segments = phase0_options['num_segments']
        transcription_order = phase0_options['transcription_order']
        segment_ends = phase0_options['segment_ends']
        ode_class = phase0_options['ode_class']

        print(num_segments)
        print(transcription_order)
        print(ode_class)
        print(segment_ends)
Exemple #15
0
def main(tot_iter):
    objectives = {0: "compliance", 1: "stress"}

    # TODO: folder path and restart # must be manually input each time
    loadFolder = loadFolder0 + ""
    restart_iter = 26

    import os
    try:
        os.mkdir(loadFolder + 'restart_' + str(restart_iter))
    except:
        pass

    try:
        os.mkdir(loadFolder + 'restart_' + str(restart_iter) + '/figs')
    except:
        pass

    inspctFlag = False
    if tot_iter < 0:
        inspctFlag = True
        tot_iter = restart_iter + 1

    # Select which problem to solve
    obj_flag = 1
    print(locals())
    print("solving single physics %s problem" % objectives[obj_flag])

    print("restarting from %d ..." % restart_iter)
    fname0 = loadFolder + 'phi%03i.pkl' % restart_iter

    with open(fname0, 'rb') as f:
        raw = pickle.load(f)

    phi0 = raw['phi']

    fname0 = loadFolder0 + 'const.pkl'
    with open(fname0, 'rb') as f:
        raw = pickle.load(f)

    # nodes = raw['mesh']
    nodes = raw['nodes']
    elem = raw['elem']
    GF_e = raw['GF_e']
    BCid_e = raw['BCid_e']
    E = raw['E']
    nu = raw['nu']
    f = raw['f']
    nelx = raw['nelx']
    nely = raw['nely']
    length_x = raw['length_x']
    length_y = raw['length_y']
    coord_e = raw['coord_e']
    tol_e = raw['tol_e']

    ############################################################################
    ###########################         FEA          ###########################
    ############################################################################
    # NB: only Q4 elements + integer-spaced mesh are assumed

    ls2fe_x = length_x / float(nelx)
    ls2fe_y = length_y / float(nely)

    num_nodes_x = nelx + 1
    num_nodes_y = nely + 1

    nELEM = nelx * nely
    nNODE = num_nodes_x * num_nodes_y

    # Declare FEA object (OpenLSTO_FEA) ==============================
    fea_solver = py_FEA(lx=length_x,
                        ly=length_y,
                        nelx=nelx,
                        nely=nely,
                        element_order=2)
    [node, elem, elem_dof] = fea_solver.get_mesh()

    ## validate the mesh
    if nELEM != elem.shape[0]:
        error("error found in the element")
    if nNODE != node.shape[0]:
        error("error found in the node")

    nDOF_e = nNODE * 2  # each node has two displacement DOFs

    # constitutive properties ========================================
    fea_solver.set_material(E=E, nu=nu, rho=1.0)

    # Boundary Conditions ============================================
    fea_solver.set_boundary(coord=coord_e, tol=tol_e)
    BCid_e = fea_solver.get_boundary()
    nDOF_e_wLag = nDOF_e + len(BCid_e)  # elasticity DOF

    ############################################################################
    ###########################         LSM          ###########################
    ############################################################################
    movelimit = 0.5

    # Declare Level-set object
    lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit)
    lsm_solver.add_holes([], [], [])
    lsm_solver.set_levelset()

    lsm_solver.set_phi_re(phi0)

    lsm_solver.reinitialise()

    ############################################################################
    ########################         T.O. LOOP          ########################
    ############################################################################
    for i_HJ in range(restart_iter, tot_iter):
        (bpts_xy, areafraction, seglength) = lsm_solver.discretise()

        # OpenMDAO ===================================================
        ## Define Group
        if (objectives[obj_flag] == "compliance"):
            model = ComplianceGroup(fea_solver=fea_solver,
                                    lsm_solver=lsm_solver,
                                    nelx=nelx,
                                    nely=nely,
                                    force=GF_e,
                                    movelimit=movelimit,
                                    BCid=BCid_e)
        elif (objectives[obj_flag] == "stress"):
            model = StressGroup(fea_solver=fea_solver,
                                lsm_solver=lsm_solver,
                                nelx=nelx,
                                nely=nely,
                                force=GF_e,
                                movelimit=movelimit,
                                pval=6.0,
                                BCid=BCid_e)

        ## Define problem for OpenMDAO object
        prob = Problem(model)

        ## Setup the problem
        prob.driver = pyOptSparseDriver()
        prob.driver.options['optimizer'] = 'IPOPT'
        prob.driver.opt_settings['linear_solver'] = 'ma27'
        prob.setup(check=False)
        prob.run_model()

        ## Total derivative using MAUD
        if (objectives[obj_flag] == "compliance"):
            ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0]
            gg = total['weight_comp.weight', 'inputs_comp.Vn'][0]
        elif (objectives[obj_flag] == "stress"):
            ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0]
            gg = total['weight_comp.weight', 'inputs_comp.Vn'][0]

        ## Assign object function sensitivities
        nBpts = int(bpts_xy.shape[0])
        Sf = -ff[:nBpts]  # equal to M2DO-perturbation
        Cf = np.multiply(
            Sf, seglength)  # Shape sensitivity (integral coefficients)

        ## Assign constraint sensitivities
        Sg = -gg[:nBpts]
        Sg[Sg <
           -1.5] = -1.5  # apply caps (bracketing) to constraint sensitivities
        Sg[Sg >
           0.5] = 0.5  # apply caps (bracketing) to constraint sensitivities
        Cg = np.multiply(
            Sg, seglength)  # Shape sensitivity (integral coefficients)

        # Suboptimize ================================================
        if 1:
            suboptim = Solvers(bpts_xy=bpts_xy,
                               Sf=Sf,
                               Sg=Sg,
                               Cf=Cf,
                               Cg=Cg,
                               length_x=length_x,
                               length_y=length_y,
                               areafraction=areafraction,
                               movelimit=movelimit)
            # suboptimization
            if 1:  # simplex
                Bpt_Vel = suboptim.simplex(isprint=False)
            else:  # bisection..
                Bpt_Vel = suboptim.bisection(isprint=False)
            timestep = 1.0
        elif 1:  # works okay now.
            bpts_sens = np.zeros((nBpts, 2))
            # issue: scaling problem
            #
            bpts_sens[:, 0] = Sf
            bpts_sens[:, 1] = Sg

            lsm_solver.set_BptsSens(bpts_sens)
            scales = lsm_solver.get_scale_factors()
            (lb2, ub2) = lsm_solver.get_Lambda_Limits()
            constraint_distance = (0.4 * nelx * nely) - areafraction.sum()

            model = LSM2D_slpGroup(lsm_solver=lsm_solver,
                                   num_bpts=nBpts,
                                   b=ub2,
                                   lb=lb2,
                                   Sf=bpts_sens[:, 0],
                                   Sg=bpts_sens[:, 1],
                                   constraintDistance=constraint_distance,
                                   movelimit=movelimit)

            subprob = Problem(model)
            subprob.setup()

            subprob.driver = ScipyOptimizeDriver()
            subprob.driver.options['optimizer'] = 'SLSQP'
            subprob.driver.options['disp'] = True
            subprob.driver.options['tol'] = 1e-10

            subprob.run_driver()
            lambdas = subprob['inputs_comp.lambdas']
            displacements_ = subprob['displacement_comp.displacements']

            displacements_[displacements_ > movelimit] = movelimit
            displacements_[displacements_ < -movelimit] = -movelimit
            timestep = 1.0  #abs(lambdas[0]*scales[0])

            Bpt_Vel = displacements_ / timestep
            # print(timestep)
            del subprob
        else:  # branch: perturb-suboptim
            bpts_sens = np.zeros((nBpts, 2))
            # issue: scaling problem
            #
            bpts_sens[:, 0] = Sf
            bpts_sens[:, 1] = Sg

            lsm_solver.set_BptsSens(bpts_sens)
            scales = lsm_solver.get_scale_factors()
            (lb2, ub2) = lsm_solver.get_Lambda_Limits()

            constraint_distance = (0.4 * nelx * nely) - areafraction.sum()
            constraintDistance = np.array([constraint_distance])
            scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance(
                constraintDistance)

            def objF_nocallback(x):
                displacement = lsm_solver.compute_displacement(x)
                displacement_np = np.asarray(displacement)
                return lsm_solver.compute_delF(displacement_np)

            def conF_nocallback(x):
                displacement = lsm_solver.compute_displacement(x)
                displacement_np = np.asarray(displacement)
                return lsm_solver.compute_delG(displacement_np,
                                               scaled_constraintDist, 1)

            cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)})
            res = sp_optim.minimize(objF_nocallback,
                                    np.zeros(2),
                                    method='SLSQP',
                                    options={'disp': True},
                                    bounds=((lb2[0], ub2[0]), (lb2[1],
                                                               ub2[1])),
                                    constraints=cons)

            lambdas = res.x
            displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas)
            displacements_[displacements_ > movelimit] = movelimit
            displacements_[displacements_ < -movelimit] = -movelimit
            timestep = 1.0  #abs(lambdas[0]*scales[0])
            Bpt_Vel = displacements_ / timestep
            # scaling
            # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel))

        lsm_solver.advect(Bpt_Vel, timestep)
        lsm_solver.reinitialise()

        if not inspctFlag:  # quickplot
            plt.figure(1)
            plt.clf()
            plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10)
            plt.axis("equal")
            plt.savefig(loadFolder + 'restart_' + str(restart_iter) + "/" +
                        "figs/bpts_%d.png" % i_HJ)

        print('loop %d is finished' % i_HJ)
        area = areafraction.sum() / (nelx * nely)
        u = prob['disp_comp.disp']
        compliance = np.dot(u, GF_e[:nDOF_e])

        # Printing/Plotting ==========================================
        if 1:  # quickplot
            plt.figure(1)
            plt.clf()
            plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10)
            plt.axis("equal")
            plt.savefig(loadFolder + 'restart_' + str(restart_iter) + "/" +
                        "figs/bpts_%d.png" % i_HJ)

        if (objectives[obj_flag] == "compliance" and not inspctFlag):
            compliance = prob['compliance_comp.compliance']
            print(compliance, area)

            fid = open(
                loadFolder + 'restart_' + str(restart_iter) + "/" + "log.txt",
                "a+")
            fid.write(str(compliance) + ", " + str(area) + "\n")
            fid.close()
        elif (objectives[obj_flag] == "stress" and not inspctFlag):
            print(prob['pnorm_comp.pnorm'][0], area)

            fid = open(
                loadFolder + 'restart_' + str(restart_iter) + "/" + "log.txt",
                "a+")
            fid.write(
                str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n")
            fid.close()

        ## Saving Phi
        phi = lsm_solver.get_phi()

        if not inspctFlag:
            raw = {}
            raw['phi'] = phi
            filename = loadFolder + 'restart_' + str(
                restart_iter) + '/' + 'phi%03i.pkl' % i_HJ
            with open(filename, 'wb') as f:
                pickle.dump(raw, f)

        del model
        del prob

        mem = virtual_memory()
        print(str(mem.available / 1024. / 1024. / 1024.) + "GB")
        if mem.available / 1024. / 1024. / 1024. < 3.0:
            print("memory explodes at iteration %3i " % i_HJ)
            exit()
Exemple #16
0
    def test_debug_print_desvar_physical_with_indices(self):
        prob = Problem()
        model = prob.model = Group()

        size = 3
        model.add_subsystem('p1', IndepVarComp('x', np.array([50.0] * size)))
        model.add_subsystem('p2', IndepVarComp('y', np.array([50.0] * size)))
        model.add_subsystem(
            'comp',
            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',
            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 = 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(check=False)

        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.])}"
        )
Exemple #17
0
    def test_betz(self):
        from openmdao.api import Problem, ScipyOptimizeDriver, IndepVarComp, ExplicitComponent

        class ActuatorDisc(ExplicitComponent):
            """Simple wind turbine model based on actuator disc theory"""
            def setup(self):

                # Inputs
                self.add_input('a', 0.5, desc="Induced Velocity Factor")
                self.add_input('Area',
                               10.0,
                               units="m**2",
                               desc="Rotor disc area")
                self.add_input('rho',
                               1.225,
                               units="kg/m**3",
                               desc="air density")
                self.add_input(
                    'Vu',
                    10.0,
                    units="m/s",
                    desc="Freestream air velocity, upstream of rotor")

                # Outputs
                self.add_output('Vr',
                                0.0,
                                units="m/s",
                                desc="Air velocity at rotor exit plane")
                self.add_output(
                    'Vd',
                    0.0,
                    units="m/s",
                    desc="Slipstream air velocity, downstream of rotor")
                self.add_output('Ct', 0.0, desc="Thrust Coefficient")
                self.add_output('thrust',
                                0.0,
                                units="N",
                                desc="Thrust produced by the rotor")
                self.add_output('Cp', 0.0, desc="Power Coefficient")
                self.add_output('power',
                                0.0,
                                units="W",
                                desc="Power produced by the rotor")

                self.declare_partials('Vr', ['a', 'Vu'])
                self.declare_partials('Vd', 'a')
                self.declare_partials('Ct', 'a')
                self.declare_partials('thrust', ['a', 'Area', 'rho', 'Vu'])
                self.declare_partials('Cp', 'a')
                self.declare_partials('power', ['a', 'Area', 'rho', 'Vu'])

            def compute(self, inputs, outputs):
                """ Considering the entire rotor as a single disc that extracts
                velocity uniformly from the incoming flow and converts it to
                power."""

                a = inputs['a']
                Vu = inputs['Vu']

                qA = .5 * inputs['rho'] * inputs['Area'] * Vu**2

                outputs['Vd'] = Vd = Vu * (1 - 2 * a)
                outputs['Vr'] = .5 * (Vu + Vd)

                outputs['Ct'] = Ct = 4 * a * (1 - a)
                outputs['thrust'] = Ct * qA

                outputs['Cp'] = Cp = Ct * (1 - a)
                outputs['power'] = Cp * qA * Vu

            def compute_partials(self, inputs, J):
                """ Jacobian of partial derivatives."""

                a = inputs['a']
                Vu = inputs['Vu']
                Area = inputs['Area']
                rho = inputs['rho']

                # pre-compute commonly needed quantities
                a_times_area = a * Area
                one_minus_a = 1.0 - a
                a_area_rho_vu = a_times_area * rho * Vu

                J['Vr', 'a'] = -Vu
                J['Vr', 'Vu'] = one_minus_a

                J['Vd', 'a'] = -2.0 * Vu

                J['Ct', 'a'] = 4.0 - 8.0 * a

                J['thrust', 'a'] = .5 * rho * Vu**2 * Area * J['Ct', 'a']
                J['thrust', 'Area'] = 2.0 * Vu**2 * a * rho * one_minus_a
                J['thrust', 'rho'] = 2.0 * a_times_area * Vu**2 * (one_minus_a)
                J['thrust', 'Vu'] = 4.0 * a_area_rho_vu * (one_minus_a)

                J['Cp',
                  'a'] = 4.0 * a * (2.0 * a - 2.0) + 4.0 * (one_minus_a)**2

                J['power', 'a'] = 2.0 * Area * Vu**3 * a * rho * (
                    2.0 * a - 2.0) + 2.0 * Area * Vu**3 * rho * one_minus_a**2
                J['power', 'Area'] = 2.0 * Vu**3 * a * rho * one_minus_a**2
                J['power',
                  'rho'] = 2.0 * a_times_area * Vu**3 * (one_minus_a)**2
                J['power',
                  'Vu'] = 6.0 * Area * Vu**2 * a * rho * one_minus_a**2

        # build the model
        prob = Problem()
        indeps = prob.model.add_subsystem('indeps',
                                          IndepVarComp(),
                                          promotes=['*'])
        indeps.add_output('a', .5)
        indeps.add_output('Area', 10.0, units='m**2')
        indeps.add_output('rho', 1.225, units='kg/m**3')
        indeps.add_output('Vu', 10.0, units='m/s')

        prob.model.add_subsystem('a_disk',
                                 ActuatorDisc(),
                                 promotes_inputs=['a', 'Area', 'rho', 'Vu'])

        # setup the optimization
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['optimizer'] = 'SLSQP'

        prob.model.add_design_var('a', lower=0., upper=1.)
        prob.model.add_design_var('Area', lower=0., upper=1.)
        # negative one so we maximize the objective
        prob.model.add_objective('a_disk.Cp', scaler=-1)

        prob.setup()
        prob.run_driver()

        # minimum value
        assert_rel_error(self, prob['a_disk.Cp'], 16. / 27., 1e-4)
        assert_rel_error(self, prob['a'], 0.33333, 1e-4)
        # There is a bug in scipy version < 1.0 that causes this value to be wrong.
        if LooseVersion(scipy.__version__) >= LooseVersion("1.0"):
            assert_rel_error(self, prob['Area'], 1.0, 1e-4)
        else:
            msg = "Outdated version of Scipy detected; this problem does not solve properly."
            raise unittest.SkipTest(msg)
Exemple #18
0
    def test(self):
        # Create a dictionary to store options about the surface
        # OM: vary 'num_y' and 'num_x' to change the size of the mesh
        mesh_dict = {
            'num_y': 5,
            'num_x': 2,
            'wing_type': 'rect',
            'symmetry': True
        }

        mesh = generate_mesh(mesh_dict)

        surf_dict = {
            # Wing definition
            'name': 'wing',  # name of the surface
            'type': 'aerostruct',
            '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': 'tube',
            'thickness_cp': np.array([.075, .075]),
            'twist_cp': np.array([-10., 15.]),
            'mesh': mesh,
            'num_x': mesh.shape[0],
            'num_y': mesh.shape[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.015,  # 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.15]),  # thickness over chord ratio (NACA0015)
            'c_max_t': .303,  # chordwise location of maximum (NACA0015)
            # thickness
            'with_viscous': True,
            'with_wave': False,  # if true, compute wave drag

            # Structural values are based on aluminum 7075
            'E': 70.e9,  # [Pa] Young's modulus of the spar
            'G': 30.e9,  # [Pa] shear modulus of the spar
            'yield':
            500.e6 / 2.5,  # [Pa] yield stress divided by 2.5 for limiting case
            'mrho': 3.e3,  # [kg/m^3] material density
            'fem_origin': 0.35,  # normalized chordwise location of the spar
            'wing_weight_ratio': 2.,
            'struct_weight_relief':
            False,  # True to add the weight of the structure to the loads on the structure
            # Constraints
            'exact_failure_constraint': False,  # if false, use KS function
        }

        surfaces = [surf_dict]

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

        # Add problem information as an independent variables component
        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=9., units='deg')
        indep_var_comp.add_output('M', val=0.84)
        indep_var_comp.add_output('re', val=1.e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s')
        indep_var_comp.add_output('R', val=11.165e6, units='m')
        indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg')
        indep_var_comp.add_output('a', val=295.4, 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 = Aerostruct(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('M', point_name + '.M')
            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('a', point_name + '.a')
            prob.model.connect('empty_cg', point_name + '.empty_cg')
            prob.model.connect('load_factor', point_name + '.load_factor')

            for surface in surfaces:

                prob.model.connect('load_factor', name + '.load_factor')

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

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

                # Connect performance calculation variables
                prob.model.connect(name + '.radius', com_name + '.radius')
                prob.model.connect(name + '.thickness',
                                   com_name + '.thickness')
                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_weight', point_name + '.' +
                    'total_perf.' + name + '_structural_weight')
                prob.model.connect(name + '.t_over_c', com_name + '.t_over_c')

        from openmdao.api import ScipyOptimizeDriver
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['tol'] = 1e-9

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.)
        prob.model.add_design_var('wing.thickness_cp',
                                  lower=0.01,
                                  upper=0.5,
                                  scaler=1e2)
        prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.)
        prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects',
                                  upper=0.)

        # Add design variables, constraisnt, and objective on the problem
        prob.model.add_design_var('alpha', lower=-10., upper=10.)
        prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.)
        prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5)

        # Set up the problem
        prob.setup()

        prob.run_driver()

        assert_rel_error(self, prob['AS_point_0.fuelburn'][0],
                         72128.75170161888, 1e-5)
    def test_brachistochrone_quick_start(self):
        import numpy as np
        from openmdao.api import Problem, Group, ScipyOptimizeDriver
        import dymos as dm
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt

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

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

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

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

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

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

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

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

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

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

        # Allow OpenMDAO to automatically determine our sparsity pattern.
        # Doing so can significant speed up the execution of Dymos.
        p.driver.options['dynamic_simul_derivs'] = True

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        plt.show()
    def test_control_rate2_path_constraint_gl(self):
        from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver
        from openmdao.utils.assert_utils import assert_rel_error
        from dymos import Phase
        from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE

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

        phase = Phase('gauss-lobatto',
                      ode_class=BrachistochroneODE,
                      num_segments=10,
                      transcription_order=5)

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

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

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

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

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

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

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

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

        p.setup()

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

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

        # Solve for the optimal trajectory
        p.run_driver()

        # Test the results
        assert_rel_error(self,
                         phase.get_values('time')[-1],
                         1.8016,
                         tolerance=1.0E-3)
def main(maxiter):
    # Select which problem to solve
    obj_flag = 1
    print(locals())
    print("solving single physics %s problem" % objectives[obj_flag])

    ############################################################################
    ###########################         FEA          ###########################
    ############################################################################
    # NB: only Q4 elements + integer-spaced mesh are assumed
    nelx = 160
    nely = 80

    length_x = 160.
    length_y = 80.

    ls2fe_x = length_x / float(nelx)
    ls2fe_y = length_y / float(nely)

    num_nodes_x = nelx + 1
    num_nodes_y = nely + 1

    nELEM = nelx * nely
    nNODE = num_nodes_x * num_nodes_y

    # NB: nodes for plotting (quickfix...)
    nodes = get_mesh(num_nodes_x, num_nodes_y, nelx, nely)

    # Declare FEA object (OpenLSTO_FEA) ==============================
    fea_solver = py_FEA(lx=length_x,
                        ly=length_y,
                        nelx=nelx,
                        nely=nely,
                        element_order=2)
    [node, elem, elem_dof] = fea_solver.get_mesh()

    ## validate the mesh
    if nELEM != elem.shape[0]:
        error("error found in the element")

    if nNODE != node.shape[0]:
        error("error found in the node")

    nDOF_e = nNODE * 2  # each node has two displacement DOFs

    # constitutive properties ========================================
    E = 1.
    nu = 0.3
    fea_solver.set_material(E=E, nu=nu, rho=1.0)  # sets elastic material only

    # Boundary Conditions ============================================
    ## Set elastic boundary conditions
    coord_e = np.array([[0., 0.], [length_x, 0.]])
    tol_e = np.array([[1e-3, 1e3], [1e-3, 1e+3]])
    fea_solver.set_boundary(coord=coord_e, tol=tol_e)

    BCid_e = fea_solver.get_boundary()
    nDOF_e_wLag = nDOF_e + len(BCid_e)  # elasticity DOF

    # Loading Conditions =============================================
    ## Set the elastic loading conditions
    coord = np.array([length_x * 0.5, 0.0])  # length_y])
    tol = np.array([4.1, 1e-3])
    load_val = -1  # dead load
    GF_e_ = fea_solver.set_force(coord=coord,
                                 tol=tol,
                                 direction=1,
                                 f=-load_val)
    GF_e = np.zeros(nDOF_e_wLag)
    GF_e[:nDOF_e] = GF_e_

    ############################################################################
    ###########################         LSM          ###########################
    ############################################################################
    movelimit = 0.5

    # Declare Level-set object
    lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit)

    # Assign holes ===================================================
    if (int(nelx) / int(nely) == 2) and (nelx >= 80):
        rad = float(nelx) / 32.0  # radius of the hole
        x1 = nelx / 10.  # x-coord of the center of the 1st hole 1st row
        y1 = 14. * nely / 80.  # y-coord of the center of the 1st row of holes
        y2 = 27. * nely / 80.  # y-coord of the center of the 2nd row of holes
        y3 = nely / 2.  # y-coord of the center of the 3rd row of holes
        y4 = 53. * nely / 80.  # y-coord of the center of the 4th row of holes
        y5 = 66. * nely / 80.  # y-coord of the center of the 5th row of holes

        hole = array([[x1, y1, rad], [3 * x1, y1, rad], [5 * x1, y1, rad],
                      [7 * x1, y1, rad], [9 * x1, y1, rad], [2 * x1, y2, rad],
                      [4 * x1, y2, rad], [6 * x1, y2, rad], [8 * x1, y2, rad],
                      [x1, y3, rad], [3 * x1, y3, rad], [5 * x1, y3, rad],
                      [7 * x1, y3, rad], [9 * x1, y3, rad], [2 * x1, y4, rad],
                      [4 * x1, y4, rad], [6 * x1, y4, rad], [8 * x1, y4, rad],
                      [x1, y5, rad], [3 * x1, y5, rad], [5 * x1, y5, rad],
                      [7 * x1, y5, rad], [9 * x1, y5, rad]])

        # NB: level set value at the corners should not be 0.0
        hole = append(
            hole,
            [[0., 0., 0.1], [0., 80., 0.1], [160., 0., 0.1], [160., 80., 0.1]],
            axis=0)

        lsm_solver.add_holes(locx=list(hole[:, 0]),
                             locy=list(hole[:, 1]),
                             radius=list(hole[:, 2]))
    else:
        lsm_solver.add_holes([], [], [])

    lsm_solver.set_levelset()

    ############################################################################
    ########################         T.O. LOOP          ########################
    ############################################################################
    for i_HJ in range(maxiter):
        (bpts_xy, areafraction, seglength) = lsm_solver.discretise()

        # OpenMDAO ===================================================
        ## Define Group
        if (objectives[obj_flag] == "compliance"):
            model = ComplianceGroup(fea_solver=fea_solver,
                                    lsm_solver=lsm_solver,
                                    nelx=nelx,
                                    nely=nely,
                                    force=GF_e,
                                    movelimit=movelimit,
                                    BCid=BCid_e)
        elif (objectives[obj_flag] == "stress"):
            model = StressGroup(fea_solver=fea_solver,
                                lsm_solver=lsm_solver,
                                nelx=nelx,
                                nely=nely,
                                force=GF_e,
                                movelimit=movelimit,
                                pval=6.0,
                                BCid=BCid_e)

        ## Define problem for OpenMDAO object
        prob = Problem(model)

        ## Setup the problem
        prob.driver = pyOptSparseDriver()
        prob.driver.options['optimizer'] = 'IPOPT'
        prob.driver.opt_settings['linear_solver'] = 'ma27'
        prob.setup(check=False)
        prob.run_model()

        ## Total derivative using MAUD
        total = prob.compute_totals()
        if (objectives[obj_flag] == "compliance"):
            ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0]
            gg = total['weight_comp.weight', 'inputs_comp.Vn'][0]
        elif (objectives[obj_flag] == "stress"):
            ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0]
            gg = total['weight_comp.weight', 'inputs_comp.Vn'][0]

        ## Assign object function sensitivities
        nBpts = int(bpts_xy.shape[0])
        Sf = -ff[:nBpts]  # equal to M2DO-perturbation
        Cf = np.multiply(
            Sf, seglength)  # Shape sensitivity (integral coefficients)

        ## Assign constraint sensitivities
        Sg = -gg[:nBpts]
        Sg[Sg <
           -1.5] = -1.5  # apply caps (bracketing) to constraint sensitivities
        Sg[Sg >
           0.5] = 0.5  # apply caps (bracketing) to constraint sensitivities
        Cg = np.multiply(
            Sg, seglength)  # Shape sensitivity (integral coefficients)

        # Suboptimize ================================================
        if 1:
            suboptim = Solvers(bpts_xy=bpts_xy,
                               Sf=Sf,
                               Sg=Sg,
                               Cf=Cf,
                               Cg=Cg,
                               length_x=length_x,
                               length_y=length_y,
                               areafraction=areafraction,
                               movelimit=movelimit)
            # suboptimization
            if 1:  # simplex
                Bpt_Vel = suboptim.simplex(isprint=False)
            else:  # bisection.
                Bpt_Vel = suboptim.bisection(isprint=False)

            timestep = 1.0
            np.savetxt('a.txt', Bpt_Vel)
        elif 1:  # works when Sf <- Sf / length is used (which means Cf <- actual Sf)
            bpts_sens = np.zeros((nBpts, 2))
            # issue: scaling problem
            #
            bpts_sens[:, 0] = Sf
            bpts_sens[:, 1] = Sg

            lsm_solver.set_BptsSens(bpts_sens)
            scales = lsm_solver.get_scale_factors()
            (lb2, ub2) = lsm_solver.get_Lambda_Limits()
            constraint_distance = (0.4 * nelx * nely) - areafraction.sum()

            model = LSM2D_slpGroup(lsm_solver=lsm_solver,
                                   num_bpts=nBpts,
                                   ub=ub2,
                                   lb=lb2,
                                   Sf=bpts_sens[:, 0],
                                   Sg=bpts_sens[:, 1],
                                   constraintDistance=constraint_distance,
                                   movelimit=movelimit)

            subprob = Problem(model)
            subprob.setup()

            subprob.driver = ScipyOptimizeDriver()
            subprob.driver.options['optimizer'] = 'SLSQP'
            subprob.driver.options['disp'] = True
            subprob.driver.options['tol'] = 1e-10
            subprob.run_driver()

            lambdas = subprob['inputs_comp.lambdas']
            displacements_ = subprob['displacement_comp.displacements']
            # displacements_[displacements_ > movelimit] = movelimit
            # displacements_[displacements_ < -movelimit] = -movelimit

            timestep = abs(lambdas[0] * scales[0])
            Bpt_Vel = displacements_ / timestep
            np.savetxt('a.txt', Bpt_Vel)
            # print(timestep)
            del subprob
        else:  # branch: perturb-suboptim
            bpts_sens = np.zeros((nBpts, 2))
            # issue: scaling problem
            #
            bpts_sens[:, 0] = Sf
            bpts_sens[:, 1] = Sg

            lsm_solver.set_BptsSens(bpts_sens)
            scales = lsm_solver.get_scale_factors()
            (lb2, ub2) = lsm_solver.get_Lambda_Limits()

            constraint_distance = (0.4 * nelx * nely) - areafraction.sum()
            constraintDistance = np.array([constraint_distance])
            scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance(
                constraintDistance)

            def objF_nocallback(x):
                displacement = lsm_solver.compute_displacement(x)
                displacement_np = np.asarray(displacement)
                return lsm_solver.compute_delF(displacement_np)

            def conF_nocallback(x):
                displacement = lsm_solver.compute_displacement(x)
                displacement_np = np.asarray(displacement)
                return lsm_solver.compute_delG(displacement_np,
                                               scaled_constraintDist, 1)

            cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)})
            res = sp_optim.minimize(objF_nocallback,
                                    np.zeros(2),
                                    method='SLSQP',
                                    options={'disp': True},
                                    bounds=((lb2[0], ub2[0]), (lb2[1],
                                                               ub2[1])),
                                    constraints=cons)

            lambdas = res.x
            displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas)
            displacements_[displacements_ > movelimit] = movelimit
            displacements_[displacements_ < -movelimit] = -movelimit
            timestep = 1.0  #abs(lambdas[0]*scales[0])
            Bpt_Vel = displacements_ / timestep
            # scaling
            # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel))

        lsm_solver.advect(Bpt_Vel, timestep)
        lsm_solver.reinitialise()
        print('loop %d is finished' % i_HJ)

        area = areafraction.sum() / (nelx * nely)
        u = prob['disp_comp.disp']
        compliance = np.dot(u, GF_e[:nDOF_e])

        # Printing/Plotting ==========================================
        if 1:  # quickplot
            plt.figure(1)
            plt.clf()
            plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10)
            plt.axis("equal")
            plt.savefig(saveFolder + "figs/bpts_%d.png" % i_HJ)

        # print([compliance[0], area])
        if (objectives[obj_flag] == "compliance"):
            compliance = prob['compliance_comp.compliance']
            print(compliance, area)

            fid = open(saveFolder + "log.txt", "a+")
            fid.write(str(compliance) + ", " + str(area) + "\n")
            fid.close()
        elif (objectives[obj_flag] == "stress"):
            print(prob['pnorm_comp.pnorm'][0], area)

            fid = open(saveFolder + "log.txt", "a+")
            fid.write(
                str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n")
            fid.close()

        ## Saving phi
        phi = lsm_solver.get_phi()

        if i_HJ == 0:
            raw = {}
            raw['mesh'] = nodes
            raw['nodes'] = nodes
            raw['elem'] = elem
            raw['GF_e'] = GF_e
            raw['BCid_e'] = BCid_e
            raw['E'] = E
            raw['nu'] = nu
            raw['f'] = load_val
            raw['nelx'] = nelx
            raw['nely'] = nely
            raw['length_x'] = length_x
            raw['length_y'] = length_y
            raw['coord_e'] = coord_e
            raw['tol_e'] = tol_e
            filename = saveFolder + 'const.pkl'
            with open(filename, 'wb') as f:
                pickle.dump(raw, f)

        raw = {}
        raw['phi'] = phi
        filename = saveFolder + 'phi%03i.pkl' % i_HJ
        with open(filename, 'wb') as f:
            pickle.dump(raw, f)

        del model
        del prob

        mem = virtual_memory()
        print(str(mem.available / 1024. / 1024. / 1024.) + "GB")
        if mem.available / 1024. / 1024. / 1024. < 3.0:
            print("memory explodes at iteration %3i " % i_HJ)
            return ()
    def test(self):
        import numpy as np

        from openaerostruct.geometry.utils import generate_mesh
        from openaerostruct.geometry.geometry_group import Geometry

        from openaerostruct.integration.aerostruct_groups import Aerostruct, AerostructPoint

        from openmdao.api import IndepVarComp, Problem, Group, SqliteRecorder

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

        mesh, twist_cp = generate_mesh(mesh_dict)

        surface = {
            # Wing definition
            'name': 'wing',  # name of the surface
            'type': 'aerostruct',
            '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': 'tube',
            'thickness_cp': np.array([.1, .2, .3]),
            'twist_cp': twist_cp,
            'mesh': mesh,
            'num_x': mesh.shape[0],
            'num_y': mesh.shape[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.015,  # 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': 0.15,  # thickness over chord ratio (NACA0015)
            'c_max_t': .303,  # chordwise location of maximum (NACA0015)
            # thickness
            'with_viscous': True,

            # Structural values are based on aluminum 7075
            'E': 70.e9,  # [Pa] Young's modulus of the spar
            'G': 30.e9,  # [Pa] shear modulus of the spar
            'yield':
            500.e6 / 2.5,  # [Pa] yield stress divided by 2.5 for limiting case
            'mrho': 3.e3,  # [kg/m^3] material density
            'fem_origin': 0.35,  # normalized chordwise location of the spar
            'wing_weight_ratio': 2.,

            # Constraints
            'exact_failure_constraint': False,  # if false, use KS function
        }

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

        # Add problem information as an independent variables component
        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=5.)
        indep_var_comp.add_output('M', val=0.84)
        indep_var_comp.add_output('re', val=1.e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s')
        indep_var_comp.add_output('R', val=11.165e6, units='m')
        indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg')
        indep_var_comp.add_output('a', val=295.4, 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=['*'])

        aerostruct_group = Aerostruct(surface=surface)

        name = 'wing'

        # Add tmp_group to the problem with the name of the surface.
        prob.model.add_subsystem(name,
                                 aerostruct_group,
                                 promotes_inputs=['load_factor'])

        point_name = 'AS_point_0'

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

        prob.model.add_subsystem(point_name,
                                 AS_point,
                                 promotes_inputs=[
                                     'v', 'alpha', 'M', 're', 'rho', 'CT', 'R',
                                     'W0', 'a', 'empty_cg', 'load_factor'
                                 ])

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

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

        # Connect performance calculation variables
        prob.model.connect(name + '.radius', com_name + '.radius')
        prob.model.connect(name + '.thickness', com_name + '.thickness')
        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_weight',
            point_name + '.' + 'total_perf.' + name + '_structural_weight')

        from openmdao.api import ScipyOptimizeDriver
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['tol'] = 1e-9

        recorder = SqliteRecorder("aerostruct.db")
        prob.driver.add_recorder(recorder)
        prob.driver.recording_options['record_derivatives'] = True

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.)
        prob.model.add_design_var('wing.thickness_cp',
                                  lower=0.01,
                                  upper=0.5,
                                  scaler=1e2)
        prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.)
        prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects',
                                  upper=0.)

        # Add design variables, constraisnt, and objective on the problem
        prob.model.add_design_var('alpha', lower=-10., upper=10.)
        prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.)
        prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5)

        # Set up the problem
        prob.setup(check=True)

        prob.run_driver()

        assert_rel_error(self, prob['AS_point_0.fuelburn'][0],
                         104400.0251030171, 1e-8)
def main(maxiter):

    # select which problem to solve
    obj_flag = 1
    print(locals())
    print("solving %s problem" % objectives[obj_flag])

    ########################################################
    ################# 		FEA 		####################
    ########################################################
    # NB: only Q4 elements + integer-spaced mesh are assumed
    nelx = 160
    nely = 80

    length_x = 160.
    length_y = 80.

    ls2fe_x = length_x / float(nelx)
    ls2fe_y = length_y / float(nely)

    num_nodes_x = nelx + 1
    num_nodes_y = nely + 1

    nELEM = nelx * nely
    nNODE = num_nodes_x * num_nodes_y

    # NB: nodes for plotting (quickfix...)
    nodes = get_mesh(num_nodes_x, num_nodes_y, nelx, nely)

    # Declare FEA object (OpenLSTO_FEA) ======================
    fea_solver = py_FEA(lx=length_x,
                        ly=length_y,
                        nelx=nelx,
                        nely=nely,
                        element_order=2)
    [node, elem, elem_dof] = fea_solver.get_mesh()

    # validate the mesh
    if nELEM != elem.shape[0]:
        error("error found in the element")
    if nNODE != node.shape[0]:
        error("error found in the node")

    nDOF_t = nNODE * 1  # each node has one temperature DOF
    nDOF_e = nNODE * 2  # each node has two displacement DOFs

    # constitutive properties =================================
    E = 1.
    nu = 0.3
    f = -1  # dead load
    K_cond = 0.1  # thermal conductivity
    alpha = 1e-5  # thermal expansion coefficient

    fea_solver.set_material(E=E, nu=nu, rho=1.0)

    # Boundary Conditions =====================================
    if 1:
        coord_e = np.array([[0., 0.], [length_x, 0.]])
        tol_e = np.array([[1e-3, 1e3], [1e-3, 1e+3]])
        fea_solver.set_boundary(coord=coord_e, tol=tol_e)

        BCid_e = fea_solver.get_boundary()
        nDOF_e_wLag = nDOF_e + len(BCid_e)  # elasticity DOF

        coord = np.array([length_x * 0.5, 0.0])  # length_y])
        tol = np.array([0.1, 1e-3])
        GF_e_ = fea_solver.set_force(coord=coord, tol=tol, direction=1, f=-f)
        GF_e = np.zeros(nDOF_e_wLag)
        GF_e[:nDOF_e] = GF_e_
    else:  # cantilever bending
        coord_e = np.array([[0, 0]])
        tol_e = np.array([[1e-3, 1e10]])
        fea_solver.set_boundary(coord=coord_e, tol=tol_e)
        BCid_e = fea_solver.get_boundary()
        nDOF_e_wLag = nDOF_e + len(BCid_e)  # elasticity DOF

        coord = np.array([length_x, length_y / 2])
        tol = np.array([0.1, 0.1])
        GF_e_ = fea_solver.set_force(coord=coord, tol=tol, direction=1, f=-1.0)
        GF_e = np.zeros(nDOF_e_wLag)
        GF_e[:nDOF_e] = GF_e_

    xlo = np.array(range(0, nNODE, num_nodes_x))
    xhi = np.array(range(nelx, nNODE, num_nodes_x))
    # xfix = np.array([num_nodes_x*(nely/2-1), num_nodes_x*nely/2,
    # num_nodes_x*(nely/2-1) + nelx, num_nodes_x*nely/2 + nelx])
    xfix = np.append(xlo, xhi)
    yfix = np.array(range(num_nodes_x * nely + 70, nNODE - 70))
    # yloid = np.array(range(70, 91))
    # fixID_d = np.append(xfix, yfix)
    #fixID_d = np.unique(fixID_d)
    #fixID = np.append(fixID_d, arange(70, 91))
    # BCid_t = np.array(np.append(xfix, arange(70,91)), dtype=int)
    BCid_t = np.array(np.append(yfix, arange(70, 91)), dtype=int)
    nDOF_t_wLag = nDOF_t + len(BCid_t)  # temperature DOF (zero temp)

    GF_t = np.zeros(nDOF_t_wLag)  # FORCE_HEAT (NB: Q matrix)
    for ee in range(nELEM):  # between element 70 to 91
        GF_t[elem[ee]] += 10.  # heat generation
    GF_t[BCid_t] = 0.0
    GF_t /= np.sum(GF_t)
    #GF_t[nDOF_t:nDOF_t+len(fixID_d)+1] = 100.
    # GF_t[:] = 0.0

    ########################################################
    ################# 		LSM 		####################
    ########################################################
    movelimit = 0.5

    # Declare Level-set object
    lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit)

    if ((nelx == 160) and (nely == 80)):  # 160 x 80 case
        hole = array(
            [[16, 14, 5], [48, 14, 5], [80, 14, 5], [112, 14, 5], [144, 14, 5],
             [32, 27, 5], [64, 27, 5], [96, 27, 5], [128, 27, 5], [16, 40, 5],
             [48, 40, 5], [80, 40, 5], [112, 40, 5], [144, 40, 5], [32, 53, 5],
             [64, 53, 5], [96, 53, 5], [128, 53, 5], [16, 66, 5], [48, 66, 5],
             [80, 66, 5], [112, 66, 5], [144, 66, 5]],
            dtype=float)

        # NB: level set value at the corners should not be 0.0
        hole = append(
            hole,
            [[0., 0., 0.1], [0., 80., 0.1], [160., 0., 0.1], [160., 80., 0.1]],
            axis=0)

        lsm_solver.add_holes(locx=list(hole[:, 0]),
                             locy=list(hole[:, 1]),
                             radius=list(hole[:, 2]))

    elif ((nelx == 80) and (nely == 40)):
        hole = np.array(
            [[8, 7, 2.5], [24, 7, 2.5], [40, 7, 2.5], [56, 7, 2.5],
             [72, 7, 2.5], [16, 13.5, 2.5], [32, 13.5, 2.5], [48, 13.5, 2.5],
             [64, 13.5, 2.5], [8, 20, 2.5], [24, 20, 2.5], [40, 20, 2.5],
             [56, 20, 2.5], [72, 20, 2.5], [16, 26.5, 2.5], [32, 26.5, 2.5],
             [48, 26.5, 2.5], [64, 26.5, 2.5], [8, 33, 2.5], [24, 33, 2.5],
             [40, 33, 2.5], [56, 33, 2.5], [72, 33, 2.5]],
            dtype=np.float)

        # NB: level set value at the corners should not be 0.0
        hole = append(
            hole,
            [[0., 0., 0.1], [0., 40., 0.1], [80., 0., 0.1], [80., 40., 0.1]],
            axis=0)

        lsm_solver.add_holes(locx=list(hole[:, 0]),
                             locy=list(hole[:, 1]),
                             radius=list(hole[:, 2]))

    else:
        lsm_solver.add_holes([], [], [])

    lsm_solver.set_levelset()

    for i_HJ in range(maxiter):
        (bpts_xy, areafraction, seglength) = lsm_solver.discretise()

        ########################################################
        ############### 		OpenMDAO 		################
        ########################################################

        # Declare Group
        if (objectives[obj_flag] == "compliance"):
            model = ComplianceGroup(fea_solver=fea_solver,
                                    lsm_solver=lsm_solver,
                                    nelx=nelx,
                                    nely=nely,
                                    force=GF_e,
                                    movelimit=movelimit,
                                    BCid=BCid_e)
        elif (objectives[obj_flag] == "stress"):
            # TODO: sensitivity has not been verified yet
            model = StressGroup(fea_solver=fea_solver,
                                lsm_solver=lsm_solver,
                                nelx=nelx,
                                nely=nely,
                                force=GF_e,
                                movelimit=movelimit,
                                pval=5.0,
                                E=E,
                                nu=nu)
        elif (objectives[obj_flag] == "conduction"):
            model = ConductionGroup(fea_solver=fea_solver,
                                    lsm_solver=lsm_solver,
                                    nelx=nelx,
                                    nely=nely,
                                    force=GF_t,
                                    movelimit=movelimit,
                                    K_cond=K_cond,
                                    BCid=BCid_t)
        elif (objectives[obj_flag] == "coupled_heat"):
            model = HeatCouplingGroup(
                fea_solver=fea_solver,
                lsm_solver=lsm_solver,
                nelx=nelx,
                nely=nely,
                force_e=GF_e,
                force_t=GF_t,
                movelimit=movelimit,
                K_cond=K_cond,
                BCid_e=BCid_e,
                BCid_t=BCid_t,
                E=E,
                nu=nu,
                alpha=alpha,
                w=0.9
            )  # if w = 0.0, thermoelastic + conduction, if w = 1.0, conduction only

        # One Problem per one OpenMDAO object
        prob = Problem(model)

        # optimize ...
        prob.driver = pyOptSparseDriver()
        prob.driver.options['optimizer'] = 'IPOPT'
        prob.driver.opt_settings['linear_solver'] = 'ma27'
        prob.setup(check=False)
        if i_HJ == 0:
            view_model(prob)
        prob.run_model()

        # Total derivative using MAUD =====================
        total = prob.compute_totals()
        if (objectives[obj_flag] == "compliance"):
            ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0]
            gg = total['weight_comp.weight', 'inputs_comp.Vn'][0]
        elif (objectives[obj_flag] == "stress"):
            ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0]
            gg = total['weight_comp.weight', 'inputs_comp.Vn'][0]
        elif (objectives[obj_flag] == "conduction"):
            ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0]
            gg = total['weight_comp.weight', 'inputs_comp.Vn'][0]
        elif (objectives[obj_flag] == "coupled_heat"):
            ff = total['objective_comp.y', 'inputs_comp.Vn'][0]
            gg = total['weight_comp.weight', 'inputs_comp.Vn'][0]

        nBpts = int(bpts_xy.shape[0])
        # # WIP checking sensitivity 10/23
        Sf = -ff[:nBpts]  # equal to M2DO-perturbation
        Cf = np.multiply(Sf, seglength)
        #np.savetxt('/home/hayoung/Desktop/a',Sf)
        #exit()

        Sg = -gg[:nBpts]
        Cg = np.multiply(Sf, seglength)
        # ## WIP

        # previous ver.
        # Cf = -ff[:nBpts]
        # Cg = -gg[:nBpts]

        # Sf = np.divide(Cf, seglength)
        # Sg = np.divide(Cg, seglength)

        # bracketing Sf and Sg
        Sg[Sg < -1.5] = -1.5
        Sg[Sg > 0.5] = 0.5
        # Sg[:] = -1.0
        Cg = np.multiply(Sg, seglength)

        ########################################################
        ############## 		suboptimize 		################
        ########################################################
        if 1:
            suboptim = Solvers(bpts_xy=bpts_xy,
                               Sf=Sf,
                               Sg=Sg,
                               Cf=Cf,
                               Cg=Cg,
                               length_x=length_x,
                               length_y=length_y,
                               areafraction=areafraction,
                               movelimit=movelimit)
            # suboptimization
            if 1:  # simplex
                Bpt_Vel = suboptim.simplex(isprint=False)
            else:  # bisection..
                Bpt_Vel = suboptim.bisection(isprint=False)
            timestep = 1.0
            np.savetxt('a.txt', Bpt_Vel)

        elif 1:  # works when Sf <- Sf / length is used (which means Cf <- actual Sf)
            bpts_sens = np.zeros((nBpts, 2))
            # issue: scaling problem
            #
            bpts_sens[:, 0] = Sf
            bpts_sens[:, 1] = Sg

            lsm_solver.set_BptsSens(bpts_sens)
            scales = lsm_solver.get_scale_factors()
            (lb2, ub2) = lsm_solver.get_Lambda_Limits()
            constraint_distance = (0.4 * nelx * nely) - areafraction.sum()

            model = LSM2D_slpGroup(lsm_solver=lsm_solver,
                                   num_bpts=nBpts,
                                   ub=ub2,
                                   lb=lb2,
                                   Sf=bpts_sens[:, 0],
                                   Sg=bpts_sens[:, 1],
                                   constraintDistance=constraint_distance,
                                   movelimit=movelimit)

            subprob = Problem(model)
            subprob.setup()

            subprob.driver = ScipyOptimizeDriver()
            subprob.driver.options['optimizer'] = 'SLSQP'
            subprob.driver.options['disp'] = True
            subprob.driver.options['tol'] = 1e-10

            subprob.run_driver()
            lambdas = subprob['inputs_comp.lambdas']
            displacements_ = subprob['displacement_comp.displacements']

            # displacements_[displacements_ > movelimit] = movelimit
            # displacements_[displacements_ < -movelimit] = -movelimit
            timestep = abs(lambdas[0] * scales[0])

            Bpt_Vel = displacements_ / timestep
            np.savetxt('a.txt', Bpt_Vel)
            # print(timestep)
            del subprob

        else:  # branch: perturb-suboptim
            bpts_sens = np.zeros((nBpts, 2))
            # issue: scaling problem
            #
            bpts_sens[:, 0] = Sf
            bpts_sens[:, 1] = Sg

            lsm_solver.set_BptsSens(bpts_sens)
            scales = lsm_solver.get_scale_factors()
            (lb2, ub2) = lsm_solver.get_Lambda_Limits()

            constraint_distance = (0.4 * nelx * nely) - areafraction.sum()
            constraintDistance = np.array([constraint_distance])
            scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance(
                constraintDistance)

            def objF_nocallback(x):
                displacement = lsm_solver.compute_displacement(x)
                displacement_np = np.asarray(displacement)
                return lsm_solver.compute_delF(displacement_np)

            def conF_nocallback(x):
                displacement = lsm_solver.compute_displacement(x)
                displacement_np = np.asarray(displacement)
                return lsm_solver.compute_delG(displacement_np,
                                               scaled_constraintDist, 1)

            cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)})
            res = sp_optim.minimize(objF_nocallback,
                                    np.zeros(2),
                                    method='SLSQP',
                                    options={'disp': True},
                                    bounds=((lb2[0], ub2[0]), (lb2[1],
                                                               ub2[1])),
                                    constraints=cons)

            lambdas = res.x
            displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas)
            displacements_[displacements_ > movelimit] = movelimit
            displacements_[displacements_ < -movelimit] = -movelimit
            timestep = 1.0  #abs(lambdas[0]*scales[0])
            Bpt_Vel = displacements_ / timestep
            # scaling
            # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel))

        lsm_solver.advect(Bpt_Vel, timestep)
        lsm_solver.reinitialise()

        print('loop %d is finished' % i_HJ)
        area = areafraction.sum() / (nelx * nely)
        try:
            u = prob['temp_comp.disp']
            compliance = np.dot(u, GF_t[:nNODE])
        except:
            u = prob['disp_comp.disp']
            # compliance = np.dot(u, GF_e[:nDOF_e])
            pass

        if 1:  # quickplot
            plt.figure(1)
            plt.clf()
            plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10)
            plt.axis("equal")
            plt.savefig(saveFolder + "figs/bpts_%d.png" % i_HJ)
            if obj_flag == 3 or obj_flag == 2:
                plt.figure(2)
                plt.clf()
                [xx, yy] = np.meshgrid(range(0, 161), range(0, 81))
                plt.contourf(xx, yy, np.reshape(u, [81, 161]))
                plt.colorbar()
                plt.axis("equal")
                plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 5)
                plt.savefig(saveFolder + "figs/temp_%d.png" % i_HJ)

        # print([compliance[0], area])
        if (objectives[obj_flag] == "compliance"):
            compliance = prob['compliance_comp.compliance']
            print(compliance, area)

            fid = open(saveFolder + "log.txt", "a+")
            fid.write(str(compliance) + ", " + str(area) + "\n")
            fid.close()
        elif (objectives[obj_flag] == "stress"):
            print(prob['pnorm_comp.pnorm'][0], area)

            fid = open(saveFolder + "log.txt", "a+")
            fid.write(
                str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n")
            fid.close()
        elif (objectives[obj_flag] == "coupled_heat"):
            obj1 = prob['objective_comp.x1'][0]
            obj2 = prob['objective_comp.x2'][0]
            obj = prob['objective_comp.y'][0]

            print([obj1, obj2, obj, area])
            fid = open(saveFolder + "log.txt", "a+")
            fid.write(
                str(obj1) + ", " + str(obj2) + ", " + str(obj) + ", " +
                str(area) + "\n")
            fid.close()

        # Saving Phi
        phi = lsm_solver.get_phi()

        if i_HJ == 0:
            raw = {}
            raw['mesh'] = nodes
            raw['nodes'] = nodes
            raw['elem'] = elem
            raw['GF_e'] = GF_e
            raw['GF_t'] = GF_t
            raw['BCid_e'] = BCid_e
            raw['BCid_t'] = BCid_t
            raw['E'] = E
            raw['nu'] = nu
            raw['f'] = f
            raw['K_cond'] = K_cond
            raw['alpha'] = alpha
            raw['nelx'] = nelx
            raw['nely'] = nely
            raw['length_x'] = length_x
            raw['length_y'] = length_y
            raw['coord_e'] = coord_e
            raw['tol_e'] = tol_e
            filename = saveFolder + 'const.pkl'
            with open(filename, 'wb') as f:
                pickle.dump(raw, f)

        raw = {}
        raw['phi'] = phi
        if obj_flag == 3:
            raw['T'] = prob['temp_comp.disp']
        filename = saveFolder + 'phi%03i.pkl' % i_HJ
        with open(filename, 'wb') as f:
            pickle.dump(raw, f)

        del model
        del prob

        mem = virtual_memory()
        print(str(mem.available / 1024. / 1024. / 1024.) + "GB")
        if mem.available / 1024. / 1024. / 1024. < 3.0:
            print("memory explodes at iteration %3i " % i_HJ)
            return ()
    def test(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 5,
            'num_x': 3,
            'wing_type': 'CRM',
            'symmetry': True,
            'num_twist_cp': 5,
            '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': 'tube',
            'mesh': mesh,
            'twist_cp': twist_cp,

            # 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.015,  # 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.15]),  # thickness over chord ratio (NACA0015)
            'c_max_t': .303,  # chordwise location of maximum (NACA0015)
            # thickness
            'with_viscous': True,  # if true, compute viscous drag
            'with_wave': False,  # if true, compute wave drag
            'span': 10.
        }

        surfaces = [surf_dict]

        n_points = 2

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

        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=6.64, units='deg')
        indep_var_comp.add_output('Mach_number', val=0.84)
        indep_var_comp.add_output('re', val=1.e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('cg', val=np.zeros((3)), units='m')

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

        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('t_over_c_cp', val=np.array([0.15]))
        indep_var_comp.add_output('span', val=12., units='m')
        indep_var_comp.add_output('twist_cp_0', val=np.zeros((5)), units='deg')
        indep_var_comp.add_output('twist_cp_1', val=np.zeros((5)), units='deg')

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

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

            # Create the aero point group and add it to the model
            aero_group = AeroPoint(surfaces=surfaces)
            point_name = 'aero_point_{}'.format(i)
            prob.model.add_subsystem(point_name, aero_group)

            # 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('cg', point_name + '.cg')

            # Connect the parameters within the model for each aero point
            for surface in surfaces:

                geom_group = Geometry(surface=surface, connect_geom_DVs=False)

                # Add tmp_group to the problem as the name of the surface.
                # Note that is a group and performance group for each
                # individual surface.
                aero_group.add_subsystem(surface['name'] + '_geom', geom_group)

                name = surface['name']
                prob.model.connect(point_name + '.CD',
                                   'multi_CD.' + str(i) + '_CD')

                # Connect the mesh from the geometry component to the analysis point
                prob.model.connect(point_name + '.' + name + '_geom.mesh',
                                   point_name + '.' + name + '.def_mesh')

                # Perform the connections with the modified names within the
                # 'aero_states' group.
                prob.model.connect(
                    point_name + '.' + name + '_geom.mesh',
                    point_name + '.aero_states.' + name + '_def_mesh')

                prob.model.connect(
                    point_name + '.' + name + '_geom.t_over_c',
                    point_name + '.' + name + '_perf.' + 't_over_c')

                # prob.model.connect(point_name + '.' + name + '_geom.span', 'span_diff_comp.span_' + str(i))

        # Connect geometric design variables to each point
        prob.model.connect('t_over_c_cp', 'aero_point_0.wing_geom.t_over_c_cp')
        prob.model.connect('t_over_c_cp', 'aero_point_1.wing_geom.t_over_c_cp')

        prob.model.connect('span', 'aero_point_0.wing_geom.span')
        prob.model.connect('span', 'aero_point_1.wing_geom.span')

        prob.model.connect('twist_cp_0', 'aero_point_0.wing_geom.twist_cp')
        prob.model.connect('twist_cp_1', 'aero_point_1.wing_geom.twist_cp')

        prob.model.add_subsystem('multi_CD',
                                 MultiCD(n_points=n_points),
                                 promotes_outputs=['CD'])

        from openmdao.api import ScipyOptimizeDriver
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['tol'] = 1e-9

        # # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('alpha', lower=-15, upper=15)

        prob.model.add_design_var('twist_cp_0', lower=-5, upper=8)
        prob.model.add_design_var('twist_cp_1', lower=-5, upper=8)

        prob.model.add_design_var('span', lower=2, upper=15)

        prob.model.add_constraint('aero_point_0.wing_perf.CL', equals=0.45)
        prob.model.add_constraint('aero_point_1.wing_perf.CL', equals=0.50)

        prob.model.add_objective('CD', scaler=1e4)

        # Set up the problem
        prob.setup()

        prob.run_driver()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.45,
                         1e-6)
        assert_rel_error(self, prob['aero_point_1.wing_perf.CL'][0], 0.5, 1e-6)
        assert_rel_error(
            self, prob['twist_cp_0'],
            np.array([8., -1.21207749, -2.42415497, -1.21207749, -1.0821358]),
            1e-6)
        assert_rel_error(
            self, prob['twist_cp_1'],
            np.array([8., -0.02049115, -0.0409823, -0.02049115, 0.77903674]),
            1e-6)
        assert_rel_error(self, prob['aero_point_1.wing_perf.CL'][0], 0.5, 1e-6)
Exemple #25
0
    def test_debug_print_option(self):

        prob = Problem()
        model = prob.model = Group()

        model.add_subsystem('p1', IndepVarComp('x', 50.0), promotes=['*'])
        model.add_subsystem('p2', IndepVarComp('y', 50.0), promotes=['*'])
        model.add_subsystem('comp', Paraboloid(), promotes=['*'])
        model.add_subsystem('con', ExecComp('c = - x + y'), promotes=['*'])

        prob.set_solver_print(level=0)

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

        prob.driver.options['debug_print'] = [
            'desvars', 'ln_cons', 'nl_cons', 'objs'
        ]

        model.add_design_var('x', lower=-50.0, upper=50.0)
        model.add_design_var('y', lower=-50.0, upper=50.0)
        model.add_objective('f_xy')
        model.add_constraint('c', upper=-15.0)

        prob.setup(check=False)

        stdout = sys.stdout
        strout = StringIO()
        sys.stdout = strout
        try:
            prob.run_driver()
        finally:
            sys.stdout = stdout

        output = strout.getvalue().split('\n')
        self.assertTrue(
            output.count("Design Vars") > 1,
            "Should be more than one design vars header printed")
        self.assertTrue(
            output.count("Nonlinear constraints") > 1,
            "Should be more than one nonlinear constraint header printed")
        self.assertTrue(
            output.count("Linear constraints") > 1,
            "Should be more than one linear constraint header printed")
        self.assertTrue(
            output.count("Objectives") > 1,
            "Should be more than one objective header printed")
        self.assertTrue(
            len([s for s in output if s.startswith('p1.x')]) > 1,
            "Should be more than one p1.x printed")
        self.assertTrue(
            len([s for s in output if s.startswith('p2.y')]) > 1,
            "Should be more than one p2.y printed")
        self.assertTrue(
            len([s for s in output if s.startswith('con.c')]) > 1,
            "Should be more than one con.c printed")
        self.assertTrue(
            len([s for s in output if s.startswith('comp.f_xy')]) > 1,
            "Should be more than one comp.f_xy printed")
Exemple #26
0
    def test(self):
        import numpy as np

        from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, \
            ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, \
            DirectSolver, LinearBlockGS, PetscKSP, SqliteRecorder

        from openaerostruct.geometry.utils import generate_mesh
        from openaerostruct.geometry.geometry_group import Geometry
        from openaerostruct.aerodynamics.aero_groups import AeroPoint

        # Create a dictionary to store options about the mesh
        mesh_dict = {'num_y' : 7,
                     'num_x' : 2,
                     'wing_type' : 'CRM',
                     'symmetry' : False,
                     'num_twist_cp' : 5}

        # Generate the aerodynamic mesh based on the previous dictionary
        mesh, twist_cp = generate_mesh(mesh_dict)

        # Create a dictionary with info and options about the aerodynamic
        # lifting surface
        surface = {
                    # Wing definition
                    'name' : 'wing',        # name of the surface
                    'type' : 'aero',
                    'symmetry' : False,     # 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' : 'tube',

                    'twist_cp' : twist_cp,
                    'mesh' : mesh,
                    'num_x' : mesh.shape[0],
                    'num_y' : mesh.shape[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.015,            # 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.15]),      # thickness over chord ratio (NACA0015)
                    'c_max_t' : .303,       # chordwise location of maximum (NACA0015)
                                            # thickness
                    'with_viscous' : True,  # if true, compute viscous drag
                    'with_wave' : False,     # if true, compute wave drag
                    }

        # Create the OpenMDAO problem
        prob = Problem()

        # Create an independent variable component that will supply the flow
        # conditions to the problem.
        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=5., units='deg')
        indep_var_comp.add_output('M', val=0.84)
        indep_var_comp.add_output('re', val=1.e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('cg', val=np.zeros((3)), units='m')

        # Add this IndepVarComp to the problem model
        prob.model.add_subsystem('prob_vars',
            indep_var_comp,
            promotes=['*'])

        # Create and add a group that handles the geometry for the
        # aerodynamic lifting surface
        geom_group = Geometry(surface=surface)
        prob.model.add_subsystem(surface['name'], geom_group)

        # Create the aero point group, which contains the actual aerodynamic
        # analyses
        aero_group = AeroPoint(surfaces=[surface])
        point_name = 'aero_point_0'
        prob.model.add_subsystem(point_name, aero_group,
            promotes_inputs=['v', 'alpha', 'M', 're', 'rho', 'cg'])

        name = surface['name']

        # Connect the mesh from the geometry component to the analysis point
        prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh')

        # Perform the connections with the modified names within the
        # 'aero_states' group.
        prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh')

        prob.model.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c')

        # Import the Scipy Optimizer and set the driver of the problem to use
        # it, which defaults to an SLSQP optimization method
        from openmdao.api import ScipyOptimizeDriver
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['tol'] = 1e-9

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.)
        prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5)
        prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4)

        # Set up and run the optimization problem
        prob.setup()
        prob.run_model()
        # prob.check_partials()
        # exit()
        prob.run_driver()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03339013029042684, 1e-5)
        assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5, 1e-6)
        assert_rel_error(self, prob['aero_point_0.CM'][1], -0.18453592482214315, 1e-4)
Exemple #27
0
def brachistochrone_min_time(transcription='gauss-lobatto',
                             num_segments=8,
                             transcription_order=3,
                             compressed=True,
                             sim_record='brach_min_time_sim.db',
                             optimizer='SLSQP',
                             dynamic_simul_derivs=True,
                             force_alloc_complex=False,
                             solve_segments=False,
                             run_driver=True):
    p = Problem(model=Group())

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

    p.driver.options['dynamic_simul_derivs'] = dynamic_simul_derivs

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

    phase = Phase(ode_class=BrachistochroneVectorStatesODE,
                  transcription=transcription)

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

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

    fix_final = not solve_segments  # can't fix final position if you're solving the segments
    phase.set_state_options('pos',
                            fix_initial=True,
                            fix_final=fix_final,
                            solve_segments=solve_segments)
    phase.set_state_options('v',
                            fix_initial=True,
                            fix_final=False,
                            solve_segments=solve_segments)

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

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

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

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

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

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

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

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

    # Plot results
    if SHOW_PLOTS:
        p.run_driver()
        exp_out = phase.simulate(record_file=sim_record)

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

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

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

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

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

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

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

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

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

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

        plt.show()

    return p
Exemple #28
0
        prob = Problem(model=Group(num_par_fd=num_par_fd))
        prob.model.approx_totals(method='fd')
        prob.model.add_subsystem('comp',
                                 LandBasedTurbine(RefBlade=blade,
                                                  Nsection_Tow=Nsection_Tow,
                                                  VerbosityCosts=True),
                                 promotes=['*'])
    else:
        prob = Problem()
        prob.model = LandBasedTurbine(RefBlade=blade,
                                      Nsection_Tow=Nsection_Tow,
                                      VerbosityCosts=True)

    if optFlag:
        # --- Solver ---
        prob.driver = ScipyOptimizeDriver()
        prob.driver.options['optimizer'] = 'SLSQP'
        prob.driver.options['tol'] = 1.e-6
        prob.driver.options['maxiter'] = 100

        #prob.driver = pyOptSparseDriver()
        #prob.driver.options['optimizer'] = 'CONMIN'
        # prob.driver.options['optimizer'] = 'SNOPT'
        # prob.driver.options['gradient method'] = "pyopt_fd"
        # ----------------------

        # --- Objective ---
        prob.model.add_objective('lcoe')
        # ----------------------

        # --- Design Variables ---
Exemple #29
0
    def test(self):
        from openaerostruct.geometry.utils import generate_mesh, write_FFD_file
        from openaerostruct.geometry.geometry_group import Geometry

        from openaerostruct.integration.aerostruct_groups import Aerostruct, AerostructPoint

        from openmdao.api import IndepVarComp, Problem, Group, SqliteRecorder
        from pygeo import DVGeometry


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

        mesh, twist_cp = generate_mesh(mesh_dict)

        surf_dict = {
                    # Wing definition
                    'name' : 'wing',        # name of the surface
                    'type' : 'aerostruct',
                    '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' : 'tube',

                    'thickness_cp' : np.array([.1, .2, .3]),

                    'mesh' : mesh,
                    'num_x' : mesh.shape[0],
                    'num_y' : mesh.shape[1],

                    'geom_manipulator' : 'FFD',
                    'mx' : 2,
                    'my' : 3,

                    # 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.015,            # 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.15]),      # thickness over chord ratio (NACA0015)
                    'c_max_t' : .303,       # chordwise location of maximum (NACA0015)
                                            # thickness
                    'with_viscous' : True,
                    'with_wave' : False,     # if true, compute wave drag

                    # Structural values are based on aluminum 7075
                    'E' : 70.e9,            # [Pa] Young's modulus of the spar
                    'G' : 30.e9,            # [Pa] shear modulus of the spar
                    'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case
                    'mrho' : 3.e3,          # [kg/m^3] material density
                    'fem_origin' : 0.35,    # normalized chordwise location of the spar
                    'wing_weight_ratio' : 2.,

                    # Constraints
                    'exact_failure_constraint' : False, # if false, use KS function
                    }

        surfaces = [surf_dict]

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

        # Add problem information as an independent variables component
        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=5., units='deg')
        indep_var_comp.add_output('M', val=0.84)
        indep_var_comp.add_output('re', val=1.e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s')
        indep_var_comp.add_output('R', val=11.165e6, units='m')
        indep_var_comp.add_output('W0', val=0.4 * 3e5,  units='kg')
        indep_var_comp.add_output('a', val=295.4, 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']

            filename = write_FFD_file(surface, surface['mx'], surface['my'])
            DVGeo = DVGeometry(filename)
            aerostruct_group = Aerostruct(surface=surface, DVGeo=DVGeo)

            # 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('M', point_name + '.M')
            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('a', point_name + '.a')
            prob.model.connect('empty_cg', point_name + '.empty_cg')
            prob.model.connect('load_factor', point_name + '.load_factor')

            for surface in surfaces:

                prob.model.connect('load_factor', name + '.load_factor')

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

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

                # Connect performance calculation variables
                prob.model.connect(name + '.radius', com_name + '.radius')
                prob.model.connect(name + '.thickness', com_name + '.thickness')
                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_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight')
                prob.model.connect(name + '.t_over_c', com_name + '.t_over_c')

        # Import the Scipy Optimizer and set the driver of the problem to use
        # it, which defaults to an SLSQP optimization method
        from openmdao.api import ScipyOptimizeDriver
        prob.driver = ScipyOptimizeDriver()

        recorder = SqliteRecorder("aerostruct_ffd.db")
        prob.driver.add_recorder(recorder)
        prob.driver.recording_options['record_derivatives'] = True

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.shape', lower=-3, upper=2)
        prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2)
        prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.)
        prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.)

        # Add design variables, constraisnt, and objective on the problem
        prob.model.add_design_var('alpha', lower=-10., upper=10.)
        prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.)
        prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5)

        # iprofile.setup()
        # iprofile.start()

        # Set up the problem
        prob.setup()

        # from openmdao.api import view_model
        # view_model(prob, outfile='aerostruct_ffd', show_browser=False)

        # prob.run_model()
        prob.run_driver()

        # prob.check_partials(compact_print=True)

        # print("\nWing CL:", prob['aero_point_0.wing_perf.CL'])
        # print("Wing CD:", prob['aero_point_0.wing_perf.CD'])


        # from helper import plot_3d_points
        #
        # mesh = prob['aero_point_0.wing.def_mesh']
        # plot_3d_points(mesh)
        #
        # filename = mesh_dict['wing_type'] + '_' + str(mesh_dict['num_x']) + '_' + str(mesh_dict['num_y'])
        # filename += '_' + str(surf_dict['mx']) + '_' + str(surf_dict['my']) + '.mesh'
        # np.save(filename, mesh)

        assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 104675.0989232741, 1e-4)
    def test_recording_remote_voi(self):
        # Create a parallel model
        model = Group()

        model.add_subsystem('par', ParallelGroup())
        model.par.add_subsystem('G1', Mygroup())
        model.par.add_subsystem('G2', Mygroup())
        model.connect('par.G1.y', 'Obj.y1')
        model.connect('par.G2.y', 'Obj.y2')

        model.add_subsystem('Obj', ExecComp('obj=y1+y2'))
        model.add_objective('Obj.obj')

        # Configure driver to record VOIs on both procs
        driver = ScipyOptimizeDriver(disp=False)

        driver.recording_options['record_desvars'] = True
        driver.recording_options['record_responses'] = True
        driver.recording_options['record_objectives'] = True
        driver.recording_options['record_constraints'] = True
        driver.recording_options['includes'] = ['par.G1.y', 'par.G2.y']

        driver.add_recorder(self.recorder)

        # Create problem and run driver
        prob = Problem(model, driver)
        prob.add_recorder(self.recorder)
        prob.setup()

        t0, t1 = run_driver(prob)
        prob.record_iteration('final')
        t2 = time()

        prob.cleanup()

        # Since the test will compare the last case recorded, just check the
        # current values in the problem. This next section is about getting those values

        # These involve collective gathers so all ranks need to run this
        expected_outputs = driver.get_design_var_values()
        expected_outputs.update(driver.get_objective_values())
        expected_outputs.update(driver.get_constraint_values())

        # includes for outputs are specified as promoted names but we need absolute names
        prom2abs = model._var_allprocs_prom2abs_list['output']
        abs_includes = [prom2abs[n][0] for n in prob.driver.recording_options['includes']]

        # Absolute path names of includes on this rank
        rrank = model.comm.rank
        rowned = model._owning_rank
        local_includes = [n for n in abs_includes if rrank == rowned[n]]

        # Get values for all vars on this rank
        inputs, outputs, residuals = model.get_nonlinear_vectors()

        # Get values for includes on this rank
        local_vars = {n: outputs[n] for n in local_includes}

        # Gather values for includes on all ranks
        all_vars = model.comm.gather(local_vars, root=0)

        if prob.comm.rank == 0:
            # Only on rank 0 do we have all the values. The all_vars variable is a list of
            # dicts from all ranks 0,1,... In this case, just ranks 0 and 1
            dct = all_vars[-1]
            for d in all_vars[:-1]:
                dct.update(d)

            expected_includes = {
                'par.G1.Cy.y': dct['par.G1.Cy.y'],
                'par.G2.Cy.y': dct['par.G2.Cy.y'],
            }

            expected_outputs.update(expected_includes)

            coordinate = [0, 'ScipyOptimize_SLSQP', (driver.iter_count-1,)]

            expected_data = ((coordinate, (t0, t1), expected_outputs, None),)
            assertDriverIterDataRecorded(self, expected_data, self.eps)

            expected_data = (('final', (t1, t2), expected_outputs),)
            assertProblemDataRecorded(self, expected_data, self.eps)
    def test_parallel(self):
        from openmdao.api import ParallelGroup, NonlinearBlockGS

        class SellarMDA(Group):
            """
            Group containing the Sellar MDA.
            """
            def setup(self):
                indeps = self.add_subsystem('indeps',
                                            IndepVarComp(),
                                            promotes=['*'])
                indeps.add_output('x', 1.0)
                indeps.add_output('z', np.array([5.0, 2.0]))
                cycle = self.add_subsystem('cycle',
                                           ParallelGroup(),
                                           promotes=['*'])
                cycle.add_subsystem('d1',
                                    SellarDis1(),
                                    promotes_inputs=['x', 'z', 'y2'],
                                    promotes_outputs=['y1'])
                cycle.add_subsystem('d2',
                                    SellarDis2(),
                                    promotes_inputs=['z', 'y1'],
                                    promotes_outputs=['y2'])

                # Nonlinear Block Gauss Seidel is a gradient free solver
                cycle.nonlinear_solver = NonlinearBlockGS()

                self.add_subsystem('obj_cmp',
                                   ExecComp(
                                       'obj = x**2 + z[1] + y1 + exp(-y2)',
                                       z=np.array([0.0, 0.0]),
                                       x=0.0),
                                   promotes=['x', 'z', 'y1', 'y2', 'obj'])

                self.add_subsystem('con_cmp1',
                                   ExecComp('con1 = 3.16 - y1'),
                                   promotes=['con1', 'y1'])
                self.add_subsystem('con_cmp2',
                                   ExecComp('con2 = y2 - 24.0'),
                                   promotes=['con2', 'y2'])

        filename = 'xdsmjs_parallel'
        out_format = 'html'
        prob = Problem(model=SellarMDA())
        model = prob.model
        prob.driver = ScipyOptimizeDriver()

        model.add_design_var('z',
                             lower=np.array([-10.0, 0.0]),
                             upper=np.array([10.0, 10.0]),
                             indices=np.arange(2, dtype=int))
        model.add_design_var('x', lower=0.0, upper=10.0)
        model.add_objective('obj')
        model.add_constraint('con1', equals=np.zeros(1))
        model.add_constraint('con2', upper=0.0)

        prob.setup(check=False)
        prob.final_setup()

        # Write output
        write_xdsm(prob,
                   filename=filename,
                   out_format=out_format,
                   quiet=QUIET,
                   show_browser=SHOW,
                   show_parallel=True)
        # Check if file was created
        self.assertTrue(os.path.isfile('.'.join([filename, out_format])))