Пример #1
0
    def solve_nonlinear(self, params, unknowns, resids):
        mesh = self.mesh.copy()
        self.geo_params.update(params)

        if fortran_flag:
            mesh = OAS_API.oas_api.manipulate_mesh(mesh,
            self.geo_params['taper'], self.geo_params['chord'],
            self.geo_params['sweep'], self.geo_params['xshear'],
            self.geo_params['span'], self.geo_params['yshear'],
            self.geo_params['dihedral'], self.geo_params['zshear'],
            self.geo_params['twist'], self.symmetry, self.rotate_x)

        else:
            taper(mesh, self.geo_params['taper'], self.symmetry)
            scale_x(mesh, self.geo_params['chord'])
            sweep(mesh, self.geo_params['sweep'], self.symmetry)
            shear_x(mesh, self.geo_params['xshear'])
            stretch(mesh, self.geo_params['span'], self.symmetry)
            shear_y(mesh, self.geo_params['yshear'])
            dihedral(mesh, self.geo_params['dihedral'], self.symmetry)
            shear_z(mesh, self.geo_params['zshear'])
            rotate(mesh, self.geo_params['twist'], self.symmetry, self.rotate_x)

        # Only compute the radius on the first iteration.
        if self.compute_radius and 'radius_cp' not in self.desvar_names:
            # Get spar radii and interpolate to radius control points.
            # Need to refactor this at some point.
            unknowns['radius'] = radii(mesh, self.surface['t_over_c'])
            self.compute_radius = False

        unknowns['mesh'] = mesh
Пример #2
0
    def solve_nonlinear(self, params, unknowns, resids):
        mesh = self.mesh.copy()
        self.geo_params.update(params)

        if fortran_flag:
            mesh = OAS_API.oas_api.manipulate_mesh(mesh, self.geo_params['taper'],
                self.geo_params['chord'], self.geo_params['sweep'], self.geo_params['xshear'],
                self.geo_params['dihedral'], self.geo_params['zshear'],
                self.geo_params['twist'], self.geo_params['span'], self.symmetry, self.rotate_x)

        else:
            taper(mesh, self.geo_params['taper'], self.symmetry)
            scale_x(mesh, self.geo_params['chord'])
            stretch(mesh, self.geo_params['span'], self.symmetry)
            sweep(mesh, self.geo_params['sweep'], self.symmetry)
            shear_x(mesh, self.geo_params['xshear'])
            dihedral(mesh, self.geo_params['dihedral'], self.symmetry)
            shear_z(mesh, self.geo_params['zshear'])
            rotate(mesh, self.geo_params['twist'], self.symmetry, self.rotate_x)

        # Only compute the radius on the first iteration.
        if self.compute_radius and 'radius_cp' not in self.desvar_names:
            # Get spar radii and interpolate to radius control points.
            # Need to refactor this at some point.
            unknowns['radius'] = radii(mesh, self.surface['t_over_c'])
            self.compute_radius = False

        unknowns['mesh'] = mesh
Пример #3
0
    OAS_prob.add_surface(surface)

    # Get the finalized surface, which includes the created mesh object.
    # Here, `surface` is a dictionary that contains information relevant to
    # one surface within the analysis or optimization.
    surface = OAS_prob.surfaces[0]

    # If you want to view the information contained within `surface`,
    # uncomment the following line of code.
    # pp(surface)

    # Obtain the number of spanwise node points from the defined surface.
    num_y = surface['num_y']

    # Create an array of radii for the spar elements.
    r = radii(surface['mesh'])

    # Obtain the starting thickness for each of the spar elements based
    # on the radii.
    thickness = r / 5

    # Define the loads here. Choose either a tip load or distributed load
    # by commenting the lines as necessary.
    loads = numpy.zeros((num_y, 6))
    P = 1e4  # load of 10 kN
    # loads[0, 2] = P  # tip load
    loads[1:, 2] = P / (num_y - 1)  # load distributed across all nodes

    # Instantiate the OpenMDAO group for the root problem.
    root = Group()
Пример #4
0
def setup(num_inboard=2, num_outboard=3, check=False, out_stream=sys.stdout):
    ''' Setup the aerostruct mesh using OpenMDAO'''

    # Define the aircraft properties
    from CRM import span, v, alpha, rho

    # Define spatialbeam properties
    from aluminum import E, G, stress, mrho

    # Create the mesh with 2 inboard points and 3 outboard points.
    # This will be mirrored to produce a mesh with 7 spanwise points,
    # or 6 spanwise panels
    # print(type(num_inboard))
    mesh = gen_crm_mesh(int(num_inboard), int(num_outboard), num_x=2)
    num_x, num_y = mesh.shape[:2]
    num_twist = np.max([int((num_y - 1) / 5), 5])
    r = radii(mesh)

    # Set the number of thickness control points and the initial thicknesses
    num_thickness = num_twist
    t = r / 10

    mesh = mesh.reshape(-1, mesh.shape[-1])
    aero_ind = np.atleast_2d(np.array([num_x, num_y]))
    fem_ind = [num_y]
    aero_ind, fem_ind = get_inds(aero_ind, fem_ind)

    # Set additional mesh parameters
    dihedral = 0.  # dihedral angle in degrees
    sweep = 0.  # shearing sweep angle in degrees
    taper = 1.  # taper ratio

    # Initial displacements of zero
    tot_n_fem = np.sum(fem_ind[:, 0])
    disp = np.zeros((tot_n_fem, 6))

    # Define Jacobians for b-spline controls
    tot_n_fem = np.sum(fem_ind[:, 0])
    num_surf = fem_ind.shape[0]
    jac_twist = get_bspline_mtx(num_twist, num_y)
    jac_thickness = get_bspline_mtx(num_thickness, tot_n_fem-num_surf)

    # Define ...
    twist_cp = np.zeros(num_twist)
    thickness_cp = np.ones(num_thickness)*np.max(t)

    # Define the design variables
    des_vars = [
        ('twist_cp', twist_cp),
        ('dihedral', dihedral),
        ('sweep', sweep),
        ('span', span),
        ('taper', taper),
        ('v', v),
        ('alpha', alpha),
        ('rho', rho),
        ('disp', disp),
        ('aero_ind', aero_ind),
        ('fem_ind', fem_ind)
    ]

    root = Group()

    root.add('des_vars',
         IndepVarComp(des_vars),
         promotes=['twist_cp','span','v','alpha','rho','disp','dihedral'])
    root.add('mesh',  # This component is needed, otherwise resulting loads matrix is NaN
         GeometryMesh(mesh, aero_ind), # changes mesh given span, sweep, twist, and des_vars
         promotes=['span','sweep','dihedral','twist','taper','mesh'])
    root.add('def_mesh',
         TransferDisplacements(aero_ind, fem_ind),
         promotes=['mesh','disp','def_mesh'])

    prob = Problem()
    prob.root = root
    prob.setup(check=check, out_stream=out_stream)
    prob.run()

    # Output the def_mesh for the aero modules
    def_mesh = prob['def_mesh']

    # Other variables needed for aero and struct modules
    params = {
        'mesh': mesh,
        'num_x': num_x,
        'num_y': num_y,
        'span': span,
        'twist_cp': twist_cp,
        'thickness_cp': thickness_cp,
        'v': v,
        'alpha': alpha,
        'rho': rho,
        'r': r,
        't': t,
        'aero_ind': aero_ind,
        'fem_ind': fem_ind,
        'num_thickness': num_thickness,
        'num_twist': num_twist,
        'sweep': sweep,
        'taper': taper,
        'dihedral': dihedral,
        'E': E,
        'G': G,
        'stress': stress,
        'mrho': mrho,
        'tot_n_fem': tot_n_fem,
        'num_surf': num_surf,
        'jac_twist': jac_twist,
        'jac_thickness': jac_thickness,
        'out_stream': out_stream,
        'check': check
    }

    return (def_mesh, params)
Пример #5
0
    def add_surface(self, input_dict={}):
        """
        Add a surface to the problem. One surface definition is needed for
        each planar lifting surface.

        Parameters
        ----------
        input_dict : dictionary
            Surface definition. Note that there are default values defined by
            `get_default_surf_dict` that are overwritten based on the
            user-provided input_dict.
        """

        # Get defaults and update surf_dict with the user-provided input
        surf_dict = self.get_default_surf_dict()
        surf_dict.update(input_dict)

        # Check to see if the user provides the mesh points. If they do,
        # get the chordwise and spanwise number of points
        if 'mesh' in surf_dict.keys():
            mesh = surf_dict['mesh']
            num_x, num_y = mesh.shape

        # If the user doesn't provide a mesh, obtain the values from surf_dict
        # to create the mesh
        elif 'num_x' in surf_dict.keys():
            num_x = surf_dict['num_x']
            num_y = surf_dict['num_y']
            span = surf_dict['span']
            chord = surf_dict['chord']
            span_cos_spacing = surf_dict['span_cos_spacing']
            chord_cos_spacing = surf_dict['chord_cos_spacing']

            # Check to make sure that an odd number of spanwise points (num_y) was provided
            if not num_y % 2:
                Error('num_y must be an odd number.')

            # Generate rectangular mesh
            if surf_dict['wing_type'] == 'rect':
                mesh = gen_rect_mesh(num_x, num_y, span, chord,
                                     span_cos_spacing, chord_cos_spacing)

            # Generate CRM mesh
            elif surf_dict['wing_type'] == 'CRM':
                npi = int(numpy.ceil(((num_y - 1) / 2) * .4))
                npo = (num_y - 1) // 2 + 2 - npi
                mesh = gen_crm_mesh(n_points_inboard=npi,
                                    n_points_outboard=npo,
                                    num_x=num_x)
                num_x, num_y = mesh.shape[:2]

            else:
                Error(
                    'wing_type option not understood. Must be either "CRM" or "rect".'
                )

            # Chop the mesh in half if using symmetry during analysis.
            # Note that this means that the provided mesh should be the full mesh
            if surf_dict['symmetry']:
                num_y = int((num_y + 1) / 2)
                mesh = mesh[:, :num_y, :]

        else:
            Error("Please either provide a mesh or a valid set of parameters.")

        # Apply the user-provided coordinate offset to position the mesh
        mesh = mesh + surf_dict['offset']

        # Get the spar radius
        r = radii(mesh)

        # Set the number of twist and thickness control points.
        # These b-spline control points are what the optimizer sees
        # and controls
        if 'num_twist' not in input_dict.keys():
            surf_dict['num_twist'] = numpy.max([int((num_y - 1) / 5), 5])
        if 'num_thickness' not in input_dict.keys():
            surf_dict['num_thickness'] = numpy.max([int((num_y - 1) / 5), 5])

        # Store updated values
        surf_dict['num_x'] = num_x
        surf_dict['num_y'] = num_y
        surf_dict['mesh'] = mesh
        surf_dict['r'] = r
        surf_dict['t'] = r / 10

        # Set default loads at the tips
        loads = numpy.zeros((r.shape[0] + 1, 6), dtype='complex')
        loads[0, 2] = 1e3
        if not surf_dict['symmetry']:
            loads[-1, 2] = 1e3
        surf_dict['loads'] = loads

        # Throw a warning if the user provides two surfaces with the same name
        name = surf_dict['name']
        for surface in self.surfaces:
            if name == surface['name']:
                print("Warning: Two surfaces have the same name.")

        # Append '_' to each repeated surface name
        if not name:
            surf_dict['name'] = name
        else:
            surf_dict['name'] = name + '_'

        # Add the individual surface description to the surface list
        self.surfaces.append(surf_dict)
Пример #6
0
from transfer import TransferDisplacements, TransferLoads
from vlm import VLMStates, VLMFunctionals
from spatialbeam import SpatialBeamStates, SpatialBeamFunctionals, radii
from materials import MaterialsTube
from functionals import FunctionalBreguetRange, FunctionalEquilibrium

from openmdao.devtools.partition_tree_n2 import view_tree
from gs_newton import HybridGSNewton

############################################################
# Change mesh size here
############################################################
# Create the mesh with 2 inboard points and 3 outboard points
mesh = gen_crm_mesh(n_points_inboard=2, n_points_outboard=3)
num_y = mesh.shape[1]
r = radii(mesh)
t = r / 10

# Define the aircraft properties
execfile('CRM.py')

# Define the material properties
execfile('aluminum.py')

# Create the top-level system
root = Group()

# Define the independent variables
indep_vars = [
    ('span', span),
    ('twist', numpy.zeros(num_y)),
Пример #7
0
def setup(num_inboard=2, num_outboard=3, check=False, out_stream=sys.stdout):
    ''' Setup the aerostruct mesh using OpenMDAO'''

    # Define the aircraft properties
    from CRM import span, v, alpha, rho

    # Define spatialbeam properties
    from aluminum import E, G, stress, mrho

    # Create the mesh with 2 inboard points and 3 outboard points.
    # This will be mirrored to produce a mesh with 7 spanwise points,
    # or 6 spanwise panels
    # print(type(num_inboard))
    mesh = gen_crm_mesh(int(num_inboard), int(num_outboard), num_x=2)
    num_x, num_y = mesh.shape[:2]
    num_twist = np.max([int((num_y - 1) / 5), 5])
    r = radii(mesh)

    # Set the number of thickness control points and the initial thicknesses
    num_thickness = num_twist
    t = r / 10

    mesh = mesh.reshape(-1, mesh.shape[-1])
    aero_ind = np.atleast_2d(np.array([num_x, num_y]))
    fem_ind = [num_y]
    aero_ind, fem_ind = get_inds(aero_ind, fem_ind)

    # Set additional mesh parameters
    dihedral = 0.  # dihedral angle in degrees
    sweep = 0.  # shearing sweep angle in degrees
    taper = 1.  # taper ratio

    # Initial displacements of zero
    tot_n_fem = np.sum(fem_ind[:, 0])
    disp = np.zeros((tot_n_fem, 6))

    # Define Jacobians for b-spline controls
    tot_n_fem = np.sum(fem_ind[:, 0])
    num_surf = fem_ind.shape[0]
    jac_twist = get_bspline_mtx(num_twist, num_y)
    jac_thickness = get_bspline_mtx(num_thickness, tot_n_fem - num_surf)

    # Define ...
    twist_cp = np.zeros(num_twist)
    thickness_cp = np.ones(num_thickness) * np.max(t)

    # Define the design variables
    des_vars = [('twist_cp', twist_cp), ('dihedral', dihedral),
                ('sweep', sweep), ('span', span), ('taper', taper), ('v', v),
                ('alpha', alpha), ('rho', rho), ('disp', disp),
                ('aero_ind', aero_ind), ('fem_ind', fem_ind)]

    root = Group()

    root.add(
        'des_vars',
        IndepVarComp(des_vars),
        promotes=['twist_cp', 'span', 'v', 'alpha', 'rho', 'disp', 'dihedral'])
    root.add(
        'mesh',  # This component is needed, otherwise resulting loads matrix is NaN
        GeometryMesh(
            mesh,
            aero_ind),  # changes mesh given span, sweep, twist, and des_vars
        promotes=['span', 'sweep', 'dihedral', 'twist', 'taper', 'mesh'])
    root.add('def_mesh',
             TransferDisplacements(aero_ind, fem_ind),
             promotes=['mesh', 'disp', 'def_mesh'])

    prob = Problem()
    prob.root = root
    prob.setup(check=check, out_stream=out_stream)
    prob.run()

    # Output the def_mesh for the aero modules
    def_mesh = prob['def_mesh']

    # Other variables needed for aero and struct modules
    params = {
        'mesh': mesh,
        'num_x': num_x,
        'num_y': num_y,
        'span': span,
        'twist_cp': twist_cp,
        'thickness_cp': thickness_cp,
        'v': v,
        'alpha': alpha,
        'rho': rho,
        'r': r,
        't': t,
        'aero_ind': aero_ind,
        'fem_ind': fem_ind,
        'num_thickness': num_thickness,
        'num_twist': num_twist,
        'sweep': sweep,
        'taper': taper,
        'dihedral': dihedral,
        'E': E,
        'G': G,
        'stress': stress,
        'mrho': mrho,
        'tot_n_fem': tot_n_fem,
        'num_surf': num_surf,
        'jac_twist': jac_twist,
        'jac_thickness': jac_thickness,
        'out_stream': out_stream,
        'check': check
    }

    return (def_mesh, params)
Пример #8
0
    def add_surface(self, input_dict={}):
        """
        Add a surface to the problem. One surface definition is needed for
        each planar lifting surface.

        Parameters
        ----------
        input_dict : dictionary
            Surface definition. Note that there are default values defined by
            `get_default_surface` that are overwritten based on the
            user-provided input_dict.
        """

        # Get defaults and update surface with the user-provided input
        surf_dict = self.get_default_surf_dict()
        surf_dict.update(input_dict)

        # Check to see if the user provides the mesh points. If they do,
        # get the chordwise and spanwise number of points
        if 'mesh' in surf_dict.keys():
            mesh = surf_dict['mesh']
            num_x, num_y = mesh.shape[:2]

        # If the user doesn't provide a mesh, obtain the values from surface
        # to create the mesh
        elif 'num_x' in surf_dict.keys():
            num_x = surf_dict['num_x']
            num_y = surf_dict['num_y']
            span = surf_dict['span']
            chord = surf_dict['root_chord']
            span_cos_spacing = surf_dict['span_cos_spacing']
            chord_cos_spacing = surf_dict['chord_cos_spacing']

            # Check to make sure that an odd number of spanwise points (num_y) was provided
            if not num_y % 2:
                Error('num_y must be an odd number.')

            # Generate rectangular mesh
            if surf_dict['wing_type'] == 'rect':
                mesh = gen_rect_mesh(num_x, num_y, span, chord,
                    span_cos_spacing, chord_cos_spacing)

            # Generate CRM mesh. Note that this outputs twist information
            # based on the data from the CRM definition paper, so we save
            # this twist information to the surf_dict.
            elif 'CRM' in surf_dict['wing_type']:
                mesh, eta, twist = gen_crm_mesh(num_x, num_y, span, chord,
                    span_cos_spacing, chord_cos_spacing, surf_dict['wing_type'])
                num_x, num_y = mesh.shape[:2]
                surf_dict['crm_twist'] = twist

            else:
                Error('wing_type option not understood. Must be either a type of ' +
                      '"CRM" or "rect".')

            # Chop the mesh in half if using symmetry during analysis.
            # Note that this means that the provided mesh should be the full mesh
            if surf_dict['symmetry']:
                num_y = int((num_y+1)/2)
                mesh = mesh[:, :num_y, :]

        else:
            Error("Please either provide a mesh or a valid set of parameters.")

        # Compute span. We need .real to make span to avoid OpenMDAO warnings.
        quarter_chord = 0.25 * mesh[-1] + 0.75 * mesh[0]
        surf_dict['span'] = max(quarter_chord[:, 1]).real - min(quarter_chord[:, 1]).real
        if surf_dict['symmetry']:
            surf_dict['span'] *= 2.

        # Apply the user-provided coordinate offset to position the mesh
        mesh = mesh + surf_dict['offset']

        # We need to initialize some variables to ones and some others to zeros.
        # Here we define the lists for each case.
        ones_list = ['chord_cp', 'thickness_cp', 'radius_cp']
        zeros_list = ['twist_cp', 'xshear_cp', 'zshear_cp']
        surf_dict['bsp_vars'] = ones_list + zeros_list

        # Loop through bspline variables and set the number of control points if
        # the user hasn't initalized the array.
        for var in surf_dict['bsp_vars']:
            numkey = 'num_' + var
            if surf_dict[var] is None:
                if numkey not in input_dict:
                    surf_dict[numkey] = np.max([int((num_y - 1) / 5), min(5, num_y-1)])
            else:
                surf_dict[numkey] = len(surf_dict[var])

        # Interpolate the twist values from the CRM wing definition to the twist
        # control points
        if 'CRM' in surf_dict['wing_type']:
            num_twist = surf_dict['num_twist_cp']

            # If the surface is symmetric, simply interpolate the initial
            # twist_cp values based on the mesh data
            if surf_dict['symmetry']:
                twist = np.interp(np.linspace(0, 1, num_twist), eta, surf_dict['crm_twist'])
            else:

                # If num_twist is odd, create the twist vector and mirror it
                # then stack the two together, but remove the duplicated twist
                # value.
                if num_twist % 2:
                    twist = np.interp(np.linspace(0, 1, (num_twist+1)/2), eta, surf_dict['crm_twist'])
                    twist = np.hstack((twist[:-1], twist[::-1]))

                # If num_twist is even, mirror the twist vector and stack
                # them together
                else:
                    twist = np.interp(np.linspace(0, 1, num_twist/2), eta, surf_dict['crm_twist'])
                    twist = np.hstack((twist, twist[::-1]))

            # Continue to use the user-defined twist_cp if inputted to the
            # surface dictionary. Otherwise, use the prescribed CRM twist.
            if surf_dict['twist_cp'] is None:
                surf_dict['twist_cp'] = twist

        # Store updated values
        surf_dict['num_x'] = num_x
        surf_dict['num_y'] = num_y
        surf_dict['mesh'] = mesh

        radius = radii(mesh, surf_dict['t_over_c'])
        surf_dict['radius'] = radius

        # Set initial thicknesses
        surf_dict['thickness'] = radius / 10

        # We now loop through the possible bspline variables and populate
        # the 'initial_geo' list with the variables that the geometry
        # or user provided. For example, the CRM wing defines an initial twist.
        # We must treat this separately so we add a twist bspline component
        # even if it is not a desvar.
        surf_dict['initial_geo'] = []
        for var in surf_dict['geo_vars']:

            # Add the bspline variables when they're needed
            if var in surf_dict['bsp_vars']:
                numkey = 'num_' + var
                if surf_dict[var] is None:

                    # Add the intialized geometry variables to either ones or zeros.
                    # These initial values do not perturb the mesh.
                    if var in ones_list:
                        surf_dict[var] = np.ones(surf_dict[numkey], dtype=data_type)
                    elif var in zeros_list:
                        surf_dict[var] = np.zeros(surf_dict[numkey], dtype=data_type)
                else:
                    surf_dict['initial_geo'].append(var)

            # If the user provided a scalar variable (span, sweep, taper, etc),
            # then include that in the initial_geo list
            elif var in input_dict.keys():
                surf_dict['initial_geo'].append(var)

        if 'thickness_cp' not in surf_dict['initial_geo']:
            surf_dict['thickness_cp'] *= np.max(surf_dict['thickness'])

        if surf_dict['loads'] is None:
            # Set default loads at the tips
            loads = np.zeros((surf_dict['thickness'].shape[0] + 1, 6), dtype=data_type)
            loads[0, 2] = 1e4
            if not surf_dict['symmetry']:
                loads[-1, 2] = 1e4
            surf_dict['loads'] = loads

        if surf_dict['disp'] is None:
            # Set default disp if not provided
            surf_dict['disp'] = np.zeros((surf_dict['num_y'], 6), dtype=data_type)

        # Throw a warning if the user provides two surfaces with the same name
        name = surf_dict['name']
        for surface in self.surfaces:
            if name == surface['name']:
                OASWarning("Two surfaces have the same name.")

        # Append '_' to each repeated surface name
        if not name:
            surf_dict['name'] = name
        else:
            surf_dict['name'] = name + '_'

        # Add the individual surface description to the surface list
        self.surfaces.append(surf_dict)
Пример #9
0
            num_x = 3  # number of spanwise nodes
            num_y = 11  # number of chordwise nodes
            num_y_sym = numpy.int((num_y + 1) / 2)
            span = 32.  # [m]
            chord = 1.  # [m]
            cosine_spacing = 0.
            full_wing_mesh = gen_mesh(num_x, num_y, span, chord,
                                      cosine_spacing)
            num_twist = numpy.max([int((num_y - 1) / 5), 5])

        half_wing_mesh = full_wing_mesh[:, (num_y_sym - 1):, :]

        ##########################
        # Define beam properties #
        ##########################
        r = radii(half_wing_mesh) / 5  # beam radius
        thick = r / 5  # beam thickness
        fem_origin = 0.5  # elastic axis position along the chord
        #zeta = zeta_vect[i]
        zeta = 0.0  # damping percentual coeff.
        zeta = float(zeta)

        E = 70.e9  # [Pa]
        poisson = 0.3
        G = E / (2 * (1 + poisson))
        mrho = 2800.  # [kg/m^3]

        ####################################
        # Define the independent variables #
        ####################################
        indep_vars = [('span', span), ('twist', numpy.zeros(num_twist)),