def get_mesh(symmetry): """ Return a mesh for testing. """ ny = (2*NY - 1) if symmetry else NY # Create a dictionary to store options about the mesh mesh_dict = {'num_y' : ny, 'num_x' : NX, 'wing_type' : 'CRM', 'symmetry' : symmetry, 'num_twist_cp' : NY} # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) surface = {} surface['symmetry'] = symmetry surface['type'] = 'aero' # Random perturbations to the mesh so that we don't mask errors subtractively. mesh[:, :, 0] += 0.05*np.random.random(mesh[:, :, 2].shape) mesh[:, :, 1] += 0.05*np.random.random(mesh[:, :, 2].shape) mesh[:, :, 2] = np.random.random(mesh[:, :, 2].shape) return mesh
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type' : 'tube', 'mesh' : mesh, 'radius_cp' : np.ones((5)) * 0.5, # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 't_over_c_cp' : np.array([0.15]), # maximum airfoil thickness 'thickness_cp' : np.ones((3)) * .1, 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, 'exact_failure_constraint' : False, } # Create the problem and assign the model group prob = Problem() ny = surf_dict['mesh'].shape[1] indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.ones((ny, 6)) * 2e5, units='N') indep_var_comp.add_output('load_factor', val=1.) struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['wing.structural_mass'][0], 117819.798089, 1e-4)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 3, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 6, 'chord_cos_spacing' : 0, 'span_cos_spacing' : 0, } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'wingbox', 'spar_thickness_cp' : np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp' : np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp' : np.array([4., 5., 8., 8., 8., 9.]), 'mesh' : mesh, 'data_x_upper' : upper_x, 'data_x_lower' : lower_x, 'data_y_upper' : upper_y, 'data_y_lower' : lower_y, 'strength_factor_for_upper_skin' : 1., # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.0078, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c' : 0.12, 'c_max_t' : .38, # chordwise location of maximum thickness 'with_viscous' : True, 'with_wave' : False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 73.1e9, # [Pa] Young's modulus 'G' : (73.1e9/2/1.33), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield' : (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho' : 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin' : 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 1.25, 'struct_weight_relief' : True, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, # Constraints 'exact_failure_constraint' : False, # if false, use KS function 'Wf_reserve' :15000., # [kg] reserve fuel mass } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=.85 * 295.07, units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=0.85) indep_var_comp.add_output('re', val=0.348*295.07*.85*1./(1.43*1e-5), units='1/m') indep_var_comp.add_output('rho', val=0.348, units='kg/m**3') indep_var_comp.add_output('CT', val=0.53/3600, units='1/s') indep_var_comp.add_output('R', val=14.307e6, units='m') indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'], units='kg') indep_var_comp.add_output('speed_of_sound', val=295.07, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: com_name = point_name + '.' + name + '_perf.' prob.model.connect(name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect(name + '.element_mass', point_name + '.coupled.' + name + '.element_mass') prob.model.connect('load_factor', point_name + '.coupled.' + name + '.load_factor') # Connect performance calculation variables prob.model.connect(name + '.nodes', com_name + 'nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') # Connect wingbox properties to von Mises stress calcs prob.model.connect(name + '.Qz', com_name + 'Qz') prob.model.connect(name + '.J', com_name + 'J') prob.model.connect(name + '.A_enc', com_name + 'A_enc') prob.model.connect(name + '.htop', com_name + 'htop') prob.model.connect(name + '.hbottom', com_name + 'hbottom') prob.model.connect(name + '.hfront', com_name + 'hfront') prob.model.connect(name + '.hrear', com_name + 'hrear') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.t_over_c', com_name + 't_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = True # Set up the problem prob.setup() AS_point.nonlinear_solver.options['iprint'] = 2 # # from openmdao.api import view_model # view_model(prob) prob.run_model() # prob.model.list_outputs(values=True, # implicit=False, # units=True, # shape=True, # bounds=True, # residuals=True, # scaling=True, # hierarchical=False, # print_arrays=True) # print(prob['AS_point_0.fuelburn'][0]) # print(prob['wing.structural_mass'][0]/1.25) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 112469.567077, 1e-5) assert_rel_error(self, prob['wing.structural_mass'][0]/1.25, 24009.5230566, 1e-5)
def get_default_surfaces(): # Create a dictionary to store options about the mesh mesh_dict = {'num_y' : 7, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) wing_dict = {'name' : 'wing', 'num_y' : 4, 'num_x' : 2, 'symmetry' : True, 'S_ref_type' : 'wetted', 'CL0' : 0.1, 'CD0' : 0.1, 'mesh' : mesh, # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, # if true, compute viscous drag 'with_wave' : False, # if true, computes wave drag 'fem_model_type' : 'tube', # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, # True to add the weight of the structure to the loads on the structure 'Wf_reserve' : 10000., } # Create a dictionary to store options about the mesh mesh_dict = {'num_y' : 5, 'num_x' : 3, 'wing_type' : 'rect', 'symmetry' : False} # Generate the aerodynamic mesh based on the previous dictionary mesh = generate_mesh(mesh_dict) tail_dict = {'name' : 'tail', 'num_y' : 5, 'num_x' : 3, 'symmetry' : False, 'mesh' : mesh} surfaces = [wing_dict, tail_dict] return surfaces
def test_multiple_masses(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 31, 'wing_type' : 'rect', 'span' : 10, 'symmetry' : True} mesh = generate_mesh(mesh_dict) surface = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type' : 'tube', 'mesh' : mesh, # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.5, # normalized chordwise location of the spar 't_over_c_cp' : np.array([0.15]), # maximum airfoil thickness 'thickness_cp' : np.ones((3)) * .1, 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, 'exact_failure_constraint' : False, } # Create the problem and assign the model group prob = Problem() ny = surface['mesh'].shape[1] surface['n_point_masses'] = 2 indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.zeros((ny, 6)), units='N') indep_var_comp.add_output('load_factor', val=1.) engine_thrusts = np.array([[10., 20.]]) point_mass_locations = np.array([[1., -1., 0.], [1., -2., 0.]]) indep_var_comp.add_output('engine_thrusts', val=engine_thrusts, units='N') indep_var_comp.add_output('point_mass_locations', val=point_mass_locations, units='m') struct_group = SpatialBeamAlone(surface=surface) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surface['name'], struct_group, promotes=['*']) # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['vonmises'][-1, 0], 137509.870021, 1e-4)
# chordwise (num_x) directions. Vary these to change the level of fidelity. num_y = 21 num_x = 3 # Create a mesh dictionary to feed to generate_mesh to actually create # the mesh array. mesh_dict = {'num_y' : num_y, 'num_x' : num_x, 'wing_type' : 'rect', 'symmetry' : True, 'span_cos_spacing' : 0.5, 'span' : 3.11, 'root_chord' : 0.3, } mesh = generate_mesh(mesh_dict) # Apply camber to the mesh camber = 1 - np.linspace(-1, 1, num_x) ** 2 camber *= 0.3 * 0.05 for ind_x in range(num_x): mesh[ind_x, :, 2] = camber[ind_x] # Introduce geometry manipulation variables to define the ScanEagle shape zshear_cp = np.zeros(10) zshear_cp[0] = .3 xshear_cp = np.zeros(10) xshear_cp[0] = .15
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'structural', 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type': 'tube', 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Structural values are based on aluminum 7075 'E': 70.e9, # [Pa] Young's modulus of the spar 'G': 30.e9, # [Pa] shear modulus of the spar 'yield': 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho': 3.e3, # [kg/m^3] material density 'fem_origin': 0.35, # normalized chordwise location of the spar 't_over_c_cp': np.array([0.15]), # maximum airfoil thickness 'thickness_cp': np.ones((3)) * .1, 'wing_weight_ratio': 2., 'struct_weight_relief': False, # True to add the weight of the structure to the loads on the structure 'exact_failure_constraint': False, } # Create the problem and assign the model group prob = Problem() ny = surf_dict['num_y'] indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.ones((ny, 6)) * 2e5, units='N') indep_var_comp.add_output('load_factor', val=2.) struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['wing.structural_weight'][0], 2437385.6547349701, 1e-4)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'thickness_cp' : np.array([.1, .2, .3]), 'twist_cp' : twist_cp, 'mesh' : mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, 'with_wave' : False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, # Constraints 'exact_failure_constraint' : False, # if false, use KS function } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=grav_constant * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('speed_of_sound', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') indep_var_comp.add_output('S_ref_total', val=150.0, units='m**2') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces,user_specified_Sref=True) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') prob.model.connect('S_ref_total', point_name + '.S_ref_total') for surface in surfaces: com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') # Set up the problem prob.setup() # from openmdao.api import view_model # view_model(prob) prob.run_model() assert_rel_error(self, prob['AS_point_0.CL'][0], 1.5775046966345903, 1e-6) assert_rel_error(self, prob['AS_point_0.CM'][1], -1.61358383281, 1e-5)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'rect', 'symmetry': True, 'span_cos_spacing': 1., 'span': 10, 'chord': 1 } mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type': 'tube', 'mesh': mesh, # Structural values are based on aluminum 7075 'E': 70.e9, # [Pa] Young's modulus of the spar 'G': 30.e9, # [Pa] shear modulus of the spar 'yield': 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho': 3.e3, # [kg/m^3] material density 'fem_origin': 0.35, # normalized chordwise location of the spar 't_over_c_cp': np.array([0.15]), # maximum airfoil thickness 'thickness_cp': np.ones((3)) * .0075, 'wing_weight_ratio': 1., 'struct_weight_relief': False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight': False, 'exact_failure_constraint': False, } # Create the problem and assign the model group prob = om.Problem() ny = surf_dict['mesh'].shape[1] loads = np.zeros((ny, 6)) loads[0, 2] = 1e4 indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('loads', val=loads, units='N') indep_var_comp.add_output('load_factor', val=1.) struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) prob.driver = om.ScipyOptimizeDriver() prob.driver.options['disp'] = True # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('wing.failure', upper=0.) prob.model.add_constraint('wing.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_objective('wing.structural_mass', scaler=1e-5) # Set up the problem prob.setup() # om.view_model(prob) prob.run_model() assert_rel_error(self, prob['wing.structural_mass'][0], 100.727314456, 1e-4) assert_rel_error(self, prob['wing.disp'][0, 2], 0.696503988153, 1e-6) np.testing.assert_allclose( prob['wing.disp'][1, :], np.array([-0., 0., 0.39925232, -0.19102602, 0., 0.]))
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 13, 'num_x': 2, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5, 'span_cos_spacing': 1. } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aerostruct', 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'thickness_cp': np.ones(2) * 0.06836728, 'twist_cp': twist_cp, 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c': 0.12, # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': False, # Structural values are based on aluminum 7075 'E': 70.e9, # [Pa] Young's modulus of the spar 'G': 30.e9, # [Pa] shear modulus of the spar 'yield': 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho': 3.e3, # [kg/m^3] material density 'fem_origin': 0.35, # normalized chordwise location of the spar 'wing_weight_ratio': 1., # Constraints 'exact_failure_constraint': False, # if false, use KS function } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5.) indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('a', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = Aerostruct(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('a', point_name + '.a') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: prob.model.connect('load_factor', name + '.load_factor') com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.K', point_name + '.coupled.' + name + '.K') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect( name + '.element_weights', point_name + '.coupled.' + name + '.element_weights') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') # Set up the problem prob.setup() # from openmdao.api import view_model # view_model(prob) prob.run_model() assert_rel_error(self, prob['AS_point_0.wing_perf.CL'][0], 0.501212803372, 1e-6) assert_rel_error(self, prob['AS_point_0.wing_perf.failure'][0], -0.434049851068, 1e-6) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 70365.875285, 1e-4) assert_rel_error(self, prob['AS_point_0.CM'][1], -0.129720748279, 1e-5)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'num_x' : 3, 'wing_type' : 'uCRM_based', 'symmetry' : True, 'chord_cos_spacing' : 0, 'span_cos_spacing' : 0, 'num_twist_cp' : 6, } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'mesh' : mesh, 'twist_cp' : np.array([4., 5., 8., 8., 8., 9.]), 'fem_model_type' : 'wingbox', 'data_x_upper' : upper_x, 'data_x_lower' : lower_x, 'data_y_upper' : upper_y, 'data_y_lower' : lower_y, 'spar_thickness_cp' : np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp' : np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'original_wingbox_airfoil_t_over_c' : 0.12, # Aerodynamic deltas. # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. # They can be used to account for things that are not included, such as contributions from the fuselage, nacelles, tail surfaces, etc. 'CL0' : 0.0, 'CD0' : 0.0078, 'with_viscous' : True, # if true, compute viscous drag 'with_wave' : True, # if true, compute wave drag # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 'c_max_t' : .38, # chordwise location of maximum thickness 't_over_c_cp' : np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), # Structural values are based on aluminum 7075 'E' : 73.1e9, # [Pa] Young's modulus 'G' : (73.1e9/2/1.33), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield' : (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho' : 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin' : 1.0, # the yield stress is multiplied by this factor for the upper skin 'wing_weight_ratio' : 1.25, 'exact_failure_constraint' : False, # if false, use KS function 'struct_weight_relief' : True, 'distributed_fuel_weight' : True, 'fuel_density' : 803., # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used) 'Wf_reserve' :15000., # [kg] reserve fuel mass } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=np.array([.85 * 295.07, .64 * 340.294]), units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('alpha_maneuver', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=np.array([0.85, 0.64])) indep_var_comp.add_output('re',val=np.array([0.348*295.07*.85*1./(1.43*1e-5), \ 1.225*340.294*.64*1./(1.81206*1e-5)]), units='1/m') indep_var_comp.add_output('rho', val=np.array([0.348, 1.225]), units='kg/m**3') indep_var_comp.add_output('CT', val=0.53/3600, units='1/s') indep_var_comp.add_output('R', val=14.307e6, units='m') indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'], units='kg') indep_var_comp.add_output('speed_of_sound', val= np.array([295.07, 340.294]), units='m/s') indep_var_comp.add_output('load_factor', val=np.array([1., 2.5])) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') indep_var_comp.add_output('fuel_mass', val=10000., units='kg') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aerostruct points for i in range(2): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aerostruct point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces, internally_connect_fuelburn=False) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v', src_indices=[i]) prob.model.connect('Mach_number', point_name + '.Mach_number', src_indices=[i]) prob.model.connect('re', point_name + '.re', src_indices=[i]) prob.model.connect('rho', point_name + '.rho', src_indices=[i]) prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound', src_indices=[i]) prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor', src_indices=[i]) prob.model.connect('fuel_mass', point_name + '.total_perf.L_equals_W.fuelburn') prob.model.connect('fuel_mass', point_name + '.total_perf.CG.fuelburn') for surface in surfaces: name = surface['name'] if surf_dict['distributed_fuel_weight']: prob.model.connect('load_factor', point_name + '.coupled.load_factor', src_indices=[i]) com_name = point_name + '.' + name + '_perf.' prob.model.connect(name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') if surf_dict['struct_weight_relief']: prob.model.connect(name + '.element_mass', point_name + '.coupled.' + name + '.element_mass') # Connect performance calculation variables prob.model.connect(name + '.nodes', com_name + 'nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') # Connect wingbox properties to von Mises stress calcs prob.model.connect(name + '.Qz', com_name + 'Qz') prob.model.connect(name + '.J', com_name + 'J') prob.model.connect(name + '.A_enc', com_name + 'A_enc') prob.model.connect(name + '.htop', com_name + 'htop') prob.model.connect(name + '.hbottom', com_name + 'hbottom') prob.model.connect(name + '.hfront', com_name + 'hfront') prob.model.connect(name + '.hrear', com_name + 'hrear') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.t_over_c', com_name + 't_over_c') prob.model.connect('alpha', 'AS_point_0' + '.alpha') prob.model.connect('alpha_maneuver', 'AS_point_1' + '.alpha') # Here we add the fuel volume constraint componenet to the model prob.model.add_subsystem('fuel_vol_delta', WingboxFuelVolDelta(surface=surface)) prob.model.connect('wing.struct_setup.fuel_vols', 'fuel_vol_delta.fuel_vols') prob.model.connect('AS_point_0.fuelburn', 'fuel_vol_delta.fuelburn') if surf_dict['distributed_fuel_weight']: prob.model.connect('wing.struct_setup.fuel_vols', 'AS_point_0.coupled.wing.struct_states.fuel_vols') prob.model.connect('fuel_mass', 'AS_point_0.coupled.wing.struct_states.fuel_mass') prob.model.connect('wing.struct_setup.fuel_vols', 'AS_point_1.coupled.wing.struct_states.fuel_vols') prob.model.connect('fuel_mass', 'AS_point_1.coupled.wing.struct_states.fuel_mass') comp = ExecComp('fuel_diff = (fuel_mass - fuelburn) / fuelburn', units='kg') prob.model.add_subsystem('fuel_diff', comp, promotes_inputs=['fuel_mass'], promotes_outputs=['fuel_diff']) prob.model.connect('AS_point_0.fuelburn', 'fuel_diff.fuelburn') ## Use these settings if you do not have pyOptSparse or SNOPT prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-8 recorder = SqliteRecorder("unit_test.db") prob.driver.add_recorder(recorder) # We could also just use prob.driver.recording_options['includes']=['*'] here, but for large meshes the database file becomes extremely large. So we just select the variables we need. prob.driver.recording_options['includes'] = [ 'alpha', 'rho', 'v', 'cg', 'AS_point_1.cg', 'AS_point_0.cg', 'AS_point_0.coupled.wing_loads.loads', 'AS_point_1.coupled.wing_loads.loads', 'AS_point_0.coupled.wing.normals', 'AS_point_1.coupled.wing.normals', 'AS_point_0.coupled.wing.widths', 'AS_point_1.coupled.wing.widths', 'AS_point_0.coupled.aero_states.wing_sec_forces', 'AS_point_1.coupled.aero_states.wing_sec_forces', 'AS_point_0.wing_perf.CL1', 'AS_point_1.wing_perf.CL1', 'AS_point_0.coupled.wing.S_ref', 'AS_point_1.coupled.wing.S_ref', 'wing.geometry.twist', 'wing.mesh', 'wing.skin_thickness', 'wing.spar_thickness', 'wing.t_over_c', 'wing.structural_mass', 'AS_point_0.wing_perf.vonmises', 'AS_point_1.wing_perf.vonmises', 'AS_point_0.coupled.wing.def_mesh', 'AS_point_1.coupled.wing.def_mesh', ] prob.driver.recording_options['record_objectives'] = True prob.driver.recording_options['record_constraints'] = True prob.driver.recording_options['record_desvars'] = True prob.driver.recording_options['record_inputs'] = True prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) prob.model.add_design_var('wing.twist_cp', lower=-15., upper=15., scaler=0.1) prob.model.add_design_var('wing.spar_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.geometry.t_over_c_cp', lower=0.07, upper=0.2, scaler=10.) prob.model.add_design_var('fuel_mass', lower=0., upper=2e5, scaler=1e-5) prob.model.add_design_var('alpha_maneuver', lower=-15., upper=15) prob.model.add_constraint('AS_point_0.CL', equals=0.5) prob.model.add_constraint('AS_point_1.L_equals_W', equals=0.) prob.model.add_constraint('AS_point_1.wing_perf.failure', upper=0.) prob.model.add_constraint('fuel_vol_delta.fuel_vol_delta', lower=0.) prob.model.add_constraint('fuel_diff', equals=0.) # Set up the problem prob.setup() prob.run_driver() # print(prob['AS_point_0.fuelburn'][0]) # print(prob['wing.structural_mass'][0]/surf_dict['wing_weight_ratio']) # print(prob['wing.geometry.t_over_c_cp']) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 101937.827384, 1e-5) assert_rel_error(self, prob['wing.structural_mass'][0]/surf_dict['wing_weight_ratio'], 36539.6437566, 1e-5) assert_rel_error(self, prob['wing.geometry.t_over_c_cp'], np.array([0.10247881, 0.08207636, 0.11114547, 0.13114547, 0.10207636, 0.09365598]), 1e-5)
def test(self): import numpy as np import openmdao.api as om from openaerostruct.geometry.utils import generate_mesh from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.aerodynamics.aero_groups import AeroPoint from openaerostruct.common.atmos_group import AtmosGroup # Create a dictionary to store options about the mesh mesh_dict = { 'num_y': 7, 'num_x': 2, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5 } # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) # Create a dictionary with info and options about the aerodynamic # lifting surface surface = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'twist_cp': twist_cp, 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, # if true, compute viscous drag 'with_wave': False, # if true, compute wave drag } # Create the OpenMDAO problem prob = om.Problem() # Create an independent variable component that will supply the flow # conditions to the problem. indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('altitude', val=35000., units='ft') # Add this IndepVarComp to the problem model prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Add this IndepVarComp to the problem model prob.model.add_subsystem('atmos', AtmosGroup(), promotes=['*']) # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) prob.model.add_subsystem(surface['name'], geom_group) # Create the aero point group, which contains the actual aerodynamic # analyses aero_group = AeroPoint(surfaces=[surface]) point_name = 'aero_point_0' prob.model.add_subsystem( point_name, aero_group, promotes_inputs=['v', 'alpha', 'Mach_number', 're', 'rho', 'cg']) name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') # Import the Scipy Optimizer and set the driver of the problem to use # it, which defaults to an SLSQP optimization method prob.driver = om.ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5) prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4) # Set up and run the optimization problem prob.setup() # prob.check_partials(compact_print=True) # exit() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.030471796067577953, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -1.7331840488188963, 1e-6)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 2, 'wing_type' : 'rect', 'symmetry' : False} mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aero', 'symmetry' : False, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'twist_cp' : np.array([0.]), 'mesh' : mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, 'with_wave' : False, # if true, compute wave drag } surfaces = [surf_dict] # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('beta', val=-5, units='deg') indep_var_comp.add_output('omega', val=np.array([0.0, 0.0, -30.0]), units='deg/s') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces, rotational=True) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('omega', point_name + '.omega') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03487336411850356, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.4615561217697067, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][0], 0.007313681048738922, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -0.11507021674483686, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][2], 0.0, 1e-6)
def test(self): import numpy as np from openaerostruct.geometry.utils import generate_mesh from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint from openaerostruct.utils.constants import grav_constant import openmdao.api as om # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 2, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surface = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'thickness_cp': np.array([.1, .2, .3]), 'twist_cp': twist_cp, 'mesh': mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, 'with_wave': False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E': 70.e9, # [Pa] Young's modulus of the spar 'G': 30.e9, # [Pa] shear modulus of the spar 'yield': 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho': 3.e3, # [kg/m^3] material density 'fem_origin': 0.35, # normalized chordwise location of the spar 'wing_weight_ratio': 2., 'struct_weight_relief': False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight': False, # Constraints 'exact_failure_constraint': False, # if false, use KS function } # Create the problem and assign the model group prob = om.Problem() # Add problem information as an independent variables component indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=grav_constant * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('speed_of_sound', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) aerostruct_group = AerostructGeometry(surface=surface) name = 'wing' # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) point_name = 'AS_point_0' # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=[surface]) prob.model.add_subsystem(point_name, AS_point, promotes_inputs=[ 'v', 'alpha', 'Mach_number', 're', 'rho', 'CT', 'R', 'W0', 'speed_of_sound', 'empty_cg', 'load_factor' ]) com_name = point_name + '.' + name + '_perf' prob.model.connect( name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') prob.driver = om.ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 recorder = om.SqliteRecorder("aerostruct.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True prob.driver.recording_options['includes'] = ['*'] # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-10., upper=10.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # Set up the problem prob.setup(check=True) # Inserting a small unit test here. Verify that beta is correctly promoted in an Aerostruct # group. assert_rel_error(self, prob['AS_point_0.beta'], 0.0) prob.run_driver() assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 97696.33252514644, 1e-8)
def setup(self): rv_dict = self.options['rv_dict'] # Create a dictionary to store options about the mesh mesh_dict = {'num_y' : 7, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) # Create a dictionary with info and options about the aerodynamic # lifting surface surface = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aero', 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'twist_cp' : twist_cp, 'mesh' : mesh, 'num_x' : mesh.shape[0], 'num_y' : mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, # if true, compute viscous drag 'with_wave' : False, # if true, compute wave drag } indep_var_comp = IndepVarComp() if "v" not in rv_dict: indep_var_comp.add_output('v', val=248.136, units='m/s') if "alpha" not in rv_dict: indep_var_comp.add_output('alpha', val=5., units='deg') if "Mach_number" not in rv_dict: indep_var_comp.add_output('M', val=0.84) if "re" not in rv_dict: indep_var_comp.add_output('re', val=1.e6, units='1/m') if "rho" not in rv_dict: indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') # Add this IndepVarComp to the problem model self.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) self.add_subsystem(surface['name'], geom_group) # Create the aero point group, which contains the actual aerodynamic # analyses aero_group = AeroPoint(surfaces=[surface]) point_name = 'aero_point_0' self.add_subsystem(point_name, aero_group, promotes_inputs=['v', 'alpha', 'Mach_number', 're', 'rho', 'cg']) name = surface['name'] # Connect the mesh from the geometry component to the analysis point self.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. self.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') self.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c')
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'rect', 'symmetry': False, 'span': 10., 'chord': 1, 'span_cos_spacing': 1. } mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aero', 'symmetry': False, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'twist_cp': np.zeros(5), 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.0, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.12]), # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, # if true, compute viscous drag 'with_wave': False, # if true, compute wave drag } surfaces = [surf_dict] # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect( name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect( name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() # # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5) prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4) # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], .45655138, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.018942466133780547, 1e-6)
def test(self): from openaerostruct.geometry.utils import generate_mesh, write_FFD_file from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint from openmdao.api import IndepVarComp, Problem, Group, SqliteRecorder from pygeo import DVGeometry # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aerostruct', 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'thickness_cp' : np.array([.1, .2, .3]), 'mesh' : mesh, 'geom_manipulator' : 'FFD', 'mx' : 2, 'my' : 3, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, 'with_wave' : False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, # Constraints 'exact_failure_constraint' : False, # if false, use KS function } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('a', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] filename = write_FFD_file(surface, surface['mx'], surface['my']) DVGeo = DVGeometry(filename) aerostruct_group = AerostructGeometry(surface=surface, DVGeo=DVGeo) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('a', point_name + '.a') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: prob.model.connect('load_factor', name + '.load_factor') com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.K', point_name + '.coupled.' + name + '.K') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') # Import the Scipy Optimizer and set the driver of the problem to use # it, which defaults to an SLSQP optimization method from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() recorder = SqliteRecorder("aerostruct_ffd.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True prob.driver.recording_options['includes'] = ['*'] # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.shape', lower=-3, upper=2) prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-10., upper=10.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # iprofile.setup() # iprofile.start() # Set up the problem prob.setup() # from openmdao.api import view_model # view_model(prob, outfile='aerostruct_ffd', show_browser=False) # prob.run_model() prob.run_driver() # prob.check_partials(compact_print=True) # print("\nWing CL:", prob['aero_point_0.wing_perf.CL']) # print("Wing CD:", prob['aero_point_0.wing_perf.CD']) # from helper import plot_3d_points # # mesh = prob['aero_point_0.wing.def_mesh'] # plot_3d_points(mesh) # # filename = mesh_dict['wing_type'] + '_' + str(mesh_dict['num_x']) + '_' + str(mesh_dict['num_y']) # filename += '_' + str(surf_dict['mx']) + '_' + str(surf_dict['my']) + '.mesh' # np.save(filename, mesh) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 104675.0989232741, 1e-3)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 3, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5, 'span_cos_spacing' : 0.} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'mesh' : mesh, 'twist_cp' : twist_cp, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, # if true, compute viscous drag 'with_wave' : False, # if true, compute wave drag 'span' : 10. } surfaces = [surf_dict] n_points = 2 # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=6.64, units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) indep_var_comp = IndepVarComp() indep_var_comp.add_output('t_over_c_cp', val=np.array([0.15])) indep_var_comp.add_output('span', val=12., units='m') indep_var_comp.add_output('twist_cp_0', val=np.zeros((5)), units='deg') indep_var_comp.add_output('twist_cp_1', val=np.zeros((5)), units='deg') prob.model.add_subsystem('geom_vars', indep_var_comp, promotes=['*']) # Loop through and add a certain number of aero points for i in range(n_points): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: geom_group = Geometry(surface=surface, connect_geom_DVs=False) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. aero_group.add_subsystem(surface['name'] + '_geom', geom_group) name = surface['name'] prob.model.connect(point_name + '.CD', 'multi_CD.' + str(i) + '_CD') # Connect the mesh from the geometry component to the analysis point prob.model.connect(point_name + '.' + name + '_geom.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(point_name + '.' + name + '_geom.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect(point_name + '.' + name + '_geom.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') # prob.model.connect(point_name + '.' + name + '_geom.span', 'span_diff_comp.span_' + str(i)) # Connect geometric design variables to each point prob.model.connect('t_over_c_cp', 'aero_point_0.wing_geom.t_over_c_cp') prob.model.connect('t_over_c_cp', 'aero_point_1.wing_geom.t_over_c_cp') prob.model.connect('span', 'aero_point_0.wing_geom.span') prob.model.connect('span', 'aero_point_1.wing_geom.span') prob.model.connect('twist_cp_0', 'aero_point_0.wing_geom.twist_cp') prob.model.connect('twist_cp_1', 'aero_point_1.wing_geom.twist_cp') prob.model.add_subsystem('multi_CD', MultiCD(n_points=n_points), promotes_outputs=['CD']) from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('alpha', lower=-15, upper=15) prob.model.add_design_var('twist_cp_0', lower=-5, upper=8) prob.model.add_design_var('twist_cp_1', lower=-5, upper=8) prob.model.add_design_var('span', lower=2, upper=15) prob.model.add_constraint('aero_point_0.wing_perf.CL', equals=0.45) prob.model.add_constraint('aero_point_1.wing_perf.CL', equals=0.50) prob.model.add_objective('CD', scaler=1e4) # Set up the problem prob.setup() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.45, 1e-6) assert_rel_error(self, prob['aero_point_1.wing_perf.CL'][0], 0.5, 1e-6) assert_rel_error(self, prob['twist_cp_0'], np.array([ 8., -1.21207749, -2.42415497, -1.21207749, -1.0821358 ]), 1e-6) assert_rel_error(self, prob['twist_cp_1'], np.array([ 8., -0.02049115, -0.0409823, -0.02049115, 0.77903674]), 1e-6) assert_rel_error(self, prob['aero_point_1.wing_perf.CL'][0], 0.5, 1e-6)
def test(self): """ This is an opt problem that tests the wingbox model with wave drag and the fuel vol constraint """ # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 6, 'chord_cos_spacing' : 0, 'span_cos_spacing' : 0, } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'wingbox', 'spar_thickness_cp' : np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp' : np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp' : np.array([4., 5., 8., 8., 8., 9.]), 'mesh' : mesh, 'data_x_upper' : upper_x, 'data_x_lower' : lower_x, 'data_y_upper' : upper_y, 'data_y_lower' : lower_y, 'strength_factor_for_upper_skin' : 1., # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.0078, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c' : 0.12, 'c_max_t' : .38, # chordwise location of maximum thickness 'with_viscous' : True, 'with_wave' : True, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 73.1e9, # [Pa] Young's modulus 'G' : (73.1e9/2/1.33), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield' : (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho' : 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin' : 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 1.25, 'struct_weight_relief' : True, 'distributed_fuel_weight' : True, # Constraints 'exact_failure_constraint' : False, # if false, use KS function 'fuel_density' : 803., # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used) 'Wf_reserve' :15000., # [kg] reserve fuel mass } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=.85 * 295.07, units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=0.85) indep_var_comp.add_output('re', val=0.348*295.07*.85*1./(1.43*1e-5), units='1/m') indep_var_comp.add_output('rho', val=0.348, units='kg/m**3') indep_var_comp.add_output('CT', val=0.53/3600, units='1/s') indep_var_comp.add_output('R', val=14.307e6, units='m') indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'], units='kg') indep_var_comp.add_output('speed_of_sound', val=295.07, units='m/s') indep_var_comp.add_output('load_factor', val=np.array([1., 2.5])) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') indep_var_comp.add_output('fuel_mass', val=10000., units='kg') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(2): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces, internally_connect_fuelburn=False) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor', src_indices=[i]) prob.model.connect('fuel_mass', point_name + '.total_perf.L_equals_W.fuelburn') prob.model.connect('fuel_mass', point_name + '.total_perf.CG.fuelburn') for surface in surfaces: prob.model.connect('load_factor', point_name + '.coupled.load_factor', src_indices=[i]) com_name = point_name + '.' + name + '_perf.' prob.model.connect(name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect(name + '.element_mass', point_name + '.coupled.' + name + '.element_mass') # Connect performance calculation variables prob.model.connect(name + '.nodes', com_name + 'nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') # Connect wingbox properties to von Mises stress calcs prob.model.connect(name + '.Qz', com_name + 'Qz') prob.model.connect(name + '.J', com_name + 'J') prob.model.connect(name + '.A_enc', com_name + 'A_enc') prob.model.connect(name + '.htop', com_name + 'htop') prob.model.connect(name + '.hbottom', com_name + 'hbottom') prob.model.connect(name + '.hfront', com_name + 'hfront') prob.model.connect(name + '.hrear', com_name + 'hrear') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.t_over_c', com_name + 't_over_c') #======================================================================================= # Here we add the fuel volume constraint componenet to the model #======================================================================================= prob.model.add_subsystem('fuel_vol_delta', WingboxFuelVolDelta(surface=surface)) prob.model.connect('wing.struct_setup.fuel_vols', 'fuel_vol_delta.fuel_vols') prob.model.connect('AS_point_0.fuelburn', 'fuel_vol_delta.fuelburn') prob.model.connect('wing.struct_setup.fuel_vols', 'AS_point_0.coupled.wing.struct_states.fuel_vols') prob.model.connect('fuel_mass', 'AS_point_0.coupled.wing.struct_states.fuel_mass') prob.model.connect('wing.struct_setup.fuel_vols', 'AS_point_1.coupled.wing.struct_states.fuel_vols') prob.model.connect('fuel_mass', 'AS_point_1.coupled.wing.struct_states.fuel_mass') comp = ExecComp('fuel_diff = (fuel_mass - fuelburn) / fuelburn', units='kg') prob.model.add_subsystem('fuel_diff', comp, promotes_inputs=['fuel_mass'], promotes_outputs=['fuel_diff']) prob.model.connect('AS_point_0.fuelburn', 'fuel_diff.fuelburn') comp = ExecComp('fuel_diff_25 = (fuel_mass - fuelburn) / fuelburn') prob.model.add_subsystem('fuel_diff_25', comp, promotes_inputs=['fuel_mass'], promotes_outputs=['fuel_diff_25']) prob.model.connect('AS_point_1.fuelburn', 'fuel_diff_25.fuelburn') #======================================================================================= #======================================================================================= from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 prob.driver.options['maxiter'] = 5 # from openmdao.api import pyOptSparseDriver # prob.driver = pyOptSparseDriver() # prob.driver.add_recorder(SqliteRecorder("cases.sql")) # prob.driver.options['optimizer'] = "SNOPT" # prob.driver.opt_settings['Major optimality tolerance'] = 1e-6 # prob.driver.opt_settings['Major feasibility tolerance'] = 1e-8 # prob.driver.opt_settings['Major iterations limit'] = 200 prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) prob.model.add_design_var('wing.twist_cp', lower=-15., upper=15., scaler=0.1) prob.model.add_design_var('wing.spar_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.geometry.t_over_c_cp', lower=0.07, upper=0.2, scaler=10.) prob.model.add_design_var('fuel_mass', lower=0., upper=2e5, scaler=1e-5) prob.model.add_constraint('AS_point_0.CL', equals=0.5) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) #======================================================================================= # Here we add the fuel volume constraint #======================================================================================= prob.model.add_constraint('fuel_vol_delta.fuel_vol_delta', lower=0.) prob.model.add_constraint('fuel_diff', equals=0.) prob.model.add_constraint('fuel_diff_25', equals=0.) #======================================================================================= #======================================================================================= # Set up the problem prob.setup() # from openmdao.api import view_model # view_model(prob) prob.run_model() # Check the partials at the initial point in the design space, # only care about relative error data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40) assert_check_partials(data, atol=1e20, rtol=1e-6) # Run the optimizer for 5 iterations prob.run_driver() # Check the partials at this point in the design space data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40) assert_check_partials(data, atol=1e20, rtol=1e-6)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'structural', 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type': 'tube', 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Structural values are based on aluminum 7075 'E': 70.e9, # [Pa] Young's modulus of the spar 'G': 30.e9, # [Pa] shear modulus of the spar 'yield': 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho': 3.e3, # [kg/m^3] material density 'fem_origin': 0.35, # normalized chordwise location of the spar 't_over_c_cp': np.array([0.15]), # maximum airfoil thickness 'thickness_cp': np.ones((3)) * .1, 'wing_weight_ratio': 2., 'exact_failure_constraint': False, } # Create the problem and assign the model group prob = Problem() ny = surf_dict['num_y'] indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.zeros((ny, 6)), units='N') indep_var_comp.add_output('load_factor', val=1.) struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('wing.failure', upper=0.) prob.model.add_constraint('wing.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_objective('wing.structural_weight', scaler=1e-5) # Set up the problem prob.setup() from openmdao.api import view_model prob.run_driver() assert_rel_error(self, prob['wing.structural_weight'][0], 133427.40492929096, 1e-4) assert_rel_error(self, prob['wing.disp'][1, 2], 0., 1e-4)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'wing_type' : 'uCRM_based', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'wingbox', 'symmetry' : True, 'spar_thickness_cp' : np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp' : np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp' : np.array([4., 5., 8., 8., 8., 9.]), 'mesh' : mesh, 'data_x_upper' : upper_x, 'data_x_lower' : lower_x, 'data_y_upper' : upper_y, 'data_y_lower' : lower_y, 'strength_factor_for_upper_skin' : 1., # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.0078, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c' : 0.12, 'c_max_t' : .38, # chordwise location of maximum thickness 'with_viscous' : True, 'with_wave' : True, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 73.1e9, # [Pa] Young's modulus 'G' : (73.1e9/2/1.33), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield' : (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho' : 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin' : 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 1.25, 'struct_weight_relief' : False, 'distributed_fuel_weight' : True, # Constraints 'exact_failure_constraint' : True, # if false, use KS function 'fuel_density' : 803., # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used) 'Wf_reserve' :15000., # [kg] reserve fuel mass } # Create the problem and assign the model group prob = Problem() ny = surf_dict['mesh'].shape[1] indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.ones((ny, 6)) * 2e5, units='N') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('fuel_mass', val=10000., units='kg') struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) if surf_dict['distributed_fuel_weight']: prob.model.connect('wing.fuel_mass', 'wing.struct_states.fuel_mass') prob.model.connect('wing.struct_setup.fuel_vols', 'wing.struct_states.fuel_vols') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.spar_thickness_cp', lower=0.01, upper=0.5, ref=1e-1) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.01, upper=0.5, ref=1e-1) prob.model.add_constraint('wing.failure', upper=0.) #prob.model.add_constraint('wing.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_objective('wing.structural_mass', scaler=1e-5) # Set up the problem prob.setup(force_alloc_complex=False) prob.run_model() data = prob.check_partials(compact_print=True, out_stream=None, method='fd') assert_check_partials(data, atol=1e20, rtol=1e-6) prob.run_driver() assert_rel_error(self, prob['wing.structural_mass'], 16704.07393593, 1e-6)
def test(self): import numpy as np from openaerostruct.geometry.utils import generate_mesh from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint from openaerostruct.utils.constants import grav_constant from openmdao.api import IndepVarComp, Problem, Group, SqliteRecorder # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 11, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surface = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'thickness_cp' : np.array([.1, .2, .3]), 'twist_cp' : twist_cp, 'mesh' : mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, 'with_wave' : False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, # Constraints 'exact_failure_constraint' : False, # if false, use KS function } # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=[248.136, 0.5 * 340.], units='m/s') indep_var_comp.add_output('alpha', val=[5., 10.], units='deg') indep_var_comp.add_output('Mach_number', val=[0.84, 0.5]) indep_var_comp.add_output('re', val=[1.e6, 0.5e6], units='1/m') indep_var_comp.add_output('rho', val=[0.38, .764], units='kg/m**3') indep_var_comp.add_output('CT', val=grav_constant * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('speed_of_sound', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=[1., 2.5]) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Add morphing variables as an independent variables component morphing_vars = IndepVarComp() morphing_vars.add_output('t_over_c_cp', val=np.array([0.15])) morphing_vars.add_output('thickness_cp', val=np.array([0.01, 0.01, 0.01]), units='m') morphing_vars.add_output('twist_cp_0', val=np.array([2., 3., 4., 4., 4.]), units='deg') morphing_vars.add_output('twist_cp_1', val=np.array([4., 4., 4., 5., 6.]), units='deg') prob.model.add_subsystem('morphing_vars', morphing_vars, promotes=['*']) # Connect geometric design variables to each point prob.model.connect('t_over_c_cp', 'AS_point_0.wing.geometry.t_over_c_cp') prob.model.connect('t_over_c_cp', 'AS_point_1.wing.geometry.t_over_c_cp') prob.model.connect('thickness_cp', 'AS_point_0.wing.tube_group.thickness_cp') prob.model.connect('thickness_cp', 'AS_point_1.wing.tube_group.thickness_cp') prob.model.connect('twist_cp_0', 'AS_point_0.wing.geometry.twist_cp') prob.model.connect('twist_cp_1', 'AS_point_1.wing.geometry.twist_cp') for point in range(2): name = 'wing' point_name = 'AS_point_{}'.format(point) # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=[surface]) prob.model.add_subsystem(point_name, AS_point) aerostruct_group = AerostructGeometry(surface=surface, connect_geom_DVs=False) AS_point.add_subsystem(name, aerostruct_group) # Connect flow properties to the analysis point prob.model.connect('alpha', point_name + '.alpha', src_indices=[point]) prob.model.connect('v', point_name + '.v', src_indices=[point]) prob.model.connect('Mach_number', point_name + '.Mach_number', src_indices=[point]) prob.model.connect('re', point_name + '.re', src_indices=[point]) prob.model.connect('rho', point_name + '.rho', src_indices=[point]) prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor', src_indices=[point]) com_name = point_name + '.' + name + '_perf' AS_point.connect(name + '.local_stiff_transformed', 'coupled.' + name + '.local_stiff_transformed') AS_point.connect(name + '.nodes', 'coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh AS_point.connect(name + '.mesh', 'coupled.' + name + '.mesh') # Connect performance calculation variables AS_point.connect(name + '.radius', name + '_perf' + '.radius') AS_point.connect(name + '.thickness', name + '_perf' + '.thickness') AS_point.connect(name + '.nodes', name + '_perf' + '.nodes') AS_point.connect(name + '.cg_location', 'total_perf.' + name + '_cg_location') AS_point.connect(name + '.structural_mass', 'total_perf.' + name + '_structural_mass') AS_point.connect(name + '.geometry.t_over_c', name + '_perf' + '.t_over_c') AS_point.connect(name + '.geometry.t_over_c', name + '.t_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 prob.driver.options['maxiter'] = 2 recorder = SqliteRecorder("morphing_aerostruct.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True prob.driver.recording_options['includes'] = ['*'] # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('twist_cp_0', lower=-10., upper=15.) prob.model.add_design_var('twist_cp_1', lower=-10., upper=15.) prob.model.add_design_var('thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.) prob.model.add_constraint('AS_point_1.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_1.wing_perf.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-15., upper=15.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_constraint('AS_point_1.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # Set up the problem prob.setup(check=True) # from openmdao.api import view_model # view_model(prob) prob.run_model() # Check the partials at the initial point in the design space, # only care about relative error data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40) assert_check_partials(data, atol=1e20, rtol=1e-6) # Run the optimizer for 2 iterations prob.run_driver() # Check the partials at this point in the design space data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40) assert_check_partials(data, atol=1e20, rtol=1e-6)
def test(self): # Create a dictionary to store options about the surface # OM: vary 'num_y' and 'num_x' to change the size of the mesh mesh_dict = {'num_y' : 5, 'num_x' : 2, 'wing_type' : 'rect', 'symmetry' : True} mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aerostruct', 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'thickness_cp' : np.ones((2)) * .1, 'twist_cp' : np.ones((2)), 'mesh' : mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, 'with_wave' : False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, # Constraints 'exact_failure_constraint' : False, # if false, use KS function } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=9., units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('a', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('a', point_name + '.a') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: prob.model.connect('load_factor', name + '.load_factor') com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.K', point_name + '.coupled.' + name + '.K') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-10., upper=10.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # Set up the problem prob.setup() prob.run_driver() assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 70754.19144483653, 1e-5)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'wing_type': 'uCRM_based', 'symmetry': True, 'num_twist_cp': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'wingbox', 'symmetry': True, 'spar_thickness_cp': np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp': np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp': np.array([4., 5., 8., 8., 8., 9.]), 'mesh': mesh, 'data_x_upper': upper_x, 'data_x_lower': lower_x, 'data_y_upper': upper_y, 'data_y_lower': lower_y, 'strength_factor_for_upper_skin': 1., # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.0078, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c': 0.12, 'c_max_t': .38, # chordwise location of maximum thickness 'with_viscous': True, 'with_wave': True, # if true, compute wave drag # Structural values are based on aluminum 7075 'E': 73.1e9, # [Pa] Young's modulus 'G': ( 73.1e9 / 2 / 1.33 ), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield': (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho': 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin': 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio': 1.25, 'struct_weight_relief': False, 'distributed_fuel_weight': True, # Constraints 'exact_failure_constraint': True, # if false, use KS function 'fuel_density': 803., # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used) 'Wf_reserve': 15000., # [kg] reserve fuel mass } # Create the problem and assign the model group prob = Problem() ny = surf_dict['mesh'].shape[1] indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.ones((ny, 6)) * 2e5, units='N') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('fuel_mass', val=10000., units='kg') struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) if surf_dict['distributed_fuel_weight']: prob.model.connect('wing.fuel_mass', 'wing.struct_states.fuel_mass') prob.model.connect('wing.struct_setup.fuel_vols', 'wing.struct_states.fuel_vols') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.spar_thickness_cp', lower=0.01, upper=0.5, ref=1e-1) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.01, upper=0.5, ref=1e-1) prob.model.add_constraint('wing.failure', upper=0.) #prob.model.add_constraint('wing.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_objective('wing.structural_weight', scaler=1e-5) # Set up the problem prob.setup(force_alloc_complex=False) prob.run_model() data = prob.check_partials(compact_print=True, out_stream=None, method='fd') assert_check_partials(data, atol=1e20, rtol=1e-6) prob.run_driver() assert_rel_error(self, prob['wing.structural_weight'], 163866.96531213, 1e-6)
def test(self): """ This is an opt problem that tests the wingbox model with wave drag and the fuel vol constraint """ # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 6, 'chord_cos_spacing' : 0, 'span_cos_spacing' : 0, } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'wingbox', 'spar_thickness_cp' : np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp' : np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp' : np.array([4., 5., 8., 8., 8., 9.]), 'mesh' : mesh, 'data_x_upper' : upper_x, 'data_x_lower' : lower_x, 'data_y_upper' : upper_y, 'data_y_lower' : lower_y, 'strength_factor_for_upper_skin' : 1., # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.0078, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c' : 0.12, 'c_max_t' : .38, # chordwise location of maximum thickness 'with_viscous' : True, 'with_wave' : True, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 73.1e9, # [Pa] Young's modulus 'G' : (73.1e9/2/1.33), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield' : (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho' : 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin' : 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 1.25, 'struct_weight_relief' : True, 'distributed_fuel_weight' : True, # Constraints 'exact_failure_constraint' : False, # if false, use KS function 'fuel_density' : 803., # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used) 'Wf_reserve' :15000., # [kg] reserve fuel mass } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=.85 * 295.07, units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=0.85) indep_var_comp.add_output('re', val=0.348*295.07*.85*1./(1.43*1e-5), units='1/m') indep_var_comp.add_output('rho', val=0.348, units='kg/m**3') indep_var_comp.add_output('CT', val=0.53/3600, units='1/s') indep_var_comp.add_output('R', val=14.307e6, units='m') indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'], units='kg') indep_var_comp.add_output('speed_of_sound', val=295.07, units='m/s') indep_var_comp.add_output('load_factor', val=np.array([1., 2.5])) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') indep_var_comp.add_output('fuel_mass', val=10000., units='kg') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(2): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces, internally_connect_fuelburn=False) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor', src_indices=[i]) prob.model.connect('fuel_mass', point_name + '.total_perf.L_equals_W.fuelburn') prob.model.connect('fuel_mass', point_name + '.total_perf.CG.fuelburn') for surface in surfaces: if i==0: prob.model.connect('load_factor', name + '.load_factor', src_indices=[i]) prob.model.connect('load_factor', point_name + '.coupled.load_factor', src_indices=[i]) com_name = point_name + '.' + name + '_perf.' prob.model.connect(name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect(name + '.element_weights', point_name + '.coupled.' + name + '.element_weights') # Connect performance calculation variables prob.model.connect(name + '.nodes', com_name + 'nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') # Connect wingbox properties to von Mises stress calcs prob.model.connect(name + '.Qz', com_name + 'Qz') prob.model.connect(name + '.J', com_name + 'J') prob.model.connect(name + '.A_enc', com_name + 'A_enc') prob.model.connect(name + '.htop', com_name + 'htop') prob.model.connect(name + '.hbottom', com_name + 'hbottom') prob.model.connect(name + '.hfront', com_name + 'hfront') prob.model.connect(name + '.hrear', com_name + 'hrear') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.t_over_c', com_name + 't_over_c') #======================================================================================= # Here we add the fuel volume constraint componenet to the model #======================================================================================= prob.model.add_subsystem('fuel_vol_delta', WingboxFuelVolDelta(surface=surface)) prob.model.connect('wing.struct_setup.fuel_vols', 'fuel_vol_delta.fuel_vols') prob.model.connect('AS_point_0.fuelburn', 'fuel_vol_delta.fuelburn') prob.model.connect('wing.struct_setup.fuel_vols', 'AS_point_0.coupled.wing.struct_states.fuel_vols') prob.model.connect('fuel_mass', 'AS_point_0.coupled.wing.struct_states.fuel_mass') prob.model.connect('wing.struct_setup.fuel_vols', 'AS_point_1.coupled.wing.struct_states.fuel_vols') prob.model.connect('fuel_mass', 'AS_point_1.coupled.wing.struct_states.fuel_mass') comp = ExecComp('fuel_diff = (fuel_mass - fuelburn) / fuelburn') prob.model.add_subsystem('fuel_diff', comp, promotes_inputs=['fuel_mass'], promotes_outputs=['fuel_diff']) prob.model.connect('AS_point_0.fuelburn', 'fuel_diff.fuelburn') comp = ExecComp('fuel_diff_25 = (fuel_mass - fuelburn) / fuelburn') prob.model.add_subsystem('fuel_diff_25', comp, promotes_inputs=['fuel_mass'], promotes_outputs=['fuel_diff_25']) prob.model.connect('AS_point_1.fuelburn', 'fuel_diff_25.fuelburn') #======================================================================================= #======================================================================================= from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 prob.driver.options['maxiter'] = 5 # from openmdao.api import pyOptSparseDriver # prob.driver = pyOptSparseDriver() # prob.driver.add_recorder(SqliteRecorder("cases.sql")) # prob.driver.options['optimizer'] = "SNOPT" # prob.driver.opt_settings['Major optimality tolerance'] = 1e-6 # prob.driver.opt_settings['Major feasibility tolerance'] = 1e-8 # prob.driver.opt_settings['Major iterations limit'] = 200 prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) prob.model.add_design_var('wing.twist_cp', lower=-15., upper=15., scaler=0.1) prob.model.add_design_var('wing.spar_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.geometry.t_over_c_cp', lower=0.07, upper=0.2, scaler=10.) prob.model.add_design_var('fuel_mass', lower=0., upper=2e5, scaler=1e-5) prob.model.add_constraint('AS_point_0.CL', equals=0.5) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) #======================================================================================= # Here we add the fuel volume constraint #======================================================================================= prob.model.add_constraint('fuel_vol_delta.fuel_vol_delta', lower=0.) prob.model.add_constraint('fuel_diff', equals=0.) prob.model.add_constraint('fuel_diff_25', equals=0.) #======================================================================================= #======================================================================================= # Set up the problem prob.setup() # from openmdao.api import view_model # view_model(prob) prob.run_model() # Check the partials at the initial point in the design space, # only care about relative error data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40) assert_check_partials(data, atol=1e20, rtol=1e-6) # Run the optimizer for 5 iterations prob.run_driver() # Check the partials at this point in the design space data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40) assert_check_partials(data, atol=1e20, rtol=1e-6)
def test(self): import numpy as np from openaerostruct.geometry.utils import generate_mesh from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.transfer.displacement_transfer import DisplacementTransfer from openaerostruct.structures.struct_groups import SpatialBeamAlone from openmdao.api import IndepVarComp, Problem, Group, SqliteRecorder # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type' : 'tube', 'mesh' : mesh, # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 't_over_c_cp' : np.array([0.15]), # maximum airfoil thickness 'thickness_cp' : np.ones((3)) * .1, 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, 'exact_failure_constraint' : False, } # Create the problem and assign the model group prob = Problem() ny = surf_dict['mesh'].shape[1] indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.ones((ny, 6)) * 2e5, units='N') indep_var_comp.add_output('load_factor', val=1.) struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['disp'] = True prob.driver.options['tol'] = 1e-9 recorder = SqliteRecorder('struct.db') prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True prob.driver.recording_options['includes'] = ['*'] # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, ref=1e-1) prob.model.add_constraint('wing.failure', upper=0.) prob.model.add_constraint('wing.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_objective('wing.structural_mass', scaler=1e-5) # Set up the problem prob.setup(force_alloc_complex=False) # prob.run_model() # prob.check_partials(compact_print=False, method='fd') # exit() prob.run_driver() assert_rel_error(self, prob['wing.structural_mass'][0], 71088.4682399, 1e-8)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 6, 'chord_cos_spacing': 0, 'span_cos_spacing': 0, } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'wingbox', 'spar_thickness_cp': np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp': np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp': np.array([4., 5., 8., 8., 8., 9.]), 'mesh': mesh, 'data_x_upper': upper_x, 'data_x_lower': lower_x, 'data_y_upper': upper_y, 'data_y_lower': lower_y, 'strength_factor_for_upper_skin': 1., # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.0078, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c': 0.12, 'c_max_t': .38, # chordwise location of maximum thickness 'with_viscous': True, 'with_wave': True, # if true, compute wave drag # Structural values are based on aluminum 7075 'E': 73.1e9, # [Pa] Young's modulus 'G': ( 73.1e9 / 2 / 1.33 ), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield': (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho': 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin': 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio': 1.25, 'struct_weight_relief': True, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight': False, # Constraints 'exact_failure_constraint': False, # if false, use KS function 'Wf_reserve': 15000., # [kg] reserve fuel mass } surfaces = [surf_dict] # Create the problem and assign the model group prob = om.Problem() # Add problem information as an independent variables component indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('v', val=.85 * 295.07, units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=0.85) indep_var_comp.add_output('re', val=0.348 * 295.07 * .85 * 1. / (1.43 * 1e-5), units='1/m') indep_var_comp.add_output('rho', val=0.348, units='kg/m**3') indep_var_comp.add_output('CT', val=0.53 / 3600, units='1/s') indep_var_comp.add_output('R', val=14.307e6, units='m') indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'], units='kg') indep_var_comp.add_output('speed_of_sound', val=295.07, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: com_name = point_name + '.' + name + '_perf.' prob.model.connect( name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect( name + '.element_mass', point_name + '.coupled.' + name + '.element_mass') # Connect performance calculation variables prob.model.connect(name + '.nodes', com_name + 'nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') # Connect wingbox properties to von Mises stress calcs prob.model.connect(name + '.Qz', com_name + 'Qz') prob.model.connect(name + '.J', com_name + 'J') prob.model.connect(name + '.A_enc', com_name + 'A_enc') prob.model.connect(name + '.htop', com_name + 'htop') prob.model.connect(name + '.hbottom', com_name + 'hbottom') prob.model.connect(name + '.hfront', com_name + 'hfront') prob.model.connect(name + '.hrear', com_name + 'hrear') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.t_over_c', com_name + 't_over_c') prob.driver = om.ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Set up the problem prob.setup() # # om.view_model(prob) prob.run_model() # prob.model.list_outputs(values=True, # implicit=False, # units=True, # shape=True, # bounds=True, # residuals=True, # scaling=True, # hierarchical=False, # print_arrays=True) print(prob['AS_point_0.fuelburn'][0]) print(prob['wing.structural_mass'][0] / 1.25) print(prob['AS_point_0.wing_perf.failure'][0]) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 89411.50246542075, 1e-5) assert_rel_error(self, prob['wing.structural_mass'][0] / 1.25, 24009.5230566, 1e-5) assert_rel_error(self, prob['AS_point_0.wing_perf.failure'][0], 1.6254327137382174, 1e-5)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type' : 'tube', 'mesh' : mesh, # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 't_over_c_cp' : np.array([0.15]), # maximum airfoil thickness 'thickness_cp' : np.ones((3)) * .1, 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, 'exact_failure_constraint' : False, } # Create the problem and assign the model group prob = Problem() ny = surf_dict['mesh'].shape[1] indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.zeros((ny, 6)), units='N') indep_var_comp.add_output('load_factor', val=1.) struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('wing.failure', upper=0.) prob.model.add_constraint('wing.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_objective('wing.structural_mass', scaler=1e-5) # Set up the problem prob.setup() from openmdao.api import view_model prob.run_driver() assert_rel_error(self, prob['wing.structural_mass'][0], 13601.162582, 1e-4) assert_rel_error(self, prob['wing.disp'][1, 2], 0., 1e-4)
num_y = 21 num_x = 3 # Create a mesh dictionary to feed to generate_mesh to actually create # the mesh array. mesh_dict = { 'num_y': num_y, 'num_x': num_x, 'wing_type': 'rect', 'symmetry': True, 'span_cos_spacing': 0.5, 'span': 3.11, 'root_chord': 0.3, } mesh = generate_mesh(mesh_dict) # Apply camber to the mesh camber = 1 - np.linspace(-1, 1, num_x)**2 camber *= 0.3 * 0.05 for ind_x in range(num_x): mesh[ind_x, :, 2] = camber[ind_x] # Introduce geometry manipulation variables to define the ScanEagle shape zshear_cp = np.zeros(10) zshear_cp[0] = .3 xshear_cp = np.zeros(10) xshear_cp[0] = .15
def test_derivs_wetted(self): # This is a much richer test with the following attributes: # - 5x7 mesh so that each dimension of all variables is unique. # - Random values given as inputs. # - The mesh has been given a random z height at all points. # - S_ref_type option is "wetted" # Create a dictionary to store options about the mesh mesh_dict = {'num_y' : 7, 'num_x' : 5, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) mesh[:, :, 2] = np.random.random(mesh[:, :, 2].shape) # Create a dictionary with info and options about the aerodynamic # lifting surface surface = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aero', 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'twist_cp' : twist_cp, 'mesh' : mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, # if true, compute viscous drag 'with_wave' : False, # if true, compute wave drag } #surfaces = get_default_surfaces() surfaces = [surface] prob = Problem() group = prob.model comp = VLMGeometry(surface=surfaces[0]) indep_var_comp = IndepVarComp() indep_var_comp.add_output('def_mesh', val=surfaces[0]['mesh'], units='m') group.add_subsystem('geom', comp) group.add_subsystem('indep_var_comp', indep_var_comp) group.connect('indep_var_comp.def_mesh', 'geom.def_mesh') prob.setup() prob['geom.def_mesh'] = np.random.random(prob['geom.def_mesh'].shape) prob.run_model() check = prob.check_partials(compact_print=True) assert_check_partials(check, atol=3e-5, rtol=1e-5)
def test(self): from openaerostruct.geometry.utils import generate_mesh, write_FFD_file from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.transfer.displacement_transfer import DisplacementTransfer from openaerostruct.aerodynamics.aero_groups import AeroPoint from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, DirectSolver, LinearBlockGS, PetscKSP, ScipyOptimizeDriver# TODO, SqliteRecorder, CaseReader, profile from openmdao.devtools import iprofile from openmdao.api import view_model from six import iteritems from pygeo import DVGeometry # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'num_x' : 3, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5, 'span_cos_spacing' : 0.} mesh, _ = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aero', 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'DVGeo' : True, 'mesh' : mesh, 'mx' : 2, 'my' : 3, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c' : 0.15, # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, # if true, compute viscous drag } surf_dict['num_x'], surf_dict['num_y'] = surf_dict['mesh'].shape[:2] surfaces = [surf_dict] # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=6.64) indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: filename = write_FFD_file(surface, surface['mx'], surface['my']) DVGeo = DVGeometry(filename) geom_group = Geometry(surface=surface, DVGeo=DVGeo) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') from openmdao.api import pyOptSparseDriver prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = "SNOPT" prob.driver.opt_settings = {'Major optimality tolerance': 1.0e-6, 'Major feasibility tolerance': 1.0e-6} # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('alpha', lower=-15, upper=15) prob.model.add_design_var('wing.shape', lower=-3, upper=2) # prob.model.add_constraint('wing.shape', equals=0., indices=range(surf_dict['my'] * 2), linear=True) prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5) prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4) # Set up the problem prob.setup() # view_model(prob, outfile='aero.html', show_browser=False) # prob.run_model() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03398038, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -0.18379626783513864, 1e-5)
def test(self): import numpy as np from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, \ ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, \ DirectSolver, LinearBlockGS, PetscKSP, SqliteRecorder from openaerostruct.geometry.utils import generate_mesh from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.aerodynamics.aero_groups import AeroPoint from openaerostruct.common.atmos_group import AtmosGroup # Create a dictionary to store options about the mesh mesh_dict = {'num_y' : 7, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) # Create a dictionary with info and options about the aerodynamic # lifting surface surface = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'twist_cp' : twist_cp, 'mesh' : mesh, 'num_x' : mesh.shape[0], 'num_y' : mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, # if true, compute viscous drag 'with_wave' : False, # if true, compute wave drag } # Create the OpenMDAO problem prob = Problem() # Create an independent variable component that will supply the flow # conditions to the problem. indep_var_comp = IndepVarComp() indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('altitude', val=35000., units='ft') # Add this IndepVarComp to the problem model prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Add this IndepVarComp to the problem model prob.model.add_subsystem('atmos', AtmosGroup(), promotes=['*']) # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) prob.model.add_subsystem(surface['name'], geom_group) # Create the aero point group, which contains the actual aerodynamic # analyses aero_group = AeroPoint(surfaces=[surface]) point_name = 'aero_point_0' prob.model.add_subsystem(point_name, aero_group, promotes_inputs=['v', 'alpha', 'Mach_number', 're', 'rho', 'cg']) name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') # Import the Scipy Optimizer and set the driver of the problem to use # it, which defaults to an SLSQP optimization method from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5) prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4) # Set up and run the optimization problem prob.setup() # prob.check_partials(compact_print=True) # exit() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.030471796067577953, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -1.7331840488188963, 1e-6)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 11, 'num_x': 3, 'wing_type': 'CRM', 'symmetry': False, 'num_twist_cp': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': False, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'mesh': mesh, 'twist_cp': twist_cp, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.0, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.10, 0.15, 0.2]), # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, # if true, compute viscous drag 'with_wave': True, # if true, compute wave drag } surfaces = [surf_dict] # Create the problem and the model group prob = om.Problem() indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect( name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect( name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') recorder = om.SqliteRecorder("aero_analysis_no_sym_wavedrag.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True prob.driver.recording_options['includes'] = ['*'] # Set up the problem prob.setup() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.464191542231, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.0222413119687, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -1.5717101821556665, 1e-6)
def test(self): from openaerostruct.geometry.utils import generate_mesh, write_FFD_file from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.transfer.displacement_transfer import DisplacementTransfer from openaerostruct.aerodynamics.aero_groups import AeroPoint from openaerostruct.integration.multipoint_comps import MultiCD from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, DirectSolver, LinearBlockGS, PetscKSP, ScipyOptimizeDriver, ExplicitComponent# TODO, SqliteRecorder, CaseReader, profile from openmdao.devtools import iprofile from openmdao.api import view_model from openmdao.utils.assert_utils import assert_check_partials from pygeo import DVGeometry # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 3, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5, 'span_cos_spacing' : 0.} mesh, _ = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aero', 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'mesh' : mesh, 'mx' : 2, 'my' : 3, 'geom_manipulator' : 'FFD', # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, # if true, compute viscous drag 'with_wave' : False, # if true, compute wave drag } surfaces = [surf_dict] n_points = 2 # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=np.ones(n_points)*6.64, units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop through and add a certain number of aero points for i in range(n_points): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha', src_indices=[i]) prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: filename = write_FFD_file(surface, surface['mx'], surface['my']) DVGeo = DVGeometry(filename) geom_group = Geometry(surface=surface, DVGeo=DVGeo) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. aero_group.add_subsystem(surface['name'] + '_geom', geom_group) name = surface['name'] prob.model.connect(point_name + '.CD', 'multi_CD.' + str(i) + '_CD') # Connect the mesh from the geometry component to the analysis point prob.model.connect(point_name + '.' + name + '_geom.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(point_name + '.' + name + '_geom.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect(point_name + '.' + name + '_geom.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') prob.model.add_subsystem('multi_CD', MultiCD(n_points=n_points), promotes_outputs=['CD']) from openmdao.api import pyOptSparseDriver prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = "SNOPT" prob.driver.opt_settings = {'Major optimality tolerance': 1.0e-5, 'Major feasibility tolerance': 1.0e-5} # # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('alpha', lower=-15, upper=15) prob.model.add_design_var('aero_point_0.wing_geom.shape', lower=-3, upper=2) prob.model.add_constraint('aero_point_0.wing_perf.CL', equals=0.45) prob.model.add_design_var('aero_point_1.wing_geom.shape', lower=-3, upper=2) prob.model.add_constraint('aero_point_1.wing_perf.CL', equals=0.5) prob.model.add_objective('CD', scaler=1e4) # Set up the problem prob.setup() prob.run_model() # Check the partials at this point in the design space data = prob.check_partials(compact_print=True, out_stream=None, method='cs', step=1e-40) assert_check_partials(data, atol=1e20, rtol=1e-6)
from openaerostruct.geometry.utils import generate_mesh from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.aerodynamics.aero_groups import AeroPoint # Create a dictionary to store options about the mesh mesh_dict = { 'num_y': 7, 'num_x': 2, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5 } # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) # Create a dictionary with info and options about the aerodynamic # lifting surface surface = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aero', 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'twist_cp': twist_cp, 'mesh': mesh, 'num_x': mesh.shape[0],
def test(self): import numpy as np from openaerostruct.geometry.utils import generate_mesh from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint from openmdao.api import IndepVarComp, Problem, Group, SqliteRecorder # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surface = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aerostruct', 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'thickness_cp' : np.array([.1, .2, .3]), 'twist_cp' : twist_cp, 'mesh' : mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, 'with_wave' : False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, # Constraints 'exact_failure_constraint' : False, # if false, use KS function } # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('a', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) aerostruct_group = AerostructGeometry(surface=surface) name = 'wing' # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group, promotes_inputs=['load_factor']) point_name = 'AS_point_0' # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=[surface]) prob.model.add_subsystem(point_name, AS_point, promotes_inputs=['v', 'alpha', 'M', 're', 'rho', 'CT', 'R', 'W0', 'a', 'empty_cg', 'load_factor']) com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.K', point_name + '.coupled.' + name + '.K') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 recorder = SqliteRecorder("aerostruct.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True prob.driver.recording_options['includes'] = ['*'] # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-10., upper=10.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # Set up the problem prob.setup(check=True) prob.run_driver() assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 104400.0251030171, 1e-8)
def test_multiple_masses(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 31, 'wing_type': 'rect', 'span': 10, 'symmetry': True } mesh = generate_mesh(mesh_dict) surface = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type': 'tube', 'mesh': mesh, # Structural values are based on aluminum 7075 'E': 70.e9, # [Pa] Young's modulus of the spar 'G': 30.e9, # [Pa] shear modulus of the spar 'yield': 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho': 3.e3, # [kg/m^3] material density 'fem_origin': 0.5, # normalized chordwise location of the spar 't_over_c_cp': np.array([0.15]), # maximum airfoil thickness 'thickness_cp': np.ones((3)) * .1, 'wing_weight_ratio': 2., 'struct_weight_relief': False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight': False, 'exact_failure_constraint': False, } # Create the problem and assign the model group prob = Problem() ny = surface['mesh'].shape[1] surface['n_point_masses'] = 2 indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.zeros((ny, 6)), units='N') indep_var_comp.add_output('load_factor', val=1.) engine_thrusts = np.array([[10., 20.]]) point_mass_locations = np.array([[1., -1., 0.], [1., -2., 0.]]) indep_var_comp.add_output('engine_thrusts', val=engine_thrusts, units='N') indep_var_comp.add_output('point_mass_locations', val=point_mass_locations, units='m') struct_group = SpatialBeamAlone(surface=surface) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surface['name'], struct_group, promotes=['*']) # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['vonmises'][-1, 0], 137509.870021, 1e-4)
fig.savefig('drag_polar.pdf') #plt.show() return CLs, CDs, CMs if __name__=='__main__': # Create a dictionary to store options about the mesh mesh_dict = {'num_y' : 7, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) # Create a dictionary with info and options about the wing wing_surface = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aero', 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'twist_cp' : twist_cp, 'mesh' : mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0).
def get_default_surfaces(): # Create a dictionary to store options about the mesh mesh_dict = { 'num_y': 7, 'num_x': 2, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5 } # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) wing_dict = { 'name': 'wing', 'num_y': 4, 'num_x': 2, 'symmetry': True, 'S_ref_type': 'wetted', 'CL0': 0.1, 'CD0': 0.1, 'mesh': mesh, # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, # if true, compute viscous drag 'with_wave': False, # if true, computes wave drag 'fem_model_type': 'tube', # Structural values are based on aluminum 7075 'E': 70.e9, # [Pa] Young's modulus of the spar 'G': 30.e9, # [Pa] shear modulus of the spar 'yield': 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho': 3.e3, # [kg/m^3] material density 'fem_origin': 0.35, # normalized chordwise location of the spar 'wing_weight_ratio': 2., 'struct_weight_relief': False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight': False, # True to add the weight of the structure to the loads on the structure 'Wf_reserve': 10000., } # Create a dictionary to store options about the mesh mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'rect', 'symmetry': False } # Generate the aerodynamic mesh based on the previous dictionary mesh = generate_mesh(mesh_dict) tail_dict = { 'name': 'tail', 'num_y': 5, 'num_x': 3, 'symmetry': False, 'mesh': mesh } surfaces = [wing_dict, tail_dict] return surfaces
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 3, 'wing_type' : 'rect', 'symmetry' : True, 'span' : 10., 'chord' : 1, 'span_cos_spacing' : 0.} mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'twist_cp' : np.zeros(5), 'mesh' : mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.0, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : False, # if true, compute viscous drag 'with_wave' : False, # if true, compute wave drag } surfaces = [surf_dict] # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() # # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5) prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4) # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], .46173591841167, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], .005524603647, 1e-6)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'thickness_cp' : np.array([.1, .2, .3]), 'twist_cp' : twist_cp, 'mesh' : mesh, 'n_point_masses' : 1, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, 'with_wave' : False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 70.e9, # [Pa] Young's modulus of the spar 'G' : 30.e9, # [Pa] shear modulus of the spar 'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho' : 3.e3, # [kg/m^3] material density 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 2., 'struct_weight_relief' : False, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight' : False, # Constraints 'exact_failure_constraint' : False, # if false, use KS function } surfaces = [surf_dict] # Create the problem and assign the model group prob = om.Problem() # Add problem information as an independent variables component indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=grav_constant * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('speed_of_sound', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') point_masses = np.array([[8000.]]) point_mass_locations = np.array([[25, -10., 0.]]) indep_var_comp.add_output('point_masses', val=point_masses, units='kg') indep_var_comp.add_output('point_mass_locations', val=point_mass_locations, units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') prob.model.connect('load_factor', point_name + '.coupled.load_factor') for surface in surfaces: com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') coupled_name = point_name + '.coupled.' + name prob.model.connect('point_masses', coupled_name + '.point_masses') prob.model.connect('point_mass_locations', coupled_name + '.point_mass_locations') # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 267518.2837095164, 1e-4) assert_rel_error(self, prob['AS_point_0.CM'][1], -0.58977996718612, 1e-5)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 11, 'num_x' : 3, 'wing_type' : 'CRM', 'symmetry' : False, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aero', 'symmetry' : False, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'mesh' : mesh, 'twist_cp' : twist_cp, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.0, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.10, 0.15, 0.2]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, # if true, compute viscous drag 'with_wave' : True, # if true, compute wave drag } surfaces = [surf_dict] # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') recorder = SqliteRecorder("aero_analysis_no_sym_wavedrag.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True prob.driver.recording_options['includes'] = ['*'] # Set up the problem prob.setup() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.464191542231, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.0222413119687, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -0.1603034566404, 1e-6)
def setup(self): # Total number of nodes to use in the spanwise (num_y) and # chordwise (num_x) directions. Vary these to change the level of fidelity. mesh_dict = self.options['mesh_dict'] num_y = mesh_dict['num_y'] num_x = mesh_dict['num_x'] mesh = generate_mesh(mesh_dict) # Apply camber to the mesh camber = 1 - np.linspace(-1, 1, num_x)**2 camber *= 0.3 * 0.05 for ind_x in range(num_x): mesh[ind_x, :, 2] = camber[ind_x] # Introduce geometry manipulation variables to define the ScanEagle shape zshear_cp = np.zeros(10) zshear_cp[0] = .3 xshear_cp = np.zeros(10) xshear_cp[0] = .15 chord_cp = np.ones(10) chord_cp[0] = .5 chord_cp[-1] = 1.5 chord_cp[-2] = 1.3 radius_cp = 0.01 * np.ones(10) # Define wing parameters surface = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'taper': 0.8, 'zshear_cp': zshear_cp, 'xshear_cp': xshear_cp, 'chord_cp': chord_cp, 'sweep': 20., 'twist_cp': np.array([2.5, 2.5, 5.]), #np.zeros((3)), 'thickness_cp': np.ones((3)) * .008, # Give OAS the radius and mesh from before 'radius_cp': radius_cp, 'mesh': mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.12]), # thickness over chord ratio 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, 'with_wave': False, # if true, compute wave drag # Material properties taken from http://www.performance-composites.com/carbonfibre/mechanicalproperties_2.asp 'yield': 350.e6, 'fem_origin': 0.35, # normalized chordwise location of the spar 'wing_weight_ratio': 1., # multiplicative factor on the computed structural weight 'struct_weight_relief': True, # True to add the weight of the structure to the loads on the structure 'distributed_fuel_weight': False, # Constraints 'exact_failure_constraint': False, # if false, use KS function } # Add problem information as an independent variables component indep_var_comp = IndepVarComp() # indep_var_comp.add_output('v', val=22.876, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('altitude', val=4.57e3, units='m') # indep_var_comp.add_output('re', val=1.e6, units='1/m') # indep_var_comp.add_output('rho', val=0.770816, units='kg/m**3') indep_var_comp.add_output('R', val=1800e3, units='m') # indep_var_comp.add_output('speed_of_sound', val=322.2, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.array([0.2, 0., 0.]), units='m') # indep_var_comp.add_output('Mach_number', val=mean_val_dict['mean_Ma']) # indep_var_comp.add_output('CT', val=mean_val_dict['mean_TSFC'], units='1/s') # indep_var_comp.add_output('W0', val=mean_val_dict['mean_W0'], units='kg') # indep_var_comp.add_output('E', val=mean_val_dict['mean_E'], units='N/m**2') # indep_var_comp.add_output('G', val=mean_val_dict['mean_G'], units='N/m**2') # indep_var_comp.add_output('mrho', val=mean_val_dict['mean_mrho'], units='kg/m**3') self.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Add atmosphere related properties self.add_subsystem('atmos', AtmosGroup(), promotes=['*']) # Add the AerostructGeometry group, which computes all the intermediary # parameters for the aero and structural analyses, like the structural # stiffness matrix and some aerodynamic geometry arrays aerostruct_group = AerostructGeometry(surface=surface) name = 'wing' # Add the group to the problem self.add_subsystem(name, aerostruct_group, promotes_inputs=['load_factor']) point_name = 'AS_point_0' # Create the aerostruct point group and add it to the model. # This contains all the actual aerostructural analyses. AS_point = AerostructPoint(surfaces=[surface]) self.add_subsystem(point_name, AS_point, promotes_inputs=[ 'v', 'alpha', 'Mach_number', 're', 'rho', 'CT', 'R', 'W0', 'speed_of_sound', 'empty_cg', 'load_factor' ]) # Issue quite a few connections within the model to make sure all of the # parameters are connected correctly. com_name = point_name + '.' + name + '_perf' self.connect( name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') self.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh self.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') # Connect performance calculation variables self.connect(name + '.radius', com_name + '.radius') self.connect(name + '.thickness', com_name + '.thickness') self.connect(name + '.nodes', com_name + '.nodes') self.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') self.connect( name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') self.connect(name + '.t_over_c', com_name + '.t_over_c')