def test_simul_coloring_example(self): from openmdao.api import Problem, IndepVarComp, ExecComp, ScipyOptimizeDriver import numpy as np # note: size must be an even number SIZE = 10 p = Problem() indeps = p.model.add_subsystem('indeps', IndepVarComp(), promotes_outputs=['*']) # the following were randomly generated using np.random.random(10)*2-1 to randomly # disperse them within a unit circle centered at the origin. indeps.add_output('x', np.array([ 0.55994437, -0.95923447, 0.21798656, -0.02158783, 0.62183717, 0.04007379, 0.46044942, -0.10129622, 0.27720413, -0.37107886])) indeps.add_output('y', np.array([ 0.52577864, 0.30894559, 0.8420792 , 0.35039912, -0.67290778, -0.86236787, -0.97500023, 0.47739414, 0.51174103, 0.10052582])) indeps.add_output('r', .7) p.model.add_subsystem('circle', ExecComp('area=pi*r**2')) p.model.add_subsystem('r_con', ExecComp('g=x**2 + y**2 - r', g=np.ones(SIZE), x=np.ones(SIZE), y=np.ones(SIZE))) thetas = np.linspace(0, np.pi/4, SIZE) p.model.add_subsystem('theta_con', ExecComp('g=arctan(y/x) - theta', g=np.ones(SIZE), x=np.ones(SIZE), y=np.ones(SIZE), theta=thetas)) p.model.add_subsystem('delta_theta_con', ExecComp('g = arctan(y/x)[::2]-arctan(y/x)[1::2]', g=np.ones(SIZE//2), x=np.ones(SIZE), y=np.ones(SIZE))) thetas = np.linspace(0, np.pi/4, SIZE) p.model.add_subsystem('l_conx', ExecComp('g=x-1', g=np.ones(SIZE), x=np.ones(SIZE))) p.model.connect('r', ('circle.r', 'r_con.r')) p.model.connect('x', ['r_con.x', 'theta_con.x', 'delta_theta_con.x']) p.model.connect('x', 'l_conx.x') p.model.connect('y', ['r_con.y', 'theta_con.y', 'delta_theta_con.y']) p.driver = ScipyOptimizeDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.options['disp'] = False p.model.add_design_var('x') p.model.add_design_var('y') p.model.add_design_var('r', lower=.5, upper=10) # nonlinear constraints p.model.add_constraint('r_con.g', equals=0) IND = np.arange(SIZE, dtype=int) ODD_IND = IND[0::2] # all odd indices p.model.add_constraint('theta_con.g', lower=-1e-5, upper=1e-5, indices=ODD_IND) p.model.add_constraint('delta_theta_con.g', lower=-1e-5, upper=1e-5) # this constrains x[0] to be 1 (see definition of l_conx) p.model.add_constraint('l_conx.g', equals=0, linear=False, indices=[0,]) # linear constraint p.model.add_constraint('y', equals=0, indices=[0,], linear=True) p.model.add_objective('circle.area', ref=-1) # setup coloring color_info = ([ [20], # uncolored column list [0, 2, 4, 6, 8], # color 1 [1, 3, 5, 7, 9], # color 2 [10, 12, 14, 16, 18], # color 3 [11, 13, 15, 17, 19], # color 4 ], [ [1, 11, 16, 21], # column 0 [2, 16], # column 1 [3, 12, 17], # column 2 [4, 17], # column 3 [5, 13, 18], # column 4 [6, 18], # column 5 [7, 14, 19], # column 6 [8, 19], # column 7 [9, 15, 20], # column 8 [10, 20], # column 9 [1, 11, 16], # column 10 [2, 16], # column 11 [3, 12, 17], # column 12 [4, 17], # column 13 [5, 13, 18], # column 14 [6, 18], # column 15 [7, 14, 19], # column 16 [8, 19], # column 17 [9, 15, 20], # column 18 [10, 20], # column 19 None, # column 20 ], None) p.driver.set_simul_deriv_color(color_info) p.setup(mode='fwd') p.run_driver() assert_almost_equal(p['circle.area'], np.pi, decimal=7)
def test_dv_at_apogee(self): from openmdao.api import Problem, Group, IndepVarComp, ExecComp, ScipyOptimizeDriver from openmdao.test_suite.test_examples.test_hohmann_transfer import VCircComp, TransferOrbitComp, DeltaVComp prob = Problem(model=Group()) model = prob.model ivc = model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) ivc.add_output('mu', val=0.0, units='km**3/s**2') ivc.add_output('r1', val=0.0, units='km') ivc.add_output('r2', val=0.0, units='km') ivc.add_output('dinc1', val=0.0, units='deg') ivc.add_output('dinc2', val=0.0, units='deg') model.add_subsystem('leo', subsys=VCircComp()) model.add_subsystem('geo', subsys=VCircComp()) model.add_subsystem('transfer', subsys=TransferOrbitComp()) model.connect('r1', ['leo.r', 'transfer.rp']) model.connect('r2', ['geo.r', 'transfer.ra']) model.connect('mu', ['leo.mu', 'geo.mu', 'transfer.mu']) model.add_subsystem('dv1', subsys=DeltaVComp()) model.connect('leo.vcirc', 'dv1.v1') model.connect('transfer.vp', 'dv1.v2') model.connect('dinc1', 'dv1.dinc') model.add_subsystem('dv2', subsys=DeltaVComp()) model.connect('transfer.va', 'dv2.v1') model.connect('geo.vcirc', 'dv2.v2') model.connect('dinc2', 'dv2.dinc') model.add_subsystem('dv_total', subsys=ExecComp('delta_v=dv1+dv2', delta_v={'units': 'km/s'}, dv1={'units': 'km/s'}, dv2={'units': 'km/s'}), promotes=['delta_v']) model.connect('dv1.delta_v', 'dv_total.dv1') model.connect('dv2.delta_v', 'dv_total.dv2') model.add_subsystem('dinc_total', subsys=ExecComp('dinc=dinc1+dinc2', dinc={'units': 'deg'}, dinc1={'units': 'deg'}, dinc2={'units': 'deg'}), promotes=['dinc']) model.connect('dinc1', 'dinc_total.dinc1') model.connect('dinc2', 'dinc_total.dinc2') prob.driver = ScipyOptimizeDriver() model.add_design_var('dinc1', lower=0, upper=28.5) model.add_design_var('dinc2', lower=0, upper=28.5) model.add_constraint('dinc', lower=28.5, upper=28.5, scaler=1.0) model.add_objective('delta_v', scaler=1.0) # Setup the problem prob.setup() prob['mu'] = 398600.4418 prob['r1'] = 6778.137 prob['r2'] = 42164.0 prob['dinc1'] = 0 prob['dinc2'] = 28.5 # Execute the model with the given inputs prob.run_model() print('Delta-V (km/s):', prob['delta_v'][0]) print('Inclination change split (deg):', prob['dinc1'][0], prob['dinc2'][0]) prob.run_driver() print('Optimized Delta-V (km/s):', prob['delta_v'][0]) print('Inclination change split (deg):', prob['dinc1'][0], prob['dinc2'][0])
def test(self): """ This is an opt problem that tests the fuel volume constraint with the wingbox model """ # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'num_x': 2, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 6, 'chord_cos_spacing': 0, 'span_cos_spacing': 0, } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'wingbox', 'spar_thickness_cp': np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp': np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp': np.array([4., 5., 8., 8., 8., 9.]), 'mesh': mesh, 'data_x_upper': upper_x, 'data_x_lower': lower_x, 'data_y_upper': upper_y, 'data_y_lower': lower_y, 'strength_factor_for_upper_skin': 1., # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.0078, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c': 0.12, 'c_max_t': .38, # chordwise location of maximum thickness 'with_viscous': True, 'with_wave': False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E': 73.1e9, # [Pa] Young's modulus 'G': ( 73.1e9 / 2 / 1.33 ), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield': (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho': 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin': 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio': 1.25, 'struct_weight_relief': True, 'distributed_fuel_weight': False, # Constraints 'exact_failure_constraint': False, # if false, use KS function 'fuel_density': 803., # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used) 'Wf_reserve': 15000., # [kg] reserve fuel mass } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=.85 * 295.07, units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=0.85) indep_var_comp.add_output('re', val=0.348 * 295.07 * .85 * 1. / (1.43 * 1e-5), units='1/m') indep_var_comp.add_output('rho', val=0.348, units='kg/m**3') indep_var_comp.add_output('CT', val=0.53 / 3600, units='1/s') indep_var_comp.add_output('R', val=14.307e6, units='m') indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'], units='kg') indep_var_comp.add_output('speed_of_sound', val=295.07, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: com_name = point_name + '.' + name + '_perf.' prob.model.connect( name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect( name + '.element_mass', point_name + '.coupled.' + name + '.element_mass') # Connect performance calculation variables prob.model.connect(name + '.nodes', com_name + 'nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') # Connect wingbox properties to von Mises stress calcs prob.model.connect(name + '.Qz', com_name + 'Qz') prob.model.connect(name + '.J', com_name + 'J') prob.model.connect(name + '.A_enc', com_name + 'A_enc') prob.model.connect(name + '.htop', com_name + 'htop') prob.model.connect(name + '.hbottom', com_name + 'hbottom') prob.model.connect(name + '.hfront', com_name + 'hfront') prob.model.connect(name + '.hrear', com_name + 'hrear') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.t_over_c', com_name + 't_over_c') #======================================================================================= # Here we add the fuel volume constraint componenet to the model #======================================================================================= prob.model.add_subsystem('fuel_vol_delta', WingboxFuelVolDelta(surface=surface)) prob.model.connect('AS_point_0.fuelburn', 'fuel_vol_delta.fuelburn') prob.model.connect('wing.struct_setup.fuel_vols', 'fuel_vol_delta.fuel_vols') #======================================================================================= #======================================================================================= 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'] = 1e-6 # prob.driver.opt_settings['Major feasibility tolerance'] = 1e-8 # prob.driver.opt_settings['Major iterations limit'] = 200 prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) prob.model.add_design_var('wing.twist_cp', lower=-15., upper=15., scaler=0.1) prob.model.add_design_var('wing.spar_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.geometry.t_over_c_cp', lower=0.07, upper=0.2, scaler=10.) prob.model.add_constraint('AS_point_0.CL', equals=0.5) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) #======================================================================================= # Here we add the fuel volume constraint #======================================================================================= prob.model.add_constraint('fuel_vol_delta.fuel_vol_delta', lower=0.) #======================================================================================= #======================================================================================= # 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_mass'][0]/1.25) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 83619.581901, 1e-5) assert_rel_error(self, prob['wing.structural_mass'][0] / 1.25, 13768.9206457, 1e-5) assert_rel_error(self, prob['fuel_vol_delta.fuel_vol_delta'][0], 39.6491222105, 1e-4)
def test_feature_vectorized_derivs(self): import numpy as np from openmdao.api import ExplicitComponent, IndepVarComp, Problem, ScipyOptimizeDriver SIZE = 5 class ExpensiveAnalysis(ExplicitComponent): def setup(self): self.add_input('x', val=np.ones(SIZE)) self.add_input('y', val=np.ones(SIZE)) self.add_output('f', shape=1) self.declare_partials('f', 'x') self.declare_partials('f', 'y') def compute(self, inputs, outputs): outputs['f'] = np.sum(inputs['x']**inputs['y']) def compute_partials(self, inputs, J): J['f', 'x'] = inputs['y'] * inputs['x']**(inputs['y'] - 1) J['f', 'y'] = (inputs['x']**inputs['y']) * np.log(inputs['x']) class CheapConstraint(ExplicitComponent): def setup(self): self.add_input('y', val=np.ones(SIZE)) self.add_output('g', shape=SIZE) row_col = np.arange(SIZE, dtype=int) self.declare_partials('g', 'y', rows=row_col, cols=row_col) self.limit = 2 * np.arange(SIZE) def compute(self, inputs, outputs): outputs['g'] = inputs['y']**2 - self.limit def compute_partials(self, inputs, J): J['g', 'y'] = 2 * inputs['y'] p = Problem() dvs = p.model.add_subsystem('des_vars', IndepVarComp(), promotes=['*']) dvs.add_output('x', 2 * np.ones(SIZE)) dvs.add_output('y', 2 * np.ones(SIZE)) p.model.add_subsystem('obj', ExpensiveAnalysis(), promotes=['x', 'y', 'f']) p.model.add_subsystem('constraint', CheapConstraint(), promotes=['y', 'g']) p.model.add_design_var('x', lower=.1, upper=10000) p.model.add_design_var('y', lower=-1000, upper=10000) p.model.add_constraint('g', upper=0, vectorize_derivs=True) p.model.add_objective('f') p.setup(mode='rev') p.run_model() p.driver = ScipyOptimizeDriver() p.run_driver() assert_rel_error(self, p['x'], [0.10000691, 0.1, 0.1, 0.1, 0.1], 1e-5) assert_rel_error(self, p['y'], [0, 1.41421, 2.0, 2.44948, 2.82842], 1e-5)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'rect', 'symmetry': True, 'span': 10., 'chord': 1, 'span_cos_spacing': 0. } mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aero', 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'twist_cp': np.zeros(5), 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.0, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': False, # if true, compute viscous drag 'with_wave': False, # if true, compute wave drag } surfaces = [surf_dict] # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect( name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect( name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() # # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5) prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4) # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], .46173591841167, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], .005524603647, 1e-6)
def test_recording_remote_voi(self): # Create a parallel model model = Group() model.add_subsystem('par', ParallelGroup()) model.par.add_subsystem('G1', Mygroup()) model.par.add_subsystem('G2', Mygroup()) model.connect('par.G1.y', 'Obj.y1') model.connect('par.G2.y', 'Obj.y2') model.add_subsystem('Obj', ExecComp('obj=y1+y2')) model.add_objective('Obj.obj') # Configure driver to record VOIs on both procs driver = ScipyOptimizeDriver(disp=False) driver.recording_options['record_desvars'] = True driver.recording_options['record_objectives'] = True driver.recording_options['record_constraints'] = True driver.recording_options['includes'] = ['par.G1.y', 'par.G2.y'] driver.add_recorder(self.recorder) # Create problem and run driver prob = Problem(model, driver) prob.add_recorder(self.recorder) prob.setup(mode='fwd') t0, t1 = run_driver(prob) prob.record('final') t2 = time() prob.cleanup() # Since the test will compare the last case recorded, just check the # current values in the problem. This next section is about getting those values # These involve collective gathers so all ranks need to run this expected_outputs = driver.get_design_var_values() expected_outputs.update(driver.get_objective_values()) expected_outputs.update(driver.get_constraint_values()) # includes for outputs are specified as promoted names but we need absolute names prom2abs = model._var_allprocs_prom2abs_list['output'] abs_includes = [ prom2abs[n][0] for n in prob.driver.recording_options['includes'] ] # Absolute path names of includes on this rank rrank = model.comm.rank rowned = model._owning_rank local_includes = [n for n in abs_includes if rrank == rowned[n]] # Get values for all vars on this rank inputs, outputs, residuals = model.get_nonlinear_vectors() # Get values for includes on this rank local_vars = {n: outputs[n] for n in local_includes} # Gather values for includes on all ranks all_vars = model.comm.gather(local_vars, root=0) if prob.comm.rank == 0: # Only on rank 0 do we have all the values. The all_vars variable is a list of # dicts from all ranks 0,1,... In this case, just ranks 0 and 1 dct = {} for d in all_vars: dct.update(d) expected_includes = { 'par.G1.Cy.y': dct['par.G1.Cy.y'], 'par.G2.Cy.y': dct['par.G2.Cy.y'], } expected_outputs.update(expected_includes) coordinate = [0, 'ScipyOptimize_SLSQP', (driver.iter_count - 1, )] expected_data = ((coordinate, (t0, t1), expected_outputs, None, None), ) assertDriverIterDataRecorded(self, expected_data, self.eps) expected_data = (('final', (t1, t2), expected_outputs), ) assertProblemDataRecorded(self, expected_data, self.eps)
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 test_brachistochrone_vector_ode_path_constraints_rk_partial_indices( self): p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneVectorStatesODE, transcription=RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.set_state_options('pos', fix_initial=True, fix_final=False) phase.set_state_options('v', fix_initial=True, fix_final=False) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665) phase.add_boundary_constraint('pos', loc='final', equals=[10, 5]) phase.add_path_constraint('pos_dot', shape=(2, ), units='m/s', indices=[1], lower=-4, upper=4) phase.add_timeseries_output('pos_dot', shape=(2, ), units='m/s') # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 pos0 = [0, 10] posf = [10, 5] p['phase0.states:pos'] = phase.interpolate(ys=[pos0, posf], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100], nodes='control_input') p['phase0.design_parameters:g'] = 9.80665 p.run_driver() assert_rel_error(self, np.min(p.get_val('phase0.timeseries.pos_dot')[:, -1]), -4, tolerance=1.0E-2) # Plot results if SHOW_PLOTS: exp_out = phase.simulate(times_per_seg=20) fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.states:pos')[:, 0] y_imp = p.get_val('phase0.timeseries.states:pos')[:, 1] x_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 0] y_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 1] ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('x (m)') ax.set_ylabel('y (m)') ax.grid(True) ax.legend(loc='upper right') fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution\nVelocity') t_imp = p.get_val('phase0.timeseries.time') t_exp = exp_out.get_val('phase0.timeseries.time') xdot_imp = p.get_val('phase0.timeseries.pos_dot')[:, 0] ydot_imp = p.get_val('phase0.timeseries.pos_dot')[:, 1] xdot_exp = exp_out.get_val('phase0.timeseries.pos_dot')[:, 0] ydot_exp = exp_out.get_val('phase0.timeseries.pos_dot')[:, 1] ax.plot(t_imp, xdot_imp, 'bo', label='implicit') ax.plot(t_exp, xdot_exp, 'b-', label='explicit') ax.plot(t_imp, ydot_imp, 'ro', label='implicit') ax.plot(t_exp, ydot_exp, 'r-', label='explicit') ax.set_xlabel('t (s)') ax.set_ylabel('v (m/s)') ax.grid(True) ax.legend(loc='upper right') fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.time') y_imp = p.get_val('phase0.timeseries.control_rates:theta_rate2') x_exp = exp_out.get_val('phase0.timeseries.time') y_exp = exp_out.get_val( 'phase0.timeseries.control_rates:theta_rate2') ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('time (s)') ax.set_ylabel('theta rate2 (rad/s**2)') ax.grid(True) ax.legend(loc='lower right') plt.show() return p
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'rect', 'symmetry': True, 'span_cos_spacing': 1., 'span': 10, 'chord': 1 } mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'structural', 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type': 'tube', 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Structural values are based on aluminum 7075 'E': 70.e9, # [Pa] Young's modulus of the spar 'G': 30.e9, # [Pa] shear modulus of the spar 'yield': 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case 'mrho': 3.e3, # [kg/m^3] material density 'fem_origin': 0.35, # normalized chordwise location of the spar 't_over_c_cp': np.array([0.15]), # maximum airfoil thickness 'thickness_cp': np.ones((3)) * .0075, 'wing_weight_ratio': 1., 'exact_failure_constraint': False, } # Create the problem and assign the model group prob = Problem() ny = surf_dict['num_y'] loads = np.zeros((ny, 6)) loads[0, 2] = 1e4 indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=loads, units='N') indep_var_comp.add_output('load_factor', val=1.) struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['disp'] = True # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.thickness_cp', lower=0.001, upper=0.25, scaler=1e2) prob.model.add_constraint('wing.failure', upper=0.) prob.model.add_constraint('wing.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_objective('wing.structural_weight', scaler=1e-5) # Set up the problem prob.setup() # from openmdao.api import view_model # view_model(prob) prob.run_driver() assert_rel_error(self, prob['wing.structural_weight'][0], 1144.8503583047038, 1e-4)
def test_cruise_results(self): p = Problem(model=Group()) if optimizer == 'SNOPT': p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = True p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major step limit'] = 0.05 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings["Linesearch tolerance"] = 0.10 p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Verify level'] = 3 else: p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase('gauss-lobatto', ode_class=AircraftODE, num_segments=1, transcription_order=13) # Pass Reference Area from an external source assumptions = p.model.add_subsystem('assumptions', IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(3600, 3600), duration_ref=3600) phase.set_state_options('range', units='km', fix_initial=True, fix_final=False, scaler=0.01, defect_scaler=0.01) phase.set_state_options('mass_fuel', fix_final=True, upper=20000.0, lower=0.0, scaler=1.0E-4, defect_scaler=1.0E-2) phase.add_control('alt', units='km', opt=False, rate_param='climb_rate') phase.add_control('mach', units=None, opt=False) phase.add_input_parameter('S', units='m**2') phase.add_input_parameter('mass_empty', units='kg') phase.add_input_parameter('mass_payload', units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=1.0) p.model.connect('assumptions.S', 'phase0.input_parameters:S') p.model.connect('assumptions.mass_empty', 'phase0.input_parameters:mass_empty') p.model.connect('assumptions.mass_payload', 'phase0.input_parameters:mass_payload') phase.add_objective('time', loc='final', ref=3600) p.model.linear_solver = DirectSolver(assemble_jac=True) p.model.options['assembled_jac_type'] = 'csc' p.setup() p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 1.515132 * 3600.0 p['phase0.states:range'] = phase.interpolate(ys=(0, 1296.4), nodes='state_input') p['phase0.states:mass_fuel'] = phase.interpolate(ys=(12236.594555, 0), nodes='state_input') p['phase0.controls:mach'] = 0.8 p['phase0.controls:alt'] = 5.0 p['assumptions.S'] = 427.8 p['assumptions.mass_empty'] = 0.15E6 p['assumptions.mass_payload'] = 84.02869 * 400 p.run_driver() tas = phase.get_values('tas_comp.TAS', units='m/s') time = phase.get_values('time', units='s') range = phase.get_values('range', units='m') assert_rel_error(self, range, tas * time, tolerance=1.0E-9)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'wing_type': 'uCRM_based', 'symmetry': True, 'num_twist_cp': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'wingbox', 'symmetry': True, 'spar_thickness_cp': np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp': np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp': np.array([4., 5., 8., 8., 8., 9.]), 'mesh': mesh, 'data_x_upper': upper_x, 'data_x_lower': lower_x, 'data_y_upper': upper_y, 'data_y_lower': lower_y, 'strength_factor_for_upper_skin': 1., # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.0078, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c': 0.12, 'c_max_t': .38, # chordwise location of maximum thickness 'with_viscous': True, 'with_wave': True, # if true, compute wave drag # Structural values are based on aluminum 7075 'E': 73.1e9, # [Pa] Young's modulus 'G': ( 73.1e9 / 2 / 1.33 ), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield': (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho': 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin': 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio': 1.25, 'struct_weight_relief': False, 'distributed_fuel_weight': True, # Constraints 'exact_failure_constraint': True, # if false, use KS function 'fuel_density': 803., # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used) 'Wf_reserve': 15000., # [kg] reserve fuel mass } # Create the problem and assign the model group prob = Problem() ny = surf_dict['mesh'].shape[1] indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.ones((ny, 6)) * 2e5, units='N') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('fuel_mass', val=10000., units='kg') struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) if surf_dict['distributed_fuel_weight']: prob.model.connect('wing.fuel_mass', 'wing.struct_states.fuel_mass') prob.model.connect('wing.struct_setup.fuel_vols', 'wing.struct_states.fuel_vols') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.spar_thickness_cp', lower=0.01, upper=0.5, ref=1e-1) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.01, upper=0.5, ref=1e-1) prob.model.add_constraint('wing.failure', upper=0.) #prob.model.add_constraint('wing.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_objective('wing.structural_mass', scaler=1e-5) # Set up the problem prob.setup(force_alloc_complex=False) prob.run_model() data = prob.check_partials(compact_print=True, out_stream=None, method='fd') assert_check_partials(data, atol=1e20, rtol=1e-6) prob.run_driver() assert_rel_error(self, prob['wing.structural_mass'], 16704.07393593, 1e-6)
def driver(self): # type: () -> Driver """Method to return a preconfigured driver. Returns ------- Driver A preconfigured driver element to be used for the Problem instance. Raises ------ ValueError Value error are raised if unsupported settings are encountered. """ if self.driver_type == 'optimizer': # Find optimizer element in CMDOWS file opt_uid = self.driver_uid opt_elem = get_element_by_uid(self.elem_cmdows, opt_uid) # Load settings from CMDOWS file opt_package = get_opt_setting_safe(opt_elem, 'package', 'SciPy') opt_algo = get_opt_setting_safe(opt_elem, 'algorithm', 'SLSQP') opt_maxiter = get_opt_setting_safe(opt_elem, 'maximumIterations', 50, expected_type='int') opt_convtol = get_opt_setting_safe(opt_elem, 'convergenceTolerance', 1e-6, expected_type='float') # Apply settings to the driver # driver if opt_package == 'SciPy': driver = ScipyOptimizeDriver() elif opt_package == 'pyOptSparse': try: from openmdao.api import pyOptSparseDriver except ImportError: raise PyOptSparseImportError() driver = pyOptSparseDriver() else: raise ValueError( 'Unsupported package {} encountered in CMDOWS file for "{}".' .format(opt_package, opt_uid)) # optimization algorithm if opt_algo == 'SLSQP': driver.options['optimizer'] = 'SLSQP' elif opt_algo == 'COBYLA': driver.options['optimizer'] = 'COBYLA' elif opt_algo == 'L-BFGS-B': driver.options['optimizer'] = 'L-BFGS-B' else: raise ValueError( 'Unsupported algorithm {} encountered in CMDOWS file for "{}".' .format(opt_algo, opt_uid)) # maximum iterations and tolerance if isinstance(driver, ScipyOptimizeDriver): driver.options['maxiter'] = opt_maxiter driver.options['tol'] = opt_convtol elif isinstance(driver, pyOptSparseDriver): driver.opt_settings['MAXIT'] = opt_maxiter driver.opt_settings['ACC'] = opt_convtol # Set default display and output settings if isinstance(driver, ScipyOptimizeDriver): driver.options['disp'] = False # Print the result return driver elif self.driver_type == 'doe': # Find DOE element in CMDOWS file doe_uid = self.driver_uid doe_elem = get_element_by_uid(self.elem_cmdows, doe_uid) # Load settings from CMDOWS file doe_method = get_doe_setting_safe(doe_elem, 'method', 'Uniform design') # type: str doe_runs = get_doe_setting_safe(doe_elem, 'runs', 5, expected_type='int', doe_method=doe_method, required_for_doe_methods=[ 'Latin hypercube design', 'Uniform design', 'Monte Carlo design' ]) doe_center_runs = get_doe_setting_safe( doe_elem, 'centerRuns', 2, expected_type='int', doe_method=doe_method, required_for_doe_methods=['Box-Behnken design']) doe_seed = get_doe_setting_safe(doe_elem, 'seed', None, expected_type='int', doe_method=doe_method, required_for_doe_methods=[ 'Latin hypercube design', 'Uniform design', 'Monte Carlo design' ]) doe_levels = get_doe_setting_safe( doe_elem, 'levels', 2, expected_type='int', doe_method=doe_method, required_for_doe_methods=['Full factorial design']) # table doe_data = [] if isinstance(doe_elem.find('settings/table'), _Element): doe_table = doe_elem.find('settings/table') doe_table_rows = [row for row in doe_table.iterchildren()] n_samples = len( [exp for exp in doe_table_rows[0].iterchildren()]) for idx in range(n_samples): data_sample = [] for row_elem in doe_table_rows: value = float( row_elem.find( 'tableElement[@experimentID="{}"]'.format( idx)).text) data_sample.append( [row_elem.attrib['relatedParameterUID'], value]) doe_data.append(data_sample) else: if doe_method in ['Custom design table']: raise ValueError( 'Table element with data for custom design table missing in ' 'CMDOWS file.') # Apply settings to the driver # define driver driver = DOEDriver() # define generator if doe_method in ['Uniform design', 'Monte Carlo design']: driver.options['generator'] = UniformGenerator( num_samples=doe_runs, seed=doe_seed) elif doe_method == 'Full factorial design': driver.options['generator'] = FullFactorialGenerator( levels=doe_levels) elif doe_method == 'Box-Behnken design': driver.options['generator'] = BoxBehnkenGenerator( center=doe_center_runs) elif doe_method == 'Latin hypercube design': driver.options['generator'] = LatinHypercubeGenerator( samples=doe_runs, criterion='maximin', seed=doe_seed) elif doe_method == 'Custom design table': driver.options['generator'] = ListGenerator(data=doe_data) else: raise ValueError( 'Could not match the doe_method {} with methods from OpenMDAO.' .format(doe_method)) return driver else: return Driver()
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'num_x': 3, 'wing_type': 'uCRM_based', 'symmetry': True, 'chord_cos_spacing': 0, 'span_cos_spacing': 0, 'num_twist_cp': 6, } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'mesh': mesh, 'twist_cp': np.array([4., 5., 8., 8., 8., 9.]), 'fem_model_type': 'wingbox', 'data_x_upper': upper_x, 'data_x_lower': lower_x, 'data_y_upper': upper_y, 'data_y_lower': lower_y, 'spar_thickness_cp': np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp': np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'original_wingbox_airfoil_t_over_c': 0.12, # Aerodynamic deltas. # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. # They can be used to account for things that are not included, such as contributions from the fuselage, nacelles, tail surfaces, etc. 'CL0': 0.0, 'CD0': 0.0078, 'with_viscous': True, # if true, compute viscous drag 'with_wave': True, # if true, compute wave drag # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 'c_max_t': .38, # chordwise location of maximum thickness 't_over_c_cp': np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), # Structural values are based on aluminum 7075 'E': 73.1e9, # [Pa] Young's modulus 'G': ( 73.1e9 / 2 / 1.33 ), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield': (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho': 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin': 1.0, # the yield stress is multiplied by this factor for the upper skin 'wing_weight_ratio': 1.25, 'exact_failure_constraint': False, # if false, use KS function 'struct_weight_relief': True, 'distributed_fuel_weight': True, 'fuel_density': 803., # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used) 'Wf_reserve': 15000., # [kg] reserve fuel mass } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=np.array([.85 * 295.07, .64 * 340.294]), units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('alpha_maneuver', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=np.array([0.85, 0.64])) indep_var_comp.add_output('re',val=np.array([0.348*295.07*.85*1./(1.43*1e-5), \ 1.225*340.294*.64*1./(1.81206*1e-5)]), units='1/m') indep_var_comp.add_output('rho', val=np.array([0.348, 1.225]), units='kg/m**3') indep_var_comp.add_output('CT', val=0.53 / 3600, units='1/s') indep_var_comp.add_output('R', val=14.307e6, units='m') indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'], units='kg') indep_var_comp.add_output('speed_of_sound', val=np.array([295.07, 340.294]), units='m/s') indep_var_comp.add_output('load_factor', val=np.array([1., 2.5])) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') indep_var_comp.add_output('fuel_mass', val=10000., units='kg') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aerostruct points for i in range(2): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aerostruct point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces, internally_connect_fuelburn=False) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v', src_indices=[i]) prob.model.connect('Mach_number', point_name + '.Mach_number', src_indices=[i]) prob.model.connect('re', point_name + '.re', src_indices=[i]) prob.model.connect('rho', point_name + '.rho', src_indices=[i]) prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound', src_indices=[i]) prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor', src_indices=[i]) prob.model.connect('fuel_mass', point_name + '.total_perf.L_equals_W.fuelburn') prob.model.connect('fuel_mass', point_name + '.total_perf.CG.fuelburn') for surface in surfaces: name = surface['name'] if surf_dict['distributed_fuel_weight']: prob.model.connect('load_factor', point_name + '.coupled.load_factor', src_indices=[i]) com_name = point_name + '.' + name + '_perf.' prob.model.connect( name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') if surf_dict['struct_weight_relief']: prob.model.connect( name + '.element_mass', point_name + '.coupled.' + name + '.element_mass') # Connect performance calculation variables prob.model.connect(name + '.nodes', com_name + 'nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') # Connect wingbox properties to von Mises stress calcs prob.model.connect(name + '.Qz', com_name + 'Qz') prob.model.connect(name + '.J', com_name + 'J') prob.model.connect(name + '.A_enc', com_name + 'A_enc') prob.model.connect(name + '.htop', com_name + 'htop') prob.model.connect(name + '.hbottom', com_name + 'hbottom') prob.model.connect(name + '.hfront', com_name + 'hfront') prob.model.connect(name + '.hrear', com_name + 'hrear') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.t_over_c', com_name + 't_over_c') prob.model.connect('alpha', 'AS_point_0' + '.alpha') prob.model.connect('alpha_maneuver', 'AS_point_1' + '.alpha') # Here we add the fuel volume constraint componenet to the model prob.model.add_subsystem('fuel_vol_delta', WingboxFuelVolDelta(surface=surface)) prob.model.connect('wing.struct_setup.fuel_vols', 'fuel_vol_delta.fuel_vols') prob.model.connect('AS_point_0.fuelburn', 'fuel_vol_delta.fuelburn') if surf_dict['distributed_fuel_weight']: prob.model.connect( 'wing.struct_setup.fuel_vols', 'AS_point_0.coupled.wing.struct_states.fuel_vols') prob.model.connect( 'fuel_mass', 'AS_point_0.coupled.wing.struct_states.fuel_mass') prob.model.connect( 'wing.struct_setup.fuel_vols', 'AS_point_1.coupled.wing.struct_states.fuel_vols') prob.model.connect( 'fuel_mass', 'AS_point_1.coupled.wing.struct_states.fuel_mass') comp = ExecComp('fuel_diff = (fuel_mass - fuelburn) / fuelburn') prob.model.add_subsystem('fuel_diff', comp, promotes_inputs=['fuel_mass'], promotes_outputs=['fuel_diff']) prob.model.connect('AS_point_0.fuelburn', 'fuel_diff.fuelburn') ## Use these settings if you do not have pyOptSparse or SNOPT prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-8 recorder = SqliteRecorder("unit_test.db") prob.driver.add_recorder(recorder) # We could also just use prob.driver.recording_options['includes']=['*'] here, but for large meshes the database file becomes extremely large. So we just select the variables we need. prob.driver.recording_options['includes'] = [ 'alpha', 'rho', 'v', 'cg', 'AS_point_1.cg', 'AS_point_0.cg', 'AS_point_0.coupled.wing_loads.loads', 'AS_point_1.coupled.wing_loads.loads', 'AS_point_0.coupled.wing.normals', 'AS_point_1.coupled.wing.normals', 'AS_point_0.coupled.wing.widths', 'AS_point_1.coupled.wing.widths', 'AS_point_0.coupled.aero_states.wing_sec_forces', 'AS_point_1.coupled.aero_states.wing_sec_forces', 'AS_point_0.wing_perf.CL1', 'AS_point_1.wing_perf.CL1', 'AS_point_0.coupled.wing.S_ref', 'AS_point_1.coupled.wing.S_ref', 'wing.geometry.twist', 'wing.mesh', 'wing.skin_thickness', 'wing.spar_thickness', 'wing.t_over_c', 'wing.structural_mass', 'AS_point_0.wing_perf.vonmises', 'AS_point_1.wing_perf.vonmises', 'AS_point_0.coupled.wing.def_mesh', 'AS_point_1.coupled.wing.def_mesh', ] prob.driver.recording_options['record_objectives'] = True prob.driver.recording_options['record_constraints'] = True prob.driver.recording_options['record_desvars'] = True prob.driver.recording_options['record_inputs'] = True prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) prob.model.add_design_var('wing.twist_cp', lower=-15., upper=15., scaler=0.1) prob.model.add_design_var('wing.spar_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.geometry.t_over_c_cp', lower=0.07, upper=0.2, scaler=10.) prob.model.add_design_var('fuel_mass', lower=0., upper=2e5, scaler=1e-5) prob.model.add_design_var('alpha_maneuver', lower=-15., upper=15) prob.model.add_constraint('AS_point_0.CL', equals=0.5) prob.model.add_constraint('AS_point_1.L_equals_W', equals=0.) prob.model.add_constraint('AS_point_1.wing_perf.failure', upper=0.) prob.model.add_constraint('fuel_vol_delta.fuel_vol_delta', lower=0.) prob.model.add_constraint('fuel_diff', equals=0.) # Set up the problem prob.setup() prob.run_driver() # print(prob['AS_point_0.fuelburn'][0]) # print(prob['wing.structural_mass'][0]/surf_dict['wing_weight_ratio']) # print(prob['wing.geometry.t_over_c_cp']) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 101937.827384, 1e-5) assert_rel_error( self, prob['wing.structural_mass'][0] / surf_dict['wing_weight_ratio'], 36539.6437566, 1e-5) assert_rel_error( self, prob['wing.geometry.t_over_c_cp'], np.array([ 0.10247881, 0.08207636, 0.11114547, 0.13114547, 0.10207636, 0.09365598 ]), 1e-5)
def test_brachistochrone_recording_for_docs(self): import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver, \ SqliteRecorder, CaseReader from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() phase = Phase('gauss-lobatto', ode_class=BrachistochroneODE, num_segments=10) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(.5, 10)) phase.set_state_options('x', fix_initial=True, fix_final=True) phase.set_state_options('y', fix_initial=True, fix_final=True) phase.set_state_options('v', fix_initial=True) phase.add_control('theta', units='deg', rate_continuity=False, lower=0.01, upper=179.9) phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = DirectSolver(assemble_jac=True) p.model.options['assembled_jac_type'] = 'csc' # Recording rec = SqliteRecorder('brachistochrone_solution.db') p.driver.recording_options['record_desvars'] = True p.driver.recording_options['record_responses'] = True p.driver.recording_options['record_objectives'] = True p.driver.recording_options['record_constraints'] = True p.model.recording_options['record_metadata'] = True p.driver.add_recorder(rec) p.model.add_recorder(rec) phase.add_recorder(rec) p.setup() p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5], nodes='control_input') # Solve for the optimal trajectory p.run_driver() # Test the results assert_rel_error(self, phase.get_values('time')[-1], 1.8016, tolerance=1.0E-3) cr = CaseReader('brachistochrone_solution.db') outputs = dict([ (o[0], o[1]) for o in cr.list_outputs(units=True, shape=True, out_stream=None) ]) assert_rel_error( self, p['phase0.controls:theta'], outputs['phase0.indep_controls.controls:theta']['value']) phase0_options = cr.system_metadata['phase0']['component_options'] num_segments = phase0_options['num_segments'] transcription_order = phase0_options['transcription_order'] segment_ends = phase0_options['segment_ends'] ode_class = phase0_options['ode_class'] print(num_segments) print(transcription_order) print(ode_class) print(segment_ends)
def main(tot_iter): objectives = {0: "compliance", 1: "stress"} # TODO: folder path and restart # must be manually input each time loadFolder = loadFolder0 + "" restart_iter = 26 import os try: os.mkdir(loadFolder + 'restart_' + str(restart_iter)) except: pass try: os.mkdir(loadFolder + 'restart_' + str(restart_iter) + '/figs') except: pass inspctFlag = False if tot_iter < 0: inspctFlag = True tot_iter = restart_iter + 1 # Select which problem to solve obj_flag = 1 print(locals()) print("solving single physics %s problem" % objectives[obj_flag]) print("restarting from %d ..." % restart_iter) fname0 = loadFolder + 'phi%03i.pkl' % restart_iter with open(fname0, 'rb') as f: raw = pickle.load(f) phi0 = raw['phi'] fname0 = loadFolder0 + 'const.pkl' with open(fname0, 'rb') as f: raw = pickle.load(f) # nodes = raw['mesh'] nodes = raw['nodes'] elem = raw['elem'] GF_e = raw['GF_e'] BCid_e = raw['BCid_e'] E = raw['E'] nu = raw['nu'] f = raw['f'] nelx = raw['nelx'] nely = raw['nely'] length_x = raw['length_x'] length_y = raw['length_y'] coord_e = raw['coord_e'] tol_e = raw['tol_e'] ############################################################################ ########################### FEA ########################### ############################################################################ # NB: only Q4 elements + integer-spaced mesh are assumed ls2fe_x = length_x / float(nelx) ls2fe_y = length_y / float(nely) num_nodes_x = nelx + 1 num_nodes_y = nely + 1 nELEM = nelx * nely nNODE = num_nodes_x * num_nodes_y # Declare FEA object (OpenLSTO_FEA) ============================== fea_solver = py_FEA(lx=length_x, ly=length_y, nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = fea_solver.get_mesh() ## validate the mesh if nELEM != elem.shape[0]: error("error found in the element") if nNODE != node.shape[0]: error("error found in the node") nDOF_e = nNODE * 2 # each node has two displacement DOFs # constitutive properties ======================================== fea_solver.set_material(E=E, nu=nu, rho=1.0) # Boundary Conditions ============================================ fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF ############################################################################ ########################### LSM ########################### ############################################################################ movelimit = 0.5 # Declare Level-set object lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit) lsm_solver.add_holes([], [], []) lsm_solver.set_levelset() lsm_solver.set_phi_re(phi0) lsm_solver.reinitialise() ############################################################################ ######################## T.O. LOOP ######################## ############################################################################ for i_HJ in range(restart_iter, tot_iter): (bpts_xy, areafraction, seglength) = lsm_solver.discretise() # OpenMDAO =================================================== ## Define Group if (objectives[obj_flag] == "compliance"): model = ComplianceGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, BCid=BCid_e) elif (objectives[obj_flag] == "stress"): model = StressGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, pval=6.0, BCid=BCid_e) ## Define problem for OpenMDAO object prob = Problem(model) ## Setup the problem prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = 'IPOPT' prob.driver.opt_settings['linear_solver'] = 'ma27' prob.setup(check=False) prob.run_model() ## Total derivative using MAUD if (objectives[obj_flag] == "compliance"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "stress"): ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] ## Assign object function sensitivities nBpts = int(bpts_xy.shape[0]) Sf = -ff[:nBpts] # equal to M2DO-perturbation Cf = np.multiply( Sf, seglength) # Shape sensitivity (integral coefficients) ## Assign constraint sensitivities Sg = -gg[:nBpts] Sg[Sg < -1.5] = -1.5 # apply caps (bracketing) to constraint sensitivities Sg[Sg > 0.5] = 0.5 # apply caps (bracketing) to constraint sensitivities Cg = np.multiply( Sg, seglength) # Shape sensitivity (integral coefficients) # Suboptimize ================================================ if 1: suboptim = Solvers(bpts_xy=bpts_xy, Sf=Sf, Sg=Sg, Cf=Cf, Cg=Cg, length_x=length_x, length_y=length_y, areafraction=areafraction, movelimit=movelimit) # suboptimization if 1: # simplex Bpt_Vel = suboptim.simplex(isprint=False) else: # bisection.. Bpt_Vel = suboptim.bisection(isprint=False) timestep = 1.0 elif 1: # works okay now. bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() model = LSM2D_slpGroup(lsm_solver=lsm_solver, num_bpts=nBpts, b=ub2, lb=lb2, Sf=bpts_sens[:, 0], Sg=bpts_sens[:, 1], constraintDistance=constraint_distance, movelimit=movelimit) subprob = Problem(model) subprob.setup() subprob.driver = ScipyOptimizeDriver() subprob.driver.options['optimizer'] = 'SLSQP' subprob.driver.options['disp'] = True subprob.driver.options['tol'] = 1e-10 subprob.run_driver() lambdas = subprob['inputs_comp.lambdas'] displacements_ = subprob['displacement_comp.displacements'] displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # print(timestep) del subprob else: # branch: perturb-suboptim bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() constraintDistance = np.array([constraint_distance]) scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance( constraintDistance) def objF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delF(displacement_np) def conF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delG(displacement_np, scaled_constraintDist, 1) cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)}) res = sp_optim.minimize(objF_nocallback, np.zeros(2), method='SLSQP', options={'disp': True}, bounds=((lb2[0], ub2[0]), (lb2[1], ub2[1])), constraints=cons) lambdas = res.x displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas) displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # scaling # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel)) lsm_solver.advect(Bpt_Vel, timestep) lsm_solver.reinitialise() if not inspctFlag: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(loadFolder + 'restart_' + str(restart_iter) + "/" + "figs/bpts_%d.png" % i_HJ) print('loop %d is finished' % i_HJ) area = areafraction.sum() / (nelx * nely) u = prob['disp_comp.disp'] compliance = np.dot(u, GF_e[:nDOF_e]) # Printing/Plotting ========================================== if 1: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(loadFolder + 'restart_' + str(restart_iter) + "/" + "figs/bpts_%d.png" % i_HJ) if (objectives[obj_flag] == "compliance" and not inspctFlag): compliance = prob['compliance_comp.compliance'] print(compliance, area) fid = open( loadFolder + 'restart_' + str(restart_iter) + "/" + "log.txt", "a+") fid.write(str(compliance) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "stress" and not inspctFlag): print(prob['pnorm_comp.pnorm'][0], area) fid = open( loadFolder + 'restart_' + str(restart_iter) + "/" + "log.txt", "a+") fid.write( str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n") fid.close() ## Saving Phi phi = lsm_solver.get_phi() if not inspctFlag: raw = {} raw['phi'] = phi filename = loadFolder + 'restart_' + str( restart_iter) + '/' + 'phi%03i.pkl' % i_HJ with open(filename, 'wb') as f: pickle.dump(raw, f) del model del prob mem = virtual_memory() print(str(mem.available / 1024. / 1024. / 1024.) + "GB") if mem.available / 1024. / 1024. / 1024. < 3.0: print("memory explodes at iteration %3i " % i_HJ) exit()
def test_debug_print_desvar_physical_with_indices(self): prob = Problem() model = prob.model = Group() size = 3 model.add_subsystem('p1', IndepVarComp('x', np.array([50.0] * size))) model.add_subsystem('p2', IndepVarComp('y', np.array([50.0] * size))) model.add_subsystem( 'comp', ExecComp('f_xy = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0', x=np.zeros(size), y=np.zeros(size), f_xy=np.zeros(size))) model.add_subsystem( 'con', ExecComp('c = - x + y', c=np.zeros(size), x=np.zeros(size), y=np.zeros(size))) model.connect('p1.x', 'comp.x') model.connect('p2.y', 'comp.y') model.connect('p1.x', 'con.x') model.connect('p2.y', 'con.y') prob.set_solver_print(level=0) prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = False model.add_design_var('p1.x', indices=[1], lower=-50.0, upper=50.0, ref=[ 5.0, ]) model.add_design_var('p2.y', indices=[1], lower=-50.0, upper=50.0) model.add_objective('comp.f_xy', index=1) model.add_constraint('con.c', indices=[1], upper=-15.0) prob.setup(check=False) prob.driver.options['debug_print'] = [ 'desvars', ] stdout = sys.stdout strout = StringIO() sys.stdout = strout try: # formatting has changed in numpy 1.14 and beyond. if LooseVersion(np.__version__) >= LooseVersion("1.14"): with printoptions(precision=2, legacy="1.13"): prob.run_driver() else: with printoptions(precision=2): prob.run_driver() finally: sys.stdout = stdout output = strout.getvalue().split('\n') # should see unscaled (physical) and the full arrays, not just what is indicated by indices self.assertEqual( output[3], "{'p1.x': array([ 50., 50., 50.]), 'p2.y': array([ 50., 50., 50.])}" )
def test_betz(self): from openmdao.api import Problem, ScipyOptimizeDriver, IndepVarComp, ExplicitComponent class ActuatorDisc(ExplicitComponent): """Simple wind turbine model based on actuator disc theory""" def setup(self): # Inputs self.add_input('a', 0.5, desc="Induced Velocity Factor") self.add_input('Area', 10.0, units="m**2", desc="Rotor disc area") self.add_input('rho', 1.225, units="kg/m**3", desc="air density") self.add_input( 'Vu', 10.0, units="m/s", desc="Freestream air velocity, upstream of rotor") # Outputs self.add_output('Vr', 0.0, units="m/s", desc="Air velocity at rotor exit plane") self.add_output( 'Vd', 0.0, units="m/s", desc="Slipstream air velocity, downstream of rotor") self.add_output('Ct', 0.0, desc="Thrust Coefficient") self.add_output('thrust', 0.0, units="N", desc="Thrust produced by the rotor") self.add_output('Cp', 0.0, desc="Power Coefficient") self.add_output('power', 0.0, units="W", desc="Power produced by the rotor") self.declare_partials('Vr', ['a', 'Vu']) self.declare_partials('Vd', 'a') self.declare_partials('Ct', 'a') self.declare_partials('thrust', ['a', 'Area', 'rho', 'Vu']) self.declare_partials('Cp', 'a') self.declare_partials('power', ['a', 'Area', 'rho', 'Vu']) def compute(self, inputs, outputs): """ Considering the entire rotor as a single disc that extracts velocity uniformly from the incoming flow and converts it to power.""" a = inputs['a'] Vu = inputs['Vu'] qA = .5 * inputs['rho'] * inputs['Area'] * Vu**2 outputs['Vd'] = Vd = Vu * (1 - 2 * a) outputs['Vr'] = .5 * (Vu + Vd) outputs['Ct'] = Ct = 4 * a * (1 - a) outputs['thrust'] = Ct * qA outputs['Cp'] = Cp = Ct * (1 - a) outputs['power'] = Cp * qA * Vu def compute_partials(self, inputs, J): """ Jacobian of partial derivatives.""" a = inputs['a'] Vu = inputs['Vu'] Area = inputs['Area'] rho = inputs['rho'] # pre-compute commonly needed quantities a_times_area = a * Area one_minus_a = 1.0 - a a_area_rho_vu = a_times_area * rho * Vu J['Vr', 'a'] = -Vu J['Vr', 'Vu'] = one_minus_a J['Vd', 'a'] = -2.0 * Vu J['Ct', 'a'] = 4.0 - 8.0 * a J['thrust', 'a'] = .5 * rho * Vu**2 * Area * J['Ct', 'a'] J['thrust', 'Area'] = 2.0 * Vu**2 * a * rho * one_minus_a J['thrust', 'rho'] = 2.0 * a_times_area * Vu**2 * (one_minus_a) J['thrust', 'Vu'] = 4.0 * a_area_rho_vu * (one_minus_a) J['Cp', 'a'] = 4.0 * a * (2.0 * a - 2.0) + 4.0 * (one_minus_a)**2 J['power', 'a'] = 2.0 * Area * Vu**3 * a * rho * ( 2.0 * a - 2.0) + 2.0 * Area * Vu**3 * rho * one_minus_a**2 J['power', 'Area'] = 2.0 * Vu**3 * a * rho * one_minus_a**2 J['power', 'rho'] = 2.0 * a_times_area * Vu**3 * (one_minus_a)**2 J['power', 'Vu'] = 6.0 * Area * Vu**2 * a * rho * one_minus_a**2 # build the model prob = Problem() indeps = prob.model.add_subsystem('indeps', IndepVarComp(), promotes=['*']) indeps.add_output('a', .5) indeps.add_output('Area', 10.0, units='m**2') indeps.add_output('rho', 1.225, units='kg/m**3') indeps.add_output('Vu', 10.0, units='m/s') prob.model.add_subsystem('a_disk', ActuatorDisc(), promotes_inputs=['a', 'Area', 'rho', 'Vu']) # setup the optimization prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.model.add_design_var('a', lower=0., upper=1.) prob.model.add_design_var('Area', lower=0., upper=1.) # negative one so we maximize the objective prob.model.add_objective('a_disk.Cp', scaler=-1) prob.setup() prob.run_driver() # minimum value assert_rel_error(self, prob['a_disk.Cp'], 16. / 27., 1e-4) assert_rel_error(self, prob['a'], 0.33333, 1e-4) # There is a bug in scipy version < 1.0 that causes this value to be wrong. if LooseVersion(scipy.__version__) >= LooseVersion("1.0"): assert_rel_error(self, prob['Area'], 1.0, 1e-4) else: msg = "Outdated version of Scipy detected; this problem does not solve properly." raise unittest.SkipTest(msg)
def test(self): # Create a dictionary to store options about the surface # OM: vary 'num_y' and 'num_x' to change the size of the mesh mesh_dict = { 'num_y': 5, 'num_x': 2, 'wing_type': 'rect', 'symmetry': True } mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aerostruct', 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'thickness_cp': np.array([.075, .075]), 'twist_cp': np.array([-10., 15.]), 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, '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 # Constraints 'exact_failure_constraint': False, # if false, use KS function } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=9., units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('a', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = Aerostruct(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('a', point_name + '.a') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: prob.model.connect('load_factor', name + '.load_factor') com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.K', point_name + '.coupled.' + name + '.K') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect( name + '.element_weights', point_name + '.coupled.' + name + '.element_weights') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-10., upper=10.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # Set up the problem prob.setup() prob.run_driver() assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 72128.75170161888, 1e-5)
def test_brachistochrone_quick_start(self): import numpy as np from openmdao.api import Problem, Group, ScipyOptimizeDriver import dymos as dm import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # # Define the OpenMDAO problem # p = Problem(model=Group()) # # Define a Trajectory object # traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # # Define a Dymos Phase object with GaussLobatto Transcription # phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=10, order=3)) traj.add_phase(name='phase0', phase=phase) # # Set the time options # Time has no targets in our ODE. # We fix the initial time so that the it is not a design variable in the optimization. # The duration of the phase is allowed to be optimized, but is bounded on [0.5, 10]. # phase.set_time_options(fix_initial=True, duration_bounds=(0.5, 10.0), units='s') # # Set the time options # Initial values of positions and velocity are all fixed. # The final value of position are fixed, but the final velocity is a free variable. # The equations of motion are not functions of position, so 'x' and 'y' have no targets. # The rate source points to the output in the ODE which provides the time derivative of the # given state. phase.set_state_options('x', fix_initial=True, fix_final=True, units='m', rate_source='xdot') phase.set_state_options('y', fix_initial=True, fix_final=True, units='m', rate_source='ydot') phase.set_state_options('v', fix_initial=True, fix_final=False, units='m/s', rate_source='vdot', targets=['v']) # Define theta as a control. phase.add_control(name='theta', units='rad', lower=0, upper=np.pi, targets=['theta']) # Minimize final time. phase.add_objective('time', loc='final') # Set the driver. p.driver = ScipyOptimizeDriver() # Allow OpenMDAO to automatically determine our sparsity pattern. # Doing so can significant speed up the execution of Dymos. p.driver.options['dynamic_simul_derivs'] = True # Setup the problem p.setup(check=True) # Now that the OpenMDAO problem is setup, we can set the values of the states. p.set_val('traj.phase0.states:x', phase.interpolate(ys=[0, 10], nodes='state_input'), units='m') p.set_val('traj.phase0.states:y', phase.interpolate(ys=[10, 5], nodes='state_input'), units='m') p.set_val('traj.phase0.states:v', phase.interpolate(ys=[0, 5], nodes='state_input'), units='m/s') p.set_val('traj.phase0.controls:theta', phase.interpolate(ys=[90, 90], nodes='control_input'), units='deg') # Run the driver to solve the problem p.run_driver() # Check the validity of our results by using scipy.integrate.solve_ivp to # integrate the solution. sim_out = traj.simulate() # Plot the results fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 4.5)) axes[0].plot(p.get_val('traj.phase0.timeseries.states:x'), p.get_val('traj.phase0.timeseries.states:y'), 'ro', label='solution') axes[0].plot(sim_out.get_val('traj.phase0.timeseries.states:x'), sim_out.get_val('traj.phase0.timeseries.states:y'), 'b-', label='simulation') axes[0].set_xlabel('x (m)') axes[0].set_ylabel('y (m/s)') axes[0].legend() axes[0].grid() axes[1].plot(p.get_val('traj.phase0.timeseries.time'), p.get_val('traj.phase0.timeseries.controls:theta', units='deg'), 'ro', label='solution') axes[1].plot(sim_out.get_val('traj.phase0.timeseries.time'), sim_out.get_val('traj.phase0.timeseries.controls:theta', units='deg'), 'b-', label='simulation') axes[1].set_xlabel('time (s)') axes[1].set_ylabel(r'$\theta$ (deg)') axes[1].legend() axes[1].grid() plt.show()
def test_control_rate2_path_constraint_gl(self): from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver from openmdao.utils.assert_utils import assert_rel_error from dymos import Phase from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() phase = Phase('gauss-lobatto', ode_class=BrachistochroneODE, num_segments=10, transcription_order=5) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(.5, 10)) phase.set_state_options('x', fix_initial=True, fix_final=True) phase.set_state_options('y', fix_initial=True, fix_final=True) phase.set_state_options('v', fix_initial=True) phase.add_control('theta', units='deg', rate_continuity=False, lower=0.01, upper=179.9) phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) phase.add_path_constraint('theta_rate2', lower=-200, upper=200, units='rad/s**2') p.model.linear_solver = DirectSolver(assemble_jac=True) p.model.options['assembled_jac_type'] = 'csc' p.setup() p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5], nodes='control_input') # Solve for the optimal trajectory p.run_driver() # Test the results assert_rel_error(self, phase.get_values('time')[-1], 1.8016, tolerance=1.0E-3)
def main(maxiter): # Select which problem to solve obj_flag = 1 print(locals()) print("solving single physics %s problem" % objectives[obj_flag]) ############################################################################ ########################### FEA ########################### ############################################################################ # NB: only Q4 elements + integer-spaced mesh are assumed nelx = 160 nely = 80 length_x = 160. length_y = 80. ls2fe_x = length_x / float(nelx) ls2fe_y = length_y / float(nely) num_nodes_x = nelx + 1 num_nodes_y = nely + 1 nELEM = nelx * nely nNODE = num_nodes_x * num_nodes_y # NB: nodes for plotting (quickfix...) nodes = get_mesh(num_nodes_x, num_nodes_y, nelx, nely) # Declare FEA object (OpenLSTO_FEA) ============================== fea_solver = py_FEA(lx=length_x, ly=length_y, nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = fea_solver.get_mesh() ## validate the mesh if nELEM != elem.shape[0]: error("error found in the element") if nNODE != node.shape[0]: error("error found in the node") nDOF_e = nNODE * 2 # each node has two displacement DOFs # constitutive properties ======================================== E = 1. nu = 0.3 fea_solver.set_material(E=E, nu=nu, rho=1.0) # sets elastic material only # Boundary Conditions ============================================ ## Set elastic boundary conditions coord_e = np.array([[0., 0.], [length_x, 0.]]) tol_e = np.array([[1e-3, 1e3], [1e-3, 1e+3]]) fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF # Loading Conditions ============================================= ## Set the elastic loading conditions coord = np.array([length_x * 0.5, 0.0]) # length_y]) tol = np.array([4.1, 1e-3]) load_val = -1 # dead load GF_e_ = fea_solver.set_force(coord=coord, tol=tol, direction=1, f=-load_val) GF_e = np.zeros(nDOF_e_wLag) GF_e[:nDOF_e] = GF_e_ ############################################################################ ########################### LSM ########################### ############################################################################ movelimit = 0.5 # Declare Level-set object lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit) # Assign holes =================================================== if (int(nelx) / int(nely) == 2) and (nelx >= 80): rad = float(nelx) / 32.0 # radius of the hole x1 = nelx / 10. # x-coord of the center of the 1st hole 1st row y1 = 14. * nely / 80. # y-coord of the center of the 1st row of holes y2 = 27. * nely / 80. # y-coord of the center of the 2nd row of holes y3 = nely / 2. # y-coord of the center of the 3rd row of holes y4 = 53. * nely / 80. # y-coord of the center of the 4th row of holes y5 = 66. * nely / 80. # y-coord of the center of the 5th row of holes hole = array([[x1, y1, rad], [3 * x1, y1, rad], [5 * x1, y1, rad], [7 * x1, y1, rad], [9 * x1, y1, rad], [2 * x1, y2, rad], [4 * x1, y2, rad], [6 * x1, y2, rad], [8 * x1, y2, rad], [x1, y3, rad], [3 * x1, y3, rad], [5 * x1, y3, rad], [7 * x1, y3, rad], [9 * x1, y3, rad], [2 * x1, y4, rad], [4 * x1, y4, rad], [6 * x1, y4, rad], [8 * x1, y4, rad], [x1, y5, rad], [3 * x1, y5, rad], [5 * x1, y5, rad], [7 * x1, y5, rad], [9 * x1, y5, rad]]) # NB: level set value at the corners should not be 0.0 hole = append( hole, [[0., 0., 0.1], [0., 80., 0.1], [160., 0., 0.1], [160., 80., 0.1]], axis=0) lsm_solver.add_holes(locx=list(hole[:, 0]), locy=list(hole[:, 1]), radius=list(hole[:, 2])) else: lsm_solver.add_holes([], [], []) lsm_solver.set_levelset() ############################################################################ ######################## T.O. LOOP ######################## ############################################################################ for i_HJ in range(maxiter): (bpts_xy, areafraction, seglength) = lsm_solver.discretise() # OpenMDAO =================================================== ## Define Group if (objectives[obj_flag] == "compliance"): model = ComplianceGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, BCid=BCid_e) elif (objectives[obj_flag] == "stress"): model = StressGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, pval=6.0, BCid=BCid_e) ## Define problem for OpenMDAO object prob = Problem(model) ## Setup the problem prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = 'IPOPT' prob.driver.opt_settings['linear_solver'] = 'ma27' prob.setup(check=False) prob.run_model() ## Total derivative using MAUD total = prob.compute_totals() if (objectives[obj_flag] == "compliance"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "stress"): ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] ## Assign object function sensitivities nBpts = int(bpts_xy.shape[0]) Sf = -ff[:nBpts] # equal to M2DO-perturbation Cf = np.multiply( Sf, seglength) # Shape sensitivity (integral coefficients) ## Assign constraint sensitivities Sg = -gg[:nBpts] Sg[Sg < -1.5] = -1.5 # apply caps (bracketing) to constraint sensitivities Sg[Sg > 0.5] = 0.5 # apply caps (bracketing) to constraint sensitivities Cg = np.multiply( Sg, seglength) # Shape sensitivity (integral coefficients) # Suboptimize ================================================ if 1: suboptim = Solvers(bpts_xy=bpts_xy, Sf=Sf, Sg=Sg, Cf=Cf, Cg=Cg, length_x=length_x, length_y=length_y, areafraction=areafraction, movelimit=movelimit) # suboptimization if 1: # simplex Bpt_Vel = suboptim.simplex(isprint=False) else: # bisection. Bpt_Vel = suboptim.bisection(isprint=False) timestep = 1.0 np.savetxt('a.txt', Bpt_Vel) elif 1: # works when Sf <- Sf / length is used (which means Cf <- actual Sf) bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() model = LSM2D_slpGroup(lsm_solver=lsm_solver, num_bpts=nBpts, ub=ub2, lb=lb2, Sf=bpts_sens[:, 0], Sg=bpts_sens[:, 1], constraintDistance=constraint_distance, movelimit=movelimit) subprob = Problem(model) subprob.setup() subprob.driver = ScipyOptimizeDriver() subprob.driver.options['optimizer'] = 'SLSQP' subprob.driver.options['disp'] = True subprob.driver.options['tol'] = 1e-10 subprob.run_driver() lambdas = subprob['inputs_comp.lambdas'] displacements_ = subprob['displacement_comp.displacements'] # displacements_[displacements_ > movelimit] = movelimit # displacements_[displacements_ < -movelimit] = -movelimit timestep = abs(lambdas[0] * scales[0]) Bpt_Vel = displacements_ / timestep np.savetxt('a.txt', Bpt_Vel) # print(timestep) del subprob else: # branch: perturb-suboptim bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() constraintDistance = np.array([constraint_distance]) scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance( constraintDistance) def objF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delF(displacement_np) def conF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delG(displacement_np, scaled_constraintDist, 1) cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)}) res = sp_optim.minimize(objF_nocallback, np.zeros(2), method='SLSQP', options={'disp': True}, bounds=((lb2[0], ub2[0]), (lb2[1], ub2[1])), constraints=cons) lambdas = res.x displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas) displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # scaling # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel)) lsm_solver.advect(Bpt_Vel, timestep) lsm_solver.reinitialise() print('loop %d is finished' % i_HJ) area = areafraction.sum() / (nelx * nely) u = prob['disp_comp.disp'] compliance = np.dot(u, GF_e[:nDOF_e]) # Printing/Plotting ========================================== if 1: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(saveFolder + "figs/bpts_%d.png" % i_HJ) # print([compliance[0], area]) if (objectives[obj_flag] == "compliance"): compliance = prob['compliance_comp.compliance'] print(compliance, area) fid = open(saveFolder + "log.txt", "a+") fid.write(str(compliance) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "stress"): print(prob['pnorm_comp.pnorm'][0], area) fid = open(saveFolder + "log.txt", "a+") fid.write( str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n") fid.close() ## Saving phi phi = lsm_solver.get_phi() if i_HJ == 0: raw = {} raw['mesh'] = nodes raw['nodes'] = nodes raw['elem'] = elem raw['GF_e'] = GF_e raw['BCid_e'] = BCid_e raw['E'] = E raw['nu'] = nu raw['f'] = load_val raw['nelx'] = nelx raw['nely'] = nely raw['length_x'] = length_x raw['length_y'] = length_y raw['coord_e'] = coord_e raw['tol_e'] = tol_e filename = saveFolder + 'const.pkl' with open(filename, 'wb') as f: pickle.dump(raw, f) raw = {} raw['phi'] = phi filename = saveFolder + 'phi%03i.pkl' % i_HJ with open(filename, 'wb') as f: pickle.dump(raw, f) del model del prob mem = virtual_memory() print(str(mem.available / 1024. / 1024. / 1024.) + "GB") if mem.available / 1024. / 1024. / 1024. < 3.0: print("memory explodes at iteration %3i " % i_HJ) return ()
def test(self): import numpy as np from openaerostruct.geometry.utils import generate_mesh from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.integration.aerostruct_groups import Aerostruct, AerostructPoint from openmdao.api import IndepVarComp, Problem, Group, SqliteRecorder # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 2, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surface = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aerostruct', 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'thickness_cp': np.array([.1, .2, .3]), 'twist_cp': twist_cp, 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c': 0.15, # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, # 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., # 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.) indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('a', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) aerostruct_group = Aerostruct(surface=surface) name = 'wing' # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group, promotes_inputs=['load_factor']) point_name = 'AS_point_0' # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=[surface]) prob.model.add_subsystem(point_name, AS_point, promotes_inputs=[ 'v', 'alpha', 'M', 're', 'rho', 'CT', 'R', 'W0', 'a', 'empty_cg', 'load_factor' ]) com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.K', point_name + '.coupled.' + name + '.K') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect( name + '.element_weights', point_name + '.coupled.' + name + '.element_weights') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') 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 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-10., upper=10.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # Set up the problem prob.setup(check=True) prob.run_driver() assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 104400.0251030171, 1e-8)
def main(maxiter): # select which problem to solve obj_flag = 1 print(locals()) print("solving %s problem" % objectives[obj_flag]) ######################################################## ################# FEA #################### ######################################################## # NB: only Q4 elements + integer-spaced mesh are assumed nelx = 160 nely = 80 length_x = 160. length_y = 80. ls2fe_x = length_x / float(nelx) ls2fe_y = length_y / float(nely) num_nodes_x = nelx + 1 num_nodes_y = nely + 1 nELEM = nelx * nely nNODE = num_nodes_x * num_nodes_y # NB: nodes for plotting (quickfix...) nodes = get_mesh(num_nodes_x, num_nodes_y, nelx, nely) # Declare FEA object (OpenLSTO_FEA) ====================== fea_solver = py_FEA(lx=length_x, ly=length_y, nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = fea_solver.get_mesh() # validate the mesh if nELEM != elem.shape[0]: error("error found in the element") if nNODE != node.shape[0]: error("error found in the node") nDOF_t = nNODE * 1 # each node has one temperature DOF nDOF_e = nNODE * 2 # each node has two displacement DOFs # constitutive properties ================================= E = 1. nu = 0.3 f = -1 # dead load K_cond = 0.1 # thermal conductivity alpha = 1e-5 # thermal expansion coefficient fea_solver.set_material(E=E, nu=nu, rho=1.0) # Boundary Conditions ===================================== if 1: coord_e = np.array([[0., 0.], [length_x, 0.]]) tol_e = np.array([[1e-3, 1e3], [1e-3, 1e+3]]) fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF coord = np.array([length_x * 0.5, 0.0]) # length_y]) tol = np.array([0.1, 1e-3]) GF_e_ = fea_solver.set_force(coord=coord, tol=tol, direction=1, f=-f) GF_e = np.zeros(nDOF_e_wLag) GF_e[:nDOF_e] = GF_e_ else: # cantilever bending coord_e = np.array([[0, 0]]) tol_e = np.array([[1e-3, 1e10]]) fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF coord = np.array([length_x, length_y / 2]) tol = np.array([0.1, 0.1]) GF_e_ = fea_solver.set_force(coord=coord, tol=tol, direction=1, f=-1.0) GF_e = np.zeros(nDOF_e_wLag) GF_e[:nDOF_e] = GF_e_ xlo = np.array(range(0, nNODE, num_nodes_x)) xhi = np.array(range(nelx, nNODE, num_nodes_x)) # xfix = np.array([num_nodes_x*(nely/2-1), num_nodes_x*nely/2, # num_nodes_x*(nely/2-1) + nelx, num_nodes_x*nely/2 + nelx]) xfix = np.append(xlo, xhi) yfix = np.array(range(num_nodes_x * nely + 70, nNODE - 70)) # yloid = np.array(range(70, 91)) # fixID_d = np.append(xfix, yfix) #fixID_d = np.unique(fixID_d) #fixID = np.append(fixID_d, arange(70, 91)) # BCid_t = np.array(np.append(xfix, arange(70,91)), dtype=int) BCid_t = np.array(np.append(yfix, arange(70, 91)), dtype=int) nDOF_t_wLag = nDOF_t + len(BCid_t) # temperature DOF (zero temp) GF_t = np.zeros(nDOF_t_wLag) # FORCE_HEAT (NB: Q matrix) for ee in range(nELEM): # between element 70 to 91 GF_t[elem[ee]] += 10. # heat generation GF_t[BCid_t] = 0.0 GF_t /= np.sum(GF_t) #GF_t[nDOF_t:nDOF_t+len(fixID_d)+1] = 100. # GF_t[:] = 0.0 ######################################################## ################# LSM #################### ######################################################## movelimit = 0.5 # Declare Level-set object lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit) if ((nelx == 160) and (nely == 80)): # 160 x 80 case hole = array( [[16, 14, 5], [48, 14, 5], [80, 14, 5], [112, 14, 5], [144, 14, 5], [32, 27, 5], [64, 27, 5], [96, 27, 5], [128, 27, 5], [16, 40, 5], [48, 40, 5], [80, 40, 5], [112, 40, 5], [144, 40, 5], [32, 53, 5], [64, 53, 5], [96, 53, 5], [128, 53, 5], [16, 66, 5], [48, 66, 5], [80, 66, 5], [112, 66, 5], [144, 66, 5]], dtype=float) # NB: level set value at the corners should not be 0.0 hole = append( hole, [[0., 0., 0.1], [0., 80., 0.1], [160., 0., 0.1], [160., 80., 0.1]], axis=0) lsm_solver.add_holes(locx=list(hole[:, 0]), locy=list(hole[:, 1]), radius=list(hole[:, 2])) elif ((nelx == 80) and (nely == 40)): hole = np.array( [[8, 7, 2.5], [24, 7, 2.5], [40, 7, 2.5], [56, 7, 2.5], [72, 7, 2.5], [16, 13.5, 2.5], [32, 13.5, 2.5], [48, 13.5, 2.5], [64, 13.5, 2.5], [8, 20, 2.5], [24, 20, 2.5], [40, 20, 2.5], [56, 20, 2.5], [72, 20, 2.5], [16, 26.5, 2.5], [32, 26.5, 2.5], [48, 26.5, 2.5], [64, 26.5, 2.5], [8, 33, 2.5], [24, 33, 2.5], [40, 33, 2.5], [56, 33, 2.5], [72, 33, 2.5]], dtype=np.float) # NB: level set value at the corners should not be 0.0 hole = append( hole, [[0., 0., 0.1], [0., 40., 0.1], [80., 0., 0.1], [80., 40., 0.1]], axis=0) lsm_solver.add_holes(locx=list(hole[:, 0]), locy=list(hole[:, 1]), radius=list(hole[:, 2])) else: lsm_solver.add_holes([], [], []) lsm_solver.set_levelset() for i_HJ in range(maxiter): (bpts_xy, areafraction, seglength) = lsm_solver.discretise() ######################################################## ############### OpenMDAO ################ ######################################################## # Declare Group if (objectives[obj_flag] == "compliance"): model = ComplianceGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, BCid=BCid_e) elif (objectives[obj_flag] == "stress"): # TODO: sensitivity has not been verified yet model = StressGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, pval=5.0, E=E, nu=nu) elif (objectives[obj_flag] == "conduction"): model = ConductionGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_t, movelimit=movelimit, K_cond=K_cond, BCid=BCid_t) elif (objectives[obj_flag] == "coupled_heat"): model = HeatCouplingGroup( fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force_e=GF_e, force_t=GF_t, movelimit=movelimit, K_cond=K_cond, BCid_e=BCid_e, BCid_t=BCid_t, E=E, nu=nu, alpha=alpha, w=0.9 ) # if w = 0.0, thermoelastic + conduction, if w = 1.0, conduction only # One Problem per one OpenMDAO object prob = Problem(model) # optimize ... prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = 'IPOPT' prob.driver.opt_settings['linear_solver'] = 'ma27' prob.setup(check=False) if i_HJ == 0: view_model(prob) prob.run_model() # Total derivative using MAUD ===================== total = prob.compute_totals() if (objectives[obj_flag] == "compliance"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "stress"): ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "conduction"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "coupled_heat"): ff = total['objective_comp.y', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] nBpts = int(bpts_xy.shape[0]) # # WIP checking sensitivity 10/23 Sf = -ff[:nBpts] # equal to M2DO-perturbation Cf = np.multiply(Sf, seglength) #np.savetxt('/home/hayoung/Desktop/a',Sf) #exit() Sg = -gg[:nBpts] Cg = np.multiply(Sf, seglength) # ## WIP # previous ver. # Cf = -ff[:nBpts] # Cg = -gg[:nBpts] # Sf = np.divide(Cf, seglength) # Sg = np.divide(Cg, seglength) # bracketing Sf and Sg Sg[Sg < -1.5] = -1.5 Sg[Sg > 0.5] = 0.5 # Sg[:] = -1.0 Cg = np.multiply(Sg, seglength) ######################################################## ############## suboptimize ################ ######################################################## if 1: suboptim = Solvers(bpts_xy=bpts_xy, Sf=Sf, Sg=Sg, Cf=Cf, Cg=Cg, length_x=length_x, length_y=length_y, areafraction=areafraction, movelimit=movelimit) # suboptimization if 1: # simplex Bpt_Vel = suboptim.simplex(isprint=False) else: # bisection.. Bpt_Vel = suboptim.bisection(isprint=False) timestep = 1.0 np.savetxt('a.txt', Bpt_Vel) elif 1: # works when Sf <- Sf / length is used (which means Cf <- actual Sf) bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() model = LSM2D_slpGroup(lsm_solver=lsm_solver, num_bpts=nBpts, ub=ub2, lb=lb2, Sf=bpts_sens[:, 0], Sg=bpts_sens[:, 1], constraintDistance=constraint_distance, movelimit=movelimit) subprob = Problem(model) subprob.setup() subprob.driver = ScipyOptimizeDriver() subprob.driver.options['optimizer'] = 'SLSQP' subprob.driver.options['disp'] = True subprob.driver.options['tol'] = 1e-10 subprob.run_driver() lambdas = subprob['inputs_comp.lambdas'] displacements_ = subprob['displacement_comp.displacements'] # displacements_[displacements_ > movelimit] = movelimit # displacements_[displacements_ < -movelimit] = -movelimit timestep = abs(lambdas[0] * scales[0]) Bpt_Vel = displacements_ / timestep np.savetxt('a.txt', Bpt_Vel) # print(timestep) del subprob else: # branch: perturb-suboptim bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() constraintDistance = np.array([constraint_distance]) scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance( constraintDistance) def objF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delF(displacement_np) def conF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delG(displacement_np, scaled_constraintDist, 1) cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)}) res = sp_optim.minimize(objF_nocallback, np.zeros(2), method='SLSQP', options={'disp': True}, bounds=((lb2[0], ub2[0]), (lb2[1], ub2[1])), constraints=cons) lambdas = res.x displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas) displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # scaling # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel)) lsm_solver.advect(Bpt_Vel, timestep) lsm_solver.reinitialise() print('loop %d is finished' % i_HJ) area = areafraction.sum() / (nelx * nely) try: u = prob['temp_comp.disp'] compliance = np.dot(u, GF_t[:nNODE]) except: u = prob['disp_comp.disp'] # compliance = np.dot(u, GF_e[:nDOF_e]) pass if 1: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(saveFolder + "figs/bpts_%d.png" % i_HJ) if obj_flag == 3 or obj_flag == 2: plt.figure(2) plt.clf() [xx, yy] = np.meshgrid(range(0, 161), range(0, 81)) plt.contourf(xx, yy, np.reshape(u, [81, 161])) plt.colorbar() plt.axis("equal") plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 5) plt.savefig(saveFolder + "figs/temp_%d.png" % i_HJ) # print([compliance[0], area]) if (objectives[obj_flag] == "compliance"): compliance = prob['compliance_comp.compliance'] print(compliance, area) fid = open(saveFolder + "log.txt", "a+") fid.write(str(compliance) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "stress"): print(prob['pnorm_comp.pnorm'][0], area) fid = open(saveFolder + "log.txt", "a+") fid.write( str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "coupled_heat"): obj1 = prob['objective_comp.x1'][0] obj2 = prob['objective_comp.x2'][0] obj = prob['objective_comp.y'][0] print([obj1, obj2, obj, area]) fid = open(saveFolder + "log.txt", "a+") fid.write( str(obj1) + ", " + str(obj2) + ", " + str(obj) + ", " + str(area) + "\n") fid.close() # Saving Phi phi = lsm_solver.get_phi() if i_HJ == 0: raw = {} raw['mesh'] = nodes raw['nodes'] = nodes raw['elem'] = elem raw['GF_e'] = GF_e raw['GF_t'] = GF_t raw['BCid_e'] = BCid_e raw['BCid_t'] = BCid_t raw['E'] = E raw['nu'] = nu raw['f'] = f raw['K_cond'] = K_cond raw['alpha'] = alpha raw['nelx'] = nelx raw['nely'] = nely raw['length_x'] = length_x raw['length_y'] = length_y raw['coord_e'] = coord_e raw['tol_e'] = tol_e filename = saveFolder + 'const.pkl' with open(filename, 'wb') as f: pickle.dump(raw, f) raw = {} raw['phi'] = phi if obj_flag == 3: raw['T'] = prob['temp_comp.disp'] filename = saveFolder + 'phi%03i.pkl' % i_HJ with open(filename, 'wb') as f: pickle.dump(raw, f) del model del prob mem = virtual_memory() print(str(mem.available / 1024. / 1024. / 1024.) + "GB") if mem.available / 1024. / 1024. / 1024. < 3.0: print("memory explodes at iteration %3i " % i_HJ) return ()
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5, 'span_cos_spacing': 0. } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type': 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type': 'tube', 'mesh': mesh, 'twist_cp': twist_cp, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0': 0.0, # CL of the surface at alpha=0 'CD0': 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam': 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp': np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, # if true, compute viscous drag 'with_wave': False, # if true, compute wave drag 'span': 10. } surfaces = [surf_dict] n_points = 2 # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=6.64, units='deg') indep_var_comp.add_output('Mach_number', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) indep_var_comp = IndepVarComp() indep_var_comp.add_output('t_over_c_cp', val=np.array([0.15])) indep_var_comp.add_output('span', val=12., units='m') indep_var_comp.add_output('twist_cp_0', val=np.zeros((5)), units='deg') indep_var_comp.add_output('twist_cp_1', val=np.zeros((5)), units='deg') prob.model.add_subsystem('geom_vars', indep_var_comp, promotes=['*']) # Loop through and add a certain number of aero points for i in range(n_points): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: geom_group = Geometry(surface=surface, connect_geom_DVs=False) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. aero_group.add_subsystem(surface['name'] + '_geom', geom_group) name = surface['name'] prob.model.connect(point_name + '.CD', 'multi_CD.' + str(i) + '_CD') # Connect the mesh from the geometry component to the analysis point prob.model.connect(point_name + '.' + name + '_geom.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect( point_name + '.' + name + '_geom.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect( point_name + '.' + name + '_geom.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') # prob.model.connect(point_name + '.' + name + '_geom.span', 'span_diff_comp.span_' + str(i)) # Connect geometric design variables to each point prob.model.connect('t_over_c_cp', 'aero_point_0.wing_geom.t_over_c_cp') prob.model.connect('t_over_c_cp', 'aero_point_1.wing_geom.t_over_c_cp') prob.model.connect('span', 'aero_point_0.wing_geom.span') prob.model.connect('span', 'aero_point_1.wing_geom.span') prob.model.connect('twist_cp_0', 'aero_point_0.wing_geom.twist_cp') prob.model.connect('twist_cp_1', 'aero_point_1.wing_geom.twist_cp') prob.model.add_subsystem('multi_CD', MultiCD(n_points=n_points), promotes_outputs=['CD']) from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('alpha', lower=-15, upper=15) prob.model.add_design_var('twist_cp_0', lower=-5, upper=8) prob.model.add_design_var('twist_cp_1', lower=-5, upper=8) prob.model.add_design_var('span', lower=2, upper=15) prob.model.add_constraint('aero_point_0.wing_perf.CL', equals=0.45) prob.model.add_constraint('aero_point_1.wing_perf.CL', equals=0.50) prob.model.add_objective('CD', scaler=1e4) # Set up the problem prob.setup() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.45, 1e-6) assert_rel_error(self, prob['aero_point_1.wing_perf.CL'][0], 0.5, 1e-6) assert_rel_error( self, prob['twist_cp_0'], np.array([8., -1.21207749, -2.42415497, -1.21207749, -1.0821358]), 1e-6) assert_rel_error( self, prob['twist_cp_1'], np.array([8., -0.02049115, -0.0409823, -0.02049115, 0.77903674]), 1e-6) assert_rel_error(self, prob['aero_point_1.wing_perf.CL'][0], 0.5, 1e-6)
def test_debug_print_option(self): prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('x', 50.0), promotes=['*']) model.add_subsystem('p2', IndepVarComp('y', 50.0), promotes=['*']) model.add_subsystem('comp', Paraboloid(), promotes=['*']) model.add_subsystem('con', ExecComp('c = - x + y'), promotes=['*']) prob.set_solver_print(level=0) prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = False prob.driver.options['debug_print'] = [ 'desvars', 'ln_cons', 'nl_cons', 'objs' ] model.add_design_var('x', lower=-50.0, upper=50.0) model.add_design_var('y', lower=-50.0, upper=50.0) model.add_objective('f_xy') model.add_constraint('c', upper=-15.0) prob.setup(check=False) stdout = sys.stdout strout = StringIO() sys.stdout = strout try: prob.run_driver() finally: sys.stdout = stdout output = strout.getvalue().split('\n') self.assertTrue( output.count("Design Vars") > 1, "Should be more than one design vars header printed") self.assertTrue( output.count("Nonlinear constraints") > 1, "Should be more than one nonlinear constraint header printed") self.assertTrue( output.count("Linear constraints") > 1, "Should be more than one linear constraint header printed") self.assertTrue( output.count("Objectives") > 1, "Should be more than one objective header printed") self.assertTrue( len([s for s in output if s.startswith('p1.x')]) > 1, "Should be more than one p1.x printed") self.assertTrue( len([s for s in output if s.startswith('p2.y')]) > 1, "Should be more than one p2.y printed") self.assertTrue( len([s for s in output if s.startswith('con.c')]) > 1, "Should be more than one con.c printed") self.assertTrue( len([s for s in output if s.startswith('comp.f_xy')]) > 1, "Should be more than one comp.f_xy printed")
def test(self): import numpy as np from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, \ ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, \ DirectSolver, LinearBlockGS, PetscKSP, SqliteRecorder from openaerostruct.geometry.utils import generate_mesh from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.aerodynamics.aero_groups import AeroPoint # Create a dictionary to store options about the mesh mesh_dict = {'num_y' : 7, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : False, 'num_twist_cp' : 5} # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) # Create a dictionary with info and options about the aerodynamic # lifting surface surface = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aero', 'symmetry' : False, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'twist_cp' : twist_cp, 'mesh' : mesh, 'num_x' : mesh.shape[0], 'num_y' : mesh.shape[1], # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.15]), # thickness over chord ratio (NACA0015) 'c_max_t' : .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous' : True, # if true, compute viscous drag 'with_wave' : False, # if true, compute wave drag } # Create the OpenMDAO problem prob = Problem() # Create an independent variable component that will supply the flow # conditions to the problem. indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('cg', val=np.zeros((3)), units='m') # Add this IndepVarComp to the problem model prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) prob.model.add_subsystem(surface['name'], geom_group) # Create the aero point group, which contains the actual aerodynamic # analyses aero_group = AeroPoint(surfaces=[surface]) point_name = 'aero_point_0' prob.model.add_subsystem(point_name, aero_group, promotes_inputs=['v', 'alpha', 'M', 're', 'rho', 'cg']) name = surface['name'] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh') # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh') prob.model.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c') # Import the Scipy Optimizer and set the driver of the problem to use # it, which defaults to an SLSQP optimization method from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5) prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4) # Set up and run the optimization problem prob.setup() prob.run_model() # prob.check_partials() # exit() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03339013029042684, 1e-5) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -0.18453592482214315, 1e-4)
def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, sim_record='brach_min_time_sim.db', optimizer='SLSQP', dynamic_simul_derivs=True, force_alloc_complex=False, solve_segments=False, run_driver=True): p = Problem(model=Group()) if optimizer == 'SNOPT': p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings['iSumm'] = 6 else: p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = dynamic_simul_derivs if transcription == 'runge-kutta': transcription = RungeKutta(num_segments=num_segments, compressed=compressed) elif transcription == 'gauss-lobatto': transcription = GaussLobatto(num_segments=num_segments, order=transcription_order, compressed=compressed) elif transcription == 'radau-ps': transcription = Radau(num_segments=num_segments, order=transcription_order, compressed=compressed) phase = Phase(ode_class=BrachistochroneVectorStatesODE, transcription=transcription) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) fix_final = not solve_segments # can't fix final position if you're solving the segments phase.set_state_options('pos', fix_initial=True, fix_final=fix_final, solve_segments=solve_segments) phase.set_state_options('v', fix_initial=True, fix_final=False, solve_segments=solve_segments) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = DirectSolver() p.setup(check=True, force_alloc_complex=force_alloc_complex) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 pos0 = [0, 10] posf = [10, 5] p['phase0.states:pos'] = phase.interpolate(ys=[pos0, posf], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100], nodes='control_input') p['phase0.design_parameters:g'] = 9.80665 p.run_model() if run_driver: p.run_driver() # Plot results if SHOW_PLOTS: p.run_driver() exp_out = phase.simulate(record_file=sim_record) fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.states:pos')[:, 0] y_imp = p.get_val('phase0.timeseries.states:pos')[:, 1] x_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 0] y_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 1] ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('x (m)') ax.set_ylabel('y (m)') ax.grid(True) ax.legend(loc='upper right') fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.time') y_imp = p.get_val('phase0.timeseries.control_rates:theta_rate2') x_exp = exp_out.get_val('phase0.timeseries.time') y_exp = exp_out.get_val('phase0.timeseries.control_rates:theta_rate2') ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('time (s)') ax.set_ylabel('theta rate2 (rad/s**2)') ax.grid(True) ax.legend(loc='lower right') plt.show() return p
prob = Problem(model=Group(num_par_fd=num_par_fd)) prob.model.approx_totals(method='fd') prob.model.add_subsystem('comp', LandBasedTurbine(RefBlade=blade, Nsection_Tow=Nsection_Tow, VerbosityCosts=True), promotes=['*']) else: prob = Problem() prob.model = LandBasedTurbine(RefBlade=blade, Nsection_Tow=Nsection_Tow, VerbosityCosts=True) if optFlag: # --- Solver --- prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1.e-6 prob.driver.options['maxiter'] = 100 #prob.driver = pyOptSparseDriver() #prob.driver.options['optimizer'] = 'CONMIN' # prob.driver.options['optimizer'] = 'SNOPT' # prob.driver.options['gradient method'] = "pyopt_fd" # ---------------------- # --- Objective --- prob.model.add_objective('lcoe') # ---------------------- # --- Design Variables ---
def test(self): from openaerostruct.geometry.utils import generate_mesh, write_FFD_file from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.integration.aerostruct_groups import Aerostruct, AerostructPoint from openmdao.api import IndepVarComp, Problem, Group, SqliteRecorder from pygeo import DVGeometry # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aerostruct', 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'tube', 'thickness_cp' : np.array([.1, .2, .3]), 'mesh' : mesh, 'num_x' : mesh.shape[0], 'num_y' : mesh.shape[1], '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., # Constraints 'exact_failure_constraint' : False, # if false, use KS function } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5., units='deg') indep_var_comp.add_output('M', val=0.84) indep_var_comp.add_output('re', val=1.e6, units='1/m') indep_var_comp.add_output('rho', val=0.38, units='kg/m**3') indep_var_comp.add_output('CT', val=9.80665 * 17.e-6, units='1/s') indep_var_comp.add_output('R', val=11.165e6, units='m') indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg') indep_var_comp.add_output('a', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] filename = write_FFD_file(surface, surface['mx'], surface['my']) DVGeo = DVGeometry(filename) aerostruct_group = Aerostruct(surface=surface, DVGeo=DVGeo) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('a', point_name + '.a') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: prob.model.connect('load_factor', name + '.load_factor') com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.K', point_name + '.coupled.' + name + '.K') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect(name + '.element_weights', point_name + '.coupled.' + name + '.element_weights') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') # Import the Scipy Optimizer and set the driver of the problem to use # it, which defaults to an SLSQP optimization method from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() recorder = SqliteRecorder("aerostruct_ffd.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.shape', lower=-3, upper=2) prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-10., upper=10.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # iprofile.setup() # iprofile.start() # Set up the problem prob.setup() # from openmdao.api import view_model # view_model(prob, outfile='aerostruct_ffd', show_browser=False) # prob.run_model() prob.run_driver() # prob.check_partials(compact_print=True) # print("\nWing CL:", prob['aero_point_0.wing_perf.CL']) # print("Wing CD:", prob['aero_point_0.wing_perf.CD']) # from helper import plot_3d_points # # mesh = prob['aero_point_0.wing.def_mesh'] # plot_3d_points(mesh) # # filename = mesh_dict['wing_type'] + '_' + str(mesh_dict['num_x']) + '_' + str(mesh_dict['num_y']) # filename += '_' + str(surf_dict['mx']) + '_' + str(surf_dict['my']) + '.mesh' # np.save(filename, mesh) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 104675.0989232741, 1e-4)
def test_recording_remote_voi(self): # Create a parallel model model = Group() model.add_subsystem('par', ParallelGroup()) model.par.add_subsystem('G1', Mygroup()) model.par.add_subsystem('G2', Mygroup()) model.connect('par.G1.y', 'Obj.y1') model.connect('par.G2.y', 'Obj.y2') model.add_subsystem('Obj', ExecComp('obj=y1+y2')) model.add_objective('Obj.obj') # Configure driver to record VOIs on both procs driver = ScipyOptimizeDriver(disp=False) driver.recording_options['record_desvars'] = True driver.recording_options['record_responses'] = True driver.recording_options['record_objectives'] = True driver.recording_options['record_constraints'] = True driver.recording_options['includes'] = ['par.G1.y', 'par.G2.y'] driver.add_recorder(self.recorder) # Create problem and run driver prob = Problem(model, driver) prob.add_recorder(self.recorder) prob.setup() t0, t1 = run_driver(prob) prob.record_iteration('final') t2 = time() prob.cleanup() # Since the test will compare the last case recorded, just check the # current values in the problem. This next section is about getting those values # These involve collective gathers so all ranks need to run this expected_outputs = driver.get_design_var_values() expected_outputs.update(driver.get_objective_values()) expected_outputs.update(driver.get_constraint_values()) # includes for outputs are specified as promoted names but we need absolute names prom2abs = model._var_allprocs_prom2abs_list['output'] abs_includes = [prom2abs[n][0] for n in prob.driver.recording_options['includes']] # Absolute path names of includes on this rank rrank = model.comm.rank rowned = model._owning_rank local_includes = [n for n in abs_includes if rrank == rowned[n]] # Get values for all vars on this rank inputs, outputs, residuals = model.get_nonlinear_vectors() # Get values for includes on this rank local_vars = {n: outputs[n] for n in local_includes} # Gather values for includes on all ranks all_vars = model.comm.gather(local_vars, root=0) if prob.comm.rank == 0: # Only on rank 0 do we have all the values. The all_vars variable is a list of # dicts from all ranks 0,1,... In this case, just ranks 0 and 1 dct = all_vars[-1] for d in all_vars[:-1]: dct.update(d) expected_includes = { 'par.G1.Cy.y': dct['par.G1.Cy.y'], 'par.G2.Cy.y': dct['par.G2.Cy.y'], } expected_outputs.update(expected_includes) coordinate = [0, 'ScipyOptimize_SLSQP', (driver.iter_count-1,)] expected_data = ((coordinate, (t0, t1), expected_outputs, None),) assertDriverIterDataRecorded(self, expected_data, self.eps) expected_data = (('final', (t1, t2), expected_outputs),) assertProblemDataRecorded(self, expected_data, self.eps)
def test_parallel(self): from openmdao.api import ParallelGroup, NonlinearBlockGS class SellarMDA(Group): """ Group containing the Sellar MDA. """ def setup(self): indeps = self.add_subsystem('indeps', IndepVarComp(), promotes=['*']) indeps.add_output('x', 1.0) indeps.add_output('z', np.array([5.0, 2.0])) cycle = self.add_subsystem('cycle', ParallelGroup(), promotes=['*']) cycle.add_subsystem('d1', SellarDis1(), promotes_inputs=['x', 'z', 'y2'], promotes_outputs=['y1']) cycle.add_subsystem('d2', SellarDis2(), promotes_inputs=['z', 'y1'], promotes_outputs=['y2']) # Nonlinear Block Gauss Seidel is a gradient free solver cycle.nonlinear_solver = NonlinearBlockGS() self.add_subsystem('obj_cmp', ExecComp( 'obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['x', 'z', 'y1', 'y2', 'obj']) self.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) self.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) filename = 'xdsmjs_parallel' out_format = 'html' prob = Problem(model=SellarMDA()) model = prob.model prob.driver = ScipyOptimizeDriver() model.add_design_var('z', lower=np.array([-10.0, 0.0]), upper=np.array([10.0, 10.0]), indices=np.arange(2, dtype=int)) model.add_design_var('x', lower=0.0, upper=10.0) model.add_objective('obj') model.add_constraint('con1', equals=np.zeros(1)) model.add_constraint('con2', upper=0.0) prob.setup(check=False) prob.final_setup() # Write output write_xdsm(prob, filename=filename, out_format=out_format, quiet=QUIET, show_browser=SHOW, show_parallel=True) # Check if file was created self.assertTrue(os.path.isfile('.'.join([filename, out_format])))