def add_geometry_to_problem(prob, surfaces): # 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) return prob
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': 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 = om.Problem() # Add problem information as an independent variables component indep_var_comp = om.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 = om.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') prob.driver = om.ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 prob.driver.options['maxiter'] = 2 recorder = om.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) # om.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): """ 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' : 11, '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('alpha_maneuver', 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=np.array([0.348, 0.9237]), 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('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') 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') 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 + '.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') 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 + '.Iz', com_name + 'Iz') 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 + '.skin_thickness', com_name + 'skin_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') 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 # 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'] = 5e-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_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_0.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_1.L_equals_W', equals=0.) prob.model.add_constraint('AS_point_1.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_driver() # prob.check_partials(form='central', compact_print=True) # print(prob['AS_point_0.fuelburn'][0]) # print(prob['wing.structural_weight'][0]/1.25) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 94556.9136969, 1e-5) assert_rel_error(self, prob['wing.structural_weight'][0]/1.25, 277535.59118440875, 1e-5)
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 '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, # 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 (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': False, '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': 1., '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=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('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=['*']) # 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: 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') # 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], -1.2725562400264683, 1e-5)
val=np.array([310.95, 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=3000., 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)
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 '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 = 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=9., 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=['*']) # 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') # 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 # 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': 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 = 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: prob.model.connect('load_factor', name + '.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') prob.model.connect( name + '.element_weights', point_name + '.coupled.' + name + '.element_weights') 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_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') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Set up the problem prob.setup() # # 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_weight'][0] / 1.25) print(prob['AS_point_0.wing_perf.failure'][0]) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 112532.399999, 1e-5) assert_rel_error(self, prob['wing.structural_weight'][0] / 1.25, 235533.421185, 1e-5) assert_rel_error(self, prob['AS_point_0.wing_perf.failure'][0], 1.70644139941, 1e-5)
def test(self): from openaerostruct.geometry.utils import generate_mesh, write_FFD_file from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint import openmdao.api as om 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 '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 = 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=['*']) # 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('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') # 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') # 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() recorder = om.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() # om.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], 97680.8964568375, 1e-3)
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 i == 0: # This load factor connects to a component used to compute weights in a mass sense. It's load factor should always just be 1. prob.model.connect('load_factor', name + '.load_factor', src_indices=[i]) 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_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') 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') 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'] = \ ['prob_vars.alpha', 'prob_vars.rho', 'prob_vars.v', 'prob_vars.cg', \ 'AS_point_1.total_perf.CG.cg', 'AS_point_0.total_perf.CG.cg', \ 'AS_point_0.coupled.wing_loads.loads', 'AS_point_1.coupled.wing_loads.loads', \ 'wing.wingbox_group.skin_thickness_bsp.skin_thickness', \ 'wing.geometry.mesh.rotate.mesh',\ 'wing.wingbox_group.spar_thickness_bsp.spar_thickness', \ 'wing.wingbox_group.spar_thickness_bsp.spar_thickness', \ 'wing.geometry.t_over_c_bsp.t_over_c', \ 'AS_point_0.wing_perf.struct_funcs.vonmises.vonmises', \ 'AS_point_1.wing_perf.struct_funcs.vonmises.vonmises', \ 'wing.struct_setup.structural_weight.structural_weight', \ 'AS_point_0.coupled.wing.def_mesh.displacement_transfer.def_mesh', \ 'AS_point_1.coupled.wing.def_mesh.displacement_transfer.def_mesh', \ 'AS_point_0.coupled.wing.aero_geom.normals', \ 'AS_point_1.coupled.wing.aero_geom.normals', \ 'AS_point_0.coupled.wing.aero_geom.widths', 'AS_point_1.coupled.wing.aero_geom.widths', \ 'AS_point_0.coupled.aero_states.panel_forces_surf.wing_sec_forces', \ 'AS_point_1.coupled.aero_states.panel_forces_surf.wing_sec_forces', \ 'AS_point_0.wing_perf.aero_funcs.coeffs.CL1', 'AS_point_1.wing_perf.aero_funcs.coeffs.CL1', \ 'AS_point_0.coupled.wing.aero_geom.S_ref', 'AS_point_1.coupled.wing.aero_geom.S_ref', 'wing.geometry.twist_bsp.twist'] 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_weight'][0]/1.25) # print(prob['wing.geometry.t_over_c_cp']) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 101946.723936, 1e-5) assert_rel_error(self, prob['wing.structural_weight'][0] / 1.25, 358406.34121, 1e-5) assert_rel_error( self, prob['wing.geometry.t_over_c_cp'], np.array([ 0.10305255, 0.08205957, 0.11089362, 0.13089362, 0.10205957, 0.09361004 ]), 1e-5)
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 '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('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') 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], 104393.448214, 1e-8)
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'] rv_dict = self.options['rv_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('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('speed_of_sound', val=322.2, units='m/s') indep_var_comp.add_output('empty_cg', val=np.array([0.2, 0., 0.]), units='m') # Create independent input variables depending on which variables are # being considered as random variables if 'Mach_number' not in rv_dict: indep_var_comp.add_output('Mach_number', val=0.071) if 'CT' not in rv_dict: indep_var_comp.add_output('CT', val=9.80665 * 8.6e-6, units='1/s') if 'W0' not in rv_dict: indep_var_comp.add_output('W0', val=10.0, units='kg') if 'R' not in rv_dict: indep_var_comp.add_output('R', val=1800, units='km') if 'load_factor' not in rv_dict: indep_var_comp.add_output('load_factor', val=1.) if 'E' not in rv_dict: indep_var_comp.add_output('E', val=85.e9, units='N/m**2') if 'G' not in rv_dict: # indep_var_comp.add_output('G', val=25.e9, units='N/m**2') indep_var_comp.add_output('G', val=5.e9, units='N/m**2') if 'mrho' not in rv_dict: indep_var_comp.add_output('mrho', val=1600, units='kg/m**3') if 'altitude' not in rv_dict: indep_var_comp.add_output('altitude', val=4.57, units='km') 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') # Make connections based on whether a variable is a random variable or not if 'E' not in rv_dict: self.connect('E', com_name + '.struct_funcs.vonmises.E') self.connect('E', name + '.struct_setup.assembly.E') if 'G' not in rv_dict: self.connect('G', com_name + '.struct_funcs.vonmises.G') self.connect('G', name + '.struct_setup.assembly.G') if 'mrho' not in rv_dict: self.connect('mrho', name + '.struct_setup.structural_weight.mrho') if 'load_factor' not in rv_dict: self.connect('load_factor', point_name + '.coupled.' + name + '.load_factor')
def get_problem(surface, ailerons): surface['control_surfaces'] = ailerons # 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=25., units='m/s') indep_var_comp.add_output('alpha', val=alpha, units='deg') indep_var_comp.add_output('re', val=5e5, units='1/m') indep_var_comp.add_output('rho', val=rho, units='kg/m**3') indep_var_comp.add_output('cg', val=cg_loc, units='m') indep_var_comp.add_output('delta_aileron', val=12.5, units='deg') indep_var_comp.add_output('omega', val=np.array([0., 0., 0.]), units='rad/s') 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], rotational=True, rollOnly=True) prob.model.add_subsystem(point_name, AS_point, promotes_inputs=[ 'v', 'alpha', 'Mach_number', 're', 'rho', 'cg', 'omega' ]) for aileron in ailerons: prob.model.connect( 'delta_aileron', point_name + '.coupled.' + name + '.control_surfaces.' + aileron['name'] + '.delta_aileron') 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 + '.t_over_c', com_name + '.t_over_c') ##from openmdao.api import ScipyOptimizeDriver #prob.driver = ScipyOptimizeDriver() #prob.driver.options['tol'] = 1e-9 # Set up the problem prob.setup(check=True) prob.model.AS_point_0.coupled.nonlinear_solver.options['maxiter'] = 10000 prob.model.AS_point_0.coupled.nonlinear_solver.options['atol'] = 1e-6 return prob
def fctOptim(mrhoi, skin, spar, span, toverc): # Starting time starttime = time.time() # Materials #sandw1=material(66.35,4.25e9,1.63e9,58.7e6/1.5,34.7,"sandw1") #sandw2=material(174.5,14.15e9,5.44e9,195.6e6/1.5,43.4,"sandw2") #sandw3=material(483,42.5e9,16.3e9,586e6/1.5,46.8,"sandw3") sandw4 = material(504.5, 42.5e9, 16.3e9, 586e6 / 1.5, 44.9, "sandw4") #sandw5=material(574.5,42.5e9,16.3e9,586e6/1.5,39.3,"sandw5") sandw5 = material(560.5, 42.5e9, 16.3e9, 586e6 / 1.5, 40.3, "sandw5") sandw6 = material(529, 42.5e9, 16.3e9, 237e6 / 1.5, 42.75, "sandw6") al7075 = material(2.80e3, 72.5e9, 27e9, 444.5e6 / 1.5, 13.15 * (1 - 0.426) + 2.61 * 0.426, "al7075") #from EDUPACK #al7075oas=material(2.78e3,73.1e9,73.1e9/2/1.33,444.5e6/1.5,13.15*(1-0.426)+2.61*0.426,"al7075") #from OAS example qiCFRP = material(1565, 54.9e9, 21e9, 670e6 / 1.5, 48.1, "qiCFRP") steel = material(7750, 200e9, 78.5e9, 562e6 / 1.5, 4.55 * (1 - 0.374) + 1.15 * 0.374, "steel") gfrp = material(1860, 21.4e9, 8.14e9, 255e6, 6.18, "gfrp") #epoxy-Eglass,woven,QI #nomat=material(1370,0.01,0.01,0.01,60,"noMaterial") nomat = material(50, 1e8, 1e4, 1e5, 6000, "noMaterial") #nomat=material(50,1e8,1e4,1e5,60,"noMaterial") fakemat = material((2.80e3 + 7750) / 2, (72.5e9 + 200e9) / 2, (27e9 + 78.5e9) / 2, (444.5e6 / 1.5 + 562e6 / 1.5) / 2, (13.15 * (1 - 0.426) + 2.61 * 0.426 + 4.55 * (1 - 0.374) + 1.15 * 0.374) / 2, "fakemat") nomatEnd = material(10000, 5e9, 2e9, 20e6 / 1.5, 60, "nomatEnd") materials = [ al7075, qiCFRP, steel, gfrp, nomat, fakemat, nomatEnd, sandw4, sandw5, sandw6 ] # materials=[al7075, qiCFRP, steel, gfrp, nomat, fakemat, nomatEnd, sandw3, sandw4, sandw5, sandw6] # materials=[al7075, qiCFRP, steel, gfrp, nomat, fakemat, nomatEnd,sandw1,sandw2,sandw3] # materials=[sandw4, sandw5, nomat, nomatEnd] # Provide coordinates for a portion of an airfoil for the wingbox cross-section as an nparray with dtype=complex (to work with the complex-step approximation for derivatives). # These should be for an airfoil with the chord scaled to 1. # We use the 10% to 60% portion of the NACA 63412 airfoil for this case # We use the coordinates available from airfoiltools.com. Using such a large number of coordinates is not necessary. # The first and last x-coordinates of the upper and lower surfaces must be the same upper_x = np.array([ 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6 ], dtype='complex128') lower_x = np.array([ 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6 ], dtype='complex128') upper_y = np.array([ 0.0513, 0.0537, 0.0559, 0.0580, 0.0600, 0.0619, 0.0636, 0.0652, 0.0668, 0.0682, 0.0696, 0.0709, 0.0721, 0.0732, 0.0742, 0.0752, 0.0761, 0.0769, 0.0776, 0.0782, 0.0788, 0.0793, 0.0797, 0.0801, 0.0804, 0.0806, 0.0808, 0.0808, 0.0808, 0.0807, 0.0806, 0.0804, 0.0801, 0.0798, 0.0794, 0.0789, 0.0784, 0.0778, 0.0771, 0.0764, 0.0757, 0.0749, 0.0740, 0.0732, 0.0723, 0.0713, 0.0703, 0.0692, 0.0681, 0.0669, 0.0657 ], dtype='complex128') lower_y = np.array([ -0.0296, -0.0307, -0.0317, -0.0326, -0.0335, -0.0343, -0.0350, -0.0357, -0.0363, -0.0368, -0.0373, -0.0378, -0.0382, -0.0386, -0.0389, -0.0391, -0.0394, -0.0395, -0.0397, -0.0398, -0.0398, -0.0398, -0.0398, -0.0397, -0.0396, -0.0394, -0.0392, -0.0389, -0.0386, -0.0382, -0.0378, -0.0374, -0.0369, -0.0363, -0.0358, -0.0352, -0.0345, -0.0338, -0.0331, -0.0324, -0.0316, -0.0308, -0.0300, -0.0292, -0.0283, -0.0274, -0.0265, -0.0256, -0.0246, -0.0237, -0.0227 ], dtype='complex128') Rcurv = RadiusCurvature(upper_x, lower_x, upper_y, lower_y) # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 15, 'num_x': 3, 'wing_type': 'rect', 'symmetry': True, 'chord_cos_spacing': 0, 'span_cos_spacing': 0, 'num_twist_cp': 4 } mesh = generate_mesh(mesh_dict) # Batteries and solar panels densityPV = 0.23 #kg/m^2 energeticDensityBattery = 435 * 0.995 * 0.95 * 0.875 * 0.97 #Wh/kg 0.995=battery controller efficiency, 0.95=end of life capacity loss of 5%, 0.97=min battery SOC of 3%, 0.875=packaging efficiency emissionBat = 0.104 / 0.995 / 0.95 / 0.875 / 0.97 #[kgCO2/Wh] night_hours = 13 #h productivityPV = 350.0 * 0.97 * 0.95 #[W/m^2] 350 from Zephyr power figure, 0.97=MPPT efficiency, 0.95=battery round trip efficiency emissionPV = 0.05 / 0.97 / 0.95 #[kgCO2/W] emissions of the needed PV surface to produce 1W emissionsPerW = emissionPV + emissionBat * night_hours #[kgCO2/W] # Dictionary for the lifting surface surf_dict = { # Wing definition 'name': 'wing', # give the surface some name 'symmetry': True, # if True, model only one half of the lifting surface 'S_ref_type': 'projected', # how we compute the wing area, # can be 'wetted' or 'projected' 'mesh': mesh, 'fem_model_type': 'wingbox', # 'wingbox' or 'tube' 'data_x_upper': upper_x, 'data_x_lower': lower_x, 'data_y_upper': upper_y, 'data_y_lower': lower_y, 'airfoil_radius_curvature': Rcurv, 'twist_cp': np.array([10., 20., 20., 20.]), # [deg] 'chord_cp': [1.5], # [m] 'span': span, #[m] 'taper': 0.3, 'spar_thickness_cp': np.array([spar, spar, spar, spar]), # [m] 'skin_thickness_cp': np.array([skin / 2, skin, skin * 1.5, 2 * skin]), # [m] 't_over_c_cp': np.array([0.75 * toverc, toverc, toverc, 1.25 * toverc]), #TODELETE '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, camber, etc. 'CL0': 0.0, # CL delta 'CD0': 0.0078, # CD delta '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.80, #'k_lam' : 0.05, # fraction of chord with laminar # flow, used for viscous drag 'c_max_t': .349, # chordwise location of maximum thickness # Materials 'materlist': materials, 'puissanceMM': 1, #power used in muli-material function # Structural values 'strength_factor_for_upper_skin': 1.0, # the yield stress is multiplied by this factor for the upper skin 'wing_weight_ratio': 1., 'exact_failure_constraint': False, # if false, use KS function 'struct_weight_relief': True, # Engines 'n_point_masses': 1, # number of point masses in the system; in this case, the engine (omit option if no point masses) # Power 'productivityPV': productivityPV, #[W/m^2] 'densityPV': densityPV + productivityPV / energeticDensityBattery * night_hours, #[kg/m^2] the weight of the batteries is counted here 'payload_power': 125.5, #[W] payload=150 + avionics=211 'motor_propeller_efficiency': 0.84, #thrusting power/electrical power used by propulsion 'co2PV': emissionsPerW * productivityPV / (densityPV + productivityPV / energeticDensityBattery * night_hours), #[kgCO2/kg] #co2 burden of PV cells and battery 'prop_density': 0.0058, #[kg/W] 'mppt_density': 0.00045, #[kg/W] } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component data for altitude=23240 m and 0 m speed = 15.56 #m/s speed_dive = 1.4 * speed #m/s gust_speed = 3.4 #m/s rho_air = 0.089 #kg/m**3 speed_sound = 295.1 #m/s #n_gust = 1 + 0.5*rho_air*speed_dive*gust_speed*2*pi/3000 indep_var_comp = IndepVarComp() indep_var_comp.add_output('Mach_number', val=np.array([ speed / speed_sound, (speed_dive**2 + gust_speed**2)**0.5 / speed_sound, 0 ])) indep_var_comp.add_output( 'v', val=np.array([speed, (speed_dive**2 + gust_speed**2)**0.5, 0]), units='m/s') indep_var_comp.add_output('re',val=np.array([rho_air*speed*1./(1.4*1e-5), \ rho_air*speed_dive*1./(1.4*1e-5), 0]), units='1/m') #L=10m, indep_var_comp.add_output('rho', val=np.array([rho_air, rho_air, 1.225]), units='kg/m**3') indep_var_comp.add_output('speed_of_sound', val=np.array([speed_sound, speed_sound, 340]), units='m/s') indep_var_comp.add_output('W0_without_point_masses', val=8, units='kg') indep_var_comp.add_output('load_factor', val=np.array([1., 1.1, 0.])) indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('alpha_gust', val=atan(gust_speed / speed_dive) * 180 / pi, units='deg') indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') indep_var_comp.add_output('mrho', val=np.array([mrhoi, mrhoi]), units='kg/m**3') indep_var_comp.add_output('engine_location', val=-0.3) #VMGM 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 groups to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) prob.model.add_subsystem('YoungMM', YoungMM(surface=surface), promotes_inputs=['mrho'], promotes_outputs=['young']) #VMGM prob.model.add_subsystem('ShearMM', ShearMM(surface=surface), promotes_inputs=['mrho'], promotes_outputs=['shear']) #VMGM prob.model.add_subsystem('YieldMM', YieldMM(surface=surface), promotes_inputs=['mrho'], promotes_outputs=['yield']) #VMGM prob.model.add_subsystem('CO2MM', CO2MM(surface=surface), promotes_inputs=['mrho'], promotes_outputs=['co2']) #VMGM prob.model.add_subsystem( 'PointMassLocations', PointMassLocations(surface=surface), promotes_inputs=['engine_location', 'span', 'nodes'], promotes_outputs=['point_mass_locations']) #VMGM prob.model.add_subsystem('PointMasses', PointMasses(surface=surface), promotes_inputs=['PV_surface'], promotes_outputs=['point_masses']) #VMGM prob.model.add_subsystem( 'W0_comp', ExecComp('W0 = W0_without_point_masses + 2*sum(point_masses)', units='kg'), promotes=['*']) prob.model.connect('mrho', name + '.struct_setup.structural_mass.mrho') #ED prob.model.connect('young', name + '.struct_setup.assembly.local_stiff.young') #VMGM prob.model.connect('shear', name + '.struct_setup.assembly.local_stiff.shear') #VMGM prob.model.connect('wing.span', 'span') #VMGM prob.model.connect('AS_point_0.total_perf.PV_surface', 'PV_surface') #VMGM prob.model.connect(name + '.nodes', 'nodes') #VMGM # Loop through and add a certain number of aerostruct points for i in range(3): # for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aerostruct 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', 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('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]) for surface in surfaces: name = surface['name'] prob.model.connect('load_factor', point_name + '.coupled.load_factor', src_indices=[i]) #for PV distributed weight 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') prob.model.connect('young', com_name + 'struct_funcs.vonmises.young') prob.model.connect('shear', com_name + 'struct_funcs.vonmises.shear') prob.model.connect('yield', com_name + 'struct_funcs.failure.yield') #VMGM prob.model.connect('young', com_name + 'struct_funcs.buckling.young') #VMGM prob.model.connect('shear', com_name + 'struct_funcs.buckling.shear') #VMGM prob.model.connect(name + '.t_over_c', com_name + 'struct_funcs.buckling.t_over_c') #VMGM # 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 + '.Qx', com_name + 'Qx') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.skin_thickness', com_name + 'skin_thickness') 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') prob.model.connect('alpha', 'AS_point_0' + '.alpha') prob.model.connect('alpha_gust', 'AS_point_1' + '.alpha') prob.model.connect('alpha', 'AS_point_2' + '.alpha') #VMGM # Here we add the co2 objective componenet to the model prob.model.add_subsystem('emittedco2', structureCO2(surfaces=surfaces), promotes_inputs=['co2'], promotes_outputs=['emitted_co2']) #VMGM prob.model.connect('wing.structural_mass', 'emittedco2.mass') prob.model.connect('AS_point_0.total_perf.PV_mass', 'emittedco2.PV_mass') prob.model.connect('wing.spars_mass', 'emittedco2.spars_mass') #VMGM #Here we add the thickness constraint to the model prob.model.add_subsystem('acceptableThickness', checkThickness(surface=surface), promotes_outputs=['acceptableThickness']) prob.model.connect('wing.geometry.t_over_c_cp', 'acceptableThickness.t_over_c') prob.model.connect('wing.chord_cp', 'acceptableThickness.chordroot') prob.model.connect('wing.skin_thickness_cp', 'acceptableThickness.skinThickness') prob.model.connect('wing.taper', 'acceptableThickness.taper') prob.model.connect('wing.struct_setup.PV_areas', 'AS_point_0.coupled.wing.struct_states.PV_areas') prob.model.connect('AS_point_0.total_perf.PV_mass', 'AS_point_0.coupled.wing.struct_states.PV_mass') prob.model.connect('wing.struct_setup.PV_areas', 'AS_point_1.coupled.wing.struct_states.PV_areas') prob.model.connect('AS_point_0.total_perf.PV_mass', 'AS_point_1.coupled.wing.struct_states.PV_mass') prob.model.connect('wing.chord_cp', 'AS_point_1.wing_perf.struct_funcs.chord') prob.model.connect('wing.taper', 'AS_point_1.wing_perf.struct_funcs.taper') prob.model.connect('wing.struct_setup.PV_areas', 'AS_point_2.coupled.wing.struct_states.PV_areas') #VMGM prob.model.connect('AS_point_0.total_perf.PV_mass', 'AS_point_2.coupled.wing.struct_states.PV_mass') #VMGM prob.model.connect('wing.chord_cp', 'AS_point_2.wing_perf.struct_funcs.chord') #VMGM prob.model.connect('wing.taper', 'AS_point_2.wing_perf.struct_funcs.taper') #VMGM # Objective function prob.model.add_objective('emitted_co2', scaler=1e-4) # Design variables prob.model.add_design_var('wing.twist_cp', lower=-20., upper=20., scaler=0.1) #VMGM prob.model.add_design_var('wing.spar_thickness_cp', lower=0.0001, upper=0.1, scaler=1e4) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.0001, upper=0.1, scaler=1e3) prob.model.add_design_var('wing.span', lower=1., upper=1000., scaler=0.1) prob.model.add_design_var('wing.chord_cp', lower=1.4, upper=500., scaler=1) ##prob.model.add_design_var('wing.span', lower=1., upper=50., scaler=0.1) ##prob.model.add_design_var('wing.chord_cp', lower=1., upper=500., scaler=1) prob.model.add_design_var('wing.taper', lower=0.3, upper=0.99, scaler=10) prob.model.add_design_var('wing.geometry.t_over_c_cp', lower=0.01, upper=0.4, scaler=10.) prob.model.add_design_var('mrho', lower=504.5, upper=504.5, scaler=0.001) #ED #prob.model.add_design_var('mrho', lower=500, upper=8000, scaler=0.001) #ED prob.model.add_design_var('engine_location', lower=-1, upper=0, scaler=10.) #VMGM # Constraints prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_constraint( 'AS_point_0.enough_power', upper=0. ) #Make sure needed power stays below the solar power producible by the wing prob.model.add_constraint( 'acceptableThickness', upper=0. ) #Make sure skin thickness fits in the wing (to avoid negative spar mass) #prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) #VMGM #prob.model.add_constraint('AS_point_0.wing_perf.buckling', upper=0.) #VMGM prob.model.add_constraint('AS_point_1.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_1.wing_perf.buckling', upper=0.) prob.model.add_constraint('AS_point_2.wing_perf.failure', upper=0.) #VMGM prob.model.add_constraint('AS_point_2.wing_perf.buckling', upper=0.) #VMGM prob.model.add_constraint( 'AS_point_0.coupled.wing.S_ref', upper=200.) # Surface constarint to avoid snowball effect #prob.model.approx_totals(method='fd', step=5e-7, form='forward', step_calc='rel') #prob.model.nonlinear_solver = newton = NewtonSolver() prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-6 prob.driver.options['maxiter'] = 250 #prob.driver.options['debug_print'] = ['desvars','ln_cons','nl_cons','totals'] recorder = SqliteRecorder("aerostructMrhoi" + str(mrhoi) + "sk" + str(skin) + "sr" + str(spar) + "sn" + str(span) + "tc" + str(toverc) + ".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', 'alpha_gust', # 'AS_point_1.cg', 'AS_point_0.cg', # 'AS_point_0.cg', #ED 'AS_point_0.coupled.wing_loads.loads', 'AS_point_1.coupled.wing_loads.loads', # 'AS_point_2.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_2.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.geometry.mesh.taper.taper', 'wing.geometry.mesh.stretch.span', 'wing.geometry.mesh.scale_x.chord', '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', # 'AS_point_0.total_perf.PV_mass', 'AS_point_0.total_perf.total_weight', 'AS_point_0.CL', 'AS_point_0.CD', 'yield', 'point_masses', #VMGM 'point_mass_locations', #VMGM 'engine_location', #VMGM ] 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 # Set up the problem prob.setup() ##prob.run_model() #ED2 ##data = prob.check_partials(out_stream=None, compact_print=True, method='cs') #ED2 ##print(data) #ED2 prob.run_driver() ##print (prob.model.list_outputs(values=False, implicit=False)) #VMGM print('The wingbox mass (including the wing_weight_ratio) is', prob['wing.structural_mass'][0], '[kg]') endtime = time.time() totaltime = endtime - starttime print('computing time is', totaltime) print('co2 emissions are', prob['emitted_co2'][0]) print('The wing surface is', prob['AS_point_0.coupled.wing.S_ref'][0], '[m2]') #VMGM return prob['wing.structural_mass'][0], totaltime, prob['mrho'][0], prob[ 'emitted_co2'][0]
def get_problem(surface, match_number=0.84, height=7000): # Create the problem and assign the model group prob = Problem() grav_constant = data_heights[height]['g'] v = match_number * data_heights[height]['speed'] re = data_heights[height]['ro'] * data_heights[height][ 'speed'] * match_number / data_heights[height]['visc'] rho = data_heights[height]['ro'] speed_of_sound = data_heights[height]['speed'] indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=v, units='m/s') # change this too indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('Mach_number', val=match_number) indep_var_comp.add_output('re', val=re, units='1/m') # change this too indep_var_comp.add_output('rho', val=rho, 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=speed_of_sound, 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 = 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) prob.setup(check=True) return prob