def configure_turbine_with_jacket(assembly, with_new_nacelle=False, flexible_blade=False, with_3pt_drive=False): """a stand-alone configure method to allow for flatter assemblies Parameters ---------- assembly : Assembly an openmdao assembly to be configured with_new_nacelle : bool False uses the default implementation, True uses an experimental implementation designed to smooth out discontinities making in amenable for gradient-based optimization flexible_blade : bool if True, internally solves the coupled aero/structural deflection using fixed point iteration. Note that the coupling is currently only in the flapwise deflection, and is primarily only important for highly flexible blades. If False, the aero loads are passed to the structure but there is no further iteration. """ # --- general turbine configuration inputs--- assembly.add( 'rho', Float(1.225, iotype='in', units='kg/m**3', desc='density of air', deriv_ignore=True)) assembly.add( 'mu', Float(1.81206e-5, iotype='in', units='kg/m/s', desc='dynamic viscosity of air', deriv_ignore=True)) assembly.add( 'shear_exponent', Float(0.2, iotype='in', desc='shear exponent', deriv_ignore=True)) assembly.add('hub_height', Float(90.0, iotype='in', units='m', desc='hub height')) assembly.add( 'turbine_class', Enum('I', ('I', 'II', 'III'), iotype='in', desc='IEC turbine class')) assembly.add( 'turbulence_class', Enum('B', ('A', 'B', 'C'), iotype='in', desc='IEC turbulence class class')) assembly.add( 'g', Float(9.81, iotype='in', units='m/s**2', desc='acceleration of gravity', deriv_ignore=True)) assembly.add( 'cdf_reference_height_wind_speed', Float( 90.0, iotype='in', desc= 'reference hub height for IEC wind speed (used in CDF calculation)' )) assembly.add('downwind', Bool(False, iotype='in', desc='flag if rotor is downwind')) assembly.add('tower_dt', Float(iotype='in', units='m', desc='tower top diameter')) # update for jacket assembly.add('generator_speed', Float(iotype='in', units='rpm', desc='generator speed')) assembly.add( 'machine_rating', Float(5000.0, units='kW', iotype='in', desc='machine rated power')) assembly.add( 'rna_weightM', Bool(True, iotype='in', desc='flag to consider or not the RNA weight effect on Moment')) assembly.add('rotor', RotorSE()) if with_new_nacelle: assembly.add('hub', HubSE()) if with_3pt_drive: assembly.add('nacelle', Drive3pt()) else: assembly.add('nacelle', Drive4pt()) else: assembly.add('nacelle', DriveWPACT()) assembly.add('hub', HubWPACT()) assembly.add('rna', RNAMass()) assembly.add('rotorloads1', RotorLoads()) assembly.add('rotorloads2', RotorLoads()) assembly.add('jacket', JacketSE()) assembly.add('maxdeflection', MaxTipDeflection()) if flexible_blade: assembly.add('fpi', FixedPointIterator()) assembly.fpi.workflow.add(['rotor']) assembly.fpi.add_parameter('rotor.delta_precurve_sub', low=-1.e99, high=1.e99) assembly.fpi.add_parameter('rotor.delta_bladeLength', low=-1.e99, high=1.e99) assembly.fpi.add_constraint( 'rotor.delta_precurve_sub = rotor.delta_precurve_sub_out') assembly.fpi.add_constraint( 'rotor.delta_bladeLength = rotor.delta_bladeLength_out') assembly.fpi.max_iteration = 20 assembly.fpi.tolerance = 1e-8 assembly.driver.workflow.add(['fpi']) else: assembly.driver.workflow.add(['rotor']) assembly.driver.workflow.add([ 'hub', 'nacelle', 'jacket', 'maxdeflection', 'rna', 'rotorloads1', 'rotorloads2' ]) # TODO: rotor drivetrain design should be connected to nacelle drivetrain design # connections to rotor assembly.connect('machine_rating', 'rotor.control.ratedPower') assembly.connect('rho', 'rotor.rho') assembly.connect('mu', 'rotor.mu') assembly.connect('shear_exponent', 'rotor.shearExp') assembly.connect('hub_height', 'rotor.hubHt') assembly.connect('turbine_class', 'rotor.turbine_class') assembly.connect('turbulence_class', 'rotor.turbulence_class') assembly.connect('g', 'rotor.g') assembly.connect('cdf_reference_height_wind_speed', 'rotor.cdf_reference_height_wind_speed') # connections to hub assembly.connect('rotor.mass_one_blade', 'hub.blade_mass') assembly.connect('rotor.root_bending_moment', 'hub.rotor_bending_moment') assembly.connect('rotor.diameter', 'hub.rotor_diameter') assembly.connect('rotor.hub_diameter', 'hub.blade_root_diameter') assembly.connect('rotor.nBlades', 'hub.blade_number') if with_new_nacelle: assembly.connect('nacelle.MB1_location', 'hub.MB1_location') assembly.connect('rotor.tilt', 'hub.gamma') assembly.connect('nacelle.L_rb', 'hub.L_rb') # connections to nacelle #TODO: fatigue option variables assembly.connect('rotor.diameter', 'nacelle.rotor_diameter') if not with_new_nacelle: assembly.connect( 'rotor.mass_all_blades + hub.hub_system_mass', 'nacelle.rotor_mass' ) #DODO: circular dependency if using DriveSE (nacelle csm --> hub, hub mass --> nacelle) if with_new_nacelle: assembly.connect('rotor.nBlades', 'nacelle.blade_number') assembly.connect('rotor.tilt', 'nacelle.shaft_angle') assembly.connect('333.3 * machine_rating / 1000.0', 'nacelle.shrink_disc_mass') assembly.connect('1.5 * rotor.ratedConditions.Q', 'nacelle.rotor_torque') assembly.connect('rotor.ratedConditions.T', 'nacelle.rotor_thrust') assembly.connect('rotor.ratedConditions.Omega', 'nacelle.rotor_speed') assembly.connect('machine_rating', 'nacelle.machine_rating') assembly.connect('rotor.root_bending_moment', 'nacelle.rotor_bending_moment') assembly.connect('generator_speed/rotor.ratedConditions.Omega', 'nacelle.gear_ratio') '''if with_new_nacelle: assembly.connect('rotor.g', 'nacelle.g')''' # Only drive smooth taking g from rotor; TODO: update when drive_smooth is updated assembly.connect( 'tower_dt', 'nacelle.tower_top_diameter' ) # OpenMDAO circular dependency issue # update for jacket input # connections to rna assembly.connect('rotor.mass_all_blades', 'rna.blades_mass') assembly.connect('rotor.I_all_blades', 'rna.blades_I') assembly.connect('hub.hub_system_mass', 'rna.hub_mass') assembly.connect('hub.hub_system_cm', 'rna.hub_cm') assembly.connect('hub.hub_system_I', 'rna.hub_I') assembly.connect('nacelle.nacelle_mass', 'rna.nac_mass') assembly.connect('nacelle.nacelle_cm', 'rna.nac_cm') assembly.connect('nacelle.nacelle_I', 'rna.nac_I') # connections to rotorloads1 assembly.connect('downwind', 'rotorloads1.downwind') assembly.connect('rna_weightM', 'rotorloads1.rna_weightM') assembly.connect('1.8 * rotor.ratedConditions.T', 'rotorloads1.F[0]') assembly.connect('rotor.ratedConditions.Q', 'rotorloads1.M[0]') assembly.connect('hub.hub_system_cm', 'rotorloads1.r_hub') assembly.connect('rna.rna_cm', 'rotorloads1.rna_cm') assembly.connect('rotor.tilt', 'rotorloads1.tilt') assembly.connect('g', 'rotorloads1.g') assembly.connect('rna.rna_mass', 'rotorloads1.m_RNA') # connections to rotorloads2 assembly.connect('downwind', 'rotorloads2.downwind') assembly.connect('rna_weightM', 'rotorloads2.rna_weightM') assembly.connect('rotor.T_extreme', 'rotorloads2.F[0]') assembly.connect('rotor.Q_extreme', 'rotorloads2.M[0]') assembly.connect('hub.hub_system_cm', 'rotorloads2.r_hub') assembly.connect('rna.rna_cm', 'rotorloads2.rna_cm') assembly.connect('rotor.tilt', 'rotorloads2.tilt') assembly.connect('g', 'rotorloads2.g') assembly.connect('rna.rna_mass', 'rotorloads2.m_RNA') # connections to jacket assembly.connect('rho', 'jacket.Windinputs.rho') # jacket input assembly.connect('mu', 'jacket.Windinputs.mu') # jacket input assembly.connect('-g', 'jacket.FrameAuxIns.gvector[2]') # jacket input assembly.connect('hub_height', 'jacket.Windinputs.HH') # jacket input assembly.connect('tower_dt', 'jacket.Twrinputs.Dt') # jacket input assembly.connect('rotor.yaw', 'jacket.RNAinputs.yawangle') # jacket input #assembly.connect('hub_height - nacelle.nacelle_cm[2]', 'jacket.Twrinputs.Htwr') # jacket input; TODO: probably irrelevant for this purpose, tower length is now determined in jacket assembly.connect('rna.rna_mass', 'jacket.RNAinputs.mass') # jacket input assembly.connect('rna.rna_cm', 'jacket.RNAinputs.CMoff') # jacket input assembly.connect('rna.rna_I_TT', 'jacket.RNAinputs.I') # jacket input # Rated rotor loads (Option 1) assembly.connect('rotor.ratedConditions.V', 'jacket.Windinputs.U50HH') # jacket input assembly.connect('rotorloads1.top_F', 'jacket.RNA_F[0:3]') # jacket input assembly.connect('rotorloads1.top_M', 'jacket.RNA_F[3:6]') # jacket input # Survival rotor loads (Option 2) #assembly.connect('rotor.V_extreme', 'tower.Windinputs.U50HH') # jacket input #assembly.connect('rotorloads2.top_F', 'jacket.RNA_F') # jacket input #assembly.connect('rotorloads2.top_M', 'jacket.RNA_M') # jacket input # connections to maxdeflection assembly.connect('rotor.Rtip', 'maxdeflection.Rtip') assembly.connect('rotor.precurveTip', 'maxdeflection.precurveTip') assembly.connect('rotor.presweepTip', 'maxdeflection.presweepTip') assembly.connect('rotor.precone', 'maxdeflection.precone') assembly.connect('rotor.tilt', 'maxdeflection.tilt') assembly.connect('hub.hub_system_cm', 'maxdeflection.hub_tt') assembly.connect( 'jacket.Twrouts.nodes[2,:]', 'maxdeflection.tower_z' ) # jacket input, had to make array dimensions explicit on instantiation for this connect to work ---THIS is the z at CMzoff, not necessarily the top flange assembly.connect('jacket.Twrouts', 'maxdeflection.Twrouts' ) # TODO: jacket input - doesnt recognize logobj assembly.connect('jacket.Twrouts.Htwr', 'maxdeflection.towerHt') # jacket input
from fusedwind.interface import implement_base from commonse.UtilizationSupplement import fatigue, hoopStressEurocode, shellBucklingEurocode, \ bucklingGL, vonMisesStressUtilization import matplotlib.pyplot as plt import frame3dd ################################################################################ ### 1. Aerodynamic and structural performance using RotorSE BladeLength = 34 HubHeight = 65 ReferenceBladeLength = 68; rotor = RotorSE() # ------------------- # === blade grid === # (Array): initial aerodynamic grid on unit radius rotor.initial_aero_grid = np.array([0.02222276, 0.06666667, 0.11111057, \ 0.16666667, 0.23333333, 0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, \ 0.63333333, 0.7, 0.76666667, 0.83333333, 0.88888943, 0.93333333, \ 0.97777724]) # (Array): initial structural grid on unit radius rotor.initial_str_grid = np.array([0.0, 0.00492790457512, 0.00652942887106, 0.00813095316699, 0.00983257273154, 0.0114340970275, 0.0130356213234, 0.02222276, 0.024446481932, 0.026048006228, 0.06666667, 0.089508406455, 0.11111057, 0.146462614229, 0.16666667, 0.195309105255, 0.23333333, 0.276686558545, 0.3, 0.333640766319,0.36666667, 0.400404310407, 0.43333333,
def __init__(self, nSection): super(FloatingTurbine, self).__init__() self.add('hub_height', IndepVarComp('hub_height', 0.0), promotes=['*']) # TODO: #Weibull/Rayleigh CDF # Rotor self.add( 'rotor', RotorSE(), promotes=[ 'idx_cylinder_aero', 'idx_cylinder_str', 'hubFraction', 'nBlades', 'turbine_class', 'sparT', 'teT', 'r_max_chord', 'chord_sub', 'theta_sub', 'precurve_sub', 'bladeLength', 'precone', 'tilt', 'yaw', 'turbulence_class', 'gust_stddev', 'VfactorPC', 'shape_parameter', 'Rtip', 'precurveTip', 'presweepTip', 'control:Vin', 'control:Vout', 'machine_rating', 'control:minOmega', 'control:maxOmega', 'control:tsr', 'control:pitch', 'pitch_extreme', 'azimuth_extreme', 'drivetrainType', 'rstar_damage', 'Mxb_damage', 'Myb_damage', 'strain_ult_spar', 'strain_ult_te', 'm_damage', 'nSector', 'tiploss', 'hubloss', 'wakerotation', 'usecd', 'AEP_loss_factor', 'tip_deflection', 'dynamic_amplication_tip_deflection' ]) # RNA self.add('rna', RNA(1)) # Tower and substructure myfloat = FloatingSE(nSection) self.add( 'sm', myfloat, promotes=[ 'radius_to_auxiliary_column', 'fairlead', 'fairlead_offset_from_shell', 'base_freeboard', 'base_section_height', 'base_outer_diameter', 'base_wall_thickness', 'auxiliary_freeboard', 'auxiliary_section_height', 'auxiliary_outer_diameter', 'auxiliary_wall_thickness', 'scope_ratio', 'anchor_radius', 'mooring_diameter', 'number_of_mooring_lines', 'mooring_type', 'anchor_type', 'drag_embedment_extra_length', 'mooring_max_offset', 'mooring_max_heel', 'mooring_cost_rate', 'permanent_ballast_density', 'base_stiffener_web_height', 'base_stiffener_web_thickness', 'base_stiffener_flange_width', 'base_stiffener_flange_thickness', 'base_stiffener_spacing', 'base_bulkhead_nodes', 'base_permanent_ballast_height', 'auxiliary_stiffener_web_height', 'auxiliary_stiffener_web_thickness', 'auxiliary_stiffener_flange_width', 'auxiliary_stiffener_flange_thickness', 'auxiliary_stiffener_spacing', 'auxiliary_bulkhead_nodes', 'auxiliary_permanent_ballast_height', 'bulkhead_mass_factor', 'ring_mass_factor', 'shell_mass_factor', 'column_mass_factor', 'outfitting_mass_fraction', 'ballast_cost_rate', 'tapered_col_cost_rate', 'outfitting_cost_rate', 'number_of_auxiliary_columns', 'pontoon_outer_diameter', 'pontoon_wall_thickness', 'cross_attachment_pontoons', 'lower_attachment_pontoons', 'upper_attachment_pontoons', 'lower_ring_pontoons', 'upper_ring_pontoons', 'outer_cross_pontoons', 'pontoon_cost_rate', 'connection_ratio_max', 'base_pontoon_attach_upper', 'base_pontoon_attach_lower', 'tower_section_height', 'tower_outer_diameter', 'tower_wall_thickness', 'tower_outfitting_factor', 'tower_buckling_length', 'tower_mass', 'loading', 'min_diameter_thickness_ratio', 'min_taper_ratio' ]) # Turbine constraints self.add('tcons', TurbineConstraints(myfloat.nFull), promotes=[ 'blade_number', 'Rtip', 'precurveTip', 'presweepTip', 'precone', 'tilt', 'tip_deflection' ]) # Turbine costs self.add('tcost', Turbine_CostsSE_2015(), promotes=['*']) # Balance of station self.add('wobos', WindOBOS(), promotes=['tax_rate']) # LCOE Calculation self.add('lcoe', PlantFinance(), promotes=['*']) # Define all input variables from all models self.add('offshore', IndepVarComp('offshore', True, pass_by_obj=True), promotes=['*']) self.add('crane', IndepVarComp('crane', False, pass_by_obj=True), promotes=['*']) # Tower #self.add('stress_standard_value', IndepVarComp('stress_standard_value', 0.0), promotes=['*']) #self.add('fatigue_parameters', IndepVarComp('fatigue_parameters', np.zeros(nDEL)), promotes=['*']) #self.add('fatigue_z', IndepVarComp('fatigue_z', np.zeros(nDEL)), promotes=['*']) #self.add('frame3dd_matrix_method', IndepVarComp('frame3dd_matrix_method', 0, pass_by_obj=True), promotes=['*']) #self.add('compute_stiffnes', IndepVarComp('compute_stiffnes', False, pass_by_obj=True), promotes=['*']) self.add('project_lifetime', IndepVarComp('project_lifetime', 0.0), promotes=['*']) #self.add('lumped_mass_matrix', IndepVarComp('lumped_mass_matrix', 0, pass_by_obj=True), promotes=['*']) #self.add('slope_SN', IndepVarComp('slope_SN', 0, pass_by_obj=True), promotes=['*']) self.add('number_of_modes', IndepVarComp('number_of_modes', 0, pass_by_obj=True), promotes=['*']) #self.add('compute_shear', IndepVarComp('compute_shear', True, pass_by_obj=True), promotes=['*']) #self.add('shift_value', IndepVarComp('shift_value', 0.0), promotes=['*']) #self.add('frame3dd_convergence_tolerance', IndepVarComp('frame3dd_convergence_tolerance', 1e-9), promotes=['*']) # TODO: Multiple load cases # Environment self.add('air_density', IndepVarComp('air_density', 0.0), promotes=['*']) self.add('air_viscosity', IndepVarComp('air_viscosity', 0.0), promotes=['*']) self.add('wind_reference_speed', IndepVarComp('wind_reference_speed', 0.0), promotes=['*']) self.add('wind_reference_height', IndepVarComp('wind_reference_height', 0.0), promotes=['*']) self.add('shearExp', IndepVarComp('shearExp', 0.0), promotes=['*']) self.add('wind_bottom_height', IndepVarComp('wind_bottom_height', 0.0), promotes=['*']) self.add('wind_beta', IndepVarComp('wind_beta', 0.0), promotes=['*']) self.add('cd_usr', IndepVarComp('cd_usr', np.inf), promotes=['*']) # Environment self.add('water_depth', IndepVarComp('water_depth', 0.0), promotes=['*']) self.add('water_density', IndepVarComp('water_density', 0.0), promotes=['*']) self.add('water_viscosity', IndepVarComp('water_viscosity', 0.0), promotes=['*']) self.add('wave_height', IndepVarComp('wave_height', 0.0), promotes=['*']) self.add('wave_period', IndepVarComp('wave_period', 0.0), promotes=['*']) self.add('mean_current_speed', IndepVarComp('mean_current_speed', 0.0), promotes=['*']) #self.add('wave_beta', IndepVarComp('wave_beta', 0.0), promotes=['*']) #self.add('wave_velocity_z0', IndepVarComp('wave_velocity_z0', 0.0), promotes=['*']) #self.add('wave_acceleration_z0', IndepVarComp('wave_acceleration_z0', 0.0), promotes=['*']) # Design standards self.add('safety_factor_frequency', IndepVarComp('safety_factor_frequency', 0.0), promotes=['*']) self.add('safety_factor_stress', IndepVarComp('safety_factor_stress', 0.0), promotes=['*']) self.add('safety_factor_materials', IndepVarComp('safety_factor_materials', 0.0), promotes=['*']) self.add('safety_factor_buckling', IndepVarComp('safety_factor_buckling', 0.0), promotes=['*']) self.add('safety_factor_fatigue', IndepVarComp('safety_factor_fatigue', 0.0), promotes=['*']) self.add('safety_factor_consequence', IndepVarComp('safety_factor_consequence', 0.0), promotes=['*']) # RNA self.add('dummy_mass', IndepVarComp('dummy_mass', 0.0), promotes=['*']) self.add('hub_mass', IndepVarComp('hub_mass', 0.0), promotes=['*']) self.add('nac_mass', IndepVarComp('nac_mass', 0.0), promotes=['*']) self.add('hub_cm', IndepVarComp('hub_cm', np.zeros((3, ))), promotes=['*']) self.add('nac_cm', IndepVarComp('nac_cm', np.zeros((3, ))), promotes=['*']) self.add('hub_I', IndepVarComp('hub_I', np.zeros(6)), promotes=['*']) self.add('nac_I', IndepVarComp('nac_I', np.zeros(6)), promotes=['*']) self.add('downwind', IndepVarComp('downwind', False, pass_by_obj=True), promotes=['*']) self.add('rna_weightM', IndepVarComp('rna_weightM', True, pass_by_obj=True), promotes=['*']) # Column self.add('morison_mass_coefficient', IndepVarComp('morison_mass_coefficient', 0.0), promotes=['*']) self.add('material_density', IndepVarComp('material_density', 0.0), promotes=['*']) self.add('E', IndepVarComp('E', 0.0), promotes=['*']) self.add('nu', IndepVarComp('nu', 0.0), promotes=['*']) self.add('yield_stress', IndepVarComp('yield_stress', 0.0), promotes=['*']) # Pontoons self.add('G', IndepVarComp('G', 0.0), promotes=['*']) # Offshore BOS # Turbine / Plant parameters, , self.add('nacelleL', IndepVarComp('nacelleL', 0.0), promotes=['*']) self.add('nacelleW', IndepVarComp('nacelleW', 0.0), promotes=['*']) self.add('distShore', IndepVarComp('distShore', 0.0), promotes=['*']) #90.0 self.add('distPort', IndepVarComp('distPort', 0.0), promotes=['*']) #90.0 self.add('distPtoA', IndepVarComp('distPtoA', 0.0), promotes=['*']) #90.0 self.add('distAtoS', IndepVarComp('distAtoS', 0.0), promotes=['*']) #90.0 self.add('substructure', IndepVarComp('substructure', 'SEMISUBMERSIBLE', pass_by_obj=True), promotes=['*']) self.add('anchor', IndepVarComp('anchor', 'DRAGEMBEDMENT', pass_by_obj=True), promotes=['*']) self.add('turbInstallMethod', IndepVarComp('turbInstallMethod', 'INDIVIDUAL', pass_by_obj=True), promotes=['*']) self.add('towerInstallMethod', IndepVarComp('towerInstallMethod', 'ONEPIECE', pass_by_obj=True), promotes=['*']) self.add('installStrategy', IndepVarComp('installStrategy', 'PRIMARYVESSEL', pass_by_obj=True), promotes=['*']) self.add('cableOptimizer', IndepVarComp('cableOptimizer', False, pass_by_obj=True), promotes=['*']) self.add('buryDepth', IndepVarComp('buryDepth', 0.0), promotes=['*']) #2.0 self.add('arrayY', IndepVarComp('arrayY', 0.0), promotes=['*']) #9.0 self.add('arrayX', IndepVarComp('arrayX', 0.0), promotes=['*']) #9.0 self.add('substructCont', IndepVarComp('substructCont', 0.0), promotes=['*']) #0.30 self.add('turbCont', IndepVarComp('turbCont', 0.0), promotes=['*']) #0.30 self.add('elecCont', IndepVarComp('elecCont', 0.0), promotes=['*']) #0.30 self.add('interConVolt', IndepVarComp('interConVolt', 0.0), promotes=['*']) #345.0 self.add('distInterCon', IndepVarComp('distInterCon', 0.0), promotes=['*']) #3.0 self.add('scrapVal', IndepVarComp('scrapVal', 0.0), promotes=['*']) #0.0 #General', , self.add('inspectClear', IndepVarComp('inspectClear', 0.0), promotes=['*']) #2.0 self.add('plantComm', IndepVarComp('plantComm', 0.0), promotes=['*']) #0.01 self.add('procurement_contingency', IndepVarComp('procurement_contingency', 0.0), promotes=['*']) #0.05 self.add('install_contingency', IndepVarComp('install_contingency', 0.0), promotes=['*']) #0.30 self.add('construction_insurance', IndepVarComp('construction_insurance', 0.0), promotes=['*']) #0.01 self.add('capital_cost_year_0', IndepVarComp('capital_cost_year_0', 0.0), promotes=['*']) #0.20 self.add('capital_cost_year_1', IndepVarComp('capital_cost_year_1', 0.0), promotes=['*']) #0.60 self.add('capital_cost_year_2', IndepVarComp('capital_cost_year_2', 0.0), promotes=['*']) #0.10 self.add('capital_cost_year_3', IndepVarComp('capital_cost_year_3', 0.0), promotes=['*']) #0.10 self.add('capital_cost_year_4', IndepVarComp('capital_cost_year_4', 0.0), promotes=['*']) #0.0 self.add('capital_cost_year_5', IndepVarComp('capital_cost_year_5', 0.0), promotes=['*']) #0.0 self.add('tax_rate', IndepVarComp('tax_rate', 0.0), promotes=['*']) #0.40 self.add('interest_during_construction', IndepVarComp('interest_during_construction', 0.0), promotes=['*']) #0.08 #Substructure & Foundation', , self.add('mpileCR', IndepVarComp('mpileCR', 0.0), promotes=['*']) #2250.0 self.add('mtransCR', IndepVarComp('mtransCR', 0.0), promotes=['*']) #3230.0 self.add('mpileD', IndepVarComp('mpileD', 0.0), promotes=['*']) #0.0 self.add('mpileL', IndepVarComp('mpileL', 0.0), promotes=['*']) #0.0 self.add('mpEmbedL', IndepVarComp('mpEmbedL', 0.0), promotes=['*']) #30.0 self.add('jlatticeCR', IndepVarComp('jlatticeCR', 0.0), promotes=['*']) #4680.0 self.add('jtransCR', IndepVarComp('jtransCR', 0.0), promotes=['*']) #4500.0 self.add('jpileCR', IndepVarComp('jpileCR', 0.0), promotes=['*']) #2250.0 self.add('jlatticeA', IndepVarComp('jlatticeA', 0.0), promotes=['*']) #26.0 self.add('jpileL', IndepVarComp('jpileL', 0.0), promotes=['*']) #47.50 self.add('jpileD', IndepVarComp('jpileD', 0.0), promotes=['*']) #1.60 self.add('ssHeaveCR', IndepVarComp('ssHeaveCR', 0.0), promotes=['*']) #6250.0 self.add('scourMat', IndepVarComp('scourMat', 0.0), promotes=['*']) #250000.0 self.add('number_install_seasons', IndepVarComp('number_install_seasons', 0, pass_by_obj=True), promotes=['*']) #1 #Electrical Infrastructure', , self.add('pwrFac', IndepVarComp('pwrFac', 0.0), promotes=['*']) #0.95 self.add('buryFac', IndepVarComp('buryFac', 0.0), promotes=['*']) #0.10 self.add('catLengFac', IndepVarComp('catLengFac', 0.0), promotes=['*']) #0.04 self.add('exCabFac', IndepVarComp('exCabFac', 0.0), promotes=['*']) #0.10 self.add('subsTopFab', IndepVarComp('subsTopFab', 0.0), promotes=['*']) #14500.0 self.add('subsTopDes', IndepVarComp('subsTopDes', 0.0), promotes=['*']) #4500000.0 self.add('topAssemblyFac', IndepVarComp('topAssemblyFac', 0.0), promotes=['*']) #0.075 self.add('subsJackCR', IndepVarComp('subsJackCR', 0.0), promotes=['*']) #6250.0 self.add('subsPileCR', IndepVarComp('subsPileCR', 0.0), promotes=['*']) #2250.0 self.add('dynCabFac', IndepVarComp('dynCabFac', 0.0), promotes=['*']) #2.0 self.add('shuntCR', IndepVarComp('shuntCR', 0.0), promotes=['*']) #35000.0 self.add('highVoltSG', IndepVarComp('highVoltSG', 0.0), promotes=['*']) #950000.0 self.add('medVoltSG', IndepVarComp('medVoltSG', 0.0), promotes=['*']) #500000.0 self.add('backUpGen', IndepVarComp('backUpGen', 0.0), promotes=['*']) #1000000.0 self.add('workSpace', IndepVarComp('workSpace', 0.0), promotes=['*']) #2000000.0 self.add('otherAncillary', IndepVarComp('otherAncillary', 0.0), promotes=['*']) #3000000.0 self.add('mptCR', IndepVarComp('mptCR', 0.0), promotes=['*']) #12500.0 self.add('arrVoltage', IndepVarComp('arrVoltage', 0.0), promotes=['*']) #33.0 self.add('cab1CR', IndepVarComp('cab1CR', 0.0), promotes=['*']) #185.889 self.add('cab2CR', IndepVarComp('cab2CR', 0.0), promotes=['*']) #202.788 self.add('cab1CurrRating', IndepVarComp('cab1CurrRating', 0.0), promotes=['*']) #300.0 self.add('cab2CurrRating', IndepVarComp('cab2CurrRating', 0.0), promotes=['*']) #340.0 self.add('arrCab1Mass', IndepVarComp('arrCab1Mass', 0.0), promotes=['*']) #20.384 self.add('arrCab2Mass', IndepVarComp('arrCab2Mass', 0.0), promotes=['*']) #21.854 self.add('cab1TurbInterCR', IndepVarComp('cab1TurbInterCR', 0.0), promotes=['*']) #8410.0 self.add('cab2TurbInterCR', IndepVarComp('cab2TurbInterCR', 0.0), promotes=['*']) #8615.0 self.add('cab2SubsInterCR', IndepVarComp('cab2SubsInterCR', 0.0), promotes=['*']) #19815.0 self.add('expVoltage', IndepVarComp('expVoltage', 0.0), promotes=['*']) #220.0 self.add('expCurrRating', IndepVarComp('expCurrRating', 0.0), promotes=['*']) #530.0 self.add('expCabMass', IndepVarComp('expCabMass', 0.0), promotes=['*']) #71.90 self.add('expCabCR', IndepVarComp('expCabCR', 0.0), promotes=['*']) #495.411 self.add('expSubsInterCR', IndepVarComp('expSubsInterCR', 0.0), promotes=['*']) #57500.0 # Vector inputs #self.add('arrayCables', IndepVarComp('arrayCables', [33, 66], pass_by_obj=True), promotes=['*']) #self.add('exportCables', IndepVarComp('exportCables', [132, 220], pass_by_obj=True), promotes=['*']) #Assembly & Installation', self.add('moorTimeFac', IndepVarComp('moorTimeFac', 0.0), promotes=['*']) #0.005 self.add('moorLoadout', IndepVarComp('moorLoadout', 0.0), promotes=['*']) #5.0 self.add('moorSurvey', IndepVarComp('moorSurvey', 0.0), promotes=['*']) #4.0 self.add('prepAA', IndepVarComp('prepAA', 0.0), promotes=['*']) #168.0 self.add('prepSpar', IndepVarComp('prepSpar', 0.0), promotes=['*']) #18.0 self.add('upendSpar', IndepVarComp('upendSpar', 0.0), promotes=['*']) #36.0 self.add('prepSemi', IndepVarComp('prepSemi', 0.0), promotes=['*']) #12.0 self.add('turbFasten', IndepVarComp('turbFasten', 0.0), promotes=['*']) #8.0 self.add('boltTower', IndepVarComp('boltTower', 0.0), promotes=['*']) #7.0 self.add('boltNacelle1', IndepVarComp('boltNacelle1', 0.0), promotes=['*']) #7.0 self.add('boltNacelle2', IndepVarComp('boltNacelle2', 0.0), promotes=['*']) #7.0 self.add('boltNacelle3', IndepVarComp('boltNacelle3', 0.0), promotes=['*']) #7.0 self.add('boltBlade1', IndepVarComp('boltBlade1', 0.0), promotes=['*']) #3.50 self.add('boltBlade2', IndepVarComp('boltBlade2', 0.0), promotes=['*']) #3.50 self.add('boltRotor', IndepVarComp('boltRotor', 0.0), promotes=['*']) #7.0 self.add('vesselPosTurb', IndepVarComp('vesselPosTurb', 0.0), promotes=['*']) #2.0 self.add('vesselPosJack', IndepVarComp('vesselPosJack', 0.0), promotes=['*']) #8.0 self.add('vesselPosMono', IndepVarComp('vesselPosMono', 0.0), promotes=['*']) #3.0 self.add('subsVessPos', IndepVarComp('subsVessPos', 0.0), promotes=['*']) #6.0 self.add('monoFasten', IndepVarComp('monoFasten', 0.0), promotes=['*']) #12.0 self.add('jackFasten', IndepVarComp('jackFasten', 0.0), promotes=['*']) #20.0 self.add('prepGripperMono', IndepVarComp('prepGripperMono', 0.0), promotes=['*']) #1.50 self.add('prepGripperJack', IndepVarComp('prepGripperJack', 0.0), promotes=['*']) #8.0 self.add('placePiles', IndepVarComp('placePiles', 0.0), promotes=['*']) #12.0 self.add('prepHamMono', IndepVarComp('prepHamMono', 0.0), promotes=['*']) #2.0 self.add('prepHamJack', IndepVarComp('prepHamJack', 0.0), promotes=['*']) #2.0 self.add('removeHamMono', IndepVarComp('removeHamMono', 0.0), promotes=['*']) #2.0 self.add('removeHamJack', IndepVarComp('removeHamJack', 0.0), promotes=['*']) #4.0 self.add('placeTemplate', IndepVarComp('placeTemplate', 0.0), promotes=['*']) #4.0 self.add('placeJack', IndepVarComp('placeJack', 0.0), promotes=['*']) #12.0 self.add('levJack', IndepVarComp('levJack', 0.0), promotes=['*']) #24.0 self.add('hamRate', IndepVarComp('hamRate', 0.0), promotes=['*']) #20.0 self.add('placeMP', IndepVarComp('placeMP', 0.0), promotes=['*']) #3.0 self.add('instScour', IndepVarComp('instScour', 0.0), promotes=['*']) #6.0 self.add('placeTP', IndepVarComp('placeTP', 0.0), promotes=['*']) #3.0 self.add('groutTP', IndepVarComp('groutTP', 0.0), promotes=['*']) #8.0 self.add('tpCover', IndepVarComp('tpCover', 0.0), promotes=['*']) #1.50 self.add('prepTow', IndepVarComp('prepTow', 0.0), promotes=['*']) #12.0 self.add('spMoorCon', IndepVarComp('spMoorCon', 0.0), promotes=['*']) #20.0 self.add('ssMoorCon', IndepVarComp('ssMoorCon', 0.0), promotes=['*']) #22.0 self.add('spMoorCheck', IndepVarComp('spMoorCheck', 0.0), promotes=['*']) #16.0 self.add('ssMoorCheck', IndepVarComp('ssMoorCheck', 0.0), promotes=['*']) #12.0 self.add('ssBall', IndepVarComp('ssBall', 0.0), promotes=['*']) #6.0 self.add('surfLayRate', IndepVarComp('surfLayRate', 0.0), promotes=['*']) #375.0 self.add('cabPullIn', IndepVarComp('cabPullIn', 0.0), promotes=['*']) #5.50 self.add('cabTerm', IndepVarComp('cabTerm', 0.0), promotes=['*']) #5.50 self.add('cabLoadout', IndepVarComp('cabLoadout', 0.0), promotes=['*']) #14.0 self.add('buryRate', IndepVarComp('buryRate', 0.0), promotes=['*']) #125.0 self.add('subsPullIn', IndepVarComp('subsPullIn', 0.0), promotes=['*']) #48.0 self.add('shorePullIn', IndepVarComp('shorePullIn', 0.0), promotes=['*']) #96.0 self.add('landConstruct', IndepVarComp('landConstruct', 0.0), promotes=['*']) #7.0 self.add('expCabLoad', IndepVarComp('expCabLoad', 0.0), promotes=['*']) #24.0 self.add('subsLoad', IndepVarComp('subsLoad', 0.0), promotes=['*']) #60.0 self.add('placeTop', IndepVarComp('placeTop', 0.0), promotes=['*']) #24.0 self.add('pileSpreadDR', IndepVarComp('pileSpreadDR', 0.0), promotes=['*']) #2500.0 self.add('pileSpreadMob', IndepVarComp('pileSpreadMob', 0.0), promotes=['*']) #750000.0 self.add('groutSpreadDR', IndepVarComp('groutSpreadDR', 0.0), promotes=['*']) #3000.0 self.add('groutSpreadMob', IndepVarComp('groutSpreadMob', 0.0), promotes=['*']) #1000000.0 self.add('seaSpreadDR', IndepVarComp('seaSpreadDR', 0.0), promotes=['*']) #165000.0 self.add('seaSpreadMob', IndepVarComp('seaSpreadMob', 0.0), promotes=['*']) #4500000.0 self.add('compRacks', IndepVarComp('compRacks', 0.0), promotes=['*']) #1000000.0 self.add('cabSurveyCR', IndepVarComp('cabSurveyCR', 0.0), promotes=['*']) #240.0 self.add('cabDrillDist', IndepVarComp('cabDrillDist', 0.0), promotes=['*']) #500.0 self.add('cabDrillCR', IndepVarComp('cabDrillCR', 0.0), promotes=['*']) #3200.0 self.add('mpvRentalDR', IndepVarComp('mpvRentalDR', 0.0), promotes=['*']) #72000.0 self.add('diveTeamDR', IndepVarComp('diveTeamDR', 0.0), promotes=['*']) #3200.0 self.add('winchDR', IndepVarComp('winchDR', 0.0), promotes=['*']) #1000.0 self.add('civilWork', IndepVarComp('civilWork', 0.0), promotes=['*']) #40000.0 self.add('elecWork', IndepVarComp('elecWork', 0.0), promotes=['*']) #25000.0 #Port & Staging', , self.add('nCrane600', IndepVarComp('nCrane600', 0, pass_by_obj=True), promotes=['*']) #0 self.add('nCrane1000', IndepVarComp('nCrane1000', 0, pass_by_obj=True), promotes=['*']) #0 self.add('crane600DR', IndepVarComp('crane600DR', 0.0), promotes=['*']) #5000.0 self.add('crane1000DR', IndepVarComp('crane1000DR', 0.0), promotes=['*']) #8000.0 self.add('craneMobDemob', IndepVarComp('craneMobDemob', 0.0), promotes=['*']) #150000.0 self.add('entranceExitRate', IndepVarComp('entranceExitRate', 0.0), promotes=['*']) #0.525 self.add('dockRate', IndepVarComp('dockRate', 0.0), promotes=['*']) #3000.0 self.add('wharfRate', IndepVarComp('wharfRate', 0.0), promotes=['*']) #2.75 self.add('laydownCR', IndepVarComp('laydownCR', 0.0), promotes=['*']) #0.25 #Engineering & Management', , self.add('estEnMFac', IndepVarComp('estEnMFac', 0.0), promotes=['*']) #0.04 #Development', , self.add('preFEEDStudy', IndepVarComp('preFEEDStudy', 0.0), promotes=['*']) #5000000.0 self.add('feedStudy', IndepVarComp('feedStudy', 0.0), promotes=['*']) #10000000.0 self.add('stateLease', IndepVarComp('stateLease', 0.0), promotes=['*']) #250000.0 self.add('outConShelfLease', IndepVarComp('outConShelfLease', 0.0), promotes=['*']) #1000000.0 self.add('saPlan', IndepVarComp('saPlan', 0.0), promotes=['*']) #500000.0 self.add('conOpPlan', IndepVarComp('conOpPlan', 0.0), promotes=['*']) #1000000.0 self.add('nepaEisMet', IndepVarComp('nepaEisMet', 0.0), promotes=['*']) #2000000.0 self.add('physResStudyMet', IndepVarComp('physResStudyMet', 0.0), promotes=['*']) #1500000.0 self.add('bioResStudyMet', IndepVarComp('bioResStudyMet', 0.0), promotes=['*']) #1500000.0 self.add('socEconStudyMet', IndepVarComp('socEconStudyMet', 0.0), promotes=['*']) #500000.0 self.add('navStudyMet', IndepVarComp('navStudyMet', 0.0), promotes=['*']) #500000.0 self.add('nepaEisProj', IndepVarComp('nepaEisProj', 0.0), promotes=['*']) #5000000.0 self.add('physResStudyProj', IndepVarComp('physResStudyProj', 0.0), promotes=['*']) #500000.0 self.add('bioResStudyProj', IndepVarComp('bioResStudyProj', 0.0), promotes=['*']) #500000.0 self.add('socEconStudyProj', IndepVarComp('socEconStudyProj', 0.0), promotes=['*']) #200000.0 self.add('navStudyProj', IndepVarComp('navStudyProj', 0.0), promotes=['*']) #250000.0 self.add('coastZoneManAct', IndepVarComp('coastZoneManAct', 0.0), promotes=['*']) #100000.0 self.add('rivsnHarbsAct', IndepVarComp('rivsnHarbsAct', 0.0), promotes=['*']) #100000.0 self.add('cleanWatAct402', IndepVarComp('cleanWatAct402', 0.0), promotes=['*']) #100000.0 self.add('cleanWatAct404', IndepVarComp('cleanWatAct404', 0.0), promotes=['*']) #100000.0 self.add('faaPlan', IndepVarComp('faaPlan', 0.0), promotes=['*']) #10000.0 self.add('endSpecAct', IndepVarComp('endSpecAct', 0.0), promotes=['*']) #500000.0 self.add('marMamProtAct', IndepVarComp('marMamProtAct', 0.0), promotes=['*']) #500000.0 self.add('migBirdAct', IndepVarComp('migBirdAct', 0.0), promotes=['*']) #500000.0 self.add('natHisPresAct', IndepVarComp('natHisPresAct', 0.0), promotes=['*']) #250000.0 self.add('addLocPerm', IndepVarComp('addLocPerm', 0.0), promotes=['*']) #200000.0 self.add('metTowCR', IndepVarComp('metTowCR', 0.0), promotes=['*']) #11518.0 self.add('decomDiscRate', IndepVarComp('decomDiscRate', 0.0), promotes=['*']) #0.03 # LCOE self.add('number_of_turbines', IndepVarComp('number_of_turbines', 0, pass_by_obj=True), promotes=['*']) self.add('annual_opex', IndepVarComp('annual_opex', 0.0), promotes=['*']) # TODO: Replace with output connection self.add('fixed_charge_rate', IndepVarComp('fixed_charge_rate', 0.0), promotes=['*']) self.add('discount_rate', IndepVarComp('discount_rate', 0.0), promotes=['*']) # Connect all input variables from all models self.connect('water_depth', ['sm.water_depth', 'wobos.waterD', 'sea_depth']) self.connect('hub_height', ['rotor.hub_height', 'sm.hub_height', 'wobos.hubH']) self.connect('tower_outer_diameter', 'wobos.towerD', src_indices=[0]) self.connect('wind_beta', 'sm.beta') self.connect('cd_usr', 'sm.cd_usr') #self.connect('wave_beta', 'sm.waveLoads.beta') self.connect('yaw', 'sm.yaw') self.connect('mean_current_speed', 'sm.Uc') self.connect('project_lifetime', ['rotor.struc.lifetime', 'wobos.projLife']) #self.connect('slope_SN', 'sm.m_SN') #self.connect('compute_shear', 'sm.shear') #self.connect('compute_stiffnes', 'sm.geom') #self.connect('frame3dd_matrix_method', 'sm.Mmethod') #self.connect('shift_value', 'sm.shift') # TODO: #self.connect('number_of_modes', ['sm.nM', 'rotor.nF']) self.connect('number_of_modes', 'rotor.nF') #self.connect('frame3dd_convergence_tolerance', 'sm.tol') #self.connect('lumped_mass_matrix', 'sm.lump') #self.connect('stress_standard_value', 'sm.DC') self.connect('safety_factor_frequency', ['rotor.gamma_freq', 'tcons.gamma_freq']) self.connect('safety_factor_stress', ['sm.gamma_f', 'rotor.gamma_f']) self.connect('safety_factor_materials', ['sm.gamma_m', 'rotor.gamma_m', 'tcons.gamma_m']) self.connect('safety_factor_buckling', 'sm.gamma_b') self.connect('safety_factor_fatigue', ['rotor.gamma_fatigue', 'sm.gamma_fatigue']) self.connect('safety_factor_consequence', 'sm.gamma_n') self.connect('rna.loads.top_F', 'sm.rna_force') self.connect('rna.loads.top_M', 'sm.rna_moment') self.connect('rna.rna_I_TT', 'sm.rna_I') self.connect('rna.rna_mass', ['wobos.rnaM', 'sm.rna_mass']) self.connect('rna.rna_cm', 'sm.rna_cg') self.connect('rotor.mass_all_blades', 'rna.blades_mass') self.connect('rotor.I_all_blades', 'rna.blades_I') self.connect('hub_mass', 'rna.hub_mass') self.connect('nac_mass', 'rna.nac_mass') self.connect('hub_cm', ['rna.hub_cm', 'tcons.hub_tt']) self.connect('nac_cm', 'rna.nac_cm') self.connect('hub_I', 'rna.hub_I') self.connect('nac_I', 'rna.nac_I') self.connect('tilt', 'rna.tilt') self.connect('rotor.Fxyz_total', 'rna.loads.F') self.connect('rotor.Mxyz_total', 'rna.loads.M') self.connect('downwind', 'rna.downwind') self.connect('rna_weightM', 'rna.rna_weightM') self.connect('air_density', ['sm.base.windLoads.rho', 'rotor.analysis.rho']) self.connect('air_viscosity', ['sm.base.windLoads.mu', 'rotor.analysis.mu']) self.connect('water_density', 'sm.water_density') self.connect('water_viscosity', 'sm.base.waveLoads.mu') self.connect('wave_height', 'sm.hmax') self.connect('wave_period', 'sm.T') self.connect('wind_reference_speed', 'sm.Uref') self.connect('wind_reference_height', ['sm.zref', 'rotor.wind.zref']) self.connect('wind_bottom_height', ['sm.z0', 'rotor.wind.z0']) self.connect('shearExp', ['sm.shearExp', 'rotor.wind.shearExp']) self.connect('morison_mass_coefficient', 'sm.cm') self.connect('material_density', 'sm.material_density') self.connect('E', 'sm.E') self.connect('G', 'sm.G') self.connect('nu', 'sm.nu') self.connect('yield_stress', 'sm.yield_stress') self.connect('anchor', 'wobos.anchor') self.connect('ballast_cost_rate', 'wobos.ballCR') self.connect('drag_embedment_extra_length', 'wobos.deaFixLeng') self.connect('mooring_cost_rate', 'wobos.moorCR') self.connect('sm.mm.mooring_cost', 'wobos.moorCost') self.connect('mooring_diameter', 'wobos.moorDia') self.connect('number_of_mooring_lines', 'wobos.moorLines') self.connect('outfitting_cost_rate', 'wobos.sSteelCR') self.connect( 'tapered_col_cost_rate', ['wobos.spStifColCR', 'wobos.spTapColCR', 'wobos.ssStifColCR']) self.connect('pontoon_cost_rate', 'wobos.ssTrussCR') self.connect('nBlades', 'blade_number') self.connect('rotor.mass_one_blade', 'blade_mass') self.connect('control:maxOmega', 'tcons.rotor_omega') self.connect('sm.load.f1', 'tcons.tower_f1') self.connect('sm.load.f2', 'tcons.tower_f2') self.connect('sm.tow.z_full', 'tcons.tower_z') self.connect('sm.tow.d_full', 'tcons.tower_d') self.connect('turbine_cost_kW', 'wobos.turbCapEx') self.connect('machine_rating', 'wobos.turbR') self.connect('rotor.diameter', 'wobos.rotorD') self.connect('bladeLength', 'wobos.bladeL') self.connect('rotor.max_chord', 'wobos.chord') self.connect('rotor.hub_diameter', 'wobos.hubD') self.connect('nacelleL', 'wobos.nacelleL') # TODO: RotorSE, remove variable self.connect('nacelleW', 'wobos.nacelleW') # TODO: RotorSE, remove variable self.connect('distShore', 'wobos.distShore') self.connect('distPort', 'wobos.distPort') self.connect('distPtoA', 'wobos.distPtoA') self.connect('distAtoS', 'wobos.distAtoS') self.connect('substructure', 'wobos.substructure') self.connect('turbInstallMethod', 'wobos.turbInstallMethod') self.connect('towerInstallMethod', 'wobos.towerInstallMethod') self.connect('installStrategy', 'wobos.installStrategy') self.connect('cableOptimizer', 'wobos.cableOptimizer') self.connect('buryDepth', 'wobos.buryDepth') self.connect('arrayY', 'wobos.arrayY') # TODO: Plant_EnergySE, remove variable self.connect('arrayX', 'wobos.arrayX') # TODO: Plant_EnergySE, remove variable self.connect('substructCont', 'wobos.substructCont') self.connect('turbCont', 'wobos.turbCont') self.connect('elecCont', 'wobos.elecCont') self.connect('interConVolt', 'wobos.interConVolt') self.connect('distInterCon', 'wobos.distInterCon') self.connect('scrapVal', 'wobos.scrapVal') self.connect('inspectClear', 'wobos.inspectClear') self.connect('plantComm', 'wobos.plantComm') self.connect('procurement_contingency', 'wobos.procurement_contingency') self.connect('install_contingency', 'wobos.install_contingency') self.connect('construction_insurance', 'wobos.construction_insurance') self.connect('capital_cost_year_0', 'wobos.capital_cost_year_0') self.connect('capital_cost_year_1', 'wobos.capital_cost_year_1') self.connect('capital_cost_year_2', 'wobos.capital_cost_year_2') self.connect('capital_cost_year_3', 'wobos.capital_cost_year_3') self.connect('capital_cost_year_4', 'wobos.capital_cost_year_4') self.connect('capital_cost_year_5', 'wobos.capital_cost_year_5') self.connect('interest_during_construction', 'wobos.interest_during_construction') self.connect('mpileCR', 'wobos.mpileCR') # TODO: JacketSE, remove variable self.connect('mtransCR', 'wobos.mtransCR') # TODO: JacketSE, remove variable self.connect('mpileD', 'wobos.mpileD') # TODO: JacketSE, remove variable self.connect('mpileL', 'wobos.mpileL') # TODO: JacketSE, remove variable self.connect('mpEmbedL', 'wobos.mpEmbedL') # TODO: JacketSE, remove variable self.connect('jlatticeCR', 'wobos.jlatticeCR') # TODO: JacketSE, remove variable self.connect('jtransCR', 'wobos.jtransCR') # TODO: JacketSE, remove variable self.connect('jpileCR', 'wobos.jpileCR') # TODO: JacketSE, remove variable self.connect('jlatticeA', 'wobos.jlatticeA') # TODO: JacketSE, remove variable self.connect('jpileL', 'wobos.jpileL') # TODO: JacketSE, remove variable self.connect('jpileD', 'wobos.jpileD') # TODO: JacketSE, remove variable self.connect('ssHeaveCR', 'wobos.ssHeaveCR') self.connect('scourMat', 'wobos.scourMat') self.connect('number_install_seasons', 'wobos.number_install_seasons') self.connect('pwrFac', 'wobos.pwrFac') self.connect('buryFac', 'wobos.buryFac') self.connect('catLengFac', 'wobos.catLengFac') self.connect('exCabFac', 'wobos.exCabFac') self.connect('subsTopFab', 'wobos.subsTopFab') self.connect('subsTopDes', 'wobos.subsTopDes') self.connect('topAssemblyFac', 'wobos.topAssemblyFac') self.connect('subsJackCR', 'wobos.subsJackCR') self.connect('subsPileCR', 'wobos.subsPileCR') self.connect('dynCabFac', 'wobos.dynCabFac') self.connect('shuntCR', 'wobos.shuntCR') self.connect('highVoltSG', 'wobos.highVoltSG') self.connect('medVoltSG', 'wobos.medVoltSG') self.connect('backUpGen', 'wobos.backUpGen') self.connect('workSpace', 'wobos.workSpace') self.connect('otherAncillary', 'wobos.otherAncillary') self.connect('mptCR', 'wobos.mptCR') self.connect('arrVoltage', 'wobos.arrVoltage') self.connect('cab1CR', 'wobos.cab1CR') self.connect('cab2CR', 'wobos.cab2CR') self.connect('cab1CurrRating', 'wobos.cab1CurrRating') self.connect('cab2CurrRating', 'wobos.cab2CurrRating') self.connect('arrCab1Mass', 'wobos.arrCab1Mass') self.connect('arrCab2Mass', 'wobos.arrCab2Mass') self.connect('cab1TurbInterCR', 'wobos.cab1TurbInterCR') self.connect('cab2TurbInterCR', 'wobos.cab2TurbInterCR') self.connect('cab2SubsInterCR', 'wobos.cab2SubsInterCR') self.connect('expVoltage', 'wobos.expVoltage') self.connect('expCurrRating', 'wobos.expCurrRating') self.connect('expCabMass', 'wobos.expCabMass') self.connect('expCabCR', 'wobos.expCabCR') self.connect('expSubsInterCR', 'wobos.expSubsInterCR') #self.connect('arrayCables', 'wobos.arrayCables') #self.connect('exportCables', 'wobos.exportCables') self.connect('moorTimeFac', 'wobos.moorTimeFac') self.connect('moorLoadout', 'wobos.moorLoadout') self.connect('moorSurvey', 'wobos.moorSurvey') self.connect('prepAA', 'wobos.prepAA') self.connect('prepSpar', 'wobos.prepSpar') self.connect('upendSpar', 'wobos.upendSpar') self.connect('prepSemi', 'wobos.prepSemi') self.connect('turbFasten', 'wobos.turbFasten') self.connect('boltTower', 'wobos.boltTower') self.connect('boltNacelle1', 'wobos.boltNacelle1') self.connect('boltNacelle2', 'wobos.boltNacelle2') self.connect('boltNacelle3', 'wobos.boltNacelle3') self.connect('boltBlade1', 'wobos.boltBlade1') self.connect('boltBlade2', 'wobos.boltBlade2') self.connect('boltRotor', 'wobos.boltRotor') self.connect('vesselPosTurb', 'wobos.vesselPosTurb') self.connect('vesselPosJack', 'wobos.vesselPosJack') self.connect('vesselPosMono', 'wobos.vesselPosMono') self.connect('subsVessPos', 'wobos.subsVessPos') self.connect('monoFasten', 'wobos.monoFasten') self.connect('jackFasten', 'wobos.jackFasten') self.connect('prepGripperMono', 'wobos.prepGripperMono') self.connect('prepGripperJack', 'wobos.prepGripperJack') self.connect('placePiles', 'wobos.placePiles') self.connect('prepHamMono', 'wobos.prepHamMono') self.connect('prepHamJack', 'wobos.prepHamJack') self.connect('removeHamMono', 'wobos.removeHamMono') self.connect('removeHamJack', 'wobos.removeHamJack') self.connect('placeTemplate', 'wobos.placeTemplate') self.connect('placeJack', 'wobos.placeJack') self.connect('levJack', 'wobos.levJack') self.connect('hamRate', 'wobos.hamRate') self.connect('placeMP', 'wobos.placeMP') self.connect('instScour', 'wobos.instScour') self.connect('placeTP', 'wobos.placeTP') self.connect('groutTP', 'wobos.groutTP') self.connect('tpCover', 'wobos.tpCover') self.connect('prepTow', 'wobos.prepTow') self.connect('spMoorCon', 'wobos.spMoorCon') self.connect('ssMoorCon', 'wobos.ssMoorCon') self.connect('spMoorCheck', 'wobos.spMoorCheck') self.connect('ssMoorCheck', 'wobos.ssMoorCheck') self.connect('ssBall', 'wobos.ssBall') self.connect('surfLayRate', 'wobos.surfLayRate') self.connect('cabPullIn', 'wobos.cabPullIn') self.connect('cabTerm', 'wobos.cabTerm') self.connect('cabLoadout', 'wobos.cabLoadout') self.connect('buryRate', 'wobos.buryRate') self.connect('subsPullIn', 'wobos.subsPullIn') self.connect('shorePullIn', 'wobos.shorePullIn') self.connect('landConstruct', 'wobos.landConstruct') self.connect('expCabLoad', 'wobos.expCabLoad') self.connect('subsLoad', 'wobos.subsLoad') self.connect('placeTop', 'wobos.placeTop') self.connect('pileSpreadDR', 'wobos.pileSpreadDR') self.connect('pileSpreadMob', 'wobos.pileSpreadMob') self.connect('groutSpreadDR', 'wobos.groutSpreadDR') self.connect('groutSpreadMob', 'wobos.groutSpreadMob') self.connect('seaSpreadDR', 'wobos.seaSpreadDR') self.connect('seaSpreadMob', 'wobos.seaSpreadMob') self.connect('compRacks', 'wobos.compRacks') self.connect('cabSurveyCR', 'wobos.cabSurveyCR') self.connect('cabDrillDist', 'wobos.cabDrillDist') self.connect('cabDrillCR', 'wobos.cabDrillCR') self.connect('mpvRentalDR', 'wobos.mpvRentalDR') self.connect('diveTeamDR', 'wobos.diveTeamDR') self.connect('winchDR', 'wobos.winchDR') self.connect('civilWork', 'wobos.civilWork') self.connect('elecWork', 'wobos.elecWork') self.connect('nCrane600', 'wobos.nCrane600') self.connect('nCrane1000', 'wobos.nCrane1000') self.connect('crane600DR', 'wobos.crane600DR') self.connect('crane1000DR', 'wobos.crane1000DR') self.connect('craneMobDemob', 'wobos.craneMobDemob') self.connect('entranceExitRate', 'wobos.entranceExitRate') self.connect('dockRate', 'wobos.dockRate') self.connect('wharfRate', 'wobos.wharfRate') self.connect('laydownCR', 'wobos.laydownCR') self.connect('estEnMFac', 'wobos.estEnMFac') self.connect('preFEEDStudy', 'wobos.preFEEDStudy') self.connect('feedStudy', 'wobos.feedStudy') self.connect('stateLease', 'wobos.stateLease') self.connect('outConShelfLease', 'wobos.outConShelfLease') self.connect('saPlan', 'wobos.saPlan') self.connect('conOpPlan', 'wobos.conOpPlan') self.connect('nepaEisMet', 'wobos.nepaEisMet') self.connect('physResStudyMet', 'wobos.physResStudyMet') self.connect('bioResStudyMet', 'wobos.bioResStudyMet') self.connect('socEconStudyMet', 'wobos.socEconStudyMet') self.connect('navStudyMet', 'wobos.navStudyMet') self.connect('nepaEisProj', 'wobos.nepaEisProj') self.connect('physResStudyProj', 'wobos.physResStudyProj') self.connect('bioResStudyProj', 'wobos.bioResStudyProj') self.connect('socEconStudyProj', 'wobos.socEconStudyProj') self.connect('navStudyProj', 'wobos.navStudyProj') self.connect('coastZoneManAct', 'wobos.coastZoneManAct') self.connect('rivsnHarbsAct', 'wobos.rivsnHarbsAct') self.connect('cleanWatAct402', 'wobos.cleanWatAct402') self.connect('cleanWatAct404', 'wobos.cleanWatAct404') self.connect('faaPlan', 'wobos.faaPlan') self.connect('endSpecAct', 'wobos.endSpecAct') self.connect('marMamProtAct', 'wobos.marMamProtAct') self.connect('migBirdAct', 'wobos.migBirdAct') self.connect('natHisPresAct', 'wobos.natHisPresAct') self.connect('addLocPerm', 'wobos.addLocPerm') self.connect('metTowCR', 'wobos.metTowCR') self.connect('decomDiscRate', 'wobos.decomDiscRate') # Link outputs from one model to inputs to another self.connect('tower_mass', 'wobos.towerM') self.connect('dummy_mass', 'sm.aux.stack_mass_in') self.connect('sm.total_cost', 'wobos.subTotCost') self.connect('sm.total_mass', 'wobos.subTotM') self.connect('wobos.total_bos_cost', 'bos_costs') self.connect('number_of_turbines', ['wobos.nTurb', 'turbine_number']) self.connect('annual_opex', 'avg_annual_opex') self.connect('rotor.AEP', 'net_aep') self.connect('wobos.totInstTime', 'construction_time') # Use complex number finite differences typeStr = 'fd' formStr = 'central' stepVal = 1e-5 stepStr = 'relative' self.deriv_options['type'] = typeStr self.deriv_options['form'] = formStr self.deriv_options['step_size'] = stepVal self.deriv_options['step_calc'] = stepStr
def execute(self): # --- Import Modules import numpy as np import os from openmdao.api import IndepVarComp, Component, Group, Problem, Brent, ScipyGMRES, ScipyOptimizer, DumpRecorder from rotorse.rotor_aeropower import RotorAeroPower from rotorse.rotor_geometry import RotorGeometry, NREL5MW, DTU10MW, NINPUT from rotorse import RPM2RS, RS2RPM, TURBULENCE_CLASS, DRIVETRAIN_TYPE from rotorse.rotor import RotorSE myref = DTU10MW() rotor = Problem() npts_coarse_power_curve = 20 # (Int): number of points to evaluate aero analysis at npts_spline_power_curve = 200 # (Int): number of points to use in fitting spline to power curve rotor.root = RotorSE(myref, npts_coarse_power_curve, npts_spline_power_curve) rotor.setup() # --- # === blade grid === rotor[ 'hubFraction'] = myref.hubFraction #0.023785 # (Float): hub location as fraction of radius rotor[ 'bladeLength'] = myref.bladeLength #96.7 # (Float, m): blade length (if not precurved or swept) otherwise length of blade before curvature rotor['precone'] = myref.precone #4. # (Float, deg): precone angle rotor['tilt'] = myref.tilt #6.0 # (Float, deg): shaft tilt rotor['yaw'] = 0.0 # (Float, deg): yaw error rotor['nBlades'] = myref.nBlades #3 # (Int): number of blades # --- # === blade geometry === rotor[ 'r_max_chord'] = myref.r_max_chord # 0.2366 #(Float): location of max chord on unit radius rotor[ 'chord_in'] = myref.chord # np.array([4.6, 4.869795, 5.990629, 3.00785428, 0.0962]) # (Array, m): chord at control points. defined at hub, then at linearly spaced locations from r_max_chord to tip rotor[ 'theta_in'] = myref.theta # np.array([14.5, 12.874, 6.724, -0.03388039, -0.037]) # (Array, deg): twist at control points. defined at linearly spaced locations from r[idx_cylinder] to tip rotor[ 'precurve_in'] = myref.precurve #np.array([-0., -0.054497, -0.175303, -0.84976143, -6.206217]) # (Array, m): precurve at control points. defined at same locations at chord, starting at 2nd control point (root must be zero precurve) rotor[ 'presweep_in'] = myref.presweep #np.array([0., 0., 0., 0., 0.]) # (Array, m): precurve at control points. defined at same locations at chord, starting at 2nd control point (root must be zero precurve) rotor[ 'sparT_in'] = myref.spar_thickness # np.array([0.03200042 0.07038508 0.08515644 0.07777004 0.01181032]) # (Array, m): spar cap thickness parameters rotor[ 'teT_in'] = myref.te_thickness # np.array([0.04200055 0.08807739 0.05437378 0.01610219 0.00345225]) # (Array, m): trailing-edge thickness parameters # --- # === atmosphere === rotor['analysis.rho'] = 1.225 # (Float, kg/m**3): density of air rotor[ 'analysis.mu'] = 1.81206e-5 # (Float, kg/m/s): dynamic viscosity of air rotor['wind.shearExp'] = 0.25 # (Float): shear exponent rotor[ 'hub_height'] = myref.hub_height #119.0 # (Float, m): hub height rotor[ 'turbine_class'] = myref.turbine_class #TURBINE_CLASS['I'] # (Enum): IEC turbine class rotor['turbulence_class'] = TURBULENCE_CLASS[ 'B'] # (Enum): IEC turbulence class class rotor[ 'wind.zref'] = myref.hub_height #119.0 # (Float): reference hub height for IEC wind speed (used in CDF calculation) rotor['gust_stddev'] = 3 # --- # === control === rotor[ 'control_Vin'] = myref.control_Vin #4.0 # (Float, m/s): cut-in wind speed rotor[ 'control_Vout'] = myref.control_Vout #25.0 # (Float, m/s): cut-out wind speed rotor[ 'control_minOmega'] = myref.control_minOmega #6.0 # (Float, rpm): minimum allowed rotor rotation speed rotor[ 'control_maxOmega'] = myref.control_maxOmega #8.88766 # (Float, rpm): maximum allowed rotor rotation speed rotor[ 'control_tsr'] = myref.control_tsr #10.58 # (Float): tip-speed ratio in Region 2 (should be optimized externally) rotor[ 'control_pitch'] = myref.control_pitch #0.0 # (Float, deg): pitch angle in region 2 (and region 3 for fixed pitch machines) rotor[ 'machine_rating'] = myref.rating #10e6 # (Float, W): rated power rotor[ 'pitch_extreme'] = 0.0 # (Float, deg): worst-case pitch at survival wind condition rotor[ 'azimuth_extreme'] = 0.0 # (Float, deg): worst-case azimuth at survival wind condition rotor[ 'VfactorPC'] = 0.7 # (Float): fraction of rated speed at which the deflection is assumed to representative throughout the power curve calculation # --- # === aero and structural analysis options === rotor[ 'nSector'] = 4 # (Int): number of sectors to divide rotor face into in computing thrust and power rotor[ 'AEP_loss_factor'] = 1.0 # (Float): availability and other losses (soiling, array, etc.) rotor[ 'drivetrainType'] = myref.drivetrain #DRIVETRAIN_TYPE['GEARED'] # (Enum) rotor[ 'dynamic_amplication_tip_deflection'] = 1.35 # (Float): a dynamic amplification factor to adjust the static deflection calculation # --- # === fatigue === r_aero = np.array([ 0.02222276, 0.06666667, 0.11111057, 0.2, 0.23333333, 0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, 0.63333333, 0.64, 0.7, 0.83333333, 0.88888943, 0.93333333, 0.97777724 ]) # (Array): new aerodynamic grid on unit radius rstar_damage = np.array( [ 0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300, 0.367, 0.433, 0.500, 0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978 ] ) # (Array): nondimensional radial locations of damage equivalent moments Mxb_damage = 1e3 * np.array([ 2.3743E+003, 2.0834E+003, 1.8108E+003, 1.5705E+003, 1.3104E+003, 1.0488E+003, 8.2367E+002, 6.3407E+002, 4.7727E+002, 3.4804E+002, 2.4458E+002, 1.6339E+002, 1.0252E+002, 5.7842E+001, 2.7349E+001, 1.1262E+001, 3.8549E+000, 4.4738E-001 ]) # (Array, N*m): damage equivalent moments about blade c.s. x-direction Myb_damage = 1e3 * np.array([ 2.7732E+003, 2.8155E+003, 2.6004E+003, 2.3933E+003, 2.1371E+003, 1.8459E+003, 1.5582E+003, 1.2896E+003, 1.0427E+003, 8.2015E+002, 6.2449E+002, 4.5229E+002, 3.0658E+002, 1.8746E+002, 9.6475E+001, 4.2677E+001, 1.5409E+001, 1.8426E+000 ]) # (Array, N*m): damage equivalent moments about blade c.s. y-direction xp = np.r_[0.0, r_aero] xx = np.r_[0.0, myref.r] rotor['rstar_damage'] = np.interp(xx, xp, rstar_damage) rotor['Mxb_damage'] = np.interp(xx, xp, Mxb_damage) rotor['Myb_damage'] = np.interp(xx, xp, Myb_damage) rotor[ 'strain_ult_spar'] = 1.0e-2 # (Float): ultimate strain in spar cap rotor[ 'strain_ult_te'] = 2500 * 1e-6 * 2 # (Float): uptimate strain in trailing-edge panels, note that I am putting a factor of two for the damage part only. rotor['gamma_fatigue'] = 1.755 # (Float): safety factor for fatigue rotor['gamma_f'] = 1.35 # (Float): safety factor for loads/stresses rotor['gamma_m'] = 1.1 # (Float): safety factor for materials rotor[ 'gamma_freq'] = 1.1 # (Float): safety factor for resonant frequencies rotor[ 'm_damage'] = 10.0 # (Float): slope of S-N curve for fatigue analysis rotor[ 'struc.lifetime'] = 20.0 # (Float): number of cycles used in fatigue analysis TODO: make function of rotation speed # ---------------- # === run and outputs === rotor.run() print 'AEP =', rotor['AEP'] print 'diameter =', rotor['diameter'] print 'rated_V =', rotor['rated_V'] print 'rated_Omega =', rotor['rated_Omega'] print 'rated_pitch =', rotor['rated_pitch'] print 'rated_T =', rotor['rated_T'] print 'rated_Q =', rotor['rated_Q'] print 'mass_one_blade =', rotor['mass_one_blade'] print 'mass_all_blades =', rotor['mass_all_blades'] print 'I_all_blades =', rotor['I_all_blades'] print 'freq =', rotor['freq'] print 'tip_deflection =', rotor['tip_deflection'] print 'root_bending_moment =', rotor['root_bending_moment'] outpath = '..\..\..\docs\images' import matplotlib.pyplot as plt plt.figure() plt.plot(rotor['V'], rotor['P'] / 1e6) plt.xlabel('wind speed (m/s)') plt.xlabel('power (W)') plt.figure() plt.plot(rotor['r_pts'], rotor['strainU_spar'], label='suction') plt.plot(rotor['r_pts'], rotor['strainL_spar'], label='pressure') plt.plot(rotor['r_pts'], rotor['eps_crit_spar'], label='critical') # plt.ylim([-6e-3, 6e-3]) plt.xlabel('r') plt.ylabel('strain') plt.legend() plt.savefig( os.path.abspath(os.path.join(outpath, 'strain_spar_dtu10mw.png'))) plt.savefig( os.path.abspath(os.path.join(outpath, 'strain_spar_dtu10mw.pdf'))) plt.figure() plt.plot(rotor['r_pts'], rotor['strainU_te'], label='suction') plt.plot(rotor['r_pts'], rotor['strainL_te'], label='pressure') plt.plot(rotor['r_pts'], rotor['eps_crit_te'], label='critical') # plt.ylim([-5e-3, 5e-3]) plt.xlabel('r') plt.ylabel('strain') plt.legend() plt.savefig( os.path.abspath(os.path.join(outpath, 'strain_te_dtu10mw.png'))) plt.savefig( os.path.abspath(os.path.join(outpath, 'strain_te_dtu10mw.pdf'))) plt.show()
from fusedwind.interface import implement_base from commonse.UtilizationSupplement import fatigue, hoopStressEurocode, shellBucklingEurocode, \ bucklingGL, vonMisesStressUtilization import matplotlib.pyplot as plt import frame3dd ################################################################################ ### 1. Aerodynamic and structural performance using RotorSE BladeLength = 34 HubHeight = 65 ReferenceBladeLength = 68 rotor = RotorSE() # ------------------- # === blade grid === # (Array): initial aerodynamic grid on unit radius rotor.initial_aero_grid = np.array([0.02222276, 0.06666667, 0.11111057, \ 0.16666667, 0.23333333, 0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, \ 0.63333333, 0.7, 0.76666667, 0.83333333, 0.88888943, 0.93333333, \ 0.97777724]) # (Array): initial structural grid on unit radius rotor.initial_str_grid = np.array([ 0.0, 0.00492790457512, 0.00652942887106, 0.00813095316699, 0.00983257273154, 0.0114340970275, 0.0130356213234, 0.02222276, 0.024446481932, 0.026048006228, 0.06666667, 0.089508406455, 0.11111057, 0.146462614229, 0.16666667, 0.195309105255, 0.23333333, 0.276686558545,
def EvaluateLCOE(BladeLength, HubHeight, MaximumRotSpeed,Verbose=False): ############################################################################ # Define baseline paremeters used for scaling ReferenceBladeLength = 35; ReferenceTowerHeight = 95 WindReferenceHeight = 50 WindReferenceMeanVelocity = 3 WeibullShapeFactor = 2.0 ShearFactor = 0.25 RatedPower = 1.5e6 # Years used for analysis Years = 25 DiscountRate = 0.08 ############################################################################ ############################################################################ ### 1. Aerodynamic and structural performance using RotorSE rotor = RotorSE() # ------------------- # === blade grid === # (Array): initial aerodynamic grid on unit radius rotor.initial_aero_grid = np.array([0.02222276, 0.06666667, 0.11111057, \ 0.16666667, 0.23333333, 0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, \ 0.63333333, 0.7, 0.76666667, 0.83333333, 0.88888943, 0.93333333, \ 0.97777724]) # (Array): initial structural grid on unit radius rotor.initial_str_grid = np.array([0.0, 0.00492790457512, 0.00652942887106, 0.00813095316699, 0.00983257273154, 0.0114340970275, 0.0130356213234, 0.02222276, 0.024446481932, 0.026048006228, 0.06666667, 0.089508406455, 0.11111057, 0.146462614229, 0.16666667, 0.195309105255, 0.23333333, 0.276686558545, 0.3, 0.333640766319,0.36666667, 0.400404310407, 0.43333333, 0.5, 0.520818918408, 0.56666667, 0.602196371696, 0.63333333, 0.667358391486, 0.683573824984, 0.7, 0.73242031601, 0.76666667, 0.83333333, 0.88888943, 0.93333333, 0.97777724, 1.0]) # (Int): first idx in r_aero_unit of non-cylindrical section, # constant twist inboard of here rotor.idx_cylinder_aero = 3 # (Int): first idx in r_str_unit of non-cylindrical section rotor.idx_cylinder_str = 14 # (Float): hub location as fraction of radius rotor.hubFraction = 0.025 # ------------------ # === blade geometry === # (Array): new aerodynamic grid on unit radius rotor.r_aero = np.array([0.02222276, 0.06666667, 0.11111057, 0.2, 0.23333333, 0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, 0.63333333, 0.64, 0.7, 0.83333333, 0.88888943, 0.93333333, 0.97777724]) # (Float): location of max chord on unit radius rotor.r_max_chord = 0.23577 # (Array, m): chord at control points. defined at hub, then at linearly spaced # locations from r_max_chord to tip ReferenceChord = [3.2612, 4.5709, 3.3178, 1.4621] rotor.chord_sub = [x * np.true_divide(BladeLength,ReferenceBladeLength) \ for x in ReferenceChord] # (Array, deg): twist at control points. defined at linearly spaced locations # from r[idx_cylinder] to tip rotor.theta_sub = [13.2783, 7.46036, 2.89317, -0.0878099] # (Array, m): precurve at control points. defined at same locations at chord, # starting at 2nd control point (root must be zero precurve) rotor.precurve_sub = [0.0, 0.0, 0.0] # (Array, m): adjustment to precurve to account for curvature from loading rotor.delta_precurve_sub = [0.0, 0.0, 0.0] # (Array, m): spar cap thickness parameters rotor.sparT = [0.05, 0.047754, 0.045376, 0.031085, 0.0061398] # (Array, m): trailing-edge thickness parameters rotor.teT = [0.1, 0.09569, 0.06569, 0.02569, 0.00569] # (Float, m): blade length (if not precurved or swept) # otherwise length of blade before curvature rotor.bladeLength = BladeLength # (Float, m): adjustment to blade length to account for curvature from # loading rotor.delta_bladeLength = 0.0 rotor.precone = 2.5 # (Float, deg): precone angle rotor.tilt = 5.0 # (Float, deg): shaft tilt rotor.yaw = 0.0 # (Float, deg): yaw error rotor.nBlades = 3 # (Int): number of blades # ------------------ # === airfoil files === basepath = os.path.join(os.path.dirname(\ os.path.realpath(__file__)), '5MW_AFFiles') # load all airfoils airfoil_types = [0]*8 airfoil_types[0] = os.path.join(basepath, 'Cylinder1.dat') airfoil_types[1] = os.path.join(basepath, 'Cylinder2.dat') airfoil_types[2] = os.path.join(basepath, 'DU40_A17.dat') airfoil_types[3] = os.path.join(basepath, 'DU35_A17.dat') airfoil_types[4] = os.path.join(basepath, 'DU30_A17.dat') airfoil_types[5] = os.path.join(basepath, 'DU25_A17.dat') airfoil_types[6] = os.path.join(basepath, 'DU21_A17.dat') airfoil_types[7] = os.path.join(basepath, 'NACA64_A17.dat') # place at appropriate radial stations af_idx = [0, 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7] n = len(af_idx) af = [0]*n for i in range(n): af[i] = airfoil_types[af_idx[i]] rotor.airfoil_files = af # (List): names of airfoil file # ---------------------- # === atmosphere === rotor.rho = 1.225 # (Float, kg/m**3): density of air rotor.mu = 1.81206e-5 # (Float, kg/m/s): dynamic viscosity of air rotor.shearExp = 0.25 # (Float): shear exponent rotor.hubHt = HubHeight # (Float, m): hub height rotor.turbine_class = 'I' # (Enum): IEC turbine class rotor.turbulence_class = 'B' # (Enum): IEC turbulence class class rotor.cdf_reference_height_wind_speed = 30.0 rotor.g = 9.81 # (Float, m/s**2): acceleration of gravity # ---------------------- # === control === rotor.control.Vin = 3.0 # (Float, m/s): cut-in wind speed rotor.control.Vout = 26.0 # (Float, m/s): cut-out wind speed rotor.control.ratedPower = RatedPower # (Float, W): rated power # (Float, rpm): minimum allowed rotor rotation speed # (Float, rpm): maximum allowed rotor rotation speed rotor.control.minOmega = 0.0 rotor.control.maxOmega = MaximumRotSpeed # (Float): tip-speed ratio in Region 2 (should be optimized externally) rotor.control.tsr = 7 # (Float, deg): pitch angle in region 2 (and region 3 for fixed pitch machines) rotor.control.pitch = 0.0 # (Float, deg): worst-case pitch at survival wind condition rotor.pitch_extreme = 0.0 # (Float, deg): worst-case azimuth at survival wind condition rotor.azimuth_extreme = 0.0 # (Float): fraction of rated speed at which the deflection is assumed to # representative throughout the power curve calculation rotor.VfactorPC = 0.7 # ---------------------- # === aero and structural analysis options === # (Int): number of sectors to divide rotor face into in computing thrust and power rotor.nSector = 4 # (Int): number of points to evaluate aero analysis at rotor.npts_coarse_power_curve = 20 # (Int): number of points to use in fitting spline to power curve rotor.npts_spline_power_curve = 200 # (Float): availability and other losses (soiling, array, etc.) rotor.AEP_loss_factor = 1.0 rotor.drivetrainType = 'geared' # (Enum) # (Int): number of natural frequencies to compute rotor.nF = 5 # (Float): a dynamic amplification factor to adjust the static deflection # calculation rotor.dynamic_amplication_tip_deflection = 1.35 # ---------------------- # === materials and composite layup === basepath = os.path.join(os.path.dirname(os.path.realpath(__file__)), \ '5MW_PrecompFiles') materials = Orthotropic2DMaterial.listFromPreCompFile(os.path.join(basepath,\ 'materials.inp')) ncomp = len(rotor.initial_str_grid) upper = [0]*ncomp lower = [0]*ncomp webs = [0]*ncomp profile = [0]*ncomp # (Array): array of leading-edge positions from a reference blade axis # (usually blade pitch axis). locations are normalized by the local chord # length. e.g. leLoc[i] = 0.2 means leading edge is 0.2*chord[i] from reference # axis. positive in -x direction for airfoil-aligned coordinate system rotor.leLoc = np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.498, 0.497, 0.465, 0.447, 0.43, 0.411, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4]) # (Array): index of sector for spar (PreComp definition of sector) rotor.sector_idx_strain_spar = [2]*ncomp # (Array): index of sector for trailing-edge (PreComp definition of sector) rotor.sector_idx_strain_te = [3]*ncomp web1 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.4114, 0.4102, 0.4094, 0.3876, 0.3755, 0.3639, 0.345, 0.3342, 0.3313, 0.3274, 0.323, 0.3206, 0.3172, 0.3138, 0.3104, 0.307, 0.3003, 0.2982, 0.2935, 0.2899, 0.2867, 0.2833, 0.2817, 0.2799, 0.2767, 0.2731, 0.2664, 0.2607, 0.2562, 0.1886, -1.0]) web2 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.5886, 0.5868, 0.5854, 0.5508, 0.5315, 0.5131, 0.4831, 0.4658, 0.4687, 0.4726, 0.477, 0.4794, 0.4828, 0.4862, 0.4896, 0.493, 0.4997, 0.5018, 0.5065, 0.5101, 0.5133, 0.5167, 0.5183, 0.5201, 0.5233, 0.5269, 0.5336, 0.5393, 0.5438, 0.6114, -1.0]) web3 = np.array([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0]) # (Array, m): chord distribution for reference section, thickness of structural # layup scaled with reference thickness (fixed t/c for this case) rotor.chord_str_ref = np.array([3.2612, 3.3100915356, 3.32587052924, 3.34159388653, 3.35823798667, 3.37384375335, 3.38939112914, 3.4774055542, 3.49839685, 3.51343645709, 3.87017220335, 4.04645623801, 4.19408216643, 4.47641008477, 4.55844487985, 4.57383098262, 4.57285771934, 4.51914315648, 4.47677655262, 4.40075650022, 4.31069949379, 4.20483735936, 4.08985563932, 3.82931757126, 3.74220276467, 3.54415796922, 3.38732428502, 3.24931446473, 3.23421422609, 3.22701537997, 3.21972125648, 3.08979310611, 2.95152261813, 2.330753331, 2.05553464181, 1.82577817774, 1.5860853279, 1.4621])* \ np.true_divide(BladeLength,ReferenceBladeLength) for i in range(ncomp): webLoc = [] if web1[i] != -1: webLoc.append(web1[i]) if web2[i] != -1: webLoc.append(web2[i]) if web3[i] != -1: webLoc.append(web3[i]) upper[i], lower[i], webs[i] = CompositeSection.initFromPreCompLayupFile\ (os.path.join(basepath, 'layup_' + str(i+1) + '.inp'), webLoc, materials) profile[i] = Profile.initFromPreCompFile(os.path.join(basepath, 'shape_' \ + str(i+1) + '.inp')) # (List): list of all Orthotropic2DMaterial objects used in # defining the geometry rotor.materials = materials # (List): list of CompositeSection objections defining the properties for # upper surface rotor.upperCS = upper # (List): list of CompositeSection objections defining the properties for # lower surface rotor.lowerCS = lower # (List): list of CompositeSection objections defining the properties for # shear webs rotor.websCS = webs # (List): airfoil shape at each radial position rotor.profile = profile # -------------------------------------- # === fatigue === # (Array): nondimensional radial locations of damage equivalent moments rotor.rstar_damage = np.array([0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300, 0.367, 0.433, 0.500, 0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978]) # (Array, N*m): damage equivalent moments about blade c.s. x-direction rotor.Mxb_damage = 1e3*np.array([2.3743E+003, 2.0834E+003, 1.8108E+003, 1.5705E+003, 1.3104E+003, 1.0488E+003, 8.2367E+002, 6.3407E+002, 4.7727E+002, 3.4804E+002, 2.4458E+002, 1.6339E+002, 1.0252E+002, 5.7842E+001, 2.7349E+001, 1.1262E+001, 3.8549E+000, 4.4738E-001]) # (Array, N*m): damage equivalent moments about blade c.s. y-direction rotor.Myb_damage = 1e3*np.array([2.7732E+003, 2.8155E+003, 2.6004E+003, 2.3933E+003, 2.1371E+003, 1.8459E+003, 1.5582E+003, 1.2896E+003, 1.0427E+003, 8.2015E+002, 6.2449E+002, 4.5229E+002, 3.0658E+002, 1.8746E+002, 9.6475E+001, 4.2677E+001, 1.5409E+001, 1.8426E+000]) rotor.strain_ult_spar = 1.0e-2 # (Float): ultimate strain in spar cap # (Float): uptimate strain in trailing-edge panels, note that I am putting a # factor of two for the damage part only. rotor.strain_ult_te = 2500*1e-6 * 2 rotor.eta_damage = 1.35*1.3*1.0 # (Float): safety factor for fatigue rotor.m_damage = 10.0 # (Float): slope of S-N curve for fatigue analysis # (Float): number of cycles used in fatigue analysis rotor.N_damage = 365*24*3600*20.0 # ---------------- # from myutilities import plt # === run and outputs === rotor.run() # Evaluate AEP Using Lewis' Functions # Weibull Wind Parameters WindReferenceHeight = 50 WindReferenceMeanVelocity = 7.5 WeibullShapeFactor = 2.0 ShearFactor = 0.25 PowerCurve = rotor.P/1e6 PowerCurveVelocity = rotor.V HubHeight = rotor.hubHt AEP,WeibullScale = CalculateAEPWeibull(PowerCurve,PowerCurveVelocity, HubHeight, \ BladeLength,WeibullShapeFactor, WindReferenceHeight, \ WindReferenceMeanVelocity, ShearFactor) NamePlateCapacity = EstimateCapacity(PowerCurve,PowerCurveVelocity, \ rotor.ratedConditions.V) # AEP At Constant 7.5m/s Wind used for benchmarking... #AEP = CalculateAEPConstantWind(PowerCurve, PowerCurveVelocity, 7.5) if (Verbose ==True): print '################### ROTORSE ######################' print 'AEP = %d MWH' %(AEP) print 'NamePlateCapacity = %fMW' %(NamePlateCapacity) print 'diameter =', rotor.diameter print 'ratedConditions.V =', rotor.ratedConditions.V print 'ratedConditions.Omega =', rotor.ratedConditions.Omega print 'ratedConditions.pitch =', rotor.ratedConditions.pitch print 'mass_one_blade =', rotor.mass_one_blade print 'mass_all_blades =', rotor.mass_all_blades print 'I_all_blades =', rotor.I_all_blades print 'freq =', rotor.freq print 'tip_deflection =', rotor.tip_deflection print 'root_bending_moment =', rotor.root_bending_moment print '#########################################################' ############################################################################# ### 2. Hub Sizing # Specify hub parameters based off rotor # Load default hub model hubS = HubSE() hubS.rotor_diameter = rotor.Rtip*2 # m hubS.blade_number = rotor.nBlades hubS.blade_root_diameter = rotor.chord_sub[0]*1.25 hubS.L_rb = rotor.hubFraction*rotor.diameter hubS.MB1_location = np.array([-0.5, 0.0, 0.0]) hubS.machine_rating = rotor.control.ratedPower hubS.blade_mass = rotor.mass_one_blade hubS.rotor_bending_moment = rotor.root_bending_moment hubS.run() RotorTotalWeight = rotor.mass_all_blades + hubS.spinner.mass + \ hubS.hub.mass + hubS.pitchSystem.mass if (Verbose==True): print '##################### Hub SE ############################' print "Estimate of Hub Component Sizes:" print "Hub Components" print ' Hub: {0:8.1f} kg'.format(hubS.hub.mass) print ' Pitch system: {0:8.1f} kg'.format(hubS.pitchSystem.mass) print ' Nose cone: {0:8.1f} kg'.format(hubS.spinner.mass) print 'Rotor Total Weight = %d kg' %RotorTotalWeight print '#########################################################' ############################################################################ ### 3. Drive train + Nacelle Mass estimation nace = Drive4pt() nace.rotor_diameter = rotor.Rtip *2 # m nace.rotor_speed = rotor.ratedConditions.Omega # #rpm m/s nace.machine_rating = hubS.machine_rating/1000 nace.DrivetrainEfficiency = 0.95 # 6.35e6 #4365248.74 # Nm nace.rotor_torque = rotor.ratedConditions.Q nace.rotor_thrust = rotor.ratedConditions.T # N nace.rotor_mass = 0.0 #accounted for in F_z # kg nace.rotor_bending_moment_x = rotor.Mxyz_0[0] nace.rotor_bending_moment_y = rotor.Mxyz_0[1] nace.rotor_bending_moment_z = rotor.Mxyz_0[2] nace.rotor_force_x = rotor.Fxyz_0[0] # N nace.rotor_force_y = rotor.Fxyz_0[1] nace.rotor_force_z = rotor.Fxyz_0[2] # N # geared 3-stage Gearbox with induction generator machine nace.drivetrain_design = 'geared' nace.gear_ratio = 96.76 # 97:1 as listed in the 5 MW reference document nace.gear_configuration = 'eep' # epicyclic-epicyclic-parallel nace.crane = True # onboard crane present nace.shaft_angle = 5.0 #deg nace.shaft_ratio = 0.10 nace.Np = [3,3,1] nace.ratio_type = 'optimal' nace.shaft_type = 'normal' nace.uptower_transformer=False nace.shrink_disc_mass = 333.3*nace.machine_rating/1000.0 # estimated nace.mb1Type = 'CARB' nace.mb2Type = 'SRB' nace.flange_length = 0.5 #m nace.overhang = 5.0 nace.gearbox_cm = 0.1 nace.hss_length = 1.5 #0 if no fatigue check, 1 if parameterized fatigue check, #2 if known loads inputs nace.check_fatigue = 0 nace.blade_number=rotor.nBlades nace.cut_in=rotor.control.Vin #cut-in m/s nace.cut_out=rotor.control.Vout #cut-out m/s nace.Vrated=rotor.ratedConditions.V #rated windspeed m/s nace.weibull_k = WeibullShapeFactor # windepeed distribution shape parameter # windspeed distribution scale parameter nace.weibull_A = WeibullScale nace.T_life=20. #design life in years nace.IEC_Class_Letter = 'B' # length from hub center to main bearing, leave zero if unknown nace.L_rb = hubS.L_rb # NREL 5 MW Tower Variables nace.tower_top_diameter = 3.78 # m nace.run() if (Verbose==True): print '##################### Drive SE ############################' print "Estimate of Nacelle Component Sizes" print 'Low speed shaft: {0:8.1f} kg'.format(nace.lowSpeedShaft.mass) print 'Main bearings: {0:8.1f} kg'.format(\ nace.mainBearing.mass + nace.secondBearing.mass) print 'Gearbox: {0:8.1f} kg'.format(nace.gearbox.mass) print 'High speed shaft & brakes: {0:8.1f} kg'.format\ (nace.highSpeedSide.mass) print 'Generator: {0:8.1f} kg'.format(nace.generator.mass) print 'Variable speed electronics: {0:8.1f} kg'.format(\ nace.above_yaw_massAdder.vs_electronics_mass) print 'Overall mainframe:{0:8.1f} kg'.format(\ nace.above_yaw_massAdder.mainframe_mass) print ' Bedplate: {0:8.1f} kg'.format(nace.bedplate.mass) print 'Electrical connections: {0:8.1f} kg'.format(\ nace.above_yaw_massAdder.electrical_mass) print 'HVAC system: {0:8.1f} kg'.format(\ nace.above_yaw_massAdder.hvac_mass ) print 'Nacelle cover: {0:8.1f} kg'.format(\ nace.above_yaw_massAdder.cover_mass) print 'Yaw system: {0:8.1f} kg'.format(nace.yawSystem.mass) print 'Overall nacelle: {0:8.1f} kg'.format(nace.nacelle_mass, \ nace.nacelle_cm[0], nace.nacelle_cm[1], nace.nacelle_cm[2], \ nace.nacelle_I[0], nace.nacelle_I[1], nace.nacelle_I[2]) print '#########################################################' ############################################################################ ### 4. Tower Mass # --- tower setup ------ from commonse.environment import PowerWind tower = set_as_top(TowerSE()) # ---- tower ------ tower.replace('wind1', PowerWind()) tower.replace('wind2', PowerWind()) # onshore (no waves) # --- geometry ---- tower.z_param = [0.0, HubHeight*0.5, HubHeight] TowerRatio = np.true_divide(HubHeight,ReferenceTowerHeight) tower.d_param = [6.0*TowerRatio, 4.935*TowerRatio, 3.87*TowerRatio] tower.t_param = [0.027*1.3*TowerRatio, 0.023*1.3*TowerRatio, \ 0.019*1.3*TowerRatio] n = 10 tower.z_full = np.linspace(0.0, HubHeight, n) tower.L_reinforced = 15.0*np.ones(n) # [m] buckling length tower.theta_stress = 0.0*np.ones(n) tower.yaw = 0.0 # --- material props --- tower.E = 210e9*np.ones(n) tower.G = 80.8e9*np.ones(n) tower.rho = 8500.0*np.ones(n) tower.sigma_y = 450.0e6*np.ones(n) # --- spring reaction data. Use float('inf') for rigid constraints. --- tower.kidx = [0] # applied at base tower.kx = [float('inf')] tower.ky = [float('inf')] tower.kz = [float('inf')] tower.ktx = [float('inf')] tower.kty = [float('inf')] tower.ktz = [float('inf')] # --- extra mass ---- tower.midx = [n-1] # RNA mass at top tower.m = [0.8] tower.mIxx = [1.14930678e+08] tower.mIyy = [2.20354030e+07] tower.mIzz = [1.87597425e+07] tower.mIxy = [0.00000000e+00] tower.mIxz = [5.03710467e+05] tower.mIyz = [0.00000000e+00] tower.mrhox = [-1.13197635] tower.mrhoy = [0.] tower.mrhoz = [0.50875268] tower.addGravityLoadForExtraMass = False # ----------- # --- wind --- tower.wind_zref = 90.0 tower.wind_z0 = 0.0 tower.wind1.shearExp = 0.14 tower.wind2.shearExp = 0.14 # --------------- # # --- loading case 1: max Thrust --- tower.wind_Uref1 = 11.73732 tower.plidx1 = [n-1] # at tower top tower.Fx1 = [0.19620519] tower.Fy1 = [0.] tower.Fz1 = [-2914124.84400512] tower.Mxx1 = [3963732.76208099] tower.Myy1 = [-2275104.79420872] tower.Mzz1 = [-346781.68192839] # # --------------- # # --- loading case 2: max wind speed --- tower.wind_Uref2 = 70.0 tower.plidx1 = [n-1] # at tower top tower.Fx1 = [930198.60063279] tower.Fy1 = [0.] tower.Fz1 = [-2883106.12368949] tower.Mxx1 = [-1683669.22411597] tower.Myy1 = [-2522475.34625363] tower.Mzz1 = [147301.97023764] # # --------------- # # --- run --- tower.run() if (Verbose==True): print '##################### Tower SE ##########################' print 'mass (kg) =', tower.mass print 'f1 (Hz) =', tower.f1 print 'f2 (Hz) =', tower.f2 print 'top_deflection1 (m) =', tower.top_deflection1 print 'top_deflection2 (m) =', tower.top_deflection2 print '#########################################################' ############################################################################ ## 5. Turbine captial costs analysis turbine = Turbine_CostsSE() # NREL 5 MW turbine component masses based on Sunderland model approach # Rotor # inline with the windpact estimates turbine.blade_mass = rotor.mass_one_blade turbine.hub_mass = hubS.hub.mass turbine.pitch_system_mass = hubS.pitchSystem.mass turbine.spinner_mass = hubS.spinner.mass # Drivetrain and Nacelle turbine.low_speed_shaft_mass = nace.lowSpeedShaft.mass turbine.main_bearing_mass=nace.mainBearing.mass turbine.second_bearing_mass = nace.secondBearing.mass turbine.gearbox_mass = nace.gearbox.mass turbine.high_speed_side_mass = nace.highSpeedSide.mass turbine.generator_mass = nace.generator.mass turbine.bedplate_mass = nace.bedplate.mass turbine.yaw_system_mass = nace.yawSystem.mass # Tower turbine.tower_mass = tower.mass*0.5 # Additional non-mass cost model input variables turbine.machine_rating = hubS.machine_rating/1000 turbine.advanced = False turbine.blade_number = rotor.nBlades turbine.drivetrain_design = 'geared' turbine.crane = False turbine.offshore = False # Target year for analysis results turbine.year = 2010 turbine.month = 12 turbine.run() if (Verbose==True): print '##################### TurbinePrice SE ####################' print "Overall rotor cost with 3 advanced blades is ${0:.2f} USD"\ .format(turbine.rotorCC.cost) print "Blade cost is ${0:.2f} USD".format(turbine.rotorCC.bladeCC.cost) print "Hub cost is ${0:.2f} USD".format(turbine.rotorCC.hubCC.cost) print "Pitch system cost is ${0:.2f} USD".format(turbine.rotorCC.pitchSysCC.cost) print "Spinner cost is ${0:.2f} USD".format(turbine.rotorCC.spinnerCC.cost) print print "Overall nacelle cost is ${0:.2f} USD".format(turbine.nacelleCC.cost) print "LSS cost is ${0:.2f} USD".format(turbine.nacelleCC.lssCC.cost) print "Main bearings cost is ${0:.2f} USD".format(turbine.nacelleCC.bearingsCC.cost) print "Gearbox cost is ${0:.2f} USD".format(turbine.nacelleCC.gearboxCC.cost) print "Hight speed side cost is ${0:.2f} USD".format(turbine.nacelleCC.hssCC.cost) print "Generator cost is ${0:.2f} USD".format(turbine.nacelleCC.generatorCC.cost) print "Bedplate cost is ${0:.2f} USD".format(turbine.nacelleCC.bedplateCC.cost) print "Yaw system cost is ${0:.2f} USD".format(turbine.nacelleCC.yawSysCC.cost) print print "Tower cost is ${0:.2f} USD".format(turbine.towerCC.cost) print print "The overall turbine cost is ${0:.2f} USD".format(turbine.turbine_cost) print '#########################################################' ############################################################################ ## 6. Operating Expenses # A simple test of nrel_csm_bos model bos = bos_csm_assembly() # Set input parameters bos = bos_csm_assembly() bos.machine_rating = hubS.machine_rating/1000 bos.rotor_diameter = rotor.diameter bos.turbine_cost = turbine.turbine_cost bos.hub_height = HubHeight bos.turbine_number = 1 bos.sea_depth = 0 bos.year = 2009 bos.month = 12 bos.multiplier = 1.0 bos.run() om = opex_csm_assembly() om.machine_rating = rotor.control.ratedPower/1000 # Need to manipulate input or underlying component will not execute om.net_aep = AEP*10e4 om.sea_depth = 0 om.year = 2009 om.month = 12 om.turbine_number = 100 om.run() if (Verbose==True): print '##################### Operating Costs ####################' print "BOS cost per turbine: ${0:.2f} USD".format(bos.bos_costs / \ bos.turbine_number) print "Average annual operational expenditures" print "OPEX on shore with 100 turbines ${:.2f}: USD".format(\ om.avg_annual_opex) print "Preventative OPEX by turbine: ${:.2f} USD".format(\ om.opex_breakdown.preventative_opex / om.turbine_number) print "Corrective OPEX by turbine: ${:.2f} USD".format(\ om.opex_breakdown.corrective_opex / om.turbine_number) print "Land Lease OPEX by turbine: ${:.2f} USD".format(\ om.opex_breakdown.lease_opex / om.turbine_number) print '#########################################################' CapitalCost = turbine.turbine_cost + bos.bos_costs / bos.turbine_number OperatingCost = om.opex_breakdown.preventative_opex / om.turbine_number + \ om.opex_breakdown.lease_opex / om.turbine_number + \ om.opex_breakdown.corrective_opex / om.turbine_number LCOE = ComputeLCOE(AEP, CapitalCost, OperatingCost, DiscountRate, Years) print '######################***********************###################' print "Levelized Cost of Energy over %d years \ is $%f/kWH" %(Years,LCOE/1000) print '######################***********************###################' return LCOE/1000
def EvaluateLCOE(BladeLength, HubHeight, MaximumRotSpeed, Verbose=False): ############################################################################ # Define baseline paremeters used for scaling ReferenceBladeLength = 35 ReferenceTowerHeight = 95 WindReferenceHeight = 50 WindReferenceMeanVelocity = 3 WeibullShapeFactor = 2.0 ShearFactor = 0.25 RatedPower = 1.5e6 # Years used for analysis Years = 25 DiscountRate = 0.08 ############################################################################ ############################################################################ ### 1. Aerodynamic and structural performance using RotorSE rotor = RotorSE() # ------------------- # === blade grid === # (Array): initial aerodynamic grid on unit radius rotor.initial_aero_grid = np.array([0.02222276, 0.06666667, 0.11111057, \ 0.16666667, 0.23333333, 0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, \ 0.63333333, 0.7, 0.76666667, 0.83333333, 0.88888943, 0.93333333, \ 0.97777724]) # (Array): initial structural grid on unit radius rotor.initial_str_grid = np.array([ 0.0, 0.00492790457512, 0.00652942887106, 0.00813095316699, 0.00983257273154, 0.0114340970275, 0.0130356213234, 0.02222276, 0.024446481932, 0.026048006228, 0.06666667, 0.089508406455, 0.11111057, 0.146462614229, 0.16666667, 0.195309105255, 0.23333333, 0.276686558545, 0.3, 0.333640766319, 0.36666667, 0.400404310407, 0.43333333, 0.5, 0.520818918408, 0.56666667, 0.602196371696, 0.63333333, 0.667358391486, 0.683573824984, 0.7, 0.73242031601, 0.76666667, 0.83333333, 0.88888943, 0.93333333, 0.97777724, 1.0 ]) # (Int): first idx in r_aero_unit of non-cylindrical section, # constant twist inboard of here rotor.idx_cylinder_aero = 3 # (Int): first idx in r_str_unit of non-cylindrical section rotor.idx_cylinder_str = 14 # (Float): hub location as fraction of radius rotor.hubFraction = 0.025 # ------------------ # === blade geometry === # (Array): new aerodynamic grid on unit radius rotor.r_aero = np.array([ 0.02222276, 0.06666667, 0.11111057, 0.2, 0.23333333, 0.3, 0.36666667, 0.43333333, 0.5, 0.56666667, 0.63333333, 0.64, 0.7, 0.83333333, 0.88888943, 0.93333333, 0.97777724 ]) # (Float): location of max chord on unit radius rotor.r_max_chord = 0.23577 # (Array, m): chord at control points. defined at hub, then at linearly spaced # locations from r_max_chord to tip ReferenceChord = [3.2612, 4.5709, 3.3178, 1.4621] rotor.chord_sub = [x * np.true_divide(BladeLength,ReferenceBladeLength) \ for x in ReferenceChord] # (Array, deg): twist at control points. defined at linearly spaced locations # from r[idx_cylinder] to tip rotor.theta_sub = [13.2783, 7.46036, 2.89317, -0.0878099] # (Array, m): precurve at control points. defined at same locations at chord, # starting at 2nd control point (root must be zero precurve) rotor.precurve_sub = [0.0, 0.0, 0.0] # (Array, m): adjustment to precurve to account for curvature from loading rotor.delta_precurve_sub = [0.0, 0.0, 0.0] # (Array, m): spar cap thickness parameters rotor.sparT = [0.05, 0.047754, 0.045376, 0.031085, 0.0061398] # (Array, m): trailing-edge thickness parameters rotor.teT = [0.1, 0.09569, 0.06569, 0.02569, 0.00569] # (Float, m): blade length (if not precurved or swept) # otherwise length of blade before curvature rotor.bladeLength = BladeLength # (Float, m): adjustment to blade length to account for curvature from # loading rotor.delta_bladeLength = 0.0 rotor.precone = 2.5 # (Float, deg): precone angle rotor.tilt = 5.0 # (Float, deg): shaft tilt rotor.yaw = 0.0 # (Float, deg): yaw error rotor.nBlades = 3 # (Int): number of blades # ------------------ # === airfoil files === basepath = os.path.join(os.path.dirname(\ os.path.realpath(__file__)), '5MW_AFFiles') # load all airfoils airfoil_types = [0] * 8 airfoil_types[0] = os.path.join(basepath, 'Cylinder1.dat') airfoil_types[1] = os.path.join(basepath, 'Cylinder2.dat') airfoil_types[2] = os.path.join(basepath, 'DU40_A17.dat') airfoil_types[3] = os.path.join(basepath, 'DU35_A17.dat') airfoil_types[4] = os.path.join(basepath, 'DU30_A17.dat') airfoil_types[5] = os.path.join(basepath, 'DU25_A17.dat') airfoil_types[6] = os.path.join(basepath, 'DU21_A17.dat') airfoil_types[7] = os.path.join(basepath, 'NACA64_A17.dat') # place at appropriate radial stations af_idx = [0, 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7] n = len(af_idx) af = [0] * n for i in range(n): af[i] = airfoil_types[af_idx[i]] rotor.airfoil_files = af # (List): names of airfoil file # ---------------------- # === atmosphere === rotor.rho = 1.225 # (Float, kg/m**3): density of air rotor.mu = 1.81206e-5 # (Float, kg/m/s): dynamic viscosity of air rotor.shearExp = 0.25 # (Float): shear exponent rotor.hubHt = HubHeight # (Float, m): hub height rotor.turbine_class = 'I' # (Enum): IEC turbine class rotor.turbulence_class = 'B' # (Enum): IEC turbulence class class rotor.cdf_reference_height_wind_speed = 30.0 rotor.g = 9.81 # (Float, m/s**2): acceleration of gravity # ---------------------- # === control === rotor.control.Vin = 3.0 # (Float, m/s): cut-in wind speed rotor.control.Vout = 26.0 # (Float, m/s): cut-out wind speed rotor.control.ratedPower = RatedPower # (Float, W): rated power # (Float, rpm): minimum allowed rotor rotation speed # (Float, rpm): maximum allowed rotor rotation speed rotor.control.minOmega = 0.0 rotor.control.maxOmega = MaximumRotSpeed # (Float): tip-speed ratio in Region 2 (should be optimized externally) rotor.control.tsr = 7 # (Float, deg): pitch angle in region 2 (and region 3 for fixed pitch machines) rotor.control.pitch = 0.0 # (Float, deg): worst-case pitch at survival wind condition rotor.pitch_extreme = 0.0 # (Float, deg): worst-case azimuth at survival wind condition rotor.azimuth_extreme = 0.0 # (Float): fraction of rated speed at which the deflection is assumed to # representative throughout the power curve calculation rotor.VfactorPC = 0.7 # ---------------------- # === aero and structural analysis options === # (Int): number of sectors to divide rotor face into in computing thrust and power rotor.nSector = 4 # (Int): number of points to evaluate aero analysis at rotor.npts_coarse_power_curve = 20 # (Int): number of points to use in fitting spline to power curve rotor.npts_spline_power_curve = 200 # (Float): availability and other losses (soiling, array, etc.) rotor.AEP_loss_factor = 1.0 rotor.drivetrainType = 'geared' # (Enum) # (Int): number of natural frequencies to compute rotor.nF = 5 # (Float): a dynamic amplification factor to adjust the static deflection # calculation rotor.dynamic_amplication_tip_deflection = 1.35 # ---------------------- # === materials and composite layup === basepath = os.path.join(os.path.dirname(os.path.realpath(__file__)), \ '5MW_PrecompFiles') materials = Orthotropic2DMaterial.listFromPreCompFile(os.path.join(basepath,\ 'materials.inp')) ncomp = len(rotor.initial_str_grid) upper = [0] * ncomp lower = [0] * ncomp webs = [0] * ncomp profile = [0] * ncomp # (Array): array of leading-edge positions from a reference blade axis # (usually blade pitch axis). locations are normalized by the local chord # length. e.g. leLoc[i] = 0.2 means leading edge is 0.2*chord[i] from reference # axis. positive in -x direction for airfoil-aligned coordinate system rotor.leLoc = np.array([ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.498, 0.497, 0.465, 0.447, 0.43, 0.411, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4 ]) # (Array): index of sector for spar (PreComp definition of sector) rotor.sector_idx_strain_spar = [2] * ncomp # (Array): index of sector for trailing-edge (PreComp definition of sector) rotor.sector_idx_strain_te = [3] * ncomp web1 = np.array([ -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.4114, 0.4102, 0.4094, 0.3876, 0.3755, 0.3639, 0.345, 0.3342, 0.3313, 0.3274, 0.323, 0.3206, 0.3172, 0.3138, 0.3104, 0.307, 0.3003, 0.2982, 0.2935, 0.2899, 0.2867, 0.2833, 0.2817, 0.2799, 0.2767, 0.2731, 0.2664, 0.2607, 0.2562, 0.1886, -1.0 ]) web2 = np.array([ -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.5886, 0.5868, 0.5854, 0.5508, 0.5315, 0.5131, 0.4831, 0.4658, 0.4687, 0.4726, 0.477, 0.4794, 0.4828, 0.4862, 0.4896, 0.493, 0.4997, 0.5018, 0.5065, 0.5101, 0.5133, 0.5167, 0.5183, 0.5201, 0.5233, 0.5269, 0.5336, 0.5393, 0.5438, 0.6114, -1.0 ]) web3 = np.array([ -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0 ]) # (Array, m): chord distribution for reference section, thickness of structural # layup scaled with reference thickness (fixed t/c for this case) rotor.chord_str_ref = np.array([3.2612, 3.3100915356, 3.32587052924, 3.34159388653, 3.35823798667, 3.37384375335, 3.38939112914, 3.4774055542, 3.49839685, 3.51343645709, 3.87017220335, 4.04645623801, 4.19408216643, 4.47641008477, 4.55844487985, 4.57383098262, 4.57285771934, 4.51914315648, 4.47677655262, 4.40075650022, 4.31069949379, 4.20483735936, 4.08985563932, 3.82931757126, 3.74220276467, 3.54415796922, 3.38732428502, 3.24931446473, 3.23421422609, 3.22701537997, 3.21972125648, 3.08979310611, 2.95152261813, 2.330753331, 2.05553464181, 1.82577817774, 1.5860853279, 1.4621])* \ np.true_divide(BladeLength,ReferenceBladeLength) for i in range(ncomp): webLoc = [] if web1[i] != -1: webLoc.append(web1[i]) if web2[i] != -1: webLoc.append(web2[i]) if web3[i] != -1: webLoc.append(web3[i]) upper[i], lower[i], webs[i] = CompositeSection.initFromPreCompLayupFile\ (os.path.join(basepath, 'layup_' + str(i+1) + '.inp'), webLoc, materials) profile[i] = Profile.initFromPreCompFile(os.path.join(basepath, 'shape_' \ + str(i+1) + '.inp')) # (List): list of all Orthotropic2DMaterial objects used in # defining the geometry rotor.materials = materials # (List): list of CompositeSection objections defining the properties for # upper surface rotor.upperCS = upper # (List): list of CompositeSection objections defining the properties for # lower surface rotor.lowerCS = lower # (List): list of CompositeSection objections defining the properties for # shear webs rotor.websCS = webs # (List): airfoil shape at each radial position rotor.profile = profile # -------------------------------------- # === fatigue === # (Array): nondimensional radial locations of damage equivalent moments rotor.rstar_damage = np.array([ 0.000, 0.022, 0.067, 0.111, 0.167, 0.233, 0.300, 0.367, 0.433, 0.500, 0.567, 0.633, 0.700, 0.767, 0.833, 0.889, 0.933, 0.978 ]) # (Array, N*m): damage equivalent moments about blade c.s. x-direction rotor.Mxb_damage = 1e3 * np.array([ 2.3743E+003, 2.0834E+003, 1.8108E+003, 1.5705E+003, 1.3104E+003, 1.0488E+003, 8.2367E+002, 6.3407E+002, 4.7727E+002, 3.4804E+002, 2.4458E+002, 1.6339E+002, 1.0252E+002, 5.7842E+001, 2.7349E+001, 1.1262E+001, 3.8549E+000, 4.4738E-001 ]) # (Array, N*m): damage equivalent moments about blade c.s. y-direction rotor.Myb_damage = 1e3 * np.array([ 2.7732E+003, 2.8155E+003, 2.6004E+003, 2.3933E+003, 2.1371E+003, 1.8459E+003, 1.5582E+003, 1.2896E+003, 1.0427E+003, 8.2015E+002, 6.2449E+002, 4.5229E+002, 3.0658E+002, 1.8746E+002, 9.6475E+001, 4.2677E+001, 1.5409E+001, 1.8426E+000 ]) rotor.strain_ult_spar = 1.0e-2 # (Float): ultimate strain in spar cap # (Float): uptimate strain in trailing-edge panels, note that I am putting a # factor of two for the damage part only. rotor.strain_ult_te = 2500 * 1e-6 * 2 rotor.eta_damage = 1.35 * 1.3 * 1.0 # (Float): safety factor for fatigue rotor.m_damage = 10.0 # (Float): slope of S-N curve for fatigue analysis # (Float): number of cycles used in fatigue analysis rotor.N_damage = 365 * 24 * 3600 * 20.0 # ---------------- # from myutilities import plt # === run and outputs === rotor.run() # Evaluate AEP Using Lewis' Functions # Weibull Wind Parameters WindReferenceHeight = 50 WindReferenceMeanVelocity = 7.5 WeibullShapeFactor = 2.0 ShearFactor = 0.25 PowerCurve = rotor.P / 1e6 PowerCurveVelocity = rotor.V HubHeight = rotor.hubHt AEP,WeibullScale = CalculateAEPWeibull(PowerCurve,PowerCurveVelocity, HubHeight, \ BladeLength,WeibullShapeFactor, WindReferenceHeight, \ WindReferenceMeanVelocity, ShearFactor) NamePlateCapacity = EstimateCapacity(PowerCurve,PowerCurveVelocity, \ rotor.ratedConditions.V) # AEP At Constant 7.5m/s Wind used for benchmarking... #AEP = CalculateAEPConstantWind(PowerCurve, PowerCurveVelocity, 7.5) if (Verbose == True): print '################### ROTORSE ######################' print 'AEP = %d MWH' % (AEP) print 'NamePlateCapacity = %fMW' % (NamePlateCapacity) print 'diameter =', rotor.diameter print 'ratedConditions.V =', rotor.ratedConditions.V print 'ratedConditions.Omega =', rotor.ratedConditions.Omega print 'ratedConditions.pitch =', rotor.ratedConditions.pitch print 'mass_one_blade =', rotor.mass_one_blade print 'mass_all_blades =', rotor.mass_all_blades print 'I_all_blades =', rotor.I_all_blades print 'freq =', rotor.freq print 'tip_deflection =', rotor.tip_deflection print 'root_bending_moment =', rotor.root_bending_moment print '#########################################################' ############################################################################# ### 2. Hub Sizing # Specify hub parameters based off rotor # Load default hub model hubS = HubSE() hubS.rotor_diameter = rotor.Rtip * 2 # m hubS.blade_number = rotor.nBlades hubS.blade_root_diameter = rotor.chord_sub[0] * 1.25 hubS.L_rb = rotor.hubFraction * rotor.diameter hubS.MB1_location = np.array([-0.5, 0.0, 0.0]) hubS.machine_rating = rotor.control.ratedPower hubS.blade_mass = rotor.mass_one_blade hubS.rotor_bending_moment = rotor.root_bending_moment hubS.run() RotorTotalWeight = rotor.mass_all_blades + hubS.spinner.mass + \ hubS.hub.mass + hubS.pitchSystem.mass if (Verbose == True): print '##################### Hub SE ############################' print "Estimate of Hub Component Sizes:" print "Hub Components" print ' Hub: {0:8.1f} kg'.format(hubS.hub.mass) print ' Pitch system: {0:8.1f} kg'.format(hubS.pitchSystem.mass) print ' Nose cone: {0:8.1f} kg'.format(hubS.spinner.mass) print 'Rotor Total Weight = %d kg' % RotorTotalWeight print '#########################################################' ############################################################################ ### 3. Drive train + Nacelle Mass estimation nace = Drive4pt() nace.rotor_diameter = rotor.Rtip * 2 # m nace.rotor_speed = rotor.ratedConditions.Omega # #rpm m/s nace.machine_rating = hubS.machine_rating / 1000 nace.DrivetrainEfficiency = 0.95 # 6.35e6 #4365248.74 # Nm nace.rotor_torque = rotor.ratedConditions.Q nace.rotor_thrust = rotor.ratedConditions.T # N nace.rotor_mass = 0.0 #accounted for in F_z # kg nace.rotor_bending_moment_x = rotor.Mxyz_0[0] nace.rotor_bending_moment_y = rotor.Mxyz_0[1] nace.rotor_bending_moment_z = rotor.Mxyz_0[2] nace.rotor_force_x = rotor.Fxyz_0[0] # N nace.rotor_force_y = rotor.Fxyz_0[1] nace.rotor_force_z = rotor.Fxyz_0[2] # N # geared 3-stage Gearbox with induction generator machine nace.drivetrain_design = 'geared' nace.gear_ratio = 96.76 # 97:1 as listed in the 5 MW reference document nace.gear_configuration = 'eep' # epicyclic-epicyclic-parallel nace.crane = True # onboard crane present nace.shaft_angle = 5.0 #deg nace.shaft_ratio = 0.10 nace.Np = [3, 3, 1] nace.ratio_type = 'optimal' nace.shaft_type = 'normal' nace.uptower_transformer = False nace.shrink_disc_mass = 333.3 * nace.machine_rating / 1000.0 # estimated nace.mb1Type = 'CARB' nace.mb2Type = 'SRB' nace.flange_length = 0.5 #m nace.overhang = 5.0 nace.gearbox_cm = 0.1 nace.hss_length = 1.5 #0 if no fatigue check, 1 if parameterized fatigue check, #2 if known loads inputs nace.check_fatigue = 0 nace.blade_number = rotor.nBlades nace.cut_in = rotor.control.Vin #cut-in m/s nace.cut_out = rotor.control.Vout #cut-out m/s nace.Vrated = rotor.ratedConditions.V #rated windspeed m/s nace.weibull_k = WeibullShapeFactor # windepeed distribution shape parameter # windspeed distribution scale parameter nace.weibull_A = WeibullScale nace.T_life = 20. #design life in years nace.IEC_Class_Letter = 'B' # length from hub center to main bearing, leave zero if unknown nace.L_rb = hubS.L_rb # NREL 5 MW Tower Variables nace.tower_top_diameter = 3.78 # m nace.run() if (Verbose == True): print '##################### Drive SE ############################' print "Estimate of Nacelle Component Sizes" print 'Low speed shaft: {0:8.1f} kg'.format(nace.lowSpeedShaft.mass) print 'Main bearings: {0:8.1f} kg'.format(\ nace.mainBearing.mass + nace.secondBearing.mass) print 'Gearbox: {0:8.1f} kg'.format(nace.gearbox.mass) print 'High speed shaft & brakes: {0:8.1f} kg'.format\ (nace.highSpeedSide.mass) print 'Generator: {0:8.1f} kg'.format(nace.generator.mass) print 'Variable speed electronics: {0:8.1f} kg'.format(\ nace.above_yaw_massAdder.vs_electronics_mass) print 'Overall mainframe:{0:8.1f} kg'.format(\ nace.above_yaw_massAdder.mainframe_mass) print ' Bedplate: {0:8.1f} kg'.format(nace.bedplate.mass) print 'Electrical connections: {0:8.1f} kg'.format(\ nace.above_yaw_massAdder.electrical_mass) print 'HVAC system: {0:8.1f} kg'.format(\ nace.above_yaw_massAdder.hvac_mass ) print 'Nacelle cover: {0:8.1f} kg'.format(\ nace.above_yaw_massAdder.cover_mass) print 'Yaw system: {0:8.1f} kg'.format(nace.yawSystem.mass) print 'Overall nacelle: {0:8.1f} kg'.format(nace.nacelle_mass, \ nace.nacelle_cm[0], nace.nacelle_cm[1], nace.nacelle_cm[2], \ nace.nacelle_I[0], nace.nacelle_I[1], nace.nacelle_I[2]) print '#########################################################' ############################################################################ ### 4. Tower Mass # --- tower setup ------ from commonse.environment import PowerWind tower = set_as_top(TowerSE()) # ---- tower ------ tower.replace('wind1', PowerWind()) tower.replace('wind2', PowerWind()) # onshore (no waves) # --- geometry ---- tower.z_param = [0.0, HubHeight * 0.5, HubHeight] TowerRatio = np.true_divide(HubHeight, ReferenceTowerHeight) tower.d_param = [6.0 * TowerRatio, 4.935 * TowerRatio, 3.87 * TowerRatio] tower.t_param = [0.027*1.3*TowerRatio, 0.023*1.3*TowerRatio, \ 0.019*1.3*TowerRatio] n = 10 tower.z_full = np.linspace(0.0, HubHeight, n) tower.L_reinforced = 15.0 * np.ones(n) # [m] buckling length tower.theta_stress = 0.0 * np.ones(n) tower.yaw = 0.0 # --- material props --- tower.E = 210e9 * np.ones(n) tower.G = 80.8e9 * np.ones(n) tower.rho = 8500.0 * np.ones(n) tower.sigma_y = 450.0e6 * np.ones(n) # --- spring reaction data. Use float('inf') for rigid constraints. --- tower.kidx = [0] # applied at base tower.kx = [float('inf')] tower.ky = [float('inf')] tower.kz = [float('inf')] tower.ktx = [float('inf')] tower.kty = [float('inf')] tower.ktz = [float('inf')] # --- extra mass ---- tower.midx = [n - 1] # RNA mass at top tower.m = [0.8] tower.mIxx = [1.14930678e+08] tower.mIyy = [2.20354030e+07] tower.mIzz = [1.87597425e+07] tower.mIxy = [0.00000000e+00] tower.mIxz = [5.03710467e+05] tower.mIyz = [0.00000000e+00] tower.mrhox = [-1.13197635] tower.mrhoy = [0.] tower.mrhoz = [0.50875268] tower.addGravityLoadForExtraMass = False # ----------- # --- wind --- tower.wind_zref = 90.0 tower.wind_z0 = 0.0 tower.wind1.shearExp = 0.14 tower.wind2.shearExp = 0.14 # --------------- # # --- loading case 1: max Thrust --- tower.wind_Uref1 = 11.73732 tower.plidx1 = [n - 1] # at tower top tower.Fx1 = [0.19620519] tower.Fy1 = [0.] tower.Fz1 = [-2914124.84400512] tower.Mxx1 = [3963732.76208099] tower.Myy1 = [-2275104.79420872] tower.Mzz1 = [-346781.68192839] # # --------------- # # --- loading case 2: max wind speed --- tower.wind_Uref2 = 70.0 tower.plidx1 = [n - 1] # at tower top tower.Fx1 = [930198.60063279] tower.Fy1 = [0.] tower.Fz1 = [-2883106.12368949] tower.Mxx1 = [-1683669.22411597] tower.Myy1 = [-2522475.34625363] tower.Mzz1 = [147301.97023764] # # --------------- # # --- run --- tower.run() if (Verbose == True): print '##################### Tower SE ##########################' print 'mass (kg) =', tower.mass print 'f1 (Hz) =', tower.f1 print 'f2 (Hz) =', tower.f2 print 'top_deflection1 (m) =', tower.top_deflection1 print 'top_deflection2 (m) =', tower.top_deflection2 print '#########################################################' ############################################################################ ## 5. Turbine captial costs analysis turbine = Turbine_CostsSE() # NREL 5 MW turbine component masses based on Sunderland model approach # Rotor # inline with the windpact estimates turbine.blade_mass = rotor.mass_one_blade turbine.hub_mass = hubS.hub.mass turbine.pitch_system_mass = hubS.pitchSystem.mass turbine.spinner_mass = hubS.spinner.mass # Drivetrain and Nacelle turbine.low_speed_shaft_mass = nace.lowSpeedShaft.mass turbine.main_bearing_mass = nace.mainBearing.mass turbine.second_bearing_mass = nace.secondBearing.mass turbine.gearbox_mass = nace.gearbox.mass turbine.high_speed_side_mass = nace.highSpeedSide.mass turbine.generator_mass = nace.generator.mass turbine.bedplate_mass = nace.bedplate.mass turbine.yaw_system_mass = nace.yawSystem.mass # Tower turbine.tower_mass = tower.mass * 0.5 # Additional non-mass cost model input variables turbine.machine_rating = hubS.machine_rating / 1000 turbine.advanced = False turbine.blade_number = rotor.nBlades turbine.drivetrain_design = 'geared' turbine.crane = False turbine.offshore = False # Target year for analysis results turbine.year = 2010 turbine.month = 12 turbine.run() if (Verbose == True): print '##################### TurbinePrice SE ####################' print "Overall rotor cost with 3 advanced blades is ${0:.2f} USD"\ .format(turbine.rotorCC.cost) print "Blade cost is ${0:.2f} USD".format(turbine.rotorCC.bladeCC.cost) print "Hub cost is ${0:.2f} USD".format(turbine.rotorCC.hubCC.cost) print "Pitch system cost is ${0:.2f} USD".format( turbine.rotorCC.pitchSysCC.cost) print "Spinner cost is ${0:.2f} USD".format( turbine.rotorCC.spinnerCC.cost) print print "Overall nacelle cost is ${0:.2f} USD".format( turbine.nacelleCC.cost) print "LSS cost is ${0:.2f} USD".format(turbine.nacelleCC.lssCC.cost) print "Main bearings cost is ${0:.2f} USD".format( turbine.nacelleCC.bearingsCC.cost) print "Gearbox cost is ${0:.2f} USD".format( turbine.nacelleCC.gearboxCC.cost) print "Hight speed side cost is ${0:.2f} USD".format( turbine.nacelleCC.hssCC.cost) print "Generator cost is ${0:.2f} USD".format( turbine.nacelleCC.generatorCC.cost) print "Bedplate cost is ${0:.2f} USD".format( turbine.nacelleCC.bedplateCC.cost) print "Yaw system cost is ${0:.2f} USD".format( turbine.nacelleCC.yawSysCC.cost) print print "Tower cost is ${0:.2f} USD".format(turbine.towerCC.cost) print print "The overall turbine cost is ${0:.2f} USD".format( turbine.turbine_cost) print '#########################################################' ############################################################################ ## 6. Operating Expenses # A simple test of nrel_csm_bos model bos = bos_csm_assembly() # Set input parameters bos = bos_csm_assembly() bos.machine_rating = hubS.machine_rating / 1000 bos.rotor_diameter = rotor.diameter bos.turbine_cost = turbine.turbine_cost bos.hub_height = HubHeight bos.turbine_number = 1 bos.sea_depth = 0 bos.year = 2009 bos.month = 12 bos.multiplier = 1.0 bos.run() om = opex_csm_assembly() om.machine_rating = rotor.control.ratedPower / 1000 # Need to manipulate input or underlying component will not execute om.net_aep = AEP * 10e4 om.sea_depth = 0 om.year = 2009 om.month = 12 om.turbine_number = 100 om.run() if (Verbose == True): print '##################### Operating Costs ####################' print "BOS cost per turbine: ${0:.2f} USD".format(bos.bos_costs / \ bos.turbine_number) print "Average annual operational expenditures" print "OPEX on shore with 100 turbines ${:.2f}: USD".format(\ om.avg_annual_opex) print "Preventative OPEX by turbine: ${:.2f} USD".format(\ om.opex_breakdown.preventative_opex / om.turbine_number) print "Corrective OPEX by turbine: ${:.2f} USD".format(\ om.opex_breakdown.corrective_opex / om.turbine_number) print "Land Lease OPEX by turbine: ${:.2f} USD".format(\ om.opex_breakdown.lease_opex / om.turbine_number) print '#########################################################' CapitalCost = turbine.turbine_cost + bos.bos_costs / bos.turbine_number OperatingCost = om.opex_breakdown.preventative_opex / om.turbine_number + \ om.opex_breakdown.lease_opex / om.turbine_number + \ om.opex_breakdown.corrective_opex / om.turbine_number LCOE = ComputeLCOE(AEP, CapitalCost, OperatingCost, DiscountRate, Years) print '######################***********************###################' print "Levelized Cost of Energy over %d years \ is $%f/kWH" % (Years, LCOE / 1000) print '######################***********************###################' return LCOE / 1000
def __init__(self, RefBlade): super(FloatingTurbine, self).__init__() self.add('hub_height', IndepVarComp('hub_height', 0.0), promotes=['*']) # TODO: #Weibull/Rayleigh CDF # Rotor self.add('rotor', RotorSE(RefBlade), promotes=['*']) # RNA self.add('rna', RNA(1), promotes=['downwind']) # Tower and substructure myfloat = FloatingSE() self.add('sm', myfloat, promotes=['*']) # Turbine constraints self.add('tcons', TurbineConstraints(myfloat.nFullTow), promotes=['*']) # Turbine costs self.add('tcost', Turbine_CostsSE_2015(), promotes=['*']) # Balance of station self.add('wobos', WindOBOS(), promotes=['*']) # LCOE Calculation self.add('lcoe', PlantFinance(), promotes=['*']) # Define all input variables from all models self.add('offshore', IndepVarComp('offshore', True, pass_by_obj=True), promotes=['*']) self.add('crane', IndepVarComp('crane', False, pass_by_obj=True), promotes=['*']) # Turbine Costs # REMOVE ONCE DRIVESE AND GENERATORSE ARE CONNECTED self.add('bearing_number', IndepVarComp('bearing_number', 0, pass_by_obj=True), promotes=['*']) self.add('bedplate_mass', IndepVarComp('bedplate_mass', 0.0), promotes=['*']) self.add('crane_cost', IndepVarComp('crane_cost', 0.0), promotes=['*']) self.add('gearbox_mass', IndepVarComp('gearbox_mass', 0.0), promotes=['*']) self.add('generator_mass', IndepVarComp('generator_mass', 0.0), promotes=['*']) self.add('hss_mass', IndepVarComp('hss_mass', 0.0), promotes=['*']) self.add('hvac_mass', IndepVarComp('hvac_mass', 0.0), promotes=['*']) self.add('lss_mass', IndepVarComp('lss_mass', 0.0), promotes=['*']) self.add('main_bearing_mass', IndepVarComp('main_bearing_mass', 0.0), promotes=['*']) self.add('cover_mass', IndepVarComp('cover_mass', 0.0), promotes=['*']) self.add('platforms_mass', IndepVarComp('platforms_mass', 0.0), promotes=['*']) self.add('pitch_system_mass', IndepVarComp('pitch_system_mass', 0.0), promotes=['*']) self.add('spinner_mass', IndepVarComp('spinner_mass', 0.0), promotes=['*']) self.add('transformer_mass', IndepVarComp('transformer_mass', 0.0), promotes=['*']) self.add('vs_electronics_mass', IndepVarComp('vs_electronics_mass', 0.0), promotes=['*']) self.add('yaw_mass', IndepVarComp('yaw_mass', 0.0), promotes=['*']) # Tower #self.add('stress_standard_value', IndepVarComp('stress_standard_value', 0.0), promotes=['*']) #self.add('fatigue_parameters', IndepVarComp('fatigue_parameters', np.zeros(nDEL)), promotes=['*']) #self.add('fatigue_z', IndepVarComp('fatigue_z', np.zeros(nDEL)), promotes=['*']) #self.add('frame3dd_matrix_method', IndepVarComp('frame3dd_matrix_method', 0, pass_by_obj=True), promotes=['*']) #self.add('compute_stiffnes', IndepVarComp('compute_stiffnes', False, pass_by_obj=True), promotes=['*']) self.add('project_lifetime', IndepVarComp('project_lifetime', 0.0), promotes=['*']) #self.add('lumped_mass_matrix', IndepVarComp('lumped_mass_matrix', 0, pass_by_obj=True), promotes=['*']) #self.add('slope_SN', IndepVarComp('slope_SN', 0, pass_by_obj=True), promotes=['*']) #self.add('number_of_modes', IndepVarComp('number_of_modes', 0, pass_by_obj=True), promotes=['*']) #self.add('compute_shear', IndepVarComp('compute_shear', True, pass_by_obj=True), promotes=['*']) #self.add('shift_value', IndepVarComp('shift_value', 0.0), promotes=['*']) #self.add('frame3dd_convergence_tolerance', IndepVarComp('frame3dd_convergence_tolerance', 1e-9), promotes=['*']) # TODO: Multiple load cases # Environment self.add('air_density', IndepVarComp('air_density', 0.0), promotes=['*']) self.add('air_viscosity', IndepVarComp('air_viscosity', 0.0), promotes=['*']) self.add('wind_reference_speed', IndepVarComp('wind_reference_speed', 0.0), promotes=['*']) self.add('wind_reference_height', IndepVarComp('wind_reference_height', 0.0), promotes=['*']) self.add('shearExp', IndepVarComp('shearExp', 0.0), promotes=['*']) self.add('wind_bottom_height', IndepVarComp('wind_bottom_height', 0.0), promotes=['*']) self.add('wind_beta', IndepVarComp('wind_beta', 0.0), promotes=['*']) self.add('cd_usr', IndepVarComp('cd_usr', np.inf), promotes=['*']) # Environment self.add('water_depth', IndepVarComp('water_depth', 0.0), promotes=['*']) self.add('water_density', IndepVarComp('water_density', 0.0), promotes=['*']) self.add('water_viscosity', IndepVarComp('water_viscosity', 0.0), promotes=['*']) self.add('wave_height', IndepVarComp('wave_height', 0.0), promotes=['*']) self.add('wave_period', IndepVarComp('wave_period', 0.0), promotes=['*']) self.add('mean_current_speed', IndepVarComp('mean_current_speed', 0.0), promotes=['*']) #self.add('wave_beta', IndepVarComp('wave_beta', 0.0), promotes=['*']) #self.add('wave_velocity_z0', IndepVarComp('wave_velocity_z0', 0.0), promotes=['*']) #self.add('wave_acceleration_z0', IndepVarComp('wave_acceleration_z0', 0.0), promotes=['*']) # Design standards self.add('gamma_freq', IndepVarComp('gamma_freq', 0.0), promotes=['*']) self.add('gamma_f', IndepVarComp('gamma_f', 0.0), promotes=['*']) self.add('gamma_m', IndepVarComp('gamma_m', 0.0), promotes=['*']) self.add('gamma_b', IndepVarComp('gamma_b', 0.0), promotes=['*']) self.add('gamma_fatigue', IndepVarComp('gamma_fatigue', 0.0), promotes=['*']) self.add('gamma_n', IndepVarComp('gamma_n', 0.0), promotes=['*']) # RNA self.add('dummy_mass', IndepVarComp('dummy_mass', 0.0), promotes=['*']) self.add('hub_mass', IndepVarComp('hub_mass', 0.0), promotes=['*']) self.add('nac_mass', IndepVarComp('nac_mass', 0.0), promotes=['*']) self.add('hub_cm', IndepVarComp('hub_cm', np.zeros((3, ))), promotes=['*']) self.add('nac_cm', IndepVarComp('nac_cm', np.zeros((3, ))), promotes=['*']) self.add('hub_I', IndepVarComp('hub_I', np.zeros(6)), promotes=['*']) self.add('nac_I', IndepVarComp('nac_I', np.zeros(6)), promotes=['*']) self.add('rna_weightM', IndepVarComp('rna_weightM', True, pass_by_obj=True), promotes=['*']) # Column self.add('morison_mass_coefficient', IndepVarComp('morison_mass_coefficient', 0.0), promotes=['*']) self.add('material_density', IndepVarComp('material_density', 0.0), promotes=['*']) self.add('E', IndepVarComp('E', 0.0), promotes=['*']) self.add('nu', IndepVarComp('nu', 0.0), promotes=['*']) self.add('yield_stress', IndepVarComp('yield_stress', 0.0), promotes=['*']) # Pontoons self.add('G', IndepVarComp('G', 0.0), promotes=['*']) # LCOE self.add('number_of_turbines', IndepVarComp('number_of_turbines', 0, pass_by_obj=True), promotes=['*']) self.add('annual_opex', IndepVarComp('annual_opex', 0.0), promotes=['*']) # TODO: Replace with output connection self.add('fixed_charge_rate', IndepVarComp('fixed_charge_rate', 0.0), promotes=['*']) self.add('discount_rate', IndepVarComp('discount_rate', 0.0), promotes=['*']) # Connect all input variables from all models self.connect('water_depth', ['waterD', 'sea_depth']) self.connect('hub_height', 'hubH') self.connect('tower_outer_diameter', 'towerD', src_indices=[0]) self.connect('wind_beta', 'beta') self.connect('mean_current_speed', 'Uc') self.connect('project_lifetime', ['struc.lifetime', 'projLife']) #self.connect('slope_SN', 'm_SN') #self.connect('compute_shear', 'shear') #self.connect('compute_stiffnes', 'geom') #self.connect('frame3dd_matrix_method', 'Mmethod') #self.connect('shift_value', 'shift') # TODO: #self.connect('number_of_modes', ['nM', 'nF']) #self.connect('frame3dd_convergence_tolerance', 'tol') #self.connect('lumped_mass_matrix', 'lump') #self.connect('stress_standard_value', 'DC') self.connect('rna.loads.top_F', 'rna_force') self.connect('rna.loads.top_M', 'rna_moment') self.connect('rna.rna_I_TT', 'rna_I') self.connect('rna.rna_mass', ['rnaM', 'rna_mass']) self.connect('rna.rna_cm', 'rna_cg') self.connect('mass_all_blades', 'rna.blades_mass') self.connect('I_all_blades', 'rna.blades_I') self.connect('hub_mass', 'rna.hub_mass') self.connect('nac_mass', 'rna.nac_mass') self.connect('hub_cm', 'rna.hub_cm') self.connect('nac_cm', 'rna.nac_cm') self.connect('hub_I', 'rna.hub_I') self.connect('nac_I', 'rna.nac_I') self.connect('tilt', 'rna.tilt') self.connect('Fxyz_total', 'rna.loads.F') self.connect('Mxyz_total', 'rna.loads.M') self.connect('rna_weightM', 'rna.rna_weightM') self.connect('air_density', ['main.windLoads.rho', 'analysis.rho']) self.connect('air_viscosity', ['main.windLoads.mu', 'analysis.mu']) self.connect('water_density', 'water_density') self.connect('water_viscosity', 'main.waveLoads.mu') self.connect('wave_height', 'Hs') self.connect('wave_period', 'T') self.connect('wind_reference_speed', 'Uref') self.connect('wind_reference_height', ['zref', 'wind.zref']) self.connect('wind_bottom_height', ['z0', 'wind.z0']) self.connect('shearExp', 'wind.shearExp') self.connect('morison_mass_coefficient', 'cm') self.connect('ballast_cost_rate', 'ballCR') self.connect('mooring_cost_rate', 'moorCR') self.connect('mooring_cost', 'moorCost') self.connect('mooring_diameter', 'moorDia') self.connect('number_of_mooring_lines', 'moorLines') self.connect('material_cost_rate', 'sSteelCR') self.connect('main.tapered_column_cost_rate', ['spStifColCR', 'spTapColCR', 'ssStifColCR']) self.connect('pontoon_cost_rate', 'ssTrussCR') self.connect('nBlades', 'blade_number') self.connect('mass_one_blade', 'blade_mass') self.connect('control_maxOmega', 'rotor_omega') self.connect('structural_frequencies', 'tower_freq') self.connect('turbine_cost_kW', 'turbCapEx') self.connect('machine_rating', 'turbR') self.connect('diameter', 'rotorD') self.connect('bladeLength', 'bladeL') self.connect('hub_diameter', 'hubD') # Link outputs from one model to inputs to another self.connect('tower_mass', 'towerM') self.connect('dummy_mass', 'off.stack_mass_in') self.connect('total_cost', 'subTotCost') self.connect('total_mass', 'subTotM') self.connect('total_bos_cost', 'bos_costs') self.connect('number_of_turbines', ['nTurb', 'turbine_number']) self.connect('annual_opex', 'avg_annual_opex') self.connect('AEP', 'net_aep') self.connect('totInstTime', 'construction_time') # Use complex number finite differences typeStr = 'fd' formStr = 'central' stepVal = 1e-5 stepStr = 'relative' self.deriv_options['type'] = typeStr self.deriv_options['form'] = formStr self.deriv_options['step_size'] = stepVal self.deriv_options['step_calc'] = stepStr
def __init__(self, RefBlade): super(MonopileTurbine, self).__init__() nFull = 5*(NSECTION) + 1 self.add('hub_height', IndepVarComp('hub_height', 0.0), promotes=['*']) self.add('foundation_height', IndepVarComp('foundation_height', 0.0), promotes=['*']) # Rotor self.add('rotor', RotorSE(RefBlade, regulation_reg_II5=False, regulation_reg_III=True, Analysis_Level=-1), promotes=['*']) # RNA self.add('drive', Drive4pt('CARB', 'SRB', 'B', 'eep', 'normal', 'geared', True, 0, True, 3), promotes=['bedplate_mass','gearbox_mass','generator_mass','hss_mass','hvac_mass','lss_mass','cover_mass', 'pitch_system_mass','platforms_mass','spinner_mass','transformer_mass','vs_electronics_mass','yaw_mass']) self.add('rna', RNA(nLC), promotes=['*']) # Tower and substructure self.add('tow',TowerSE(nLC, NSECTION+1, nFull, nDEL, wind='PowerWind'), promotes=['material_density','E','G','tower_section_height', 'tower_outer_diameter','tower_wall_thickness', 'tower_outfitting_factor','tower_buckling_length','downwind', 'max_taper','min_d_to_t','rna_mass','rna_cg','rna_I','hub_cm', 'tower_mass','tower_I_base','hub_height','tip_position', 'foundation_height','monopile','soil_G','soil_nu', 'suctionpile_depth','tip_deflection_margin', 'gamma_f','gamma_m','gamma_b','gamma_n','gamma_fatigue', 'labor_cost_rate','material_cost_rate','painting_cost_rate']) # Turbine constraints self.add('tcons', TurbineConstraints(nFull), promotes=['*']) # Turbine costs self.add('tcost', Turbine_CostsSE_2015(), promotes=['*']) # Balance of station self.add('wobos', WindOBOS(), promotes=['*'])#tax_rate']) # LCOE Calculation self.add('lcoe', PlantFinance(), promotes=['*']) # Define all input variables from all models self.add('offshore', IndepVarComp('offshore', True, pass_by_obj=True), promotes=['*']) self.add('crane', IndepVarComp('crane', False, pass_by_obj=True), promotes=['*']) # Turbine Costs # REMOVE ONCE DRIVESE AND GENERATORSE ARE CONNECTED self.add('bearing_number', IndepVarComp('bearing_number', 0, pass_by_obj=True), promotes=['*']) #self.add('hub_mass', IndepVarComp('hub_mass', 0.0), promotes=['*']) #self.add('bedplate_mass', IndepVarComp('bedplate_mass', 0.0), promotes=['*']) self.add('crane_cost', IndepVarComp('crane_cost', 0.0), promotes=['*']) #self.add('gearbox_mass', IndepVarComp('gearbox_mass', 0.0), promotes=['*']) #self.add('generator_mass', IndepVarComp('generator_mass', 0.0), promotes=['*']) #self.add('hss_mass', IndepVarComp('hss_mass', 0.0), promotes=['*']) #self.add('hvac_mass', IndepVarComp('hvac_mass', 0.0), promotes=['*']) #self.add('lss_mass', IndepVarComp('lss_mass', 0.0), promotes=['*']) #self.add('main_bearing_mass', IndepVarComp('main_bearing_mass', 0.0), promotes=['*']) #self.add('cover_mass', IndepVarComp('cover_mass', 0.0), promotes=['*']) #self.add('platforms_mass', IndepVarComp('platforms_mass', 0.0), promotes=['*']) #self.add('pitch_system_mass', IndepVarComp('pitch_system_mass', 0.0), promotes=['*']) #self.add('spinner_mass', IndepVarComp('spinner_mass', 0.0), promotes=['*']) #self.add('transformer_mass', IndepVarComp('transformer_mass', 0.0), promotes=['*']) #self.add('vs_electronics_mass', IndepVarComp('vs_electronics_mass', 0.0), promotes=['*']) #self.add('yaw_mass', IndepVarComp('yaw_mass', 0.0), promotes=['*']) # Tower and Frame3DD options self.add('stress_standard_value', IndepVarComp('stress_standard_value', 0.0), promotes=['*']) self.add('frame3dd_matrix_method', IndepVarComp('frame3dd_matrix_method', 0, pass_by_obj=True), promotes=['*']) self.add('compute_stiffness', IndepVarComp('compute_stiffness', False, pass_by_obj=True), promotes=['*']) self.add('project_lifetime', IndepVarComp('project_lifetime', 0.0), promotes=['*']) self.add('lumped_mass_matrix', IndepVarComp('lumped_mass_matrix', 0, pass_by_obj=True), promotes=['*']) self.add('slope_SN', IndepVarComp('slope_SN', 0, pass_by_obj=True), promotes=['*']) self.add('number_of_modes', IndepVarComp('number_of_modes', NFREQ, pass_by_obj=True), promotes=['*']) self.add('compute_shear', IndepVarComp('compute_shear', True, pass_by_obj=True), promotes=['*']) self.add('shift_value', IndepVarComp('shift_value', 0.0), promotes=['*']) self.add('frame3dd_convergence_tolerance', IndepVarComp('frame3dd_convergence_tolerance', 1e-7), promotes=['*']) self.add('max_taper_ratio', IndepVarComp('max_taper_ratio', 0.0), promotes=['*']) self.add('min_diameter_thickness_ratio', IndepVarComp('min_diameter_thickness_ratio', 0.0), promotes=['*']) # Environment #self.add('air_density', IndepVarComp('air_density', 0.0), promotes=['*']) #self.add('air_viscosity', IndepVarComp('air_viscosity', 0.0), promotes=['*']) self.add('wind_reference_speed', IndepVarComp('wind_reference_speed', 0.0), promotes=['*']) self.add('wind_reference_height', IndepVarComp('wind_reference_height', 0.0), promotes=['*']) self.add('shearExp', IndepVarComp('shearExp', 0.0), promotes=['*']) self.add('wind_bottom_height', IndepVarComp('wind_bottom_height', 0.0), promotes=['*']) self.add('wind_beta', IndepVarComp('wind_beta', 0.0), promotes=['*']) self.add('cd_usr', IndepVarComp('cd_usr', np.inf), promotes=['*']) # Environment self.add('water_depth', IndepVarComp('water_depth', 0.0), promotes=['*']) self.add('water_density', IndepVarComp('water_density', 0.0), promotes=['*']) self.add('water_viscosity', IndepVarComp('water_viscosity', 0.0), promotes=['*']) self.add('wave_height', IndepVarComp('wave_height', 0.0), promotes=['*']) self.add('wave_period', IndepVarComp('wave_period', 0.0), promotes=['*']) self.add('mean_current_speed', IndepVarComp('mean_current_speed', 0.0), promotes=['*']) self.add('wave_beta', IndepVarComp('wave_beta', 0.0), promotes=['*']) # Design standards self.add('gamma_freq', IndepVarComp('gamma_freq', 0.0), promotes=['*']) self.add('gamma_f', IndepVarComp('gamma_f', 0.0), promotes=['*']) self.add('gamma_m', IndepVarComp('gamma_m', 0.0), promotes=['*']) self.add('gamma_b', IndepVarComp('gamma_b', 0.0), promotes=['*']) self.add('gamma_fatigue', IndepVarComp('gamma_fatigue', 0.0), promotes=['*']) self.add('gamma_n', IndepVarComp('gamma_n', 0.0), promotes=['*']) # RNA #self.add('nac_mass', IndepVarComp('nac_mass', 0.0), promotes=['*']) #self.add('hub_cm', IndepVarComp('hub_cm', np.zeros((3,))), promotes=['*']) #self.add('nac_cm', IndepVarComp('nac_cm', np.zeros((3,))), promotes=['*']) #self.add('hub_I', IndepVarComp('hub_I', np.zeros(6)), promotes=['*']) #self.add('nac_I', IndepVarComp('nac_I', np.zeros(6)), promotes=['*']) self.add('rna_weightM', IndepVarComp('rna_weightM', True, pass_by_obj=True), promotes=['*']) # Column self.add('morison_mass_coefficient', IndepVarComp('morison_mass_coefficient', 0.0), promotes=['*']) self.add('material_density', IndepVarComp('material_density', 0.0), promotes=['*']) self.add('E', IndepVarComp('E', 0.0), promotes=['*']) self.add('yield_stress', IndepVarComp('yield_stress', 0.0), promotes=['*']) # Pontoons self.add('G', IndepVarComp('G', 0.0), promotes=['*']) # LCOE self.add('labor_cost_rate', IndepVarComp('labor_cost_rate', 0.0), promotes=['*']) self.add('material_cost_rate', IndepVarComp('material_cost_rate', 0.0), promotes=['*']) self.add('painting_cost_rate', IndepVarComp('painting_cost_rate', 0.0), promotes=['*']) self.add('number_of_turbines', IndepVarComp('number_of_turbines', 0, pass_by_obj=True), promotes=['*']) self.add('annual_opex', IndepVarComp('annual_opex', 0.0), promotes=['*']) # TODO: Replace with output connection self.add('fixed_charge_rate', IndepVarComp('fixed_charge_rate', 0.0), promotes=['*']) self.add('discount_rate', IndepVarComp('discount_rate', 0.0), promotes=['*']) # Connect all input variables from all models self.connect('water_depth', ['tow.z_floor','waterD', 'sea_depth','mpileL']) self.connect('hub_height', ['hub_height', 'hubH']) self.connect('tower_outer_diameter', 'towerD', src_indices=[NSECTION]) self.connect('tower_outer_diameter', 'mpileD', src_indices=[0]) self.connect('suctionpile_depth', 'mpEmbedL') self.connect('wind_beta', 'tow.windLoads.beta') self.connect('wave_beta', 'tow.waveLoads.beta') self.connect('cd_usr', 'tow.cd_usr') self.connect('yaw', 'tow.distLoads.yaw') self.connect('mean_current_speed', 'tow.wave.Uc') self.connect('project_lifetime', ['struc.lifetime','tow.life', 'projLife']) self.connect('number_of_modes', 'tow.nM') self.connect('frame3dd_convergence_tolerance', 'tow.tol') self.connect('lumped_mass_matrix', 'tow.lump') self.connect('stress_standard_value', 'tow.DC') self.connect('shift_value', 'tow.shift') self.connect('compute_shear', 'tow.shear') self.connect('slope_SN', 'tow.m_SN') self.connect('compute_stiffness', 'tow.geom') self.connect('frame3dd_matrix_method', 'tow.Mmethod') self.connect('diameter','drive.rotor_diameter') self.connect('rated_Q','drive.rotor_torque') self.connect('rated_Omega','drive.rotor_rpm') self.connect('Mxyz_total','drive.rotor_bending_moment_x', src_indices=[0]) self.connect('Mxyz_total','drive.rotor_bending_moment_y', src_indices=[1]) self.connect('Mxyz_total','drive.rotor_bending_moment_z', src_indices=[2]) self.connect('Fxyz_total','drive.rotor_thrust', src_indices=[0]) self.connect('Fxyz_total','drive.rotor_force_y', src_indices=[1]) self.connect('Fxyz_total','drive.rotor_force_z', src_indices=[2]) self.connect('mass_one_blade','drive.blade_mass') self.connect('chord', 'drive.blade_root_diameter', src_indices=[0]) self.connect('drivetrainEff', 'drive.drivetrain_efficiency', src_indices=[0]) self.connect('mass_all_blades', 'blades_mass') self.connect('drive.hub_system_mass', 'hub_mass') self.connect('drive.nacelle_mass', 'nac_mass') self.connect('I_all_blades', 'blades_I') self.connect('drive.hub_system_I', 'hub_I') self.connect('drive.nacelle_I', 'nac_I') self.connect('drive.hub_system_cm', 'hub_cm') self.connect('drive.nacelle_cm', 'nac_cm') self.connect('drive.mb1_mass', 'main_bearing_mass') #self.connect('drive.hub_system_cm', 'hub_tt') self.connect('Fxyz_total','loads.F') self.connect('Mxyz_total','loads.M') self.connect('loads.top_F', 'tow.pre.rna_F') self.connect('loads.top_M', 'tow.pre.rna_M') self.connect('rna_I_TT', 'rna_I') self.connect('rna_mass', 'rnaM') self.connect('rna_cm', 'rna_cg') self.connect('rho', 'tow.windLoads.rho') #,'powercurve.rho']) self.connect('mu', 'tow.windLoads.mu')#,'powercurve.mu']) self.connect('water_density',['tow.wave.rho','tow.waveLoads.rho']) self.connect('water_viscosity', 'tow.waveLoads.mu') self.connect('wave_height', 'tow.wave.hmax') self.connect('wave_period', 'tow.wave.T') self.connect('wind_reference_speed', 'tow.wind.Uref') self.connect('wind_reference_height', ['tow.wind.zref','wind.zref']) self.connect('wind_bottom_height', ['tow.z0','wind.z0']) self.connect('shearExp', ['tow.wind.shearExp', 'wind.shearExp']) self.connect('morison_mass_coefficient', 'tow.cm') self.connect('yield_stress', 'tow.sigma_y') self.connect('max_taper_ratio', 'max_taper') self.connect('min_diameter_thickness_ratio', 'min_d_to_t') self.connect('nBlades','blade_number') self.connect('mass_one_blade', 'blade_mass') self.connect('control_maxOmega', 'rotor_omega') self.connect('tow.post.structural_frequencies', 'tower_freq') #self.connect('tow.z_full', 'tower_z') #self.connect('tow.d_full', 'tower_d') self.connect('turbine_cost_kW', 'turbCapEx') self.connect('machine_rating', ['turbR','drive.machine_rating']) self.connect('diameter', 'rotorD') self.connect('bladeLength', 'bladeL') self.connect('hub_diameter', 'hubD') # Link outputs from one model to inputs to another self.connect('tower_mass', 'towerM') self.connect('material_cost_rate', 'sSteelCR') self.connect('tower_cost', 'subTotCost') self.connect('tower_mass', 'subTotM') self.connect('total_bos_cost', 'bos_costs') self.connect('number_of_turbines', ['nTurb', 'turbine_number']) self.connect('annual_opex', 'avg_annual_opex') self.connect('AEP', 'net_aep') self.connect('totInstTime', 'construction_time') # TODO Compare Rotor hub_diameter to Drive hub_diameter # TODO: Match Rotor Drivetrain Type to DriveSE Drivetrain options # TODO: Match Rotor CSMDrivetrain and efficiency to DriveSE # Use complex number finite differences self.deriv_options['type'] = 'fd' self.deriv_options['form'] = 'central' self.deriv_options['step_size'] = 1e-5 self.deriv_options['step_calc'] = 'relative'
def configure_turbine(assembly, with_new_nacelle=True, flexible_blade=False, with_3pt_drive=False): """a stand-alone configure method to allow for flatter assemblies Parameters ---------- assembly : Assembly an openmdao assembly to be configured with_new_nacelle : bool False uses the default implementation, True uses an experimental implementation designed to smooth out discontinities making in amenable for gradient-based optimization flexible_blade : bool if True, internally solves the coupled aero/structural deflection using fixed point iteration. Note that the coupling is currently only in the flapwise deflection, and is primarily only important for highly flexible blades. If False, the aero loads are passed to the structure but there is no further iteration. """ # --- general turbine configuration inputs--- assembly.add( 'rho', Float(1.225, iotype='in', units='kg/m**3', desc='density of air', deriv_ignore=True)) assembly.add( 'mu', Float(1.81206e-5, iotype='in', units='kg/m/s', desc='dynamic viscosity of air', deriv_ignore=True)) assembly.add( 'shear_exponent', Float(0.2, iotype='in', desc='shear exponent', deriv_ignore=True)) assembly.add('hub_height', Float(90.0, iotype='in', units='m', desc='hub height')) assembly.add( 'turbine_class', Enum('I', ('I', 'II', 'III', 'IV'), iotype='in', desc='IEC turbine class')) assembly.add( 'turbulence_class', Enum('B', ('A', 'B', 'C'), iotype='in', desc='IEC turbulence class class')) assembly.add( 'g', Float(9.81, iotype='in', units='m/s**2', desc='acceleration of gravity', deriv_ignore=True)) assembly.add( 'cdf_reference_height_wind_speed', Float( 90.0, iotype='in', desc= 'reference hub height for IEC wind speed (used in CDF calculation)' )) assembly.add('downwind', Bool(False, iotype='in', desc='flag if rotor is downwind')) assembly.add( 'tower_d', Array([0.0], iotype='in', units='m', desc='diameters along tower')) assembly.add('generator_speed', Float(iotype='in', units='rpm', desc='generator speed')) assembly.add( 'machine_rating', Float(5000.0, units='kW', iotype='in', desc='machine rated power')) assembly.add( 'rna_weightM', Bool(True, iotype='in', desc='flag to consider or not the RNA weight effect on Moment')) assembly.add('rotor', RotorSE()) if with_new_nacelle: assembly.add('hub', HubSE()) assembly.add('hubSystem', Hub_System_Adder_drive()) assembly.add('moments', blade_moment_transform()) assembly.add('forces', blade_force_transform()) if with_3pt_drive: assembly.add('nacelle', Drive3pt()) else: assembly.add('nacelle', Drive4pt()) else: assembly.add('nacelle', DriveWPACT()) assembly.add('hub', HubWPACT()) assembly.add('rna', RNAMass()) assembly.add('rotorloads1', RotorLoads()) assembly.add('rotorloads2', RotorLoads()) assembly.add('tower', TowerSE()) assembly.add('maxdeflection', MaxTipDeflection()) if flexible_blade: assembly.add('fpi', FixedPointIterator()) assembly.fpi.workflow.add(['rotor']) assembly.fpi.add_parameter('rotor.delta_precurve_sub', low=-1.e99, high=1.e99) assembly.fpi.add_parameter('rotor.delta_bladeLength', low=-1.e99, high=1.e99) assembly.fpi.add_constraint( 'rotor.delta_precurve_sub = rotor.delta_precurve_sub_out') assembly.fpi.add_constraint( 'rotor.delta_bladeLength = rotor.delta_bladeLength_out') assembly.fpi.max_iteration = 20 assembly.fpi.tolerance = 1e-8 assembly.driver.workflow.add(['fpi']) else: assembly.driver.workflow.add(['rotor']) assembly.driver.workflow.add([ 'hub', 'nacelle', 'tower', 'maxdeflection', 'rna', 'rotorloads1', 'rotorloads2' ]) if with_new_nacelle: assembly.driver.workflow.add(['hubSystem', 'moments', 'forces']) # TODO: rotor drivetrain design should be connected to nacelle drivetrain design # connections to rotor assembly.connect('machine_rating', 'rotor.control.ratedPower') assembly.connect('rho', 'rotor.rho') assembly.connect('mu', 'rotor.mu') assembly.connect('shear_exponent', 'rotor.shearExp') assembly.connect('hub_height', 'rotor.hubHt') assembly.connect('turbine_class', 'rotor.turbine_class') assembly.connect('turbulence_class', 'rotor.turbulence_class') assembly.connect('g', 'rotor.g') assembly.connect('cdf_reference_height_wind_speed', 'rotor.cdf_reference_height_wind_speed') # connections to hub and hub system assembly.connect('rotor.mass_one_blade', 'hub.blade_mass') assembly.connect('rotor.root_bending_moment', 'hub.rotor_bending_moment') assembly.connect('rotor.diameter', ['hub.rotor_diameter']) assembly.connect('rotor.hub_diameter', 'hub.blade_root_diameter') assembly.connect('rotor.nBlades', 'hub.blade_number') if with_new_nacelle: assembly.connect('machine_rating', 'hub.machine_rating') assembly.connect('rotor.diameter', ['hubSystem.rotor_diameter']) assembly.connect('nacelle.MB1_location', 'hubSystem.MB1_location') # TODO: bearing locations assembly.connect('nacelle.L_rb', 'hubSystem.L_rb') assembly.connect('rotor.tilt', 'hubSystem.shaft_angle') assembly.connect('hub.hub_diameter', 'hubSystem.hub_diameter') assembly.connect('hub.hub_thickness', 'hubSystem.hub_thickness') assembly.connect('hub.hub_mass', 'hubSystem.hub_mass') assembly.connect('hub.spinner_mass', 'hubSystem.spinner_mass') assembly.connect('hub.pitch_system_mass', 'hubSystem.pitch_system_mass') # connections to nacelle #TODO: fatigue option variables assembly.connect('rotor.diameter', 'nacelle.rotor_diameter') assembly.connect('1.5 * rotor.ratedConditions.Q', 'nacelle.rotor_torque') assembly.connect('rotor.ratedConditions.T', 'nacelle.rotor_thrust') assembly.connect('rotor.ratedConditions.Omega', 'nacelle.rotor_speed') assembly.connect('machine_rating', 'nacelle.machine_rating') assembly.connect('rotor.root_bending_moment', 'nacelle.rotor_bending_moment') assembly.connect('generator_speed/rotor.ratedConditions.Omega', 'nacelle.gear_ratio') assembly.connect( 'tower_d[-1]', 'nacelle.tower_top_diameter') # OpenMDAO circular dependency issue assembly.connect( 'rotor.mass_all_blades + hub.hub_system_mass', 'nacelle.rotor_mass') # assuming not already in rotor force / moments # variable connections for new nacelle if with_new_nacelle: assembly.connect('rotor.nBlades', 'nacelle.blade_number') assembly.connect('rotor.tilt', 'nacelle.shaft_angle') assembly.connect('333.3 * machine_rating / 1000.0', 'nacelle.shrink_disc_mass') assembly.connect('rotor.hub_diameter', 'nacelle.blade_root_diameter') #moments # assembly.connect('rotor.Q_extreme','nacelle.rotor_bending_moment_x') assembly.connect('rotor.Mxyz_0', 'moments.b1') assembly.connect('rotor.Mxyz_120', 'moments.b2') assembly.connect('rotor.Mxyz_240', 'moments.b3') assembly.connect('rotor.Pitch', 'moments.pitch_angle') assembly.connect('rotor.TotalCone', 'moments.cone_angle') assembly.connect('moments.Mx', 'nacelle.rotor_bending_moment_x' ) #accounted for in ratedConditions.Q assembly.connect('moments.My', 'nacelle.rotor_bending_moment_y') assembly.connect('moments.Mz', 'nacelle.rotor_bending_moment_z') #forces # assembly.connect('rotor.T_extreme','nacelle.rotor_force_x') assembly.connect('rotor.Fxyz_0', 'forces.b1') assembly.connect('rotor.Fxyz_120', 'forces.b2') assembly.connect('rotor.Fxyz_240', 'forces.b3') assembly.connect('rotor.Pitch', 'forces.pitch_angle') assembly.connect('rotor.TotalCone', 'forces.cone_angle') assembly.connect('forces.Fx', 'nacelle.rotor_force_x') assembly.connect('forces.Fy', 'nacelle.rotor_force_y') assembly.connect('forces.Fz', 'nacelle.rotor_force_z') '''if with_new_nacelle: assembly.connect('rotor.g', 'nacelle.g') # Only drive smooth taking g from rotor; TODO: update when drive_smooth is updated''' # connections to rna assembly.connect('rotor.mass_all_blades', 'rna.blades_mass') assembly.connect('rotor.I_all_blades', 'rna.blades_I') if with_new_nacelle: assembly.connect('hubSystem.hub_system_mass', 'rna.hub_mass') assembly.connect('hubSystem.hub_system_cm', 'rna.hub_cm') assembly.connect('hubSystem.hub_system_I', 'rna.hub_I') else: assembly.connect('hub.hub_system_mass', 'rna.hub_mass') assembly.connect('hub.hub_system_cm', 'rna.hub_cm') assembly.connect('hub.hub_system_I', 'rna.hub_I') assembly.connect('nacelle.nacelle_mass', 'rna.nac_mass') assembly.connect('nacelle.nacelle_cm', 'rna.nac_cm') assembly.connect('nacelle.nacelle_I', 'rna.nac_I') # connections to rotorloads1 assembly.connect('downwind', 'rotorloads1.downwind') assembly.connect('rna_weightM', 'rotorloads1.rna_weightM') assembly.connect('1.8 * rotor.ratedConditions.T', 'rotorloads1.F[0]') assembly.connect('rotor.ratedConditions.Q', 'rotorloads1.M[0]') if with_new_nacelle: assembly.connect('hubSystem.hub_system_cm', 'rotorloads1.r_hub') else: assembly.connect('hub.hub_system_cm', 'rotorloads1.r_hub') assembly.connect('rna.rna_cm', 'rotorloads1.rna_cm') assembly.connect('rotor.tilt', 'rotorloads1.tilt') assembly.connect('g', 'rotorloads1.g') assembly.connect('rna.rna_mass', 'rotorloads1.m_RNA') # connections to rotorloads2 assembly.connect('downwind', 'rotorloads2.downwind') assembly.connect('rna_weightM', 'rotorloads2.rna_weightM') assembly.connect('rotor.T_extreme', 'rotorloads2.F[0]') assembly.connect('rotor.Q_extreme', 'rotorloads2.M[0]') if with_new_nacelle: assembly.connect('hubSystem.hub_system_cm', 'rotorloads2.r_hub') else: assembly.connect('hub.hub_system_cm', 'rotorloads2.r_hub') assembly.connect('rna.rna_cm', 'rotorloads2.rna_cm') assembly.connect('rotor.tilt', 'rotorloads2.tilt') assembly.connect('g', 'rotorloads2.g') assembly.connect('rna.rna_mass', 'rotorloads2.m_RNA') # connections to tower assembly.connect('rho', 'tower.wind_rho') assembly.connect('mu', 'tower.wind_mu') assembly.connect('g', 'tower.g') assembly.connect('hub_height', 'tower.wind_zref') assembly.connect('tower_d', 'tower.d_param') assembly.connect('rotor.ratedConditions.V', 'tower.wind_Uref1') assembly.connect('rotor.V_extreme', 'tower.wind_Uref2') assembly.connect('rotor.yaw', 'tower.yaw') assembly.connect('hub_height - nacelle.nacelle_cm[2]', 'tower.z_param[-1]') #TODO: hub height should be derived assembly.connect('rna.rna_mass', 'tower.m[0]') assembly.connect('rna.rna_cm[0]', 'tower.mrhox[0]') assembly.connect('rna.rna_cm[1]', 'tower.mrhoy[0]') assembly.connect('rna.rna_cm[2]', 'tower.mrhoz[0]') assembly.connect('rna.rna_I_TT[0]', 'tower.mIxx[0]') assembly.connect('rna.rna_I_TT[1]', 'tower.mIyy[0]') assembly.connect('rna.rna_I_TT[2]', 'tower.mIzz[0]') assembly.connect('rna.rna_I_TT[3]', 'tower.mIxy[0]') assembly.connect('rna.rna_I_TT[4]', 'tower.mIxz[0]') assembly.connect('rna.rna_I_TT[5]', 'tower.mIyz[0]') assembly.connect('rotorloads1.top_F[0]', 'tower.Fx1[0]') assembly.connect('rotorloads1.top_F[1]', 'tower.Fy1[0]') assembly.connect('rotorloads1.top_F[2]', 'tower.Fz1[0]') assembly.connect('rotorloads1.top_M[0]', 'tower.Mxx1[0]') assembly.connect('rotorloads1.top_M[1]', 'tower.Myy1[0]') assembly.connect('rotorloads1.top_M[2]', 'tower.Mzz1[0]') assembly.connect('rotorloads2.top_F[0]', 'tower.Fx2[0]') assembly.connect('rotorloads2.top_F[1]', 'tower.Fy2[0]') assembly.connect('rotorloads2.top_F[2]', 'tower.Fz2[0]') assembly.connect('rotorloads2.top_M[0]', 'tower.Mxx2[0]') assembly.connect('rotorloads2.top_M[1]', 'tower.Myy2[0]') assembly.connect('rotorloads2.top_M[2]', 'tower.Mzz2[0]') # connections to maxdeflection assembly.connect('rotor.Rtip', 'maxdeflection.Rtip') assembly.connect('rotor.precurveTip', 'maxdeflection.precurveTip') assembly.connect('rotor.presweepTip', 'maxdeflection.presweepTip') assembly.connect('rotor.precone', 'maxdeflection.precone') assembly.connect('rotor.tilt', 'maxdeflection.tilt') if with_new_nacelle: assembly.connect('hubSystem.hub_system_cm', 'maxdeflection.hub_tt') else: assembly.connect('hub.hub_system_cm', 'maxdeflection.hub_tt') assembly.connect('tower.z_param', 'maxdeflection.tower_z') assembly.connect('tower.d_param', 'maxdeflection.tower_d') assembly.connect('hub_height - nacelle.nacelle_cm[2]', 'maxdeflection.towerHt')