def taper(mesh, taper_ratio, symmetry): """ Alter the spanwise chord to produce a tapered wing. Parameters ---------- mesh : array_like Nodal mesh defining the initial aerodynamic surface. taper_ratio : float Taper ratio for the wing; 1 is untapered, 0 goes to a point. symmetry : boolean Flag set to true if surface is reflected about y=0 plane. Returns ------- mesh : array_like Nodal mesh defining the tapered aerodynamic surface. """ le = mesh[0] te = mesh[-1] num_x, num_y, _ = mesh.shape center_chord = .5 * te + .5 * le if symmetry: taper = numpy.linspace(1, taper_ratio, num_y)[::-1] jac = get_bspline_mtx(num_y, num_y, order=2) taper = jac.dot(taper) for i in xrange(num_x): for ind in xrange(3): mesh[i, :, ind] = (mesh[i, :, ind] - center_chord[:, ind]) * \ taper + center_chord[:, ind] else: ny2 = int((num_y + 1) / 2) taper = numpy.linspace(1, taper_ratio, ny2)[::-1] jac = get_bspline_mtx(ny2, ny2, order=2) taper = jac.dot(taper) dx = numpy.hstack((taper, taper[::-1][1:])) for i in xrange(num_x): for ind in xrange(3): mesh[i, :, ind] = (mesh[i, :, ind] - center_chord[:, ind]) * \ dx + center_chord[:, ind] return mesh
def __init__(self, cpname, ptname, n_input, n_output): super(Bspline, self).__init__() self.cpname = cpname self.ptname = ptname self.jac = get_bspline_mtx(n_input, n_output, order=min(n_input, 4)) self.add_param(cpname, val=np.zeros(n_input)) self.add_output(ptname, val=np.zeros(n_output))
def solve_nonlinear(self, params, unknowns, resids): jac = get_bspline_mtx(self.num_twist, self.n, self.mesh) h_cp = params['twist'] h = jac.dot(h_cp) self.new_mesh[:] = self.mesh stretch(self.new_mesh, params['span']) sweep(self.new_mesh, params['sweep']) rotate(self.new_mesh, h) dihedral(self.new_mesh, params['dihedral']) taper(self.new_mesh, params['taper']) unknowns['mesh'] = self.new_mesh[:, :self.half + 1, :]
def taper(mesh, taper_ratio): """ Change the spanwise chord to produce a tapered wing. """ le = mesh[0] te = mesh[-1] num_x, num_y, _ = mesh.shape ny2 = int((num_y + 1) / 2) center_chord = .5 * te + .5 * le span = le[-1, 1] - le[0, 1] taper = numpy.linspace(1, taper_ratio, ny2)[::-1] jac = get_bspline_mtx(ny2, ny2, mesh, order=2) taper = jac.dot(taper) dx = numpy.hstack((taper, taper[::-1][1:])) for i in xrange(num_x): for ind in xrange(3): mesh[i, :, ind] = (mesh[i, :, ind] - center_chord[:, ind]) * \ dx + center_chord[:, ind] return mesh
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)
def aero(def_mesh=None, params=None): if (params is None) or (def_mesh is None): tmpmesh, params = setup() if not def_mesh: def_mesh = tmpmesh # Unpack variables mesh = params.get('mesh') num_x = params.get('num_x') num_y = params.get('num_y') span = params.get('span') twist_cp = params.get('twist_cp') thickness_cp = params.get('thickness_cp') v = params.get('v') alpha = params.get('alpha') rho = params.get('rho') r = params.get('r') t = params.get('t') aero_ind = params.get('aero_ind') fem_ind = params.get('fem_ind') num_thickness = params.get('num_thickness') num_twist = params.get('num_twist') sweep = params.get('sweep') taper = params.get('taper') disp = params.get('disp') dihedral = params.get('dihedral') check = params.get('check') out_stream = params.get('out_stream') # 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) disp = np.zeros((num_y, 6)) # for display? # Define the design variables des_vars = [ ('twist_cp', np.zeros(num_twist)), ('dihedral', dihedral), ('sweep', sweep), ('span', span), ('taper', taper), ('v', v), ('alpha', alpha), ('rho', rho), ('disp', np.zeros((tot_n_fem, 6))), ('def_mesh', def_mesh) ] root = Group() root.add('des_vars', IndepVarComp(des_vars), promotes=['twist_cp','span','v','alpha','rho','disp','dihedral','def_mesh']) # root.add('twist_bsp', # What is this doing? # Bspline('twist_cp', 'twist', jac_twist), # promotes=['*']) # root.add('thickness_bsp', # What is this doing? # Bspline('thickness_cp', 'thickness', jac_thickness), # promotes=['*']) # root.add('tube', # MaterialsTube(fem_ind), # promotes=['*']) root.add('VLMstates', VLMStates(aero_ind), promotes=[ 'def_mesh','b_pts','mid_b','c_pts','widths','normals','S_ref', # VLMGeometry 'alpha','circulations','v', # VLMCirculations 'rho','sec_forces' # VLMForces ]) root.add('loads', TransferLoads(aero_ind, fem_ind), promotes=['def_mesh','sec_forces','loads']) prob = Problem() prob.root = root prob.setup(check=check, out_stream=out_stream) prob.run() return prob['loads'] # Output the Loads matrix
def setup_aerostruct(self): """ Specific method to add the necessary components to the problem for an aerostructural problem. """ # Set the problem name if the user doesn't if 'prob_name' not in self.prob_dict.keys(): self.prob_dict['prob_name'] = 'aerostruct' # Create the base root-level group root = Group() coupled = Group() # Create the problem and assign the root group self.prob = Problem() self.prob.root = root # Loop over each surface in the surfaces list for surface in self.surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] tmp_group = Group() # Add independent variables that do not belong to a specific component indep_vars = [ ('twist_cp', numpy.zeros(surface['num_twist'])), ('thickness_cp', numpy.ones(surface['num_thickness']) * numpy.max(surface['t'])), ('r', surface['r']), ('dihedral', surface['dihedral']), ('sweep', surface['sweep']), ('span', surface['span']), ('taper', surface['taper']) ] # Obtain the Jacobians to interpolate the data from the b-spline # control points jac_twist = get_bspline_mtx(surface['num_twist'], surface['num_y']) jac_thickness = get_bspline_mtx(surface['num_thickness'], surface['num_y'] - 1) # Add components to include in the surface's group tmp_group.add('indep_vars', IndepVarComp(indep_vars), promotes=['*']) tmp_group.add('twist_bsp', Bspline('twist_cp', 'twist', jac_twist), promotes=['*']) tmp_group.add('thickness_bsp', Bspline('thickness_cp', 'thickness', jac_thickness), promotes=['*']) tmp_group.add('tube', MaterialsTube(surface), promotes=['*']) # Add tmp_group to the problem with the name of the surface. name_orig = name name = name[:-1] exec(name + ' = tmp_group') exec('root.add("' + name + '", ' + name + ', promotes=[])') # Add components to the 'coupled' group for each surface. # The 'coupled' group must contain all components and parameters # needed to converge the aerostructural system. tmp_group = Group() tmp_group.add('mesh', GeometryMesh(surface), promotes=['*']) tmp_group.add('def_mesh', TransferDisplacements(surface), promotes=['*']) tmp_group.add('aero_geom', VLMGeometry(surface), promotes=['*']) tmp_group.add('struct_states', SpatialBeamStates(surface), promotes=['*']) tmp_group.struct_states.ln_solver = LinearGaussSeidel() name = name_orig exec(name + ' = tmp_group') exec('coupled.add("' + name[:-1] + '", ' + name + ', promotes=[])') # Add a loads component to the coupled group exec('coupled.add("' + name_orig + 'loads' + '", ' + 'TransferLoads(surface)' + ', promotes=[])') # Add a performance group which evaluates the data after solving # the coupled system tmp_group = Group() tmp_group.add('struct_funcs', SpatialBeamFunctionals(surface), promotes=['*']) tmp_group.add('aero_funcs', VLMFunctionals(surface), promotes=['*']) name = name_orig + 'perf' exec(name + ' = tmp_group') exec('root.add("' + name + '", ' + name + ', promotes=["rho", "v", "alpha", "Re", "M"])') # Add a single 'aero_states' component for the whole system within the # coupled group. coupled.add('aero_states', VLMStates(self.surfaces, self.prob_dict), promotes=['v', 'alpha', 'rho']) # Explicitly connect parameters from each surface's group and the common # 'aero_states' group. for surface in self.surfaces: name = surface['name'] # Perform the connections with the modified names within the # 'aero_states' group. root.connect('coupled.' + name[:-1] + '.def_mesh', 'coupled.aero_states.' + name + 'def_mesh') root.connect('coupled.' + name[:-1] + '.b_pts', 'coupled.aero_states.' + name + 'b_pts') root.connect('coupled.' + name[:-1] + '.c_pts', 'coupled.aero_states.' + name + 'c_pts') root.connect('coupled.' + name[:-1] + '.normals', 'coupled.aero_states.' + name + 'normals') # Connect the results from 'aero_states' to the performance groups root.connect('coupled.aero_states.' + name + 'sec_forces', name + 'perf' + '.sec_forces') # Connect the results from 'coupled' to the performance groups root.connect('coupled.' + name[:-1] + '.def_mesh', 'coupled.' + name + 'loads.def_mesh') root.connect('coupled.aero_states.' + name + 'sec_forces', 'coupled.' + name + 'loads.sec_forces') root.connect('coupled.' + name + 'loads.loads', name + 'perf.loads') # Connect the output of the loads component with the FEM # displacement parameter. This links the coupling within the coupled # group that necessitates the subgroup solver. root.connect('coupled.' + name + 'loads.loads', 'coupled.' + name[:-1] + '.loads') # Connect aerodyamic design variables root.connect(name[:-1] + '.dihedral', 'coupled.' + name[:-1] + '.dihedral') root.connect(name[:-1] + '.span', 'coupled.' + name[:-1] + '.span') root.connect(name[:-1] + '.sweep', 'coupled.' + name[:-1] + '.sweep') root.connect(name[:-1] + '.taper', 'coupled.' + name[:-1] + '.taper') root.connect(name[:-1] + '.twist', 'coupled.' + name[:-1] + '.twist') # Connect structural design variables root.connect(name[:-1] + '.A', 'coupled.' + name[:-1] + '.A') root.connect(name[:-1] + '.Iy', 'coupled.' + name[:-1] + '.Iy') root.connect(name[:-1] + '.Iz', 'coupled.' + name[:-1] + '.Iz') root.connect(name[:-1] + '.J', 'coupled.' + name[:-1] + '.J') # Connect performance calculation variables root.connect(name[:-1] + '.r', name + 'perf.r') root.connect(name[:-1] + '.A', name + 'perf.A') # Connection performance functional variables root.connect(name + 'perf.weight', 'fuelburn.' + name + 'weight') root.connect(name + 'perf.weight', 'eq_con.' + name + 'weight') root.connect(name + 'perf.L', 'eq_con.' + name + 'L') root.connect(name + 'perf.CL', 'fuelburn.' + name + 'CL') root.connect(name + 'perf.CD', 'fuelburn.' + name + 'CD') # Connect paramters from the 'coupled' group to the performance # group. root.connect('coupled.' + name[:-1] + '.nodes', name + 'perf.nodes') root.connect('coupled.' + name[:-1] + '.disp', name + 'perf.disp') root.connect('coupled.' + name[:-1] + '.S_ref', name + 'perf.S_ref') # Set solver properties for the coupled group coupled.ln_solver = ScipyGMRES() coupled.ln_solver.options['iprint'] = 1 coupled.ln_solver.preconditioner = LinearGaussSeidel() coupled.aero_states.ln_solver = LinearGaussSeidel() coupled.nl_solver = NLGaussSeidel() coupled.nl_solver.options['iprint'] = 1 # Ensure that the groups are ordered correctly within the coupled group # so that a system with multiple surfaces is solved corretly. order_list = [] for surface in self.surfaces: order_list.append(surface['name'][:-1]) order_list.append('aero_states') for surface in self.surfaces: order_list.append(surface['name'] + 'loads') coupled.set_order(order_list) # Add the coupled group to the root problem root.add('coupled', coupled, promotes=['v', 'alpha', 'rho']) # Add problem information as an independent variables component prob_vars = [('v', self.prob_dict['v']), ('alpha', self.prob_dict['alpha']), ('M', self.prob_dict['M']), ('Re', self.prob_dict['Re']), ('rho', self.prob_dict['rho'])] root.add('prob_vars', IndepVarComp(prob_vars), promotes=['*']) # Add functionals to evaluate performance of the system. # Note that only the interesting results are promoted here; not all # of the parameters. root.add('fuelburn', FunctionalBreguetRange(self.surfaces, self.prob_dict), promotes=['fuelburn']) root.add('eq_con', FunctionalEquilibrium(self.surfaces, self.prob_dict), promotes=['eq_con', 'fuelburn']) # Actually set up the system self.setup_prob()
def setup_aero(self): """ Specific method to add the necessary components to the problem for an aerodynamic problem. """ # Set the problem name if the user doesn't if 'prob_name' not in self.prob_dict.keys(): self.prob_dict['prob_name'] = 'aero' # Create the base root-level group root = Group() # Create the problem and assign the root group self.prob = Problem() self.prob.root = root # Loop over each surface in the surfaces list for surface in self.surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] tmp_group = Group() # Add independent variables that do not belong to a specific component indep_vars = [('twist_cp', numpy.zeros(surface['num_twist'])), ('dihedral', surface['dihedral']), ('sweep', surface['sweep']), ('span', surface['span']), ('taper', surface['taper']), ('disp', numpy.zeros((surface['num_y'], 6)))] # Obtain the Jacobian to interpolate the data from the b-spline # control points jac_twist = get_bspline_mtx(surface['num_twist'], surface['num_y']) # Add aero components to the surface-specific group tmp_group.add('indep_vars', IndepVarComp(indep_vars), promotes=['*']) tmp_group.add('twist_bsp', Bspline('twist_cp', 'twist', jac_twist), promotes=['*']) tmp_group.add('mesh', GeometryMesh(surface), promotes=['*']) tmp_group.add('def_mesh', TransferDisplacements(surface), promotes=['*']) tmp_group.add('vlmgeom', VLMGeometry(surface), promotes=['*']) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. name_orig = name.strip('_') name = name_orig exec(name + ' = tmp_group') exec('root.add("' + name + '", ' + name + ', promotes=[])') # Add a performance group for each surface name = name_orig + '_perf' exec('root.add("' + name + '", ' + 'VLMFunctionals(surface)' + ', promotes=["v", "alpha", "M", "Re", "rho"])') # Add problem information as an independent variables component prob_vars = [('v', self.prob_dict['v']), ('alpha', self.prob_dict['alpha']), ('M', self.prob_dict['M']), ('Re', self.prob_dict['Re']), ('rho', self.prob_dict['rho'])] root.add('prob_vars', IndepVarComp(prob_vars), promotes=['*']) # Add a single 'aero_states' component that solves for the circulations # and forces from all the surfaces. # While other components only depends on a single surface, # this component requires information from all surfaces because # each surface interacts with the others. root.add('aero_states', VLMStates(self.surfaces, self.prob_dict), promotes=['circulations', 'v', 'alpha', 'rho']) # Explicitly connect parameters from each surface's group and the common # 'aero_states' group. # This is necessary because the VLMStates component requires information # from each surface, but this information is stored within each # surface's group. for surface in self.surfaces: name = surface['name'] # Perform the connections with the modified names within the # 'aero_states' group. root.connect(name[:-1] + '.def_mesh', 'aero_states.' + name + 'def_mesh') root.connect(name[:-1] + '.b_pts', 'aero_states.' + name + 'b_pts') root.connect(name[:-1] + '.c_pts', 'aero_states.' + name + 'c_pts') root.connect(name[:-1] + '.normals', 'aero_states.' + name + 'normals') # Connect the results from 'aero_states' to the performance groups root.connect('aero_states.' + name + 'sec_forces', name + 'perf' + '.sec_forces') # Connect S_ref for performance calcs root.connect(name[:-1] + '.S_ref', name + 'perf' + '.S_ref') # Actually set up the problem self.setup_prob()
def setup_struct(self): """ Specific method to add the necessary components to the problem for a structural problem. """ # Set the problem name if the user doesn't if 'prob_name' not in self.prob_dict.keys(): self.prob_dict['prob_name'] = 'struct' # Create the base root-level group root = Group() # Create the problem and assign the root group self.prob = Problem() self.prob.root = root # Loop over each surface in the surfaces list for surface in self.surfaces: # Get the surface name and create a group to contain components # only for this surface. # This group's name is whatever the surface's name is. # The default is 'wing'. name = surface['name'] tmp_group = Group() surface['r'] = surface['r'] / 5 surface['t'] = surface['r'] / 20 # Add independent variables that do not belong to a specific component. # Note that these are the only ones necessary for structual-only # analysis and optimization. indep_vars = [ ('thickness_cp', numpy.ones(surface['num_thickness']) * numpy.max(surface['t'])), ('r', surface['r']), ('loads', surface['loads']) ] # Obtain the Jacobians to interpolate the data from the b-spline # control points jac_twist = get_bspline_mtx(surface['num_twist'], surface['num_y']) jac_thickness = get_bspline_mtx(surface['num_thickness'], surface['num_y'] - 1) # Add structural components to the surface-specific group tmp_group.add('indep_vars', IndepVarComp(indep_vars), promotes=['*']) tmp_group.add('twist_bsp', Bspline('twist_cp', 'twist', jac_twist), promotes=['*']) tmp_group.add('thickness_bsp', Bspline('thickness_cp', 'thickness', jac_thickness), promotes=['*']) tmp_group.add('mesh', GeometryMesh(surface), promotes=['*']) tmp_group.add('tube', MaterialsTube(surface), promotes=['*']) tmp_group.add('struct_states', SpatialBeamStates(surface), promotes=['*']) tmp_group.add('struct_funcs', SpatialBeamFunctionals(surface), promotes=['*']) # Add tmp_group to the problem with the name of the surface. # The default is 'wing'. nm = name name = name[:-1] exec(name + ' = tmp_group') exec('root.add("' + name + '", ' + name + ', promotes=[])') # Actually set up the problem self.setup_prob()
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)
def aero(def_mesh=None, params=None): if (params is None) or (def_mesh is None): tmpmesh, params = setup() if not def_mesh: def_mesh = tmpmesh # Unpack variables mesh = params.get('mesh') num_x = params.get('num_x') num_y = params.get('num_y') span = params.get('span') twist_cp = params.get('twist_cp') thickness_cp = params.get('thickness_cp') v = params.get('v') alpha = params.get('alpha') rho = params.get('rho') r = params.get('r') t = params.get('t') aero_ind = params.get('aero_ind') fem_ind = params.get('fem_ind') num_thickness = params.get('num_thickness') num_twist = params.get('num_twist') sweep = params.get('sweep') taper = params.get('taper') disp = params.get('disp') dihedral = params.get('dihedral') check = params.get('check') out_stream = params.get('out_stream') # 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) disp = np.zeros((num_y, 6)) # for display? # Define the design variables des_vars = [('twist_cp', np.zeros(num_twist)), ('dihedral', dihedral), ('sweep', sweep), ('span', span), ('taper', taper), ('v', v), ('alpha', alpha), ('rho', rho), ('disp', np.zeros((tot_n_fem, 6))), ('def_mesh', def_mesh)] root = Group() root.add('des_vars', IndepVarComp(des_vars), promotes=[ 'twist_cp', 'span', 'v', 'alpha', 'rho', 'disp', 'dihedral', 'def_mesh' ]) # root.add('twist_bsp', # What is this doing? # Bspline('twist_cp', 'twist', jac_twist), # promotes=['*']) # root.add('thickness_bsp', # What is this doing? # Bspline('thickness_cp', 'thickness', jac_thickness), # promotes=['*']) # root.add('tube', # MaterialsTube(fem_ind), # promotes=['*']) root.add( 'VLMstates', VLMStates(aero_ind), promotes=[ 'def_mesh', 'b_pts', 'mid_b', 'c_pts', 'widths', 'normals', 'S_ref', # VLMGeometry 'alpha', 'circulations', 'v', # VLMCirculations 'rho', 'sec_forces' # VLMForces ]) root.add('loads', TransferLoads(aero_ind, fem_ind), promotes=['def_mesh', 'sec_forces', 'loads']) prob = Problem() prob.root = root prob.setup(check=check, out_stream=out_stream) prob.run() return prob['loads'] # Output the Loads matrix
fem_ind = [num_y] aero_ind, fem_ind = get_inds(aero_ind, fem_ind) num_thickness = num_twist t = r/10 # Define the aircraft properties execfile('CRM.py') # Define the material properties execfile('aluminum.py') # Create the top-level system root = Group() tot_n_fem = numpy.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 the independent variables indep_vars = [ ('span', span), ('twist_cp', numpy.zeros(num_twist)), ('thickness_cp', numpy.ones(num_thickness)*numpy.max(t)), ('v', v), ('alpha', alpha), ('rho', rho), ('r', r), ('t', t), ('aero_ind', aero_ind) ]
def setup_aerostruct(self): """ Specific method to add the necessary components to the problem for an aerostructural problem. """ # Set the problem name if the user doesn't if 'prob_name' not in self.prob_dict.keys(): self.prob_dict['prob_name'] = 'aerostruct' # Create the base root-level group root = Group() coupled = Group() # Create the problem and assign the root group self.prob = Problem() self.prob.root = root # Loop over each surface in the surfaces list for surface in self.surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] tmp_group = Group() # Add independent variables that do not belong to a specific component indep_vars = [ (name + 'twist_cp', numpy.zeros(surface['num_twist'])), (name + 'thickness_cp', numpy.ones(surface['num_thickness']) * numpy.max(surface['t'])), (name + 'r', surface['r']), (name + 'dihedral', surface['dihedral']), (name + 'sweep', surface['sweep']), (name + 'span', surface['span']), (name + 'taper', surface['taper']) ] # Obtain the Jacobians to interpolate the data from the b-spline # control points jac_twist = get_bspline_mtx(surface['num_twist'], surface['num_y']) jac_thickness = get_bspline_mtx(surface['num_thickness'], surface['num_y'] - 1) # Add components to include in the '_pre_solve' group tmp_group.add('indep_vars', IndepVarComp(indep_vars), promotes=['*']) tmp_group.add('twist_bsp', Bspline(name + 'twist_cp', name + 'twist', jac_twist), promotes=['*']) tmp_group.add('thickness_bsp', Bspline(name + 'thickness_cp', name + 'thickness', jac_thickness), promotes=['*']) tmp_group.add('tube', MaterialsTube(surface), promotes=['*']) # Add tmp_group to the problem with the name of the surface and # '_pre_solve' appended. name_orig = name #.strip('_') name = name + 'pre_solve' exec(name + ' = tmp_group') exec('root.add("' + name + '", ' + name + ', promotes=["*"])') # Add components to the 'coupled' group for each surface tmp_group = Group() tmp_group.add('mesh', GeometryMesh(surface), promotes=['*']) tmp_group.add('def_mesh', TransferDisplacements(surface), promotes=['*']) tmp_group.add('vlmgeom', VLMGeometry(surface), promotes=['*']) tmp_group.add('spatialbeamstates', SpatialBeamStates(surface), promotes=['*']) tmp_group.spatialbeamstates.ln_solver = LinearGaussSeidel() name = name_orig + 'group' exec(name + ' = tmp_group') exec('coupled.add("' + name + '", ' + name + ', promotes=["*"])') # Add a loads component to the coupled group exec('coupled.add("' + name_orig + 'loads' + '", ' + 'TransferLoads(surface)' + ', promotes=["*"])') # Add a '_post_solve' group which evaluates the data after solving # the coupled system tmp_group = Group() tmp_group.add('spatialbeamfuncs', SpatialBeamFunctionals(surface), promotes=['*']) tmp_group.add('vlmfuncs', VLMFunctionals(surface), promotes=['*']) name = name_orig + 'post_solve' exec(name + ' = tmp_group') exec('root.add("' + name + '", ' + name + ', promotes=["*"])') # Add a single 'VLMStates' component for the whole system coupled.add('vlmstates', VLMStates(self.surfaces, self.prob_dict), promotes=['*']) # Set solver properties for the coupled group coupled.ln_solver = ScipyGMRES() coupled.ln_solver.options['iprint'] = 1 coupled.ln_solver.preconditioner = LinearGaussSeidel() coupled.vlmstates.ln_solver = LinearGaussSeidel() coupled.nl_solver = NLGaussSeidel() coupled.nl_solver.options['iprint'] = 1 # Ensure that the groups are ordered correctly within the coupled group order_list = [] for surface in self.surfaces: order_list.append(surface['name'] + 'group') order_list.append('vlmstates') for surface in self.surfaces: order_list.append(surface['name'] + 'loads') coupled.set_order(order_list) # Add the coupled group to the root problem root.add('coupled', coupled, promotes=['*']) # Add problem information as an independent variables component prob_vars = [('v', self.prob_dict['v']), ('alpha', self.prob_dict['alpha']), ('M', self.prob_dict['M']), ('Re', self.prob_dict['Re']), ('rho', self.prob_dict['rho'])] root.add('prob_vars', IndepVarComp(prob_vars), promotes=['*']) # Add functionals to evaluate performance of the system root.add('fuelburn', FunctionalBreguetRange(self.surfaces, self.prob_dict), promotes=['*']) root.add('eq_con', FunctionalEquilibrium(self.surfaces, self.prob_dict), promotes=['*']) self.setup_prob()
def setup_aero(self): """ Specific method to add the necessary components to the problem for an aerodynamic problem. """ # Set the problem name if the user doesn't if 'prob_name' not in self.prob_dict.keys(): self.prob_dict['prob_name'] = 'aero' # Create the base root-level group root = Group() # Create the problem and assign the root group self.prob = Problem() self.prob.root = root # Loop over each surface in the surfaces list for surface in self.surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] tmp_group = Group() # Add independent variables that do not belong to a specific component indep_vars = [(name + 'twist_cp', numpy.zeros(surface['num_twist'])), (name + 'dihedral', surface['dihedral']), (name + 'sweep', surface['sweep']), (name + 'span', surface['span']), (name + 'taper', surface['taper']), (name + 'disp', numpy.zeros((surface['num_y'], 6)))] # Obtain the Jacobian to interpolate the data from the b-spline # control points jac_twist = get_bspline_mtx(surface['num_twist'], surface['num_y']) # Add aero components to the surface-specific group tmp_group.add('indep_vars', IndepVarComp(indep_vars), promotes=['*']) tmp_group.add('twist_bsp', Bspline(name + 'twist_cp', name + 'twist', jac_twist), promotes=['*']) tmp_group.add('mesh', GeometryMesh(surface), promotes=['*']) tmp_group.add('def_mesh', TransferDisplacements(surface), promotes=['*']) tmp_group.add('vlmgeom', VLMGeometry(surface), promotes=['*']) # Add tmp_group to the problem with the name of the surface and # '_pre_solve' appended. # Note that is a '_pre_solve' and '_post_solve' group for each # individual surface. name_orig = name.strip('_') name = name_orig + '_pre_solve' exec(name + ' = tmp_group') exec('root.add("' + name + '", ' + name + ', promotes=["*"])') # Add a '_post_solve' group name = name_orig + '_post_solve' exec('root.add("' + name + '", ' + 'VLMFunctionals(surface)' + ', promotes=["*"])') # Add problem information as an independent variables component prob_vars = [('v', self.prob_dict['v']), ('alpha', self.prob_dict['alpha']), ('M', self.prob_dict['M']), ('Re', self.prob_dict['Re']), ('rho', self.prob_dict['rho'])] root.add('prob_vars', IndepVarComp(prob_vars), promotes=['*']) # Add a single 'VLMStates' component that solves for the circulations # and forces from all the surfaces. # While other components only depends on a single surface, # this component requires information from all surfaces because # each surface interacts with the others. root.add('vlmstates', VLMStates(self.surfaces, self.prob_dict), promotes=['*']) self.setup_prob()