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 compute(self, inputs, outputs, discrete_inputs, discrete_outputs): # initialization point # if discrete_inputs['blade_in_overwrite'] != {}: # blade = copy.deepcopy(discrete_inputs['blade_in_overwrite']) # else: blade = copy.deepcopy(self.refBlade) NINPUT = len(blade['ctrl_pts']['r_in']) # Set inputs to update blade geometry Rhub = inputs['hubFraction'] * inputs['bladeLength'] Rtip = Rhub + inputs['bladeLength'] outputs['Rhub'] = Rhub outputs['Rtip'] = Rtip r_in = blade['ctrl_pts']['r_in'] outputs['r_in'] = Rhub + (Rtip - Rhub) * np.array(r_in) blade['ctrl_pts']['bladeLength'] = inputs['bladeLength'] blade['ctrl_pts']['r_in'] = r_in blade['ctrl_pts']['chord_in'] = inputs['chord_in'] blade['ctrl_pts']['theta_in'] = inputs['theta_in'] blade['ctrl_pts']['precurve_in'] = inputs['precurve_in'] blade['ctrl_pts']['presweep_in'] = inputs['presweep_in'] blade['ctrl_pts']['sparT_in'] = inputs['sparT_in'] blade['ctrl_pts']['teT_in'] = inputs['teT_in'] blade['ctrl_pts']['r_max_chord'] = inputs['r_max_chord'] #check that airfoil positions are increasing correct_af_position = False airfoil_position = copy.deepcopy(inputs['airfoil_position']).tolist() for i in reversed(range(1, len(airfoil_position))): if airfoil_position[i] <= airfoil_position[i - 1]: airfoil_position[i - 1] = airfoil_position[i] - 0.001 correct_af_position = True if correct_af_position: blade['outer_shape_bem']['airfoil_position'][ 'grid'] = airfoil_position warning_corrected_airfoil_position = "Airfoil spanwise positions must be increasing. Changed from: %s to: %s" % ( inputs['airfoil_position'].tolist(), airfoil_position) warnings.warn(warning_corrected_airfoil_position) else: blade['outer_shape_bem']['airfoil_position']['grid'] = inputs[ 'airfoil_position'].tolist() # Update refBlade = ReferenceBlade() refBlade.verbose = False refBlade.NINPUT = len(outputs['r_in']) refBlade.NPTS = len(blade['pf']['s']) refBlade.analysis_level = blade['analysis_level'] if blade['analysis_level'] < 3: refBlade.spar_var = blade['precomp']['spar_var'] refBlade.te_var = blade['precomp']['te_var'] blade_out = refBlade.update(blade) # Get geometric outputs outputs['hub_diameter'] = 2.0 * Rhub outputs['r'] = Rhub + (Rtip - Rhub) * np.array(blade_out['pf']['s']) outputs['diameter'] = 2.0 * outputs['r'][-1] outputs['chord'] = blade_out['pf']['chord'] outputs['max_chord'] = max(blade_out['pf']['chord']) outputs['theta'] = blade_out['pf']['theta'] outputs['precurve'] = blade_out['pf']['precurve'] outputs['presweep'] = blade_out['pf']['presweep'] outputs['rthick'] = blade_out['pf']['rthick'] outputs['le_location'] = blade_out['pf']['p_le'] # airfoils = blade_out['airfoils'] outputs['airfoils_cl'] = blade_out['airfoils_cl'] outputs['airfoils_cd'] = blade_out['airfoils_cd'] outputs['airfoils_cm'] = blade_out['airfoils_cm'] outputs['airfoils_aoa'] = blade_out['airfoils_aoa'] outputs['airfoils_Re'] = blade_out['airfoils_Re'] upperCS = blade_out['precomp']['upperCS'] lowerCS = blade_out['precomp']['lowerCS'] websCS = blade_out['precomp']['websCS'] profile = blade_out['precomp']['profile'] materials = blade_out['precomp']['materials'] for i in range(len(profile)): outputs['airfoils_coord_x'][:, i] = blade_out['profile'][:, 0, i] outputs['airfoils_coord_y'][:, i] = blade_out['profile'][:, 1, i] # Assumptions: # - if the composite layer is divided into multiple regions (i.e. if the spar cap is split into 3 regions due to the web locations), # the middle region is selected with int(n_reg/2), note for an even number of regions, this rounds up sector_idx_strain_spar_ss = blade_out['precomp'][ 'sector_idx_strain_spar_ss'] sector_idx_strain_spar_ps = blade_out['precomp'][ 'sector_idx_strain_spar_ps'] sector_idx_strain_te_ss = blade_out['precomp'][ 'sector_idx_strain_te_ss'] sector_idx_strain_te_ps = blade_out['precomp'][ 'sector_idx_strain_te_ps'] # Get Beam Properties beam = PreComp(outputs['r'], outputs['chord'], outputs['theta'], outputs['le_location'], outputs['precurve'], outputs['presweep'], profile, materials, upperCS, lowerCS, websCS, sector_idx_strain_spar_ps, sector_idx_strain_spar_ss, sector_idx_strain_te_ps, sector_idx_strain_te_ss) EIxx, EIyy, GJ, EA, EIxy, x_ec, y_ec, rhoA, rhoJ, Tw_iner, flap_iner, edge_iner = beam.sectionProperties( ) outputs['eps_crit_spar'] = beam.panelBucklingStrain( sector_idx_strain_spar_ss) outputs['eps_crit_te'] = beam.panelBucklingStrain( sector_idx_strain_te_ss) xu_strain_spar, xl_strain_spar, yu_strain_spar, yl_strain_spar = beam.criticalStrainLocations( sector_idx_strain_spar_ss, sector_idx_strain_spar_ps) xu_strain_te, xl_strain_te, yu_strain_te, yl_strain_te = beam.criticalStrainLocations( sector_idx_strain_te_ss, sector_idx_strain_te_ps) outputs['z'] = outputs['r'] outputs['EIxx'] = EIxx outputs['EIyy'] = EIyy outputs['GJ'] = GJ outputs['EA'] = EA outputs['EIxy'] = EIxy outputs['x_ec'] = x_ec outputs['y_ec'] = y_ec outputs['rhoA'] = rhoA outputs['rhoJ'] = rhoJ outputs['Tw_iner'] = Tw_iner outputs['flap_iner'] = flap_iner outputs['edge_iner'] = edge_iner outputs['xu_strain_spar'] = xu_strain_spar outputs['xl_strain_spar'] = xl_strain_spar outputs['yu_strain_spar'] = yu_strain_spar outputs['yl_strain_spar'] = yl_strain_spar outputs['xu_strain_te'] = xu_strain_te outputs['xl_strain_te'] = xl_strain_te outputs['yu_strain_te'] = yu_strain_te outputs['yl_strain_te'] = yl_strain_te # Blade cost model bcm = blade_cost_model( options=self.options ) # <------------- options, import blade cost model bcm.name = blade_out['config']['name'] bcm.materials = materials bcm.upperCS = upperCS bcm.lowerCS = lowerCS bcm.websCS = websCS bcm.profile = profile bcm.chord = outputs['chord'] bcm.r = (outputs['r'] - outputs['Rhub']) / ( outputs['Rtip'] - outputs['Rhub']) * float(inputs['bladeLength']) bcm.bladeLength = float(inputs['bladeLength']) bcm.le_location = outputs['le_location'] blade_cost, blade_mass = bcm.execute_blade_cost_model() outputs['total_blade_cost'] = blade_cost outputs['total_blade_mass'] = blade_mass # discrete_outputs['blade_out'] = blade_out outputs['sparT_in_out'] = inputs['sparT_in']
-1] #0.025 # (Float): hub location as fraction of radius rotor['hub_height'] = blade['config'][ 'hub_height'] # (Float, m): hub height rotor['turbine_class'] = blade['config']['turbine_class'].upper( ) #TURBINE_CLASS['I'] # (Enum): IEC turbine class return rotor if __name__ == "__main__": # Turbine Ontology input fname_input = "turbine_inputs/nrel5mw_mod_update.yaml" # Initialize blade design refBlade = ReferenceBlade() refBlade.verbose = True refBlade.NINPUT = NINPUT refBlade.NPITS = 50 refBlade.validate = False refBlade.fname_schema = "turbine_inputs/IEAontology_schema.yaml" refBlade.spar_var = ['Spar_Cap_SS', 'Spar_Cap_PS'] refBlade.te_var = 'TE_reinforcement' blade = refBlade.initialize(fname_input) # setup rotor = Problem() rotor.model = RotorGeometry(RefBlade=blade, topLevelFlag=True) rotor.setup() rotor = Init_RotorGeometry_wRefBlade(rotor, blade)
prob['drive.hss_input_length'] = 1.5 prob['drive.yaw_motors_number'] = 1 return prob if __name__ == "__main__": optFlag = False # Reference rotor design fname_schema = "../../rotorse/turbine_inputs/IEAontology_schema.yaml" fname_input = "../../rotorse/turbine_inputs/nrel5mw_mod_update.yaml" Analysis_Level = 0 # 0: Run CCBlade; 1: Update FAST model at each iteration but do not run; 2: Run FAST w/ ElastoDyn; 3: (Not implemented) Run FAST w/ BeamDyn # Initialize blade design refBlade = ReferenceBlade() refBlade.verbose = True 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 # Initialize OpenMDAO problem and FloatingSE Group if MPI: num_par_fd = MPI.COMM_WORLD.Get_size() prob = Problem(model=Group(num_par_fd=num_par_fd))
if __name__ == '__main__': # Turbine Ontology input fname_schema = "turbine_inputs/IEAontology_schema.yaml" fname_input = "turbine_inputs/nrel5mw_mod_update.yaml" # fname_input = "/mnt/c/Users/egaertne/IEA-15-240-RWT/WISDEM/IEA-15-240-RWT.yaml" # fname_input = "/mnt/c/Users/egaertne/IEA-15-240-RWT/WISDEM/IEA-15-240-RWT_TipShape.yaml" output_folder = "test/" fname_output = output_folder + 'test_out.yaml' Analysis_Level = 0 # 0: Run CCBlade; 1: Update FAST model at each iteration but do not run; 2: Run FAST w/ ElastoDyn; 3: (Not implemented) Run FAST w/ BeamDyn # Initialize blade design refBlade = ReferenceBlade() refBlade.verbose = True refBlade.NINPUT = 8 refBlade.NPTS = 50 refBlade.apply_stall_delay = False 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) # Set FAST Inputs if Analysis_Level >= 1: # File management FASTpref = {}
ax.set_ylim(mid_y - max_range, mid_y + max_range) ax.set_zlim(mid_z - max_range, mid_z + max_range) ax.view_init(azim=-90., elev=-180.) plt.show() return None if __name__ == "__main__": fname_input = "/mnt/c/Users/egaertne/WISDEM/nrel15mw/design/turbine_inputs/NREL15MW_opt_v03.yaml" dir_out = "/mnt/c/Users/egaertne/WISDEM/nrel15mw/design/outputs/NREL15MW_opt_v03/post" ## Load and Format Blade refBlade = ReferenceBlade() refBlade.verbose = True refBlade.spar_var = ['Spar_cap_ss', 'Spar_cap_ps'] refBlade.te_var = 'TE_reinforcement' refBlade.NINPUT = 8 refBlade.NPITS = 50 # refBlade.NPTS_AfProfile = 200 refBlade.validate = False # refBlade.fname_schema = "turbine_inputs/IEAontology_schema.yaml" blade = refBlade.initialize(fname_input) plt_vars = ['Spar_cap_ss', 'Spar_cap_ps'] plot_lofted(blade, plt_vars, dir_out)
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)
return blade if __name__ == "__main__": optFlag = False fname_schema = 'IEAontology_schema.yaml' fname_input = 'IEA-15-240-RWT.yaml' fname_output = 'IEA-15-240-RWT_out.yaml' folder_output = os.getcwd() + os.sep + 'outputs' if not os.path.isdir(folder_output): os.mkdir(folder_output) Analysis_Level = 0 # 0: Run CCBlade; 1: Update FAST model at each iteration but do not run; 2: Run FAST w/ ElastoDyn; 3: (Not implemented) Run FAST w/ BeamDyn # Initialize blade design refBlade = ReferenceBlade() refBlade.verbose = True refBlade.NINPUT = 8 Nsection_Tow = 15 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) FASTpref = {} FASTpref['Analysis_Level'] = Analysis_Level # Set FAST Inputs if Analysis_Level >= 1: # File management