def test_outputs(self): surfaces = get_default_surfaces() group = Group() 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, promotes=['*']) group.add_subsystem('indep_var_comp', indep_var_comp, promotes=['*']) prob = Problem() prob.model.add_subsystem('group', group, promotes=['*']) prob.setup() prob.run_model() assert_rel_error(self, prob['widths'], np.array([11.95624787, 11.90425878, 11.44086572]), 1e-6) assert_rel_error(self, prob['cos_sweep'], np.array([9.7938336, 9.79384207, 9.79385053]), 1e-6) assert_rel_error(self, prob['S_ref'], np.array([415.02211208]), 1e-6) assert_rel_error(self, prob['chords'], np.array([2.72796, 5.1252628, 7.8891638, 13.6189974]), 1e-6) assert_rel_error(self, prob['lengths'], np.array([2.72796, 5.1252628, 7.8891638, 13.6189974]), 1e-6)
def setup(self): surface = self.options['surface'] promotes = [] if surface['struct_weight_relief']: promotes = promotes + list( set(['nodes', 'element_weights', 'load_factor'])) if surface['distributed_fuel_weight']: promotes = promotes + list(set(['nodes', 'load_factor'])) self.add_subsystem('struct_states', SpatialBeamStates(surface=surface), promotes_inputs=['K', 'forces', 'loads'] + promotes, promotes_outputs=['disp']) self.add_subsystem('def_mesh', DisplacementTransferGroup(surface=surface), promotes_inputs=['nodes', 'mesh', 'disp'], promotes_outputs=['def_mesh']) self.add_subsystem('aero_geom', VLMGeometry(surface=surface), promotes_inputs=['def_mesh'], promotes_outputs=[ 'b_pts', 'widths', 'cos_sweep', 'lengths', 'chords', 'normals', 'S_ref' ]) self.linear_solver = LinearRunOnce()
def setup(self): surface = self.options['surface'] self.add_subsystem('struct_states', SpatialBeamStates(surface=surface), promotes_inputs=[ 'K', 'forces', 'loads', 'element_weights', 'nodes' ], promotes_outputs=['disp']) self.add_subsystem('def_mesh', DisplacementTransfer(surface=surface), promotes_inputs=['mesh', 'disp'], promotes_outputs=['def_mesh']) self.add_subsystem('aero_geom', VLMGeometry(surface=surface), promotes_inputs=['def_mesh'], promotes_outputs=[ 'b_pts', 'c_pts', 'widths', 'cos_sweep', 'lengths', 'chords', 'normals', 'S_ref' ]) self.linear_solver = LinearRunOnce()
def setup(self): surfaces = self.options['surfaces'] for surface in surfaces: name = surface['name'] self.connect(name + '.normals', 'aero_states.' + name + '_normals') # self.connect(name + '.b_pts', 'aero_states.' + name + '_b_pts') # self.connect(name + '.c_pts', 'aero_states.' + name + '_c_pts') # self.connect(name + '.cos_sweep', 'aero_states.' + name + '_cos_sweep') # self.connect(name + '.widths', 'aero_states.' + name + '_widths') # Connect the results from 'aero_states' to the performance groups self.connect('aero_states.' + name + '_sec_forces', name + '_perf' + '.sec_forces') # Connect S_ref for performance calcs self.connect(name + '.S_ref', name + '_perf.S_ref') self.connect(name + '.widths', name + '_perf.widths') self.connect(name + '.chords', name + '_perf.chords') self.connect(name + '.lengths', name + '_perf.lengths') self.connect(name + '.cos_sweep', name + '_perf.cos_sweep') # Connect S_ref for performance calcs self.connect(name + '.S_ref', 'total_perf.' + name + '_S_ref') self.connect(name + '.widths', 'total_perf.' + name + '_widths') self.connect(name + '.chords', 'total_perf.' + name + '_chords') self.connect(name + '.b_pts', 'total_perf.' + name + '_b_pts') self.connect(name + '_perf' + '.CL', 'total_perf.' + name + '_CL') self.connect(name + '_perf' + '.CD', 'total_perf.' + name + '_CD') self.connect('aero_states.' + name + '_sec_forces', 'total_perf.' + name + '_sec_forces') self.add_subsystem(name, VLMGeometry(surface=surface)) # 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. aero_states = VLMStates(surfaces=surfaces) aero_states.linear_solver = LinearRunOnce() self.add_subsystem('aero_states', aero_states, promotes_inputs=['v', 'alpha', 'rho'], promotes_outputs=['circulations']) # 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 surfaces: self.add_subsystem(surface['name'] +'_perf', VLMFunctionals(surface=surface), promotes_inputs=["v", "alpha", "M", "re", "rho"]) self.add_subsystem('total_perf', TotalAeroPerformance(surfaces=surfaces), promotes_inputs=['v', 'rho', 'cg', 'S_ref_total'], promotes_outputs=['CM', 'CL', 'CD'])
def setup(self): surface = self.options['surface'] promotes = [] if surface['struct_weight_relief']: promotes = promotes + list( set(['nodes', 'element_mass', 'load_factor'])) if surface['distributed_fuel_weight']: promotes = promotes + list(set(['nodes', 'load_factor'])) if 'n_point_masses' in surface.keys(): promotes = promotes + list( set([ 'point_mass_locations', 'point_masses', 'nodes', 'load_factor', 'engine_thrusts' ])) self.add_subsystem( 'struct_states', SpatialBeamStates(surface=surface), promotes_inputs=['local_stiff_transformed', 'forces', 'loads'] + promotes, promotes_outputs=['disp']) self.add_subsystem('def_mesh', DisplacementTransferGroup(surface=surface), promotes_inputs=['nodes', 'mesh', 'disp'], promotes_outputs=['def_mesh']) normals_name = 'undeflected_normals' self.add_subsystem('aero_geom', VLMGeometry(surface=surface), promotes_inputs=['def_mesh'], promotes_outputs=[ 'b_pts', 'widths', 'cos_sweep', 'lengths', 'chords', ('normals', normals_name), 'S_ref' ]) # Add control surfaces if 'control_surfaces' in surface: for ctrl_surf in surface['control_surfaces']: #TODO: fixed name only works with one control surface deflected_normals_name = "normals" #"{}_normals".format(ctrl_surf['name']) self.add_subsystem( ctrl_surf['name'], ControlSurface(surface=surface, panels=ctrl_surf['panels']), promotes_inputs=[('normals', normals_name), 'delta_aileron' ], #,f"delta_{control_surf['name']}"], promotes_outputs=[('deflected_normals', deflected_normals_name)]) #iterate through names normals_name = deflected_normals_name else: pass #No control surface to add #self.connect(normals_name,'normals') self.linear_solver = LinearRunOnce()
def test(self): surfaces = get_default_surfaces() group = om.Group() comp = VLMGeometry(surface=surfaces[0]) indep_var_comp = om.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') run_test(self, group)
def setup(self): surface = self.options['surface'] promotes = [] if surface['struct_weight_relief']: promotes = promotes + list( set(['nodes', 'element_mass', 'load_factor'])) if surface['distributed_fuel_weight']: promotes = promotes + list(set(['nodes', 'load_factor'])) if 'n_point_masses' in surface.keys(): promotes = promotes + list( set([ 'point_mass_locations', 'point_masses', 'nodes', 'load_factor', 'engine_thrusts' ])) self.add_subsystem( 'struct_states', SpatialBeamStates(surface=surface), promotes_inputs=['local_stiff_transformed', 'forces', 'loads'] + promotes, promotes_outputs=['disp']) self.add_subsystem('def_mesh', DisplacementTransferGroup(surface=surface), promotes_inputs=['nodes', 'mesh', 'disp'], promotes_outputs=['def_mesh']) self.add_subsystem('aero_geom', VLMGeometry(surface=surface), promotes_inputs=['def_mesh'], promotes_outputs=[ 'b_pts', 'widths', 'cos_sweep', 'lengths', 'chords', 'S_ref' ]) # Add control surfaces if 'control_surfaces' in surface: self.add_subsystem( 'control_surfaces', ControlSurfacesGroup( control_surfaces=surface['control_surfaces'], mesh=surface['mesh']), promotes_inputs=['def_mesh']) self.linear_solver = om.LinearRunOnce()
def setup(self): surfaces = self.options['surfaces'] rotational = self.options['rotational'] # Loop through each surface and connect relevant parameters for surface in surfaces: name = surface['name'] self.connect(name + '.normals', 'aero_states.' + name + '_normals') # Connect the results from 'aero_states' to the performance groups self.connect('aero_states.' + name + '_sec_forces', name + '_perf' + '.sec_forces') # Connect S_ref for performance calcs self.connect(name + '.S_ref', name + '_perf.S_ref') self.connect(name + '.widths', name + '_perf.widths') self.connect(name + '.chords', name + '_perf.chords') self.connect(name + '.lengths', name + '_perf.lengths') self.connect(name + '.cos_sweep', name + '_perf.cos_sweep') # Connect S_ref for performance calcs self.connect(name + '.S_ref', 'total_perf.' + name + '_S_ref') self.connect(name + '.widths', 'total_perf.' + name + '_widths') self.connect(name + '.chords', 'total_perf.' + name + '_chords') self.connect(name + '.b_pts', 'total_perf.' + name + '_b_pts') self.connect(name + '_perf' + '.CL', 'total_perf.' + name + '_CL') self.connect(name + '_perf' + '.CD', 'total_perf.' + name + '_CD') self.connect('aero_states.' + name + '_sec_forces', 'total_perf.' + name + '_sec_forces') self.add_subsystem(name, VLMGeometry(surface=surface)) # 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. if self.options['compressible'] == True: aero_states = CompressibleVLMStates(surfaces=surfaces, rotational=rotational) prom_in = ['v', 'alpha', 'beta', 'rho', 'Mach_number'] else: aero_states = VLMStates(surfaces=surfaces, rotational=rotational) prom_in = ['v', 'alpha', 'beta', 'rho'] aero_states.linear_solver = om.LinearRunOnce() if rotational: prom_in.extend(['omega', 'cg']) self.add_subsystem('aero_states', aero_states, promotes_inputs=prom_in, promotes_outputs=['circulations']) # 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 surfaces: self.add_subsystem(surface['name'] + '_perf', VLMFunctionals(surface=surface), promotes_inputs=[ 'v', 'alpha', 'beta', 'Mach_number', 're', 'rho' ]) # Add the total aero performance group to compute the CL, CD, and CM # of the total aircraft. This accounts for all lifting surfaces. self.add_subsystem( 'total_perf', TotalAeroPerformance( surfaces=surfaces, user_specified_Sref=self.options['user_specified_Sref']), promotes_inputs=['v', 'rho', 'cg', 'S_ref_total'], promotes_outputs=['CM', 'CL', 'CD'])
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 '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)