def test_linear_analysis_error(self): # test fwd mode prob = om.Problem() model = prob.model # takes 6 iterations normally linear_solver = om.LinearBlockGS(maxiter=2, err_on_non_converge=True) model.add_subsystem( 'sub', SellarDerivatives(nonlinear_solver=om.NonlinearRunOnce(), linear_solver=linear_solver)) model.nonlinear_solver = om.NewtonSolver(solve_subsystems=True) prob.setup(mode='fwd') prob.set_solver_print(level=2) # test if the analysis error is raised properly on all procs try: prob.run_model() except om.AnalysisError as err: self.assertEqual( str(err), "Solver 'LN: LNBGS' on system 'sub' failed to converge in 2 iterations." ) else: self.fail("expected AnalysisError") # test rev mode prob = om.Problem() model = prob.model # takes 6 iterations normally linear_solver = om.LinearBlockGS(maxiter=2, err_on_non_converge=True) model.add_subsystem( 'sub', SellarDerivatives(nonlinear_solver=om.NonlinearRunOnce(), linear_solver=linear_solver)) model.nonlinear_solver = om.NewtonSolver(solve_subsystems=True) prob.setup(mode='rev') prob.set_solver_print(level=2) # test if the analysis error is raised properly on all procs try: prob.run_model() except om.AnalysisError as err: self.assertEqual( str(err), "Solver 'LN: LNBGS' on system 'sub' failed to converge in 2 iterations." ) else: self.fail("expected AnalysisError")
def test_circuit_voltage_source(self): import openmdao.api as om from openmdao.test_suite.scripts.circuit_analysis import Circuit p = om.Problem() model = p.model model.add_subsystem('ground', om.IndepVarComp('V', 0., units='V')) # replacing the fixed current source with a BalanceComp to represent a fixed Voltage source # model.add_subsystem('source', om.IndepVarComp('I', 0.1, units='A')) model.add_subsystem('batt', om.IndepVarComp('V', 1.5, units='V')) bal = model.add_subsystem('batt_balance', om.BalanceComp()) bal.add_balance('I', units='A', eq_units='V') model.add_subsystem('circuit', Circuit()) model.add_subsystem('batt_deltaV', om.ExecComp('dV = V1 - V2', V1={'units':'V'}, V2={'units':'V'}, dV={'units':'V'})) # current into the circuit is now the output state from the batt_balance comp model.connect('batt_balance.I', 'circuit.I_in') model.connect('ground.V', ['circuit.Vg','batt_deltaV.V2']) model.connect('circuit.n1.V', 'batt_deltaV.V1') # set the lhs and rhs for the battery residual model.connect('batt.V', 'batt_balance.rhs:I') model.connect('batt_deltaV.dV', 'batt_balance.lhs:I') p.setup() ################### # Solver Setup ################### # change the circuit solver to RunOnce because we're # going to converge at the top level of the model with newton instead p.model.circuit.nonlinear_solver = om.NonlinearRunOnce() p.model.circuit.linear_solver = om.LinearRunOnce() # Put Newton at the top so it can also converge the new BalanceComp residual newton = p.model.nonlinear_solver = om.NewtonSolver() p.model.linear_solver = om.DirectSolver() newton.options['iprint'] = 2 newton.options['maxiter'] = 20 newton.options['solve_subsystems'] = True newton.linesearch = om.ArmijoGoldsteinLS() newton.linesearch.options['maxiter'] = 10 newton.linesearch.options['iprint'] = 2 # set initial guesses from the current source problem p['circuit.n1.V'] = 9.8 p['circuit.n2.V'] = .7 p.run_model() assert_near_equal(p['circuit.n1.V'], 1.5, 1e-5) assert_near_equal(p['circuit.n2.V'], 0.65113362, 1e-5) assert_near_equal(p['circuit.R1.I'], 0.015, 1e-5) assert_near_equal(p['circuit.R2.I'], 8.48866375e-05, 1e-5) assert_near_equal(p['circuit.D1.I'], 8.48866375e-05, 1e-5)
def test_aitken(self): prob = om.Problem() model = prob.model aitken = om.LinearBlockGS() aitken.options['use_aitken'] = True aitken.options['err_on_non_converge'] = True # It takes 6 iterations without Aitken. aitken.options['maxiter'] = 4 sub = model.add_subsystem( 'sub', SellarDerivatives(nonlinear_solver=om.NonlinearRunOnce(), linear_solver=aitken)) model.nonlinear_solver = om.NewtonSolver(solve_subsystems=True) prob.setup(mode='fwd') prob.set_solver_print(level=0) prob.run_model() assert_near_equal(prob.get_val('sub.y1'), 25.58830273, .00001) assert_near_equal(prob.get_val('sub.y2'), 12.05848819, .00001) prob = om.Problem() model = prob.model aitken = om.LinearBlockGS() aitken.options['use_aitken'] = True aitken.options['err_on_non_converge'] = True # It takes 6 iterations without Aitken. aitken.options['maxiter'] = 4 sub = model.add_subsystem( 'sub', SellarDerivatives(nonlinear_solver=om.NonlinearRunOnce(), linear_solver=aitken)) model.nonlinear_solver = om.NewtonSolver(solve_subsystems=True) prob.setup(mode='rev') prob.set_solver_print(level=0) prob.run_model() assert_near_equal(prob.get_val('sub.y1'), 25.58830273, .00001) assert_near_equal(prob.get_val('sub.y2'), 12.05848819, .00001)
def test_converge_diverge_groups(self): # Test derivatives for converge-diverge-groups topology. prob = om.Problem() model = prob.model = ConvergeDivergeGroups() model.linear_solver = om.ScipyKrylov() model.nonlinear_solver = om.NonlinearRunOnce() model.g1.nonlinear_solver = om.NonlinearRunOnce() model.g1.g2.nonlinear_solver = om.NonlinearRunOnce() model.g3.nonlinear_solver = om.NonlinearRunOnce() prob.set_solver_print(level=0) prob.setup(check=False, mode='fwd') prob.run_model() # Make sure value is fine. assert_rel_error(self, prob['c7.y1'], -102.7, 1e-6)
def initialize_problem(Analysis_Level): # Initialize blade design refBlade = ReferenceBlade() refBlade.verbose = True refBlade.NINPUT = 200 Nsection_Tow = 19 refBlade.NPTS = 200 refBlade.spar_var = ['Spar_cap_ss', 'Spar_cap_ps'] # SS, then PS refBlade.te_var = 'TE_reinforcement' refBlade.validate = False refBlade.fname_schema = fname_schema blade = refBlade.initialize(fname_input) FASTpref = {} FASTpref['Analysis_Level'] = Analysis_Level # Set FAST Inputs if Analysis_Level >= 1: # File management FASTpref['FAST_ver'] = 'OpenFAST' FASTpref['dev_branch'] = True FASTpref['FAST_exe'] = '~/local/bin/openfast' FASTpref['FAST_directory'] = '../OpenFAST' # Path to fst directory files FASTpref['FAST_InputFile'] = 'IEA-15-240-RWT.fst' # FAST input file (ext=.fst) FASTpref['Turbsim_exe'] = '~/local/bin/turbsim' FASTpref['FAST_namingOut'] = 'IEA-15-240-RWT' FASTpref['FAST_runDirectory'] = 'temp/' + FASTpref['FAST_namingOut'] # Run Settings FASTpref['cores'] = 1 FASTpref['debug_level'] = 2 # verbosity: set to 0 for quiet, 1 & 2 for increasing levels of output # DLCs FASTpref['DLC_gust'] = None # Max deflection # FASTpref['DLC_gust'] = RotorSE_DLC_1_4_Rated # Max deflection ### Not in place yet FASTpref['DLC_extrm'] = None # Max strain # FASTpref['DLC_extrm'] = RotorSE_DLC_7_1_Steady # Max strain ### Not in place yet FASTpref['DLC_turbulent'] = None # FASTpref['DLC_turbulent'] = RotorSE_DLC_1_1_Turb # Alternate turbulent case, replacing rated and extreme DLCs for calculating max deflection and strain FASTpref['DLC_powercurve'] = None # AEP # FASTpref['DLC_powercurve'] = None # AEP # Initialize, read initial FAST files to avoid doing it iteratively fast = InputReader_OpenFAST(FAST_ver=FASTpref['FAST_ver'], dev_branch=FASTpref['dev_branch']) fast.FAST_InputFile = FASTpref['FAST_InputFile'] fast.FAST_directory = FASTpref['FAST_directory'] fast.execute() fst_vt = fast.fst_vt else: fst_vt = {} prob = om.Problem() prob.model=MonopileTurbine(RefBlade=blade, Nsection_Tow=Nsection_Tow, VerbosityCosts=False, FASTpref=FASTpref) prob.model.nonlinear_solver = om.NonlinearRunOnce() prob.model.linear_solver = om.DirectSolver() return prob, blade, fst_vt
def test_undeclared_options(self): # Test that using options that should not exist in class cause an error solver = om.NonlinearRunOnce() msg = "\"NonlinearRunOnce: Option '%s' cannot be set because it has not been declared.\"" for option in ['atol', 'rtol', 'maxiter', 'err_on_maxiter']: with self.assertRaises(KeyError) as context: solver.options[option] = 1 self.assertEqual(str(context.exception), msg % option)
def test_feature_solver(self): prob = om.Problem() model = prob.model model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy']) model.nonlinear_solver = om.NonlinearRunOnce() prob.setup(check=False, mode='fwd') prob.set_val('x', 4.0) prob.set_val('y', 6.0) prob.run_model() assert_near_equal(prob.get_val('f_xy'), 122.0)
def test_feature_solver(self): import openmdao.api as om from openmdao.test_suite.components.paraboloid import Paraboloid prob = om.Problem() model = prob.model model.add_subsystem('p1', om.IndepVarComp('x', 0.0), promotes=['x']) model.add_subsystem('p2', om.IndepVarComp('y', 0.0), promotes=['y']) model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy']) model.nonlinear_solver = om.NonlinearRunOnce() prob.setup(check=False, mode='fwd') prob['x'] = 4.0 prob['y'] = 6.0 prob.run_model() assert_rel_error(self, prob['f_xy'], 122.0)
def setup(self): ivc = self.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('time', val=np.array([ 0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, 1.00, 1.25, 1.25, 1.50, 1.50, 1.75, 1.75, 2.00 ]), units='s') ivc.add_output('h', val=np.array([0.5, 0.5, 0.5, 0.5]), units='s') self.add_subsystem('cnty_iter_group', RungeKuttaStateContinuityIterGroup( num_segments=num_seg, method='RK4', state_options=state_options, time_units='s', ode_class=TestODE, ode_init_kwargs={}, k_solver_class=om.NonlinearRunOnce), promotes_outputs=['states:*']) self.connect('h', 'cnty_iter_group.h') self.connect('time', 'cnty_iter_group.ode.t') src_idxs = np.arange(16, dtype=int).reshape((num_seg, 4, 1)) self.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) self.nonlinear_solver = om.NonlinearRunOnce() self.linear_solver = om.DirectSolver()
model.connect('ground.V', ['circuit.Vg', 'batt_deltaV.V2']) model.connect('circuit.n1.V', 'batt_deltaV.V1') # set the lhs and rhs for the battery residual model.connect('batt.V', 'batt_balance.rhs:I') model.connect('batt_deltaV.dV', 'batt_balance.lhs:I') p.setup() ################### # Solver Setup ################### # change the circuit solver to RunOnce because we're # going to converge at the top level of the model with newton instead p.model.circuit.nonlinear_solver = om.NonlinearRunOnce() p.model.circuit.linear_solver = om.LinearRunOnce() # Put Newton at the top so it can also converge the new BalanceComp residual newton = p.model.nonlinear_solver = om.NewtonSolver() p.model.linear_solver = om.DirectSolver() newton.options['iprint'] = 2 newton.options['maxiter'] = 20 newton.options['solve_subsystems'] = True newton.linesearch = om.ArmijoGoldsteinLS() newton.linesearch.options['maxiter'] = 10 newton.linesearch.options['iprint'] = 2 # set initial guesses from the current source problem p['circuit.n1.V'] = 9.8 p['circuit.n2.V'] = .7
def test_continuity_comp_connected_scalar_no_iteration_fwd(self): num_seg = 4 state_options = { 'y': { 'shape': (1, ), 'units': 'm', 'targets': ['y'], 'defect_scaler': None, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': True } } p = om.Problem(model=om.Group()) ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states:y', units='m', shape=(1, 1)) p.model.add_subsystem('continuity_comp', RungeKuttaStateContinuityComp( num_segments=num_seg, state_options=state_options), promotes_inputs=['*'], promotes_outputs=['*']) p.model.nonlinear_solver = om.NonlinearRunOnce() p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['initial_states:y'] = 0.5 p['states:y'] = np.array([[0.50000000], [1.425130208333333], [2.639602661132812], [4.006818970044454], [5.301605229265987]]) p['state_integrals:y'] = np.array([[1.0], [1.0], [1.0], [1.0]]) p.run_model() p.model.run_apply_nonlinear() # Test that the residuals of the states are the expected values outputs = p.model.list_outputs(print_arrays=True, residuals=True, out_stream=None) y_f = p['states:y'][1:, ...] y_i = p['states:y'][:-1, ...] dy_given = y_f - y_i dy_computed = p['state_integrals:y'] expected_resids = np.zeros((num_seg + 1, 1)) expected_resids[1:, ...] = dy_given - dy_computed op_dict = dict([op for op in outputs]) assert_near_equal(op_dict['continuity_comp.states:y']['resids'], expected_resids) # Test the partials cpd = p.check_partials(method='cs') J_fwd = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_fwd'] J_fd = cpd['continuity_comp']['states:y', 'state_integrals:y']['J_fd'] J_fwd = cpd['continuity_comp']['states:y', 'states:y']['J_fwd'] J_fd = cpd['continuity_comp']['states:y', 'states:y']['J_fd'] J_fd[0, 0] = -1.0 assert_near_equal(J_fwd, J_fd)
refBlade.NINPUT = 8 refBlade.NPTS = 50 refBlade.spar_var = ['Spar_Cap_SS', 'Spar_Cap_PS'] # SS, then PS refBlade.te_var = 'TE_reinforcement' refBlade.validate = False refBlade.fname_schema = fname_schema blade = refBlade.initialize(fname_input) # Initialize tower design Nsection_Tow = 6 # Create a problem for our LandBasedTurbine prob = om.Problem() prob.model = LandBasedTurbine(RefBlade=blade, Nsection_Tow=Nsection_Tow, VerbosityCosts=True) prob.model.nonlinear_solver = om.NonlinearRunOnce() prob.model.linear_solver = om.DirectSolver() #prob.model.approx_totals() prob.setup() prob = Init_LandBasedAssembly(prob, blade, Nsection_Tow) prob.run_model() # landbosse_costs_by_module_type_operation = prob['landbosse_costs_by_module_type_operation'] # print('###### LandBOSSE Costs ########################################') # for cost in landbosse_costs_by_module_type_operation: # print(cost) # print('###############################################################') # # landbosse_details_by_module = prob['landbosse_details_by_module']
def run_problem(optFlag=False, prob_ref=None): # Initialize blade design refBlade = ReferenceBlade() if rank == 0: refBlade.verbose = True else: refBlade.verbose = False refBlade.NINPUT = 8 Nsection_Tow = 19 refBlade.NPTS = 30 refBlade.spar_var = ['Spar_cap_ss', 'Spar_cap_ps'] # SS, then PS refBlade.te_var = 'TE_reinforcement' refBlade.le_var = 'le_reinf' refBlade.validate = False refBlade.fname_schema = fname_schema blade = refBlade.initialize(fname_input) Analysis_Level = 0 FASTpref = {} FASTpref['Analysis_Level'] = Analysis_Level fst_vt = {} # Initialize and execute OpenMDAO problem with input data if MPI: num_par_fd = MPI.COMM_WORLD.Get_size() prob = om.Problem(model=om.Group(num_par_fd=num_par_fd)) prob.model.approx_totals(method='fd') prob.model.add_subsystem('comp', Optimize_MonopileTurbine( RefBlade=blade, Nsection_Tow=Nsection_Tow, folder_output=folder_output), promotes=['*']) else: prob = om.Problem() prob.model = Optimize_MonopileTurbine(RefBlade=blade, Nsection_Tow=Nsection_Tow, folder_output=folder_output) prob.model.nonlinear_solver = om.NonlinearRunOnce() prob.model.linear_solver = om.DirectSolver() if optFlag and not prob_ref is None: if MPI: num_par_fd = MPI.COMM_WORLD.Get_size() prob = om.Problem(model=om.Group(num_par_fd=num_par_fd)) prob.model.approx_totals(method='fd') prob.model.add_subsystem('comp', Optimize_MonopileTurbine( RefBlade=blade, Nsection_Tow=Nsection_Tow, folder_output=folder_output), promotes=['*']) else: prob = om.Problem() prob.model = Optimize_MonopileTurbine(RefBlade=blade, Nsection_Tow=Nsection_Tow, folder_output=folder_output) # --- Driver --- prob.driver = om.pyOptSparseDriver() prob.driver.options['optimizer'] = 'CONMIN' prob.driver.opt_settings['ITMAX'] = 15 prob.driver.opt_settings['IPRINT'] = 4 # ---------------------- # --- Objective --- # prob.model.add_objective('lcoe') prob.model.add_objective('AEP', scaler=-1.) #prob.model.add_objective('mass_one_blade') # ---------------------- # --- Design Variables --- indices_no_root = range(2, refBlade.NINPUT) indices_no_root_no_tip = range(2, refBlade.NINPUT - 1) indices_no_max_chord = range(3, refBlade.NINPUT) prob.model.add_design_var('sparT_in', indices=indices_no_root_no_tip, lower=0.001, upper=0.200) prob.model.add_design_var('chord_in', indices=indices_no_max_chord, lower=0.5, upper=7.0) prob.model.add_design_var('theta_in', indices=indices_no_root, lower=-7.5, upper=20.0) prob.model.add_design_var('teT_in', lower=prob_ref['teT_in'] * 0.5, upper=0.1) #prob.model.add_design_var('leT_in', lower=prob_ref['leT_in']*0.5, upper=0.1) # ---------------------- # --- Constraints --- prob.model.add_subsystem('freq_check', blade_freq_check(), promotes=['freq_check_out']) prob.model.connect('freq_curvefem', 'freq_check.freq_curvefem') #, src_indices=[0]) # Rotor prob.model.add_constraint('tip_deflection_ratio', upper=1.0) # prob.model.add_constraint('no_stall_constraint', upper=1.0) prob.model.add_constraint('freq_check_out', lower=1.1) #prob.model.add_constraint('rated_Q', lower=21.4e6, upper=21.6e6) # prob.model.add_constraint('mass_one_blade', upper=prob_ref['mass_one_blade']*1.02) prob.model.add_constraint('AEP', lower=0.99 * prob_ref['AEP']) # ---------------------- # --- Recorder --- filename_opt_log = folder_output + 'log_opt_' + blade['config']['name'] prob.driver.add_recorder(om.SqliteRecorder(filename_opt_log)) prob.driver.recording_options['includes'] = [ 'AEP', 'total_blade_cost', 'lcoe', 'tip_deflection_ratio', 'mass_one_blade', 'theta_in' ] prob.driver.recording_options['record_objectives'] = True prob.driver.recording_options['record_constraints'] = True prob.driver.recording_options['record_desvars'] = True # ---------------------- # Initialize variable inputs prob = initialize_variables(prob, blade, Analysis_Level, fst_vt) # Run initial condition no matter what print('Running at Initial Position:') prob.run_model() print('########################################') print('') print('Control variables') print('Rotor diam: {:8.3f} m'.format(prob['diameter'][0])) print('TSR: {:8.3f} -'.format(prob['control_tsr'][0])) print('Rated vel: {:8.3f} m/s'.format(prob['rated_V'][0])) print('Rated rpm: {:8.3f} rpm'.format(prob['rated_Omega'][0])) print('Rated pitch: {:8.3f} deg'.format(prob['rated_pitch'][0])) print('Rated thrust: {:8.3f} N'.format(prob['rated_T'][0])) print('Rated torque: {:8.3f} N-m'.format(prob['rated_Q'][0])) print('') print('Constraints') print('Max TD: {:8.3f} m'.format(prob['tip_deflection'][0])) print('TD ratio: {:8.3f} -'.format(prob['tip_deflection_ratio'][0])) print('Blade root M: {:8.3f} N-m'.format(prob['root_bending_moment'][0])) print('') print('Objectives') print('AEP: {:8.3f} GWh'.format(prob['AEP'][0])) print('LCoE: {:8.4f} $/MWh'.format(prob['lcoe'][0])) print('') print('Blades') print('Blade mass: {:8.3f} kg'.format(prob['mass_one_blade'][0])) print('Blade cost: {:8.3f} $'.format(prob['total_blade_cost'][0])) print('Blade freq: {:8.3f} Hz'.format(prob['freq_curvefem'][0])) print('3 blade M_of_I: ', prob['I_all_blades'], ' kg-m^2') print('Hub M: ', prob['Mxyz_total'], ' kg-m^2') print('') print('RNA Summary') print('RNA mass: {:8.3f} kg'.format(prob['tow.pre.mass'][0])) print('RNA C_of_G (TT): ', prob['rna_cg'], ' m') print('RNA M_of_I: ', prob['tow.pre.mI'], ' kg-m^2') print('') print('Tower') print('Tower top F: ', prob['tow.pre.rna_F'], ' N') print('Tower top M: ', prob['tow.pre.rna_M'], ' N-m') print('Tower freqs: ', prob['tow.post.structural_frequencies'], ' Hz') print('Tower vel: {:8.3f} kg'.format(prob['tow.wind.Uref'][0])) print('Tower mass: {:8.3f} kg'.format(prob['tower_mass'][0])) print('Tower cost: {:8.3f} $'.format(prob['tower_cost'][0])) print('########################################') # Angle of attack and stall angle faoa, axaoa = plt.subplots(1, 1, figsize=(5.3, 4)) axaoa.plot(prob['r'], prob['nostallconstraint.aoa_along_span'], label='Initial aoa') axaoa.plot(prob['r'], prob['nostallconstraint.stall_angle_along_span'], '.', label='Initial stall') axaoa.legend(fontsize=12) plt.xlabel('Blade Span [m]', fontsize=14, fontweight='bold') plt.ylabel('Angle [deg]', fontsize=14, fontweight='bold') plt.xticks(fontsize=12) plt.yticks(fontsize=12) plt.grid(color=[0.8, 0.8, 0.8], linestyle='--') plt.subplots_adjust(bottom=0.15, left=0.15) fig_name = 'aoa.png' faoa.savefig(folder_output + fig_name) # Complete data dump #prob.model.list_inputs(units=True) #prob.model.list_outputs(units=True) if optFlag: if rank == 0: print('Running Optimization:') print('N design var: ', 2 * len(indices_no_root_no_tip) + len(indices_no_root) + 1) if not MPI: prob.model.approx_totals() prob.run_driver() if rank == 0: # --- Save output .yaml --- refBlade.write_ontology(fname_output, prob['blade_out'], refBlade.wt_ref) # --- Outputs plotting --- print('AEP: \t\t\t %f\t%f GWh \t Difference: %f %%' % (prob_ref['AEP'] * 1e-6, prob['AEP'] * 1e-6, (prob['AEP'] - prob_ref['AEP']) / prob_ref['AEP'] * 100.)) print( 'LCoE: \t\t\t %f\t%f USD/MWh \t Difference: %f %%' % (prob_ref['lcoe'] * 1.e003, prob['lcoe'] * 1.e003, (prob['lcoe'] - prob_ref['lcoe']) / prob_ref['lcoe'] * 100.)) print('Blade cost: \t\t\t %f\t%f USD \t Difference: %f %%' % (prob_ref['total_blade_cost'], prob['total_blade_cost'], (prob['total_blade_cost'] - prob_ref['total_blade_cost']) / prob_ref['total_blade_cost'] * 100.)) print('Blade mass: \t\t\t %f\t%f kg \t Difference: %f %%' % (prob_ref['total_blade_mass'], prob['total_blade_mass'], (prob['total_blade_mass'] - prob_ref['total_blade_mass']) / prob_ref['total_blade_mass'] * 100.)) print('Tower cost: \t\t\t %f\t%f USD \t Difference: %f %%' % (prob_ref['tower_cost'], prob['tower_cost'], (prob['tower_cost'] - prob_ref['tower_cost']) / prob_ref['tower_cost'] * 100.)) print('Tower mass: \t\t\t %f\t%f kg \t Difference: %f %%' % (prob_ref['tower_mass'], prob['tower_mass'], (prob['tower_mass'] - prob_ref['tower_mass']) / prob_ref['tower_mass'] * 100.)) # ---------------------- # Theta ft, axt = plt.subplots(1, 1, figsize=(5.3, 4)) axt.plot(prob_ref['r'], prob_ref['theta'], label='Initial') axt.plot(prob_ref['r_in'], prob_ref['theta_in'], '.') axt.plot(prob['r'], prob['theta'], label='Optimized') axt.plot(prob['r_in'], prob['theta_in'], '.') axt.legend(fontsize=12) plt.xlabel('Blade Span [m]', fontsize=14, fontweight='bold') plt.ylabel('Twist [deg]', fontsize=14, fontweight='bold') plt.xticks(fontsize=12) plt.yticks(fontsize=12) plt.grid(color=[0.8, 0.8, 0.8], linestyle='--') plt.subplots_adjust(bottom=0.15, left=0.15) fig_name = 'theta.png' ft.savefig(folder_output + fig_name) # Angle of attack and stall angle faoa, axaoa = plt.subplots(1, 1, figsize=(5.3, 4)) axaoa.plot(prob_ref['r'], prob_ref['nostallconstraint.aoa_along_span'], label='Initial aoa') axaoa.plot(prob_ref['r'], prob_ref['nostallconstraint.stall_angle_along_span'], '.', label='Initial stall') axaoa.plot(prob['r'], prob['nostallconstraint.aoa_along_span'], label='Optimized aoa') axaoa.plot(prob['r'], prob['nostallconstraint.stall_angle_along_span'], '.', label='Optimized stall') axaoa.legend(fontsize=12) plt.xlabel('Blade Span [m]', fontsize=14, fontweight='bold') plt.ylabel('Angle [deg]', fontsize=14, fontweight='bold') plt.xticks(fontsize=12) plt.yticks(fontsize=12) plt.grid(color=[0.8, 0.8, 0.8], linestyle='--') plt.subplots_adjust(bottom=0.15, left=0.15) fig_name = 'aoa.png' ft.savefig(folder_output + fig_name) plt.show() return prob, blade
def testAssembly(self): # Global inputs and outputs fname_schema = mydir + os.sep + 'IEAontology_schema.yaml' fname_input = mydir + os.sep + 'IEA-15-240-RWT.yaml' # Initialize blade design refBlade = ReferenceBlade() refBlade.verbose = True refBlade.NINPUT = 8 Nsection_Tow = 19 refBlade.NPTS = 30 refBlade.spar_var = ['Spar_cap_ss', 'Spar_cap_ps'] # SS, then PS refBlade.te_var = 'TE_reinforcement' refBlade.validate = False refBlade.fname_schema = fname_schema blade = refBlade.initialize(fname_input) Analysis_Level = 0 FASTpref = {} FASTpref['Analysis_Level'] = Analysis_Level fst_vt = {} prob = om.Problem() prob.model = MonopileTurbine(RefBlade=blade, Nsection_Tow=Nsection_Tow, VerbosityCosts=False, FASTpref=FASTpref) prob.model.nonlinear_solver = om.NonlinearRunOnce() prob.model.linear_solver = om.DirectSolver() prob.setup() prob = Init_RotorSE_wRefBlade(prob, blade, Analysis_Level=Analysis_Level, fst_vt=fst_vt) # Environmental parameters for the tower prob['significant_wave_height'] = 4.52 prob['significant_wave_period'] = 9.45 prob['water_depth'] = 30. prob['wind_reference_height'] = prob['hub_height'] = 150. prob['shearExp'] = 0.11 prob['rho'] = 1.225 prob['mu'] = 1.7934e-5 prob['water_density'] = 1025.0 prob['water_viscosity'] = 1.3351e-3 prob['wind_beta'] = prob['wave_beta'] = 0.0 # Steel properties for the tower prob['material_density'] = 7850.0 prob['E'] = 210e9 prob['G'] = 79.3e9 prob['yield_stress'] = 345e6 prob['soil_G'] = 140e6 prob['soil_nu'] = 0.4 # Design constraints prob['max_taper_ratio'] = 0.4 prob['min_diameter_thickness_ratio'] = 120.0 # Safety factors prob['gamma_fatigue'] = 1.755 # (Float): safety factor for fatigue prob['gamma_f'] = 1.35 # (Float): safety factor for loads/stresses prob['gamma_m'] = 1.3 # (Float): safety factor for materials prob[ 'gamma_freq'] = 1.1 # (Float): safety factor for resonant frequencies prob['gamma_n'] = 1.0 prob['gamma_b'] = 1.1 # Tower prob['tower_buckling_length'] = 30.0 prob['tower_outfitting_factor'] = 1.07 prob['foundation_height'] = -30. prob['suctionpile_depth'] = 45. prob['tower_section_height'] = np.array([ 5., 5., 5., 5., 5., 5., 5., 5., 5., 13., 13., 13., 13., 13., 13., 13., 13., 13., 12.58244309 ]) prob['tower_outer_diameter'] = np.array([ 10., 10., 10., 10., 10., 10., 10., 10., 10., 10., 10., 9.92647687, 9.44319282, 8.83283769, 8.15148167, 7.38976138, 6.90908962, 6.74803581, 6.57231775, 6.5 ]) prob['tower_wall_thickness'] = np.array([ 0.05534138, 0.05344902, 0.05150928, 0.04952705, 0.04751736, 0.04551709, 0.0435267, 0.04224176, 0.04105759, 0.0394965, 0.03645589, 0.03377851, 0.03219233, 0.03070819, 0.02910109, 0.02721289, 0.02400931, 0.0208264, 0.02399756 ]) prob['tower_buckling_length'] = 15.0 prob['transition_piece_mass'] = 100e3 prob['transition_piece_height'] = 15.0 prob['DC'] = 80.0 prob['shear'] = True prob['geom'] = True prob['tower_force_discretization'] = 5.0 prob['nM'] = 2 prob['Mmethod'] = 1 prob['lump'] = 0 prob['tol'] = 1e-9 prob['shift'] = 0.0 # Offshore BOS prob['wtiv'] = 'example_wtiv' prob['feeder'] = 'future_feeder' prob['num_feeders'] = 1 prob['oss_install_vessel'] = 'example_heavy_lift_vessel' prob['site_distance'] = 40.0 prob['site_distance_to_landfall'] = 40.0 prob['site_distance_to_interconnection'] = 40.0 prob['plant_turbine_spacing'] = 7 prob['plant_row_spacing'] = 7 prob['plant_substation_distance'] = 1 prob['tower_deck_space'] = 0. prob['nacelle_deck_space'] = 0. prob['blade_deck_space'] = 0. prob['port_cost_per_month'] = 2e6 prob['monopile_deck_space'] = 0. prob['transition_piece_deck_space'] = 0. prob['commissioning_pct'] = 0.01 prob['decommissioning_pct'] = 0.15 prob['project_lifetime'] = prob['lifetime'] = 20.0 prob['number_of_turbines'] = 40 prob['annual_opex'] = 43.56 # $/kW/yr #prob['bos_costs'] = 1234.5 # $/kW prob['tower_add_gravity'] = True # For turbine costs prob['offshore'] = True prob['crane'] = False prob['bearing_number'] = 2 prob['crane_cost'] = 0.0 prob['labor_cost_rate'] = 3.0 prob['material_cost_rate'] = 2.0 prob['painting_cost_rate'] = 28.8 # Drivetrain prob['tilt'] = 6.0 prob['overhang'] = 11.075 prob['hub_cm'] = np.array([-10.685, 0.0, 5.471]) prob['nac_cm'] = np.array([-5.718, 0.0, 4.048]) prob['hub_I'] = np.array( [1382171.187, 2169261.099, 2160636.794, 0.0, 0.0, 0.0]) prob['nac_I'] = np.array( [13442265.552, 21116729.439, 18382414.385, 0.0, 0.0, 0.0]) prob['hub_mass'] = 190e3 prob['nac_mass'] = 797.275e3 - 190e3 prob['hss_mass'] = 0.0 prob['lss_mass'] = 19.504e3 prob['cover_mass'] = 0.0 prob['pitch_system_mass'] = 50e3 prob['platforms_mass'] = 0.0 prob['spinner_mass'] = 0.0 prob['transformer_mass'] = 0.0 prob['vs_electronics_mass'] = 0.0 prob['yaw_mass'] = 100e3 prob['gearbox_mass'] = 0.0 prob['generator_mass'] = 226.7e3 + 145.25e3 prob['bedplate_mass'] = 39.434e3 prob['main_bearing_mass'] = 4.699e3 prob.run_model() # Make sure we get here self.assertTrue(True)
def test_continuity_comp_no_iteration(self): num_seg = 4 state_options = { 'y': { 'shape': (1, ), 'units': 'm', 'targets': ['y'], 'fix_initial': True, 'fix_final': False, 'propagation': 'forward', 'defect_scaler': None, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': False } } p = om.Problem(model=om.Group()) ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('time', val=np.array([ 0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, 1.00, 1.25, 1.25, 1.50, 1.50, 1.75, 1.75, 2.00 ]), units='s') ivc.add_output('h', val=np.array([0.5, 0.5, 0.5, 0.5]), units='s') p.model.add_subsystem('cnty_iter_group', RungeKuttaStateContinuityIterGroup( num_segments=num_seg, method='RK4', state_options=state_options, time_units='s', ode_class=TestODE, ode_init_kwargs={}, k_solver_class=om.NonlinearRunOnce), promotes_outputs=['states:*']) p.model.connect('h', 'cnty_iter_group.h') p.model.connect('time', 'cnty_iter_group.ode.t') src_idxs = np.arange(16, dtype=int).reshape((num_seg, 4, 1)) p.model.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) p.model.nonlinear_solver = om.NonlinearRunOnce() p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['states:y'] = np.array([[0.50000000], [1.425130208333333], [2.639602661132812], [4.006818970044454], [5.301605229265987]]) p['cnty_iter_group.k_comp.k:y'] = np.array([[[0.75000000 ], [0.90625000], [0.94531250], [1.09765625]], [[1.087565104166667], [1.203206380208333], [1.232116699218750], [1.328623453776042]], [[1.319801330566406], [1.368501663208008], [1.380676746368408], [1.385139703750610]], [[1.378409485022227], [1.316761856277783], [1.301349949091673], [1.154084459568063]]]) p.run_model() p.model.run_apply_nonlinear() # Test that the residuals of the states are the expected values outputs = p.model.list_outputs(print_arrays=True, residuals=True, out_stream=None) expected_resids = np.zeros((num_seg + 1, 1)) op_dict = dict([op for op in outputs]) assert_rel_error( self, op_dict['cnty_iter_group.continuity_comp.states:y']['resids'], expected_resids) # Test the partials cpd = p.check_partials(method='cs', out_stream=None) J_fwd = cpd['cnty_iter_group.continuity_comp'][ 'states:y', 'state_integrals:y']['J_fwd'] J_fd = cpd['cnty_iter_group.continuity_comp'][ 'states:y', 'state_integrals:y']['J_fd'] assert_rel_error(self, J_fwd, J_fd) J_fwd = cpd['cnty_iter_group.continuity_comp']['states:y', 'states:y']['J_fwd'] J_fd = cpd['cnty_iter_group.continuity_comp']['states:y', 'states:y']['J_fd'] J_fd[0, 0] = -1.0 assert_rel_error(self, J_fwd, J_fd)