def get_mesh(symmetry):
    """
    Return a mesh for testing.
    """
    ny = (2*NY - 1) if symmetry else NY

    # Create a dictionary to store options about the mesh
    mesh_dict = {'num_y' : ny,
                 'num_x' : NX,
                 'wing_type' : 'CRM',
                 'symmetry' : symmetry,
                 'num_twist_cp' : NY}

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

    surface = {}
    surface['symmetry'] = symmetry
    surface['type'] = 'aero'

    # Random perturbations to the mesh so that we don't mask errors subtractively.
    mesh[:, :, 0] += 0.05*np.random.random(mesh[:, :, 2].shape)
    mesh[:, :, 1] += 0.05*np.random.random(mesh[:, :, 2].shape)
    mesh[:, :, 2] = np.random.random(mesh[:, :, 2].shape)

    return mesh
    def test(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {'num_y' : 7,
                     '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
                    'symmetry' : True,     # if true, model one half of wing
                                            # reflected across the plane y = 0
                    'fem_model_type' : 'tube',

                    'mesh' : mesh,
                    'radius_cp' : np.ones((5)) * 0.5,

                    # 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)) * .1,
                    'wing_weight_ratio' : 2.,
                    'struct_weight_relief' : False,    # True to add the weight of the structure to the loads on the structure
                    'distributed_fuel_weight' : False,
                    'exact_failure_constraint' : False,
                    }

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

        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)

        # Set up the problem
        prob.setup()

        prob.run_model()

        assert_rel_error(self, prob['wing.structural_mass'][0], 117819.798089, 1e-4)
    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' : 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,    # True to add the weight of the structure to the loads on the structure
                    'distributed_fuel_weight' : False,
                    # Constraints
                    'exact_failure_constraint' : False, # if false, use KS function
                    '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')
                prob.model.connect('load_factor', point_name + '.coupled.' + name + '.load_factor')

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

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

        # Set up the problem
        prob.setup()

        AS_point.nonlinear_solver.options['iprint'] = 2
        #
        # from openmdao.api import view_model
        # view_model(prob)

        prob.run_model()

        # prob.model.list_outputs(values=True,
        #                         implicit=False,
        #                         units=True,
        #                         shape=True,
        #                         bounds=True,
        #                         residuals=True,
        #                         scaling=True,
        #                         hierarchical=False,
        #                         print_arrays=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], 112469.567077, 1e-5)
        assert_rel_error(self, prob['wing.structural_mass'][0]/1.25, 24009.5230566, 1e-5)
예제 #4
0
def get_default_surfaces():
    # Create a dictionary to store options about the mesh
    mesh_dict = {'num_y' : 7,
                 'num_x' : 2,
                 'wing_type' : 'CRM',
                 'symmetry' : True,
                 'num_twist_cp' : 5}

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

    wing_dict = {'name' : 'wing',
                 'num_y' : 4,
                 'num_x' : 2,
                 'symmetry' : True,
                 'S_ref_type' : 'wetted',
                 'CL0' : 0.1,
                 'CD0' : 0.1,
                 'mesh' : mesh,

                 # 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, computes wave drag
                 'fem_model_type' : 'tube',

                 # 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
                 'distributed_fuel_weight' : False,    # True to add the weight of the structure to the loads on the structure
                 'Wf_reserve' : 10000.,

                 }

    # Create a dictionary to store options about the mesh
    mesh_dict = {'num_y' : 5,
                 'num_x' : 3,
                 'wing_type' : 'rect',
                 'symmetry' : False}

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

    tail_dict = {'name' : 'tail',
                 'num_y' : 5,
                 'num_x' : 3,
                 'symmetry' : False,
                 'mesh' : mesh}

    surfaces = [wing_dict, tail_dict]

    return surfaces
    def test_multiple_masses(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {'num_y' : 31,
                     'wing_type' : 'rect',
                     'span' : 10,
                     'symmetry' : True}

        mesh = generate_mesh(mesh_dict)

        surface = {
                    # Wing definition
                    'name' : 'wing',        # name of the surface
                    'symmetry' : True,     # if true, model one half of wing
                                            # reflected across the plane y = 0
                    'fem_model_type' : 'tube',

                    'mesh' : mesh,

                    # 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.5,    # normalized chordwise location of the spar
                    't_over_c_cp' : np.array([0.15]),      # maximum airfoil thickness
                    'thickness_cp' : np.ones((3)) * .1,
                    'wing_weight_ratio' : 2.,
                    'struct_weight_relief' : False,    # True to add the weight of the structure to the loads on the structure
                    'distributed_fuel_weight' : False,
                    'exact_failure_constraint' : False,
                    }

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

        ny = surface['mesh'].shape[1]
        surface['n_point_masses'] = 2

        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('loads', val=np.zeros((ny, 6)), units='N')
        indep_var_comp.add_output('load_factor', val=1.)

        engine_thrusts = np.array([[10., 20.]])

        point_mass_locations = np.array([[1., -1., 0.],
                                         [1., -2., 0.]])

        indep_var_comp.add_output('engine_thrusts', val=engine_thrusts, units='N')
        indep_var_comp.add_output('point_mass_locations', val=point_mass_locations, units='m')

        struct_group = SpatialBeamAlone(surface=surface)

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

        prob.model.add_subsystem(surface['name'], struct_group, promotes=['*'])

        # Set up the problem
        prob.setup()

        prob.run_model()

        assert_rel_error(self, prob['vonmises'][-1, 0], 137509.870021, 1e-4)
예제 #6
0
# chordwise (num_x) directions. Vary these to change the level of fidelity.
num_y = 21
num_x = 3

# Create a mesh dictionary to feed to generate_mesh to actually create
# the mesh array.
mesh_dict = {'num_y' : num_y,
             'num_x' : num_x,
             'wing_type' : 'rect',
             'symmetry' : True,
             'span_cos_spacing' : 0.5,
             'span' : 3.11,
             'root_chord' : 0.3,
             }

mesh = generate_mesh(mesh_dict)

# Apply camber to the mesh
camber = 1 - np.linspace(-1, 1, num_x) ** 2
camber *= 0.3 * 0.05

for ind_x in range(num_x):
    mesh[ind_x, :, 2] = camber[ind_x]

# Introduce geometry manipulation variables to define the ScanEagle shape
zshear_cp = np.zeros(10)
zshear_cp[0] = .3

xshear_cp = np.zeros(10)
xshear_cp[0] = .15
    def test(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 7,
            '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': '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)) * .1,
            'wing_weight_ratio': 2.,
            'struct_weight_relief':
            False,  # True to add the weight of the structure to the loads on the structure
            'exact_failure_constraint': False,
        }

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

        ny = surf_dict['num_y']

        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=2.)

        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)

        # Set up the problem
        prob.setup()

        prob.run_model()

        assert_rel_error(self, prob['wing.structural_weight'][0],
                         2437385.6547349701, 1e-4)
    def test(self):
        # 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
                    '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,

                    # 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
                    'distributed_fuel_weight' : False,
                    # 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('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('CT', val=grav_constant * 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('speed_of_sound', 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')
        indep_var_comp.add_output('S_ref_total', val=150.0, units='m**2')

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

            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')
            prob.model.connect('S_ref_total', point_name + '.S_ref_total')

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

                # 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_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass')
                prob.model.connect(name + '.t_over_c', com_name + '.t_over_c')

        # Set up the problem
        prob.setup()

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

        prob.run_model()

        assert_rel_error(self, prob['AS_point_0.CL'][0], 1.5775046966345903, 1e-6)
        assert_rel_error(self, prob['AS_point_0.CM'][1], -1.61358383281, 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_cos_spacing': 1.,
            'span': 10,
            'chord': 1
        }

        mesh = 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
            'fem_model_type': 'tube',
            'mesh': mesh,

            # 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.,
            'struct_weight_relief':
            False,  # True to add the weight of the structure to the loads on the structure
            'distributed_fuel_weight': False,
            'exact_failure_constraint': False,
        }

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

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

        loads = np.zeros((ny, 6))
        loads[0, 2] = 1e4
        indep_var_comp = om.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)

        prob.driver = om.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.01,
                                  upper=0.5,
                                  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_mass', scaler=1e-5)

        # Set up the problem
        prob.setup()

        # om.view_model(prob)

        prob.run_model()

        assert_rel_error(self, prob['wing.structural_mass'][0], 100.727314456,
                         1e-4)
        assert_rel_error(self, prob['wing.disp'][0, 2], 0.696503988153, 1e-6)
        np.testing.assert_allclose(
            prob['wing.disp'][1, :],
            np.array([-0., 0., 0.39925232, -0.19102602, 0., 0.]))
예제 #10
0
    def test(self):
        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 13,
            'num_x': 2,
            'wing_type': 'CRM',
            'symmetry': True,
            'num_twist_cp': 5,
            'span_cos_spacing': 1.
        }

        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.ones(2) * 0.06836728,
            '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.12,  # thickness over chord ratio (NACA0015)
            'c_max_t': .303,  # chordwise location of maximum (NACA0015)
            # thickness
            'with_viscous': False,

            # 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': 1.,

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

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

        # Set up the problem
        prob.setup()

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

        prob.run_model()

        assert_rel_error(self, prob['AS_point_0.wing_perf.CL'][0],
                         0.501212803372, 1e-6)
        assert_rel_error(self, prob['AS_point_0.wing_perf.failure'][0],
                         -0.434049851068, 1e-6)
        assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 70365.875285,
                         1e-4)
        assert_rel_error(self, prob['AS_point_0.CM'][1], -0.129720748279, 1e-5)
    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', units='kg')
        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(self):
        import numpy as np

        import openmdao.api as om

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

        # Create a dictionary to store options about the mesh
        mesh_dict = {
            'num_y': 7,
            'num_x': 2,
            'wing_type': 'CRM',
            'symmetry': True,
            '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
            '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': 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 = om.Problem()

        # Create an independent variable component that will supply the flow
        # conditions to the problem.
        indep_var_comp = om.IndepVarComp()
        indep_var_comp.add_output('alpha', val=5., units='deg')
        indep_var_comp.add_output('Mach_number', val=0.84)
        indep_var_comp.add_output('altitude', val=35000., units='ft')

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

        # Add this IndepVarComp to the problem model
        prob.model.add_subsystem('atmos', AtmosGroup(), 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', 'Mach_number', '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
        prob.driver = om.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.check_partials(compact_print=True)
        # exit()
        prob.run_driver()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0],
                         0.030471796067577953, 1e-6)
        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], -1.7331840488188963,
                         1e-6)
예제 #13
0
    def test(self):

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

        mesh = generate_mesh(mesh_dict)

        surf_dict = {
                    # 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'

                    'twist_cp' : np.array([0.]),

                    'mesh' : mesh,

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

        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('beta', val=-5, units='deg')
        indep_var_comp.add_output('omega', val=np.array([0.0, 0.0, -30.0]), units='deg/s')
        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=['*'])

        # 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, rotational=True)
            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('omega', point_name + '.omega')
            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:

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

        # Set up the problem
        prob.setup()

        prob.run_model()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03487336411850356, 1e-6)
        assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.4615561217697067, 1e-6)
        assert_rel_error(self, prob['aero_point_0.CM'][0], 0.007313681048738922, 1e-6)
        assert_rel_error(self, prob['aero_point_0.CM'][1], -0.11507021674483686, 1e-6)
        assert_rel_error(self, prob['aero_point_0.CM'][2], 0.0, 1e-6)
예제 #14
0
    def test(self):
        import numpy as np

        from openaerostruct.geometry.utils import generate_mesh
        from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint
        from openaerostruct.utils.constants import grav_constant

        import openmdao.api as om

        # 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
            '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,

            # 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
            'distributed_fuel_weight': False,
            # Constraints
            'exact_failure_constraint': False,  # if false, use KS function
        }

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

        # Add problem information as an independent variables component
        indep_var_comp = om.IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=5., 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('CT',
                                  val=grav_constant * 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('speed_of_sound', 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 = AerostructGeometry(surface=surface)

        name = 'wing'

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

        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', 'Mach_number', 're', 'rho',
                                     'CT', 'R', 'W0', 'speed_of_sound',
                                     'empty_cg', 'load_factor'
                                 ])

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

        # 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_mass',
            point_name + '.' + 'total_perf.' + name + '_structural_mass')
        prob.model.connect(name + '.t_over_c', com_name + '.t_over_c')

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

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

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

        # Inserting a small unit test here. Verify that beta is correctly promoted in an Aerostruct
        # group.
        assert_rel_error(self, prob['AS_point_0.beta'], 0.0)

        prob.run_driver()

        assert_rel_error(self, prob['AS_point_0.fuelburn'][0],
                         97696.33252514644, 1e-8)
예제 #15
0
    def setup(self):
        rv_dict = self.options['rv_dict']

        # Create a dictionary to store options about the mesh
        mesh_dict = {'num_y' : 7,
                     'num_x' : 2,
                     'wing_type' : 'CRM',
                     'symmetry' : True,
                     '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' : 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' : 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
                    }

        indep_var_comp = IndepVarComp()
        if "v" not in rv_dict:
            indep_var_comp.add_output('v', val=248.136, units='m/s')
        if "alpha" not in rv_dict:
            indep_var_comp.add_output('alpha', val=5., units='deg')
        if "Mach_number" not in rv_dict:
            indep_var_comp.add_output('M', val=0.84)
        if "re" not in rv_dict:
            indep_var_comp.add_output('re', val=1.e6, units='1/m')
        if "rho" not in rv_dict:
            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
        self.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)
        self.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'
        self.add_subsystem(point_name, aero_group,
            promotes_inputs=['v', 'alpha', 'Mach_number', 're', 'rho', 'cg'])

        name = surface['name']

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

        # Perform the connections with the modified names within the
        # 'aero_states' group.
        self.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh')
        self.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c')
예제 #16
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': False,
            'span': 10.,
            'chord': 1,
            'span_cos_spacing': 1.
        }

        mesh = generate_mesh(mesh_dict)

        surf_dict = {
            # 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': 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.12]),  # 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
        }

        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], .45655138,
                         1e-6)
        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0],
                         0.018942466133780547, 1e-6)
    def test(self):
        from openaerostruct.geometry.utils import generate_mesh, write_FFD_file

        from openaerostruct.integration.aerostruct_groups import AerostructGeometry, 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,

                    '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.,
                    'struct_weight_relief' : False,    # True to add the weight of the structure to the loads on the structure
                    'distributed_fuel_weight' : False,
                    # 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 = AerostructGeometry(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')
                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')

                # 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
        prob.driver.recording_options['includes'] = ['*']

        # 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-3)
    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)
    def test(self):
        """
        This is an opt problem that tests the wingbox model with wave drag and the fuel vol constraint
        """

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

        mesh, twist_cp = generate_mesh(mesh_dict)

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

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

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

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

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

                    # Structural values are based on aluminum 7075
                    'E' : 73.1e9,              # [Pa] Young's modulus
                    'G' : (73.1e9/2/1.33),     # [Pa] shear modulus (calculated using E and the Poisson's ratio here)
                    'yield' : (420.e6 / 1.5),  # [Pa] allowable yield stress
                    'mrho' : 2.78e3,           # [kg/m^3] material density
                    'strength_factor_for_upper_skin' : 1.0, # the yield stress is multiplied by this factor for the upper skin
                    # 'fem_origin' : 0.35,    # normalized chordwise location of the spar
                    'wing_weight_ratio' : 1.25,
                    'struct_weight_relief' : True,
                    'distributed_fuel_weight' : True,
                    # 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=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 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(2):

            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, 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')
            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', 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:

                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')
                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('wing.struct_setup.fuel_vols', 'fuel_vol_delta.fuel_vols')

        prob.model.connect('AS_point_0.fuelburn', 'fuel_vol_delta.fuelburn')
        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', units='kg')
        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')

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

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

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

        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.)
        prob.model.add_constraint('fuel_diff', equals=0.)
        prob.model.add_constraint('fuel_diff_25', equals=0.)
        #=======================================================================================
        #=======================================================================================

        # Set up the problem
        prob.setup()

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

        prob.run_model()

        # Check the partials at the initial point in the design space,
        # only care about relative error
        data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40)
        assert_check_partials(data, atol=1e20, rtol=1e-6)

        # Run the optimizer for 5 iterations
        prob.run_driver()

        # Check the partials at this point in the design space
        data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40)
        assert_check_partials(data, atol=1e20, rtol=1e-6)
    def test(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 7,
            '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': '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)) * .1,
            'wing_weight_ratio': 2.,
            'exact_failure_constraint': False,
        }

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

        ny = surf_dict['num_y']

        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('loads', val=np.zeros((ny, 6)), 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()

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.thickness_cp',
                                  lower=0.01,
                                  upper=0.5,
                                  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

        prob.run_driver()

        assert_rel_error(self, prob['wing.structural_weight'][0],
                         133427.40492929096, 1e-4)
        assert_rel_error(self, prob['wing.disp'][1, 2], 0., 1e-4)
    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)
예제 #22
0
    def test(self):
        import numpy as np

        from openaerostruct.geometry.utils import generate_mesh
        from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint
        from openaerostruct.utils.constants import grav_constant

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

        # Create a dictionary to store options about the surface
        mesh_dict = {'num_y' : 11,
                     '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
                    '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,

                    # 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
                    'distributed_fuel_weight' : False,
                    # 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, 0.5 * 340.], units='m/s')
        indep_var_comp.add_output('alpha', val=[5., 10.], units='deg')
        indep_var_comp.add_output('Mach_number', val=[0.84, 0.5])
        indep_var_comp.add_output('re', val=[1.e6, 0.5e6], units='1/m')
        indep_var_comp.add_output('rho', val=[0.38, .764], units='kg/m**3')
        indep_var_comp.add_output('CT', val=grav_constant * 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('speed_of_sound', val=295.4, units='m/s')
        indep_var_comp.add_output('load_factor', val=[1., 2.5])
        indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m')

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

        # Add morphing variables as an independent variables component
        morphing_vars = IndepVarComp()
        morphing_vars.add_output('t_over_c_cp', val=np.array([0.15]))
        morphing_vars.add_output('thickness_cp', val=np.array([0.01, 0.01, 0.01]), units='m')
        morphing_vars.add_output('twist_cp_0', val=np.array([2., 3., 4., 4., 4.]), units='deg')
        morphing_vars.add_output('twist_cp_1', val=np.array([4., 4., 4., 5., 6.]), units='deg')

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

        # Connect geometric design variables to each point
        prob.model.connect('t_over_c_cp', 'AS_point_0.wing.geometry.t_over_c_cp')
        prob.model.connect('t_over_c_cp', 'AS_point_1.wing.geometry.t_over_c_cp')

        prob.model.connect('thickness_cp', 'AS_point_0.wing.tube_group.thickness_cp')
        prob.model.connect('thickness_cp', 'AS_point_1.wing.tube_group.thickness_cp')

        prob.model.connect('twist_cp_0', 'AS_point_0.wing.geometry.twist_cp')
        prob.model.connect('twist_cp_1', 'AS_point_1.wing.geometry.twist_cp')

        for point in range(2):

            name = 'wing'

            point_name = 'AS_point_{}'.format(point)

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

            prob.model.add_subsystem(point_name, AS_point)

            aerostruct_group = AerostructGeometry(surface=surface, connect_geom_DVs=False)
            AS_point.add_subsystem(name, aerostruct_group)

            # Connect flow properties to the analysis point
            prob.model.connect('alpha', point_name + '.alpha', src_indices=[point])
            prob.model.connect('v', point_name + '.v', src_indices=[point])
            prob.model.connect('Mach_number', point_name + '.Mach_number', src_indices=[point])
            prob.model.connect('re', point_name + '.re', src_indices=[point])
            prob.model.connect('rho', point_name + '.rho', src_indices=[point])
            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', src_indices=[point])

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

            # Connect aerodyamic mesh to coupled group mesh
            AS_point.connect(name + '.mesh', 'coupled.' + name + '.mesh')

            # Connect performance calculation variables
            AS_point.connect(name + '.radius', name + '_perf' + '.radius')
            AS_point.connect(name + '.thickness', name + '_perf' + '.thickness')
            AS_point.connect(name + '.nodes', name + '_perf' + '.nodes')
            AS_point.connect(name + '.cg_location', 'total_perf.' + name + '_cg_location')
            AS_point.connect(name + '.structural_mass', 'total_perf.' + name + '_structural_mass')
            AS_point.connect(name + '.geometry.t_over_c', name + '_perf' + '.t_over_c')
            AS_point.connect(name + '.geometry.t_over_c', name + '.t_over_c')

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

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

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('twist_cp_0', lower=-10., upper=15.)
        prob.model.add_design_var('twist_cp_1', lower=-10., upper=15.)
        prob.model.add_design_var('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.)
        prob.model.add_constraint('AS_point_1.wing_perf.failure', upper=0.)
        prob.model.add_constraint('AS_point_1.wing_perf.thickness_intersects', upper=0.)

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

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

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

        prob.run_model()

        # Check the partials at the initial point in the design space,
        # only care about relative error
        data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40)

        assert_check_partials(data, atol=1e20, rtol=1e-6)

        # Run the optimizer for 2 iterations
        prob.run_driver()

        # Check the partials at this point in the design space
        data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40)
        assert_check_partials(data, atol=1e20, rtol=1e-6)
    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.ones((2)) * .1,
                    'twist_cp' : np.ones((2)),

                    'mesh' : mesh,

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

                # 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], 70754.19144483653, 1e-5)
예제 #24
0
    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_weight', 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_weight'], 163866.96531213,
                         1e-6)
    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', units='kg')
        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)
예제 #26
0
    def test(self):
        """
        This is an opt problem that tests the wingbox model with wave drag and the fuel vol constraint
        """

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

        mesh, twist_cp = generate_mesh(mesh_dict)

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

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

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

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

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

                    # Structural values are based on aluminum 7075
                    'E' : 73.1e9,              # [Pa] Young's modulus
                    'G' : (73.1e9/2/1.33),     # [Pa] shear modulus (calculated using E and the Poisson's ratio here)
                    'yield' : (420.e6 / 1.5),  # [Pa] allowable yield stress
                    'mrho' : 2.78e3,           # [kg/m^3] material density
                    'strength_factor_for_upper_skin' : 1.0, # the yield stress is multiplied by this factor for the upper skin
                    # 'fem_origin' : 0.35,    # normalized chordwise location of the spar
                    'wing_weight_ratio' : 1.25,
                    'struct_weight_relief' : True,
                    'distributed_fuel_weight' : True,
                    # 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=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 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(2):

            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, 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')
            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', 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:

                if i==0:
                    prob.model.connect('load_factor', name + '.load_factor', src_indices=[i])
                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')
                prob.model.connect(name + '.element_weights', point_name + '.coupled.' + name + '.element_weights')

                # 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_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight')

                # 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('wing.struct_setup.fuel_vols', 'fuel_vol_delta.fuel_vols')

        prob.model.connect('AS_point_0.fuelburn', 'fuel_vol_delta.fuelburn')
        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')

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

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

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

        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.)
        prob.model.add_constraint('fuel_diff', equals=0.)
        prob.model.add_constraint('fuel_diff_25', equals=0.)
        #=======================================================================================
        #=======================================================================================

        # Set up the problem
        prob.setup()

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

        prob.run_model()

        # Check the partials at the initial point in the design space,
        # only care about relative error
        data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40)
        assert_check_partials(data, atol=1e20, rtol=1e-6)

        # Run the optimizer for 5 iterations
        prob.run_driver()

        # Check the partials at this point in the design space
        data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40)
        assert_check_partials(data, atol=1e20, rtol=1e-6)
예제 #27
0
    def test(self):

        import numpy as np

        from openaerostruct.geometry.utils import generate_mesh
        from openaerostruct.geometry.geometry_group import Geometry
        from openaerostruct.transfer.displacement_transfer import DisplacementTransfer
        from openaerostruct.structures.struct_groups import SpatialBeamAlone

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

        # Create a dictionary to store options about the surface
        mesh_dict = {'num_y' : 7,
                     '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
                    'symmetry' : True,     # if true, model one half of wing
                                            # reflected across the plane y = 0
                    'fem_model_type' : 'tube',

                    'mesh' : mesh,

                    # 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)) * .1,
                    'wing_weight_ratio' : 2.,
                    'struct_weight_relief' : False,    # True to add the weight of the structure to the loads on the structure
                    'distributed_fuel_weight' : False,
                    'exact_failure_constraint' : False,
                    }

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

        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
        prob.driver.options['tol'] = 1e-9

        recorder = SqliteRecorder('struct.db')
        prob.driver.add_recorder(recorder)
        prob.driver.recording_options['record_derivatives'] = True
        prob.driver.recording_options['includes'] = ['*']

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.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()
        # prob.check_partials(compact_print=False, method='fd')
        # exit()
        prob.run_driver()

        assert_rel_error(self, prob['wing.structural_mass'][0], 71088.4682399, 1e-8)
예제 #28
0
    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': 6,
            'chord_cos_spacing': 0,
            'span_cos_spacing': 0,
        }

        mesh, twist_cp = generate_mesh(mesh_dict)

        surf_dict = {
            # Wing definition
            'name':
            'wing',  # name of the surface
            'symmetry':
            True,  # if true, model one half of wing
            # reflected across the plane y = 0
            'S_ref_type':
            'wetted',  # how we compute the wing area,
            # can be 'wetted' or 'projected'
            'fem_model_type':
            'wingbox',
            'spar_thickness_cp':
            np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]),  # [m]
            'skin_thickness_cp':
            np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]),
            'twist_cp':
            np.array([4., 5., 8., 8., 8., 9.]),
            'mesh':
            mesh,
            'data_x_upper':
            upper_x,
            'data_x_lower':
            lower_x,
            'data_y_upper':
            upper_y,
            'data_y_lower':
            lower_y,
            'strength_factor_for_upper_skin':
            1.,

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

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

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

        surfaces = [surf_dict]

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

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

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

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

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

            aerostruct_group = AerostructGeometry(surface=surface)

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

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

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

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

            prob.model.add_subsystem(point_name, AS_point)

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

            for surface in surfaces:

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

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

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

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

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

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

        # Set up the problem
        prob.setup()
        #
        # om.view_model(prob)

        prob.run_model()

        # prob.model.list_outputs(values=True,
        #                         implicit=False,
        #                         units=True,
        #                         shape=True,
        #                         bounds=True,
        #                         residuals=True,
        #                         scaling=True,
        #                         hierarchical=False,
        #                         print_arrays=True)

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

        assert_rel_error(self, prob['AS_point_0.fuelburn'][0],
                         89411.50246542075, 1e-5)
        assert_rel_error(self, prob['wing.structural_mass'][0] / 1.25,
                         24009.5230566, 1e-5)
        assert_rel_error(self, prob['AS_point_0.wing_perf.failure'][0],
                         1.6254327137382174, 1e-5)
    def test(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {'num_y' : 7,
                     '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
                    'symmetry' : True,     # if true, model one half of wing
                                            # reflected across the plane y = 0
                    'fem_model_type' : 'tube',

                    'mesh' : mesh,

                    # 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)) * .1,
                    'wing_weight_ratio' : 2.,
                    'struct_weight_relief' : False,    # True to add the weight of the structure to the loads on the structure
                    'distributed_fuel_weight' : False,
                    'exact_failure_constraint' : False,
                    }

        # 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.zeros((ny, 6)), 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()

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, 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_mass', scaler=1e-5)

        # Set up the problem
        prob.setup()

        from openmdao.api import view_model

        prob.run_driver()

        assert_rel_error(self, prob['wing.structural_mass'][0], 13601.162582, 1e-4)
        assert_rel_error(self, prob['wing.disp'][1, 2], 0., 1e-4)
예제 #30
0
num_y = 21
num_x = 3

# Create a mesh dictionary to feed to generate_mesh to actually create
# the mesh array.
mesh_dict = {
    'num_y': num_y,
    'num_x': num_x,
    'wing_type': 'rect',
    'symmetry': True,
    'span_cos_spacing': 0.5,
    'span': 3.11,
    'root_chord': 0.3,
}

mesh = generate_mesh(mesh_dict)

# Apply camber to the mesh
camber = 1 - np.linspace(-1, 1, num_x)**2
camber *= 0.3 * 0.05

for ind_x in range(num_x):
    mesh[ind_x, :, 2] = camber[ind_x]

# Introduce geometry manipulation variables to define the ScanEagle shape
zshear_cp = np.zeros(10)
zshear_cp[0] = .3

xshear_cp = np.zeros(10)
xshear_cp[0] = .15
예제 #31
0
    def test_derivs_wetted(self):
        # This is a much richer test with the following attributes:
        # - 5x7 mesh so that each dimension of all variables is unique.
        # - Random values given as inputs.
        # - The mesh has been given a random z height at all points.
        # - S_ref_type option is "wetted"
        # Create a dictionary to store options about the mesh
        mesh_dict = {'num_y' : 7,
                     'num_x' : 5,
                     'wing_type' : 'CRM',
                     'symmetry' : True,
                     'num_twist_cp' : 5}

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

        mesh[:, :, 2] = np.random.random(mesh[:, :, 2].shape)

        # Create a dictionary with info and options about the aerodynamic
        # lifting surface
        surface = {
                    # 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' : twist_cp,
                    'mesh' : mesh,

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

        #surfaces = get_default_surfaces()
        surfaces = [surface]

        prob = Problem()
        group = prob.model

        comp = VLMGeometry(surface=surfaces[0])

        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('def_mesh', val=surfaces[0]['mesh'], units='m')

        group.add_subsystem('geom', comp)
        group.add_subsystem('indep_var_comp', indep_var_comp)

        group.connect('indep_var_comp.def_mesh', 'geom.def_mesh')

        prob.setup()

        prob['geom.def_mesh'] = np.random.random(prob['geom.def_mesh'].shape)

        prob.run_model()

        check = prob.check_partials(compact_print=True)
        assert_check_partials(check, atol=3e-5, rtol=1e-5)
예제 #32
0
    def test(self):

        from openaerostruct.geometry.utils import generate_mesh, write_FFD_file
        from openaerostruct.geometry.geometry_group import Geometry
        from openaerostruct.transfer.displacement_transfer import DisplacementTransfer

        from openaerostruct.aerodynamics.aero_groups import AeroPoint

        from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, DirectSolver, LinearBlockGS, PetscKSP, ScipyOptimizeDriver# TODO, SqliteRecorder, CaseReader, profile
        from openmdao.devtools import iprofile
        from openmdao.api import view_model
        from six import iteritems
        from pygeo import DVGeometry

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

                    'DVGeo' : True,
                    'mesh' : mesh,
                    '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' : 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
                    }

        surf_dict['num_x'], surf_dict['num_y'] = surf_dict['mesh'].shape[:2]

        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=6.64)
        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:

            filename = write_FFD_file(surface, surface['mx'], surface['my'])
            DVGeo = DVGeometry(filename)
            geom_group = Geometry(surface=surface, DVGeo=DVGeo)

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

        from openmdao.api import pyOptSparseDriver
        prob.driver = pyOptSparseDriver()
        prob.driver.options['optimizer'] = "SNOPT"
        prob.driver.opt_settings = {'Major optimality tolerance': 1.0e-6,
                                    'Major feasibility tolerance': 1.0e-6}

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

        # prob.model.add_constraint('wing.shape', equals=0., indices=range(surf_dict['my'] * 2), linear=True)
        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()

        # view_model(prob, outfile='aero.html', show_browser=False)

        # prob.run_model()
        prob.run_driver()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03398038, 1e-6)
        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.18379626783513864, 1e-5)
    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
        from openaerostruct.common.atmos_group import AtmosGroup

        # Create a dictionary to store options about the mesh
        mesh_dict = {'num_y' : 7,
                     'num_x' : 2,
                     'wing_type' : 'CRM',
                     'symmetry' : True,
                     '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
                    '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' : 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('alpha', val=5., units='deg')
        indep_var_comp.add_output('Mach_number', val=0.84)
        indep_var_comp.add_output('altitude', val=35000., units='ft')

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

        # Add this IndepVarComp to the problem model
        prob.model.add_subsystem('atmos',
            AtmosGroup(),
            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', 'Mach_number', '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.check_partials(compact_print=True)
        # exit()
        prob.run_driver()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.030471796067577953, 1e-6)
        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], -1.7331840488188963, 1e-6)
예제 #34
0
    def test(self):

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

        mesh, twist_cp = generate_mesh(mesh_dict)

        surf_dict = {
            # Wing definition
            'name': 'wing',  # name of the surface
            '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'
            '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.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.10, 0.15,
                      0.2]),  # 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': True,  # if true, compute wave drag
        }

        surfaces = [surf_dict]

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

        indep_var_comp = om.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('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=['*'])

        # 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('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:

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

        recorder = om.SqliteRecorder("aero_analysis_no_sym_wavedrag.db")
        prob.driver.add_recorder(recorder)
        prob.driver.recording_options['record_derivatives'] = True
        prob.driver.recording_options['includes'] = ['*']

        # Set up the problem
        prob.setup()

        prob.run_driver()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0],
                         0.464191542231, 1e-6)
        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0],
                         0.0222413119687, 1e-6)
        assert_rel_error(self, prob['aero_point_0.CM'][1], -1.5717101821556665,
                         1e-6)
    def test(self):

        from openaerostruct.geometry.utils import generate_mesh, write_FFD_file
        from openaerostruct.geometry.geometry_group import Geometry
        from openaerostruct.transfer.displacement_transfer import DisplacementTransfer

        from openaerostruct.aerodynamics.aero_groups import AeroPoint
        from openaerostruct.integration.multipoint_comps import MultiCD

        from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, DirectSolver, LinearBlockGS, PetscKSP, ScipyOptimizeDriver, ExplicitComponent# TODO, SqliteRecorder, CaseReader, profile
        from openmdao.devtools import iprofile
        from openmdao.api import view_model
        from openmdao.utils.assert_utils import assert_check_partials
        from pygeo import DVGeometry

        # 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, _ = 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',

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

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

        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=np.ones(n_points)*6.64, 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 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', src_indices=[i])
            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:

                filename = write_FFD_file(surface, surface['mx'], surface['my'])
                DVGeo = DVGeometry(filename)
                geom_group = Geometry(surface=surface, DVGeo=DVGeo)

                # 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.add_subsystem('multi_CD', MultiCD(n_points=n_points), promotes_outputs=['CD'])

        from openmdao.api import pyOptSparseDriver
        prob.driver = pyOptSparseDriver()
        prob.driver.options['optimizer'] = "SNOPT"
        prob.driver.opt_settings = {'Major optimality tolerance': 1.0e-5,
                                    'Major feasibility tolerance': 1.0e-5}

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

        prob.model.add_design_var('aero_point_0.wing_geom.shape', lower=-3, upper=2)
        prob.model.add_constraint('aero_point_0.wing_perf.CL', equals=0.45)

        prob.model.add_design_var('aero_point_1.wing_geom.shape', lower=-3, upper=2)
        prob.model.add_constraint('aero_point_1.wing_perf.CL', equals=0.5)

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

        # Set up the problem
        prob.setup()

        prob.run_model()

        # Check the partials at this point in the design space
        data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40)
        assert_check_partials(data, atol=1e20, rtol=1e-6)
예제 #36
0
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': True,
    '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': 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': twist_cp,
    'mesh': mesh,
    'num_x': mesh.shape[0],
예제 #37
0
    def test(self):
        import numpy as np

        from openaerostruct.geometry.utils import generate_mesh

        from openaerostruct.integration.aerostruct_groups import AerostructGeometry, 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,

                    # 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
                    'distributed_fuel_weight' : False,
                    # 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., 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=['*'])

        aerostruct_group = AerostructGeometry(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')
        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')

        # 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

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

        # 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)
예제 #38
0
    def test_multiple_masses(self):

        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 31,
            'wing_type': 'rect',
            'span': 10,
            'symmetry': True
        }

        mesh = generate_mesh(mesh_dict)

        surface = {
            # Wing definition
            'name': 'wing',  # name of the surface
            'symmetry': True,  # if true, model one half of wing
            # reflected across the plane y = 0
            'fem_model_type': 'tube',
            'mesh': mesh,

            # 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.5,  # normalized chordwise location of the spar
            't_over_c_cp': np.array([0.15]),  # maximum airfoil thickness
            'thickness_cp': np.ones((3)) * .1,
            'wing_weight_ratio': 2.,
            'struct_weight_relief':
            False,  # True to add the weight of the structure to the loads on the structure
            'distributed_fuel_weight': False,
            'exact_failure_constraint': False,
        }

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

        ny = surface['mesh'].shape[1]
        surface['n_point_masses'] = 2

        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('loads', val=np.zeros((ny, 6)), units='N')
        indep_var_comp.add_output('load_factor', val=1.)

        engine_thrusts = np.array([[10., 20.]])

        point_mass_locations = np.array([[1., -1., 0.], [1., -2., 0.]])

        indep_var_comp.add_output('engine_thrusts',
                                  val=engine_thrusts,
                                  units='N')
        indep_var_comp.add_output('point_mass_locations',
                                  val=point_mass_locations,
                                  units='m')

        struct_group = SpatialBeamAlone(surface=surface)

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

        prob.model.add_subsystem(surface['name'], struct_group, promotes=['*'])

        # Set up the problem
        prob.setup()

        prob.run_model()

        assert_rel_error(self, prob['vonmises'][-1, 0], 137509.870021, 1e-4)
예제 #39
0
    fig.savefig('drag_polar.pdf')
    #plt.show()

    return CLs, CDs, CMs


if __name__=='__main__':
    # Create a dictionary to store options about the mesh
    mesh_dict = {'num_y' : 7,
                'num_x' : 2,
                'wing_type' : 'CRM',
                'symmetry' : True,
                '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 wing
    wing_surface = {
                # 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' : twist_cp,
                'mesh' : mesh,
                # Aerodynamic performance of the lifting surface at
                # an angle of attack of 0 (alpha=0).
예제 #40
0
def get_default_surfaces():
    # Create a dictionary to store options about the mesh
    mesh_dict = {
        'num_y': 7,
        'num_x': 2,
        'wing_type': 'CRM',
        'symmetry': True,
        'num_twist_cp': 5
    }

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

    wing_dict = {
        'name': 'wing',
        'num_y': 4,
        'num_x': 2,
        'symmetry': True,
        'S_ref_type': 'wetted',
        'CL0': 0.1,
        'CD0': 0.1,
        'mesh': mesh,

        # 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, computes wave drag
        'fem_model_type': 'tube',

        # 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
        'distributed_fuel_weight':
        False,  # True to add the weight of the structure to the loads on the structure
        'Wf_reserve': 10000.,
    }

    # Create a dictionary to store options about the mesh
    mesh_dict = {
        'num_y': 5,
        'num_x': 3,
        'wing_type': 'rect',
        'symmetry': False
    }

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

    tail_dict = {
        'name': 'tail',
        'num_y': 5,
        'num_x': 3,
        'symmetry': False,
        'mesh': mesh
    }

    surfaces = [wing_dict, tail_dict]

    return surfaces
    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
                    '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,

                    # 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('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=['*'])

        # 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('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:

                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)
    def test(self):
        # 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
                    '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,
                    'n_point_masses' : 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
                    'distributed_fuel_weight' : False,
                    # Constraints
                    'exact_failure_constraint' : False, # if false, use KS function
                    }

        surfaces = [surf_dict]

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

        # Add problem information as an independent variables component
        indep_var_comp = om.IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=5., 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('CT', val=grav_constant * 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('speed_of_sound', 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')

        point_masses = np.array([[8000.]])

        point_mass_locations = np.array([[25, -10., 0.]])

        indep_var_comp.add_output('point_masses', val=point_masses, units='kg')
        indep_var_comp.add_output('point_mass_locations', val=point_mass_locations, 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')
            prob.model.connect('load_factor', point_name + '.coupled.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')

                # 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_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass')
                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')

        # Set up the problem
        prob.setup()

        prob.run_model()

        assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 267518.2837095164, 1e-4)
        assert_rel_error(self, prob['AS_point_0.CM'][1], -0.58977996718612, 1e-5)
    def test(self):

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

        mesh, twist_cp = generate_mesh(mesh_dict)

        surf_dict = {
                    # 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'

                    '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.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.10, 0.15, 0.2]),      # 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' : True,     # 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')

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

        # Set up the problem
        prob.setup()

        prob.run_driver()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.464191542231, 1e-6)
        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.0222413119687, 1e-6)
        assert_rel_error(self, prob['aero_point_0.CM'][1], -0.1603034566404, 1e-6)
예제 #44
0
    def setup(self):
        # Total number of nodes to use in the spanwise (num_y) and
        # chordwise (num_x) directions. Vary these to change the level of fidelity.

        mesh_dict = self.options['mesh_dict']
        num_y = mesh_dict['num_y']
        num_x = mesh_dict['num_x']

        mesh = generate_mesh(mesh_dict)

        # Apply camber to the mesh
        camber = 1 - np.linspace(-1, 1, num_x)**2
        camber *= 0.3 * 0.05

        for ind_x in range(num_x):
            mesh[ind_x, :, 2] = camber[ind_x]

        # Introduce geometry manipulation variables to define the ScanEagle shape
        zshear_cp = np.zeros(10)
        zshear_cp[0] = .3

        xshear_cp = np.zeros(10)
        xshear_cp[0] = .15

        chord_cp = np.ones(10)
        chord_cp[0] = .5
        chord_cp[-1] = 1.5
        chord_cp[-2] = 1.3

        radius_cp = 0.01 * np.ones(10)

        # Define wing parameters
        surface = {
            # 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',
            'taper': 0.8,
            'zshear_cp': zshear_cp,
            'xshear_cp': xshear_cp,
            'chord_cp': chord_cp,
            'sweep': 20.,
            'twist_cp': np.array([2.5, 2.5, 5.]),  #np.zeros((3)),
            'thickness_cp': np.ones((3)) * .008,

            # Give OAS the radius and mesh from before
            'radius_cp': radius_cp,
            'mesh': mesh,

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

            # Material properties taken from http://www.performance-composites.com/carbonfibre/mechanicalproperties_2.asp
            'yield': 350.e6,
            'fem_origin': 0.35,  # normalized chordwise location of the spar
            'wing_weight_ratio':
            1.,  # multiplicative factor on the computed structural weight
            'struct_weight_relief':
            True,  # True to add the weight of the structure to the loads on the structure
            'distributed_fuel_weight': False,
            # Constraints
            'exact_failure_constraint': False,  # if false, use KS function
        }

        # Add problem information as an independent variables component
        indep_var_comp = IndepVarComp()
        # indep_var_comp.add_output('v', val=22.876, units='m/s')
        indep_var_comp.add_output('alpha', val=5., units='deg')
        indep_var_comp.add_output('altitude', val=4.57e3, units='m')
        # indep_var_comp.add_output('re', val=1.e6, units='1/m')
        # indep_var_comp.add_output('rho', val=0.770816, units='kg/m**3')
        indep_var_comp.add_output('R', val=1800e3, units='m')
        # indep_var_comp.add_output('speed_of_sound', val=322.2, units='m/s')
        indep_var_comp.add_output('load_factor', val=1.)
        indep_var_comp.add_output('empty_cg',
                                  val=np.array([0.2, 0., 0.]),
                                  units='m')

        # indep_var_comp.add_output('Mach_number', val=mean_val_dict['mean_Ma'])
        # indep_var_comp.add_output('CT', val=mean_val_dict['mean_TSFC'], units='1/s')
        # indep_var_comp.add_output('W0', val=mean_val_dict['mean_W0'],  units='kg')
        # indep_var_comp.add_output('E', val=mean_val_dict['mean_E'], units='N/m**2')
        # indep_var_comp.add_output('G', val=mean_val_dict['mean_G'], units='N/m**2')
        # indep_var_comp.add_output('mrho', val=mean_val_dict['mean_mrho'], units='kg/m**3')

        self.add_subsystem('prob_vars', indep_var_comp, promotes=['*'])
        # Add atmosphere related properties
        self.add_subsystem('atmos', AtmosGroup(), promotes=['*'])

        # Add the AerostructGeometry group, which computes all the intermediary
        # parameters for the aero and structural analyses, like the structural
        # stiffness matrix and some aerodynamic geometry arrays
        aerostruct_group = AerostructGeometry(surface=surface)

        name = 'wing'

        # Add the group to the problem
        self.add_subsystem(name,
                           aerostruct_group,
                           promotes_inputs=['load_factor'])

        point_name = 'AS_point_0'

        # Create the aerostruct point group and add it to the model.
        # This contains all the actual aerostructural analyses.
        AS_point = AerostructPoint(surfaces=[surface])

        self.add_subsystem(point_name,
                           AS_point,
                           promotes_inputs=[
                               'v', 'alpha', 'Mach_number', 're', 'rho', 'CT',
                               'R', 'W0', 'speed_of_sound', 'empty_cg',
                               'load_factor'
                           ])

        # Issue quite a few connections within the model to make sure all of the
        # parameters are connected correctly.
        com_name = point_name + '.' + name + '_perf'
        self.connect(
            name + '.local_stiff_transformed',
            point_name + '.coupled.' + name + '.local_stiff_transformed')
        self.connect(name + '.nodes',
                     point_name + '.coupled.' + name + '.nodes')

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

        # Connect performance calculation variables
        self.connect(name + '.radius', com_name + '.radius')
        self.connect(name + '.thickness', com_name + '.thickness')
        self.connect(name + '.nodes', com_name + '.nodes')
        self.connect(name + '.cg_location',
                     point_name + '.' + 'total_perf.' + name + '_cg_location')
        self.connect(
            name + '.structural_weight',
            point_name + '.' + 'total_perf.' + name + '_structural_weight')
        self.connect(name + '.t_over_c', com_name + '.t_over_c')