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') # Add this IndepVarComp to the problem model prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) prob.model.add_subsystem(surface['name'], geom_group) # Create the aero point group, which contains the actual aerodynamic # analyses aero_group = AeroPoint(surfaces=[surface]) point_name = 'aero_point_0' prob.model.add_subsystem( point_name, aero_group, promotes_inputs=['v', 'alpha', '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')
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)
def setup(self): shape = self.options['shape'] shape = (1, ) self.add_subsystem('aerodynamics_geometry_group', AerodynamicsGeometryGroup(shape=shape), promotes=['*']) # indep_var_comp = om.IndepVarComp() # indep_var_comp.add_output('v', val=50, units='m/s') # indep_var_comp.add_output('Mach_number', val=0.3) # indep_var_comp.add_output('re', val=1.e5, units='1/m') # indep_var_comp.add_output('rho') # indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') # indep_var_comp.add_output('alpha', val = 2.) # indep_var_comp.add_output('beta', val = 0.) # indep_var_comp.add_output('xshear', val = np.zeros((9))) # indep_var_comp.add_output('yshear', val = np.zeros((9))) # indep_var_comp.add_output('zshear', val = np.zeros((9))) # self.add_subsystem('inputs_comp', indep_var_comp, promotes=['*']) mesh_dict = { 'num_y': 17, 'num_x': 9, 'wing_type': 'rect', 'symmetry': True, 'chord': 0.1, 'span': 1., 'xshear': 0., 'yshear': 0., 'zshear': 0., } mesh = generate_mesh(mesh_dict) surface = { 'name': 'wing', 'symmetry': True, 'S_ref_type': 'wetted', 'twist_cp': np.array([-10., -3., 2.]), 'mesh': mesh, 'CL0': 0.0, 'CD0': 0.001, 'k_lam': 0.05, 't_over_c_cp': np.array([0.1875]), 'c_max_t': 0.1, 'with_viscous': True, 'with_wave': False, 'sweep': 6., 'taper': 0., 'dihedral': 0., } geom_group = Geometry(surface=surface) self.add_subsystem(surface['name'], geom_group) aero_group = AeroPoint(surfaces=[surface]) point_name = 'aero_point' self.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point # # make connections in run file #self.connect('v', point_name + '.v') # self.connect('cruise_alpha', point_name + '.alpha') # made! # #self.connect('Mach_number', point_name + '.Mach_number') # self.connect('re', point_name + '.re') # #self.connect('rho', point_name + '.rho') # self.connect('cg', point_name + '.cg') # Connect the mesh from the geometry component to the analysis point self.connect('wing.mesh', 'aero_point.wing.def_mesh') # Perform the connections with the modified names within the 'aero_states' group. self.connect('wing.mesh', 'aero_point.aero_states.wing_def_mesh') self.connect('wing.t_over_c', 'aero_point.wing_perf.t_over_c') self.connect('wing_span', 'wing.mesh.stretch.span') self.connect('oas_wing_chord', 'wing.mesh.scale_x.chord') # group = CruiseAeroGroup( # shape=shape # ) # self.add_subsystem('cruise_aero_group', group, promotes=['*']) group = CruiseLiftDragGroup(shape=shape) self.add_subsystem('cruise_lift_drag_group', group, promotes=['*'])
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): # 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 = 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('omega', val=np.array([30.0, 0.0, 0.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.034758588209493596, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.46156798274410005, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][0], 0.07287199378862094, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -0.11507066985988826, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][2], 0.010803003923282652, 1e-6)
'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': False, # if true, compute viscous drag, 'with_wave': False, } # end of surface dictionary name = surface['name'] # Add geometry to the problem as the name of the surface. # These groups are responsible for manipulating the geometry of the mesh, # in this case spanwise twist. geom_group = Geometry(surface=surface) prob.model.add_subsystem(name, geom_group) # Create the aero point group for this flight condition and add it to the model aero_group = AeroPoint(surfaces=[surface], rotational=True) point_name = 'aero_point_0' prob.model.add_subsystem(point_name, aero_group, promotes_inputs=[ 'v', 'alpha', 'beta', 'omega', 'Mach_number', 're', 'rho', 'cg' ]) # 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')
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, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], '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') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 recorder = SqliteRecorder("aero_opt_wavedrag.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_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_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.022662637, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -0.179451279, 1e-6)
def run_OAS(inputs, with_viscous=True, with_wave=True, t_over_c=np.array([0.12])): # 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": "projected", # how we compute the wing area, # can be 'wetted' or 'projected' "twist_cp": inputs["twist"], "mesh": inputs["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": t_over_c, # thickness over chord ratio (NACA0015) "c_max_t": 0.37, # chordwise location of maximum (NACA0015) # thickness "with_viscous": with_viscous, # if true, compute viscous drag "with_wave": with_wave, # 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("v", val=inputs["v"], units="m/s") indep_var_comp.add_output("alpha", val=inputs["alpha"], units="deg") indep_var_comp.add_output("Mach_number", val=inputs["Mach_number"]) indep_var_comp.add_output("re", val=inputs["re"], units="1/m") indep_var_comp.add_output("rho", val=inputs["rho"], units="kg/m**3") indep_var_comp.add_output("cg", val=np.zeros((3)), units="m") # Add this IndepVarComp to the problem model prob.model.add_subsystem("prob_vars", indep_var_comp, promotes=["*"]) # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) prob.model.add_subsystem(surface["name"], geom_group) # Create the aero point group, which contains the actual aerodynamic # analyses aero_group = AeroPoint(surfaces=[surface]) point_name = "aero_point_0" prob.model.add_subsystem( point_name, aero_group, promotes_inputs=["v", "alpha", "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") # Set up and run the model prob.setup() prob.run_model() outputs = {} outputs["CL"] = prob["aero_point_0.wing_perf.CL"] outputs["CD"] = prob["aero_point_0.wing_perf.CD"] return outputs
def test(self): # 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 } 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', '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 = [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.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True prob.driver.recording_options['includes'] = ['*'] # Set up the problem prob.setup() # om.view_model(prob) prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.038041969673747206, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5112640267782032, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -1.735548800386354, 1e-6)
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): 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, GeomMatch 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 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' : 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] 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) 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') prob.model.connect(point_name + '.wing_geom.shape', 'geom_match.' + str(i) + '_shape') # 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.add_subsystem('multi_CD', MultiCD(n_points=n_points), promotes_outputs=['CD']) prob.model.add_subsystem('geom_match', GeomMatch(n_points=n_points, mx=surf_dict['mx'], my=surf_dict['my']), promotes_outputs=['shape_diff']) 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_constraint('shape_diff', equals=0., indices=range(surf_dict['my'] * (n_points - 1) * 1), linear=True) # prob.model.add_constraint('shape_diff', equals=0., linear=True) prob.model.add_objective('CD', scaler=1e4) # Set up the problem prob.setup() # prob.run_model() prob.run_driver() # prob.check_partials(compact_print=True) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.45, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03229527496681374, 1e-6) assert_rel_error(self, prob['aero_point_1.wing_perf.CL'][0], 0.5, 1e-6) assert_rel_error(self, prob['aero_point_1.wing_perf.CD'][0], 0.033767398588947985, 1e-6)
def setup(self): nx = int(self.options["num_x"]) ny = int(self.options["num_y"]) n_twist = int(self.options["num_twist"]) # ================================================================= # Set up mesh # ================================================================= self.add_subsystem( "mesh", PlanformMesh(num_x=nx, num_y=ny), promotes_inputs=[ ("S", "ac|geom|wing|S_ref"), ("AR", "ac|geom|wing|AR"), ("taper", "ac|geom|wing|taper"), ("sweep", "ac|geom|wing|c4sweep"), ], ) # Add bspline component for twist x_interp = np.linspace(0.0, 1.0, ny) comp = self.add_subsystem( "twist_bsp", om.SplineComp(method="bsplines", x_interp_val=x_interp, num_cp=n_twist, interp_options={"order": min(n_twist, 4)}), promotes_inputs=[("twist_cp", "ac|geom|wing|twist")], ) comp.add_spline(y_cp_name="twist_cp", y_interp_name="twist", y_units="deg") # Apply twist spline to mesh self.add_subsystem( "twist_mesh", Rotate(val=np.zeros(ny), mesh_shape=(nx, ny, 3), symmetry=True)) self.connect("twist_bsp.twist", "twist_mesh.twist") self.connect("mesh.mesh", "twist_mesh.in_mesh") # ================================================================= # Compute atmospheric and fluid properties # ================================================================= self.add_subsystem( "temp", TemperatureComp(num_nodes=1), promotes_inputs=["fltcond|h", "fltcond|TempIncrement"]) self.add_subsystem("pressure", PressureComp(num_nodes=1), promotes_inputs=["fltcond|h"]) self.add_subsystem("density", DensityComp(num_nodes=1)) self.connect("temp.fltcond|T", "density.fltcond|T") self.connect("pressure.fltcond|p", "density.fltcond|p") self.add_subsystem("sound_speed", SpeedOfSoundComp(num_nodes=1)) self.connect("temp.fltcond|T", "sound_speed.fltcond|T") self.add_subsystem( "airspeed", om.ExecComp("Utrue = Mach * a", Utrue={ "units": "m/s", "val": 200.0 }, a={ "units": "m/s", "val": 300.0 }), promotes_inputs=[("Mach", "fltcond|M")], ) self.connect("sound_speed.fltcond|a", "airspeed.a") # Compute dimensionalized Reynolds number (use linear interpolation from standard atmosphere up # to 35k ft to estimate dynamic viscosity) self.add_subsystem( "Re_calc", om.ExecComp( "re = rho * u / (-3.329134*10**(-10) * h + 1.792398*10**(-5))", re={ "units": "1/m", "val": 1e6 }, rho={ "units": "kg/m**3", "val": 1.0 }, u={ "units": "m/s", "val": 100.0 }, h={ "units": "m", "val": 1.0 }, ), promotes_inputs=[("h", "fltcond|h")], ) self.connect("density.fltcond|rho", "Re_calc.rho") self.connect("airspeed.Utrue", "Re_calc.u") # ================================================================= # Call OpenAeroStruct # ================================================================= surf_dict = { "name": "wing", "mesh": np.zeros((nx, ny, 3)), # this must be defined # because the VLMGeometry component uses the shape of the mesh in this # dictionary to determine the size of the mesh; the values don't matter "symmetry": True, # if true, model one half of wing # reflected across the plane y = 0 "S_ref_type": "projected", # how we compute the wing area, # can be 'wetted' or 'projected' # 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": np.array([0.12]), # thickness over chord ratio (NACA SC2-0612) "c_max_t": 0.37, # chordwise location of maximum (NACA SC2-0612) # thickness "with_viscous": True, # if true, compute viscous drag "with_wave": True, # if true, compute wave drag } # Overwrite any options in the surface dict with those provided in the options if self.options["surf_options"] is not None: for key in self.options["surf_options"]: surf_dict[key] = self.options["surf_options"][key] self.add_subsystem( "aero_point", AeroPoint(surfaces=[surf_dict]), promotes_inputs=[("Mach_number", "fltcond|M"), ("alpha", "fltcond|alpha")], promotes_outputs=[ (f"{surf_dict['name']}_perf.CD", "fltcond|CD"), (f"{surf_dict['name']}_perf.CL", "fltcond|CL"), ], ) self.connect( "twist_mesh.mesh", [ f"aero_point.{surf_dict['name']}.def_mesh", f"aero_point.aero_states.{surf_dict['name']}_def_mesh" ], ) self.connect("airspeed.Utrue", "aero_point.v") self.connect("density.fltcond|rho", "aero_point.rho") self.connect("Re_calc.re", "aero_point.re") # Set input defaults for inputs that go to multiple locations self.set_input_defaults("fltcond|M", 0.1) self.set_input_defaults("fltcond|alpha", 0.0) # Set the thickness to chord ratio for wave and viscous drag calculation. # It must have a thickness to chord ratio for each panel, so there must be # ny-1 elements. Allow either one value (and duplicate it ny-1 times) or # an array of length ny-1, but nothing else. # NOTE: for aerostructural cases, this should be a design variable with control points over a spline if isinstance(surf_dict["t_over_c"], (int, float)) or surf_dict["t_over_c"].size == 1: self.set_input_defaults( f"aero_point.{surf_dict['name']}_perf.t_over_c", val=surf_dict["t_over_c"] * np.ones(ny - 1)) elif surf_dict["t_over_c"].size == ny - 1: self.set_input_defaults( f"aero_point.{surf_dict['name']}_perf.t_over_c", val=surf_dict["t_over_c"]) else: raise ValueError( f"t_over_c in the surface dict must be either a number or an ndarray " f"with either one or ny-1 elements, not {surf_dict['t_over_c']}" )
def __init__(self): # 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 } # Create the OpenMDAO problem self.prob = Problem() # Create an independent variable component that will supply the flow # conditions to the problem. indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('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') # Add this IndepVarComp to the problem model self.prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) self.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' self.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 self.prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. self.prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') self.prob.model.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') self.prob.setup()
def compute_drag_polar_ground_effect(Mach, alphas, heights, surfaces, trimmed=False, visualize=False): if isinstance(surfaces, dict): surfaces = [ surfaces, ] # 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('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=0.0, units='deg') indep_var_comp.add_output('height_agl', val=8000, units='m') indep_var_comp.add_output('Mach_number', val=Mach) indep_var_comp.add_output('re', val=1.0e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') # Add this IndepVarComp to the problem model prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) for surface in surfaces: name = surface['name'] # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) prob.model.add_subsystem(name, geom_group) # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', 'aero.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + '.mesh', 'aero.aero_states.' + name + '_def_mesh') # Create the aero point group, which contains the actual aerodynamic # analyses point_name = 'aero' aero_group = AeroPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, aero_group, promotes_inputs=[ 'v', 'alpha', 'Mach_number', 're', 'rho', 'cg', 'height_agl' ]) # For trimmed polar, setup balance component if trimmed == True: bal = om.BalanceComp() bal.add_balance(name='tail_rotation', rhs_val=0.0, units='deg') prob.model.add_subsystem('balance', bal, promotes_outputs=['tail_rotation']) prob.model.connect('aero.CM', 'balance.lhs:tail_rotation', src_indices=[1]) prob.model.connect('tail_rotation', 'tail.twist_cp') prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=True) prob.model.nonlinear_solver.options['iprint'] = 2 prob.model.nonlinear_solver.options['maxiter'] = 10 prob.model.linear_solver = om.DirectSolver() if visualize: prob.driver = om.ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 recorder = om.SqliteRecorder("polar_ground_effect.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True prob.driver.recording_options['includes'] = ['*'] prob.driver.options['maxiter'] = 1 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('cg', lower=-0.0, upper=0.0) prob.model.add_objective('aero.CL', scaler=1e4) prob.setup() # prob['tail_rotation'] = -0.75 span = prob['wing.mesh.stretch.span'] prob.run_model() # prob.check_partials(compact_print = True) # prob.model.list_outputs(prom_name = True) prob.model.list_outputs(residuals=True) CLs = [] CDs = [] CMs = [] for height in heights: CLs_h = [] CDs_h = [] CMs_h = [] for a in alphas: prob['alpha'] = a prob['height_agl'] = height prob.run_model() CLs_h.append(prob['aero.CL'][0]) CDs_h.append(prob['aero.CD'][0]) CMs_h.append(prob['aero.CM'][1]) # Take only the longitudinal CM # print(a, prob['aero.CL'], prob['aero.CD'], prob['aero.CM'][1]) CLs.append(CLs_h) CDs.append(CDs_h) CMs.append(CMs_h) # Plot the drag polar if visualize: prob.run_driver() fig, ax = plt.subplots(nrows=1) for ih, height in enumerate(heights): ax.plot(CLs[ih], CDs[ih], label='h/b=' + '%.1f' % (height / span)[0]) ax.set_ylabel('CDi') ax.set_xlabel('CL') ax.legend() fig, ax = plt.subplots(nrows=1) # compute ground effect correction factor and plot CLs_arr = np.array(CLs) CDs_arr = np.array(CDs) k = CDs_arr[:, -1] / CLs_arr[:, -1]**2 k = k / k[0] hob = np.array(heights) / span ax.plot(hob, k) ax.set_xscale('log') ax.set_xlabel('h/b') ax.set_ylabel('$C_{Di}/C_{Di,\infty}$') plt.show() return CLs, CDs, CMs
def test(self): # 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': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aero', 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'twist_cp': twist_cp, 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c': 0.15, # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, # if true, compute viscous drag } # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'num_x': 2, 'wing_type': 'rect', 'symmetry': True, 'offset': np.array([50, 0., 0.]) } mesh = generate_mesh(mesh_dict) surf_dict2 = { # Wing definition 'name': 'tail', # 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' '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.0, # CD of the surface at alpha=0 'fem_origin': 0.35, # 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 } surfaces = [surf_dict, surf_dict2] # 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.) 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') # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.037210478659832125, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5124736932248048, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -0.18108463722015625, 1e-6)
def test(self): import numpy as np 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 import openmdao.api as om # 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 } surfaces = [surf_dict] n_points = 2 # 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=np.ones(n_points) * 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=['*']) # 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('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) # 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']) prob.driver = om.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('aero_point_0.wing_geom.twist_cp', lower=-5, upper=8) prob.model.add_constraint('aero_point_0.wing_perf.CL', equals=0.45) prob.model.add_design_var('aero_point_1.wing_geom.twist_cp', lower=-5, upper=8) 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() # print('gona check') # prob.run_model() # prob.check_partials(compact_print=True) # exit() 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_0.wing_perf.CD'][0], 0.03231556149303963, 1e-6) assert_rel_error(self, prob['aero_point_1.wing_perf.CL'][0], 0.5, 1e-6) assert_rel_error(self, prob['aero_point_1.wing_perf.CD'][0], 0.03376555561457066, 1e-6)
def compute_drag_polar(Mach, alphas, surfaces, trimmed=False): if isinstance(surfaces, dict): surfaces = [ surfaces, ] # Create the OpenMDAO problem prob = Problem() # Create an independent variable component that will supply the flow # conditions to the problem. indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=Mach) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') # Add this IndepVarComp to the problem model prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) for surface in surfaces: name = surface['name'] # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) prob.model.add_subsystem(name, geom_group) # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', 'aero.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + '.mesh', 'aero.aero_states.' + name + '_def_mesh') # Create the aero point group, which contains the actual aerodynamic # analyses point_name = 'aero' aero_group = AeroPoint(surfaces=surfaces) prob.model.add_subsystem( point_name, aero_group, promotes_inputs=['v', 'alpha', 'Mach_number', 're', 'rho', 'cg']) # For trimmed polar, setup balance component if trimmed == True: bal = BalanceComp() bal.add_balance(name='tail_rotation', rhs_val=0., units='deg') prob.model.add_subsystem('balance', bal, promotes_outputs=['tail_rotation']) prob.model.connect('aero.CM', 'balance.lhs:tail_rotation', src_indices=[1]) prob.model.connect('tail_rotation', 'tail.twist_cp') prob.model.nonlinear_solver = NonlinearBlockGS(use_aitken=True) prob.model.nonlinear_solver.options['iprint'] = 2 prob.model.nonlinear_solver.options['maxiter'] = 100 prob.model.linear_solver = DirectSolver() prob.setup() #prob['tail_rotation'] = -0.75 prob.run_model() #prob.check_partials(compact_print = True) #prob.model.list_outputs(prom_name = True) prob.model.list_outputs(residuals=True) CLs = [] CDs = [] CMs = [] for a in alphas: prob['alpha'] = a prob.run_model() CLs.append(prob['aero.CL'][0]) CDs.append(prob['aero.CD'][0]) CMs.append(prob['aero.CM'][1]) # Take only the longitudinal CM #print(a, prob['aero.CL'], prob['aero.CD'], prob['aero.CM'][1]) # Plot CL vs alpha and drag polar fig, axes = plt.subplots(nrows=3) axes[0].plot(alphas, CLs) axes[1].plot(alphas, CMs) axes[2].plot(CLs, CDs) fig.savefig('drag_polar.pdf') #plt.show() return CLs, CDs, CMs
def test(self): from openaerostruct.geometry.utils import generate_mesh, write_FFD_file from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.aerodynamics.aero_groups import AeroPoint from openaerostruct.integration.multipoint_comps import MultiCD import openmdao.api as om 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.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', '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': 0.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 = 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=np.ones(n_points) * 6.64, units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('re', val=1.0e6, 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: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] # FFD setup 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 with the name of the surface. prob.model.add_subsystem(name + '_geom', geom_group) # 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('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 drag coeff at this point to the multi_CD component, which does the summation. 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(name + '_geom.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect( name + '_geom.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect( 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']) prob.driver = om.ScipyOptimizeDriver() # Setup problem and add design variables, constraint, and objective # design variable is the wing shape, and angle-of-attack at each point. prob.model.add_design_var('alpha', lower=-15, upper=15) prob.model.add_design_var('wing_geom.shape', lower=-3, upper=2) # set different target CL value at each point. 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.5) # objective is the sum of CDs at each point. 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='fd', step=1e-5) assert_check_partials(data, atol=1e20, rtol=1e-3)
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 '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_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] # 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=['*']) # 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('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 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], -1.7736315914915437, 1e-5)
def test(self): import numpy as np from openaerostruct.geometry.utils import generate_mesh from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.aerodynamics.aero_groups import AeroPoint from openmdao.api import IndepVarComp, Problem, Group # Instantiate 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=['*']) # 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': 1. } 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 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'twist_cp': np.zeros(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.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': False, # if true, compute viscous drag, 'with_wave': False, # if true, compute wave drag 'sweep': 0., 'dihedral': 0., 'taper': 1., } # end of surface dictionary 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) # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=[surface]) point_name = 'aero_point_0' 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') name = 'wing' # 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_design_var('wing.sweep', lower=-10., upper=30.) prob.model.add_design_var('wing.dihedral', 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_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0],\ 0.0049392534859265614, 1e-6)
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 # 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, # 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('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') # Add this IndepVarComp to the problem model prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) prob.model.add_subsystem(surface['name'], geom_group) # Create the aero point group, which contains the actual aerodynamic # analyses aero_group = AeroPoint(surfaces=[surface]) point_name = 'aero_point_0' prob.model.add_subsystem( point_name, aero_group, promotes_inputs=['v', 'alpha', '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 recorder = om.SqliteRecorder("aero.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_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.033389699871650073, 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.7885550372372376, 1e-6)
'vsp', VSPeCRM(horiz_tail_name="Tail", vert_tail_name="VerticalTail", wing_name="Wing")) prob.model.connect('vsp.wing_mesh', 'aero.wing.def_mesh') prob.model.connect('vsp.wing_mesh', 'aero.aero_states.wing_def_mesh') prob.model.connect('vsp.horiz_tail_mesh', 'aero.horiz_tail.def_mesh') prob.model.connect('vsp.horiz_tail_mesh', 'aero.aero_states.horiz_tail_def_mesh') prob.model.connect('vsp.vert_tail_mesh', 'aero.vert_tail.def_mesh') prob.model.connect('vsp.vert_tail_mesh', 'aero.aero_states.vert_tail_def_mesh') # Create the aero point group, which contains the actual aerodynamic # analyses aero_group = AeroPoint(surfaces=surfaces) prob.model.add_subsystem( 'aero', aero_group, promotes_inputs=['v', 'alpha', 'Mach_number', 're', 'rho', 'cg']) prob.setup() # Initial conditions #prob.set_val('v', val=248.136, units='m/s') #prob.set_val('alpha', val=0.0, units='deg') #prob.set_val('Mach_number', val=0.1) # 70 mph approx. TODO: make exact #prob.set_val('re', val=1.0e6, units='1/m') #prob.set_val('rho', val=0.38, units='kg/m**3') #prob.set_val('cg', val=np.zeros((3)), units='m')