def setUp(self): self.nace = DriveWPACT() self.nace.rotor_diameter = 126.0 # m self.nace.rotor_speed = 12.1 # rpm m/s self.nace.machine_rating = 5000.0 DrivetrainEfficiency = 0.95 self.nace.rotor_torque = 1.5 * ( self.nace.machine_rating * 1000. / DrivetrainEfficiency) / ( self.nace.rotor_speed * (pi / 30.)) # 6.35e6 #4365248.74 # Nm self.nace.rotor_thrust = 2.5448e5 self.nace.rotor_mass = 142585.75 #kg # NREL 5 MW Drivetrain variables self.nace.drivetrain_design = 'geared' # geared 3-stage Gearbox with induction generator machine self.nace.gear_ratio = 96.76 # 97:1 as listed in the 5 MW reference document self.nace.gear_configuration = 'eep' # epicyclic-epicyclic-parallel self.nace.bevel = 0 # no bevel stage self.nace.crane = True # onboard crane present # NREL 5 MW Tower Variables self.nace.tower_top_diameter = 3.78 # m
print ' Nose cone: {0:8.1f} kg'.format(hub.spinner.mass) # 1810.50 print 'Hub system total: {0:8.1f} kg'.format(hub.hub_system_mass) # 50458.95 print ' cm {0:6.2f} {1:6.2f} {2:6.2f} [m, m, m]'.format( hub.hub_system_cm[0], hub.hub_system_cm[1], hub.hub_system_cm[2]) print ' I {0:6.1f} {1:6.1f} {2:6.1f} [kg*m^2, kg*m^2, kg*m^2]'.format( hub.hub_system_I[0], hub.hub_system_I[1], hub.hub_system_I[2]) print # 4 --------- # 5 --------- # test of drivetrain model # NREL 5 MW Rotor Variables nace = DriveWPACT() nace.rotor_diameter = 126.0 # m nace.rotor_speed = 12.1 # rpm m/s nace.machine_rating = 5000.0 nace.DrivetrainEfficiency = 0.95 nace.rotor_torque = 1.5 * (nace.machine_rating * 1000 / nace.DrivetrainEfficiency) / ( nace.rotor_speed * (pi / 30)) # 6.35e6 #4365248.74 # Nm nace.rotor_thrust = 2.5448e5 nace.rotor_mass = 142585.75 #kg nace.rotor_speed = 12.1 #rpm # NREL 5 MW Drivetrain variables nace.drivetrain_design = 'geared' # geared 3-stage Gearbox with induction generator machine nace.gear_ratio = 96.76 # 97:1 as listed in the 5 MW reference document
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
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. """ #SEAM variables ---------------------------------- #d2e = Float(0.73, iotype='in', desc='Dollars to Euro ratio' assembly.add( 'rated_power', Float(3000., iotype='in', units='kW', desc='Turbine rated power', group='Global')) assembly.add( 'hub_height', Float(100., iotype='in', units='m', desc='Hub height', group='Global')) assembly.add( 'rotor_diameter', Float(110., iotype='in', units='m', desc='Rotor diameter', group='Global')) # assembly.add('site_type',Enum('onshore', values=('onshore', 'offshore'), iotype='in', desc='Site type', group='Global')) assembly.add( 'tower_bottom_diameter', Float(4., iotype='in', desc='Tower bottom diameter', group='Global')) assembly.add( 'tower_top_diameter', Float(2., iotype='in', desc='Tower top diameter', group='Global')) assembly.add('project_lifetime', Float(iotype='in', desc='Operating years', group='Global')) assembly.add( 'rho_steel', Float(7.8e3, iotype='in', desc='density of steel', group='Tower')) assembly.add( 'lifetime_cycles', Float(1.e7, iotype='in', desc='Equivalent lifetime cycles', group='Rotor')) assembly.add( 'stress_limit_extreme_tower', Float(iotype='in', units='MPa', desc='Tower ultimate strength', group='Tower')) assembly.add( 'stress_limit_fatigue_tower', Float(iotype='in', units='MPa', desc='Tower fatigue strength', group='Tower')) assembly.add( 'safety_factor_tower', Float(iotype='in', desc='Tower loads safety factor', group='Tower')) assembly.add('PMtarget_tower', Float(1., iotype='in', desc='', group='Tower')) assembly.add( 'wohler_exponent_tower', Float(4., iotype='in', desc='Tower fatigue Wohler exponent', group='Tower')) assembly.add('tower_z', Array(iotype='out', desc='Tower discretization')) assembly.add('tower_wall_thickness', Array(iotype='out', units='m', desc='Tower wall thickness')) assembly.add('tower_mass', Float(iotype='out', units='kg', desc='Tower mass')) assembly.add( 'tsr', Float(iotype='in', units='m', desc='Design tip speed ratio', group='Aero')) assembly.add( 'F', Float(iotype='in', desc='Rotor power loss factor', group='Aero')) assembly.add( 'wohler_exponent_blade_flap', Float(iotype='in', desc='Wohler Exponent blade flap', group='Rotor')) assembly.add('nSigma4fatFlap', Float(iotype='in', desc='', group='Loads')) assembly.add('nSigma4fatTower', Float(iotype='in', desc='', group='Loads')) assembly.add('dLoad_dU_factor_flap', Float(iotype='in', desc='', group='Loads')) assembly.add('dLoad_dU_factor_tower', Float(iotype='in', desc='', group='Loads')) assembly.add( 'blade_edge_dynload_factor_ext', Float(iotype='in', desc='Extreme dynamic edgewise loads factor', group='Loads')) assembly.add( 'blade_edge_dynload_factor_fat', Float(iotype='in', desc='Fatigue dynamic edgewise loads factor', group='Loads')) assembly.add('PMtarget_blades', Float(1., iotype='in', desc='', group='Rotor')) assembly.add('max_tipspeed', Float(iotype='in', desc='Maximum tip speed', group='Aero')) assembly.add( 'n_wsp', Int(iotype='in', desc='Number of wind speed bins', group='Aero')) assembly.add( 'min_wsp', Float(0.0, iotype='in', units='m/s', desc='min wind speed', group='Aero')) assembly.add( 'max_wsp', Float(iotype='in', units='m/s', desc='max wind speed', group='Aero')) assembly.add( 'turbulence_int', Float(iotype='in', desc='Reference turbulence intensity', group='Plant_AEP')) # assembly.add('WeibullInput', Bool(True, iotype='in', desc='Flag for Weibull input', group='AEP')) assembly.add( 'weibull_C', Float(iotype='in', units='m/s', desc='Weibull scale factor', group='AEP')) assembly.add( 'weibull_k', Float(iotype='in', desc='Weibull shape or form factor', group='AEP')) assembly.add( 'blade_sections', Int(iotype='in', desc='number of sections along blade', group='Rotor')) assembly.add( 'wohler_exponent_blade_flap', Float(iotype='in', desc='Blade flap fatigue Wohler exponent', group='Rotor')) assembly.add( 'MaxChordrR', Float(iotype='in', units='m', desc='Spanwise position of maximum chord', group='Rotor')) assembly.add( 'tif_blade_root_flap_ext', Float(1., iotype='in', desc='Technology improvement factor flap extreme', group='Rotor')) assembly.add( 'tif_blade_root_edge_ext', Float(1., iotype='in', desc='Technology improvement factor edge extreme', group='Rotor')) assembly.add( 'tif_blade_root_flap_fat', Float(1., iotype='in', desc='Technology improvement factor flap LEQ', group='Rotor')) assembly.add( 'sc_frac_flap', Float(iotype='in', desc='spar cap fraction of chord', group='Rotor')) assembly.add( 'sc_frac_edge', Float(iotype='in', desc='spar cap fraction of thickness', group='Rotor')) assembly.add( 'safety_factor_blade', Float(iotype='in', desc='Blade loads safety factor', group='Rotor')) assembly.add( 'stress_limit_extreme_blade', Float(iotype='in', units='MPa', desc='Blade ultimate strength', group='Rotor')) assembly.add( 'stress_limit_fatigue_blade', Float(iotype='in', units='MPa', desc='Blade fatigue strength', group='Rotor')) assembly.add( 'AddWeightFactorBlade', Float(iotype='in', desc='Additional weight factor for blade shell', group='Rotor')) assembly.add( 'blade_material_density', Float(iotype='in', units='kg/m**3', desc='Average density of blade materials', group='Rotor')) assembly.add('blade_mass', Float(iotype='out', units='kg', desc='Blade mass')) # assembly.add('mean_wsp', Float(iotype = 'in', units = 'm/s', desc = 'mean wind speed', group='Aero')) # [m/s] assembly.add('air_density', Float(iotype='in', units='kg/m**3', desc='density of air', group='Plant_AEP')) # [kg / m^3] assembly.add('max_Cp', Float(iotype='in', desc='max CP', group='Aero')) assembly.add( 'gearloss_const', Float(iotype='in', desc='Gear loss constant', group='Drivetrain')) assembly.add( 'gearloss_var', Float(iotype='in', desc='Gear loss variable', group='Drivetrain')) assembly.add('genloss', Float(iotype='in', desc='Generator loss', group='Drivetrain')) assembly.add('convloss', Float(iotype='in', desc='Converter loss', group='Drivetrain')) # Outputs assembly.add( 'rated_wind_speed', Float(units='m / s', iotype='out', desc='wind speed for rated power')) assembly.add( 'ideal_power_curve', Array(iotype='out', units='kW', desc='total power before losses and turbulence')) assembly.add( 'power_curve', Array(iotype='out', units='kW', desc='total power including losses and turbulence')) assembly.add( 'wind_curve', Array(iotype='out', units='m/s', desc='wind curve associated with power curve')) assembly.add( 'aep', Float(iotype='out', units='mW*h', desc='Annual energy production in mWh')) assembly.add( 'total_aep', Float(iotype='out', units='mW*h', desc='AEP for total years of production')) # END SEAM Variables ---------------------- # Add SEAM components and connections assembly.add('loads', SEAMLoads()) assembly.add('tower_design', SEAMTower(21)) assembly.add('blade_design', SEAMBladeStructure()) assembly.add('aep_calc', SEAM_PowerCurve()) assembly.driver.workflow.add( ['loads', 'tower_design', 'blade_design', 'aep_calc']) assembly.connect('loads.tower_bottom_moment_max', 'tower_design.tower_bottom_moment_max') assembly.connect('loads.tower_bottom_moment_leq', 'tower_design.tower_bottom_moment_leq') assembly.connect('loads.blade_root_flap_max', 'blade_design.blade_root_flap_max') assembly.connect('loads.blade_root_edge_max', 'blade_design.blade_root_edge_max') assembly.connect('loads.blade_root_flap_leq', 'blade_design.blade_root_flap_leq') assembly.connect('loads.blade_root_edge_leq', 'blade_design.blade_root_edge_leq') connect_io(assembly, assembly.aep_calc) connect_io(assembly, assembly.loads) connect_io(assembly, assembly.tower_design) connect_io(assembly, assembly.blade_design) # End SEAM add components and connections ------------- if with_new_nacelle: assembly.add('hub', HubSE()) assembly.add('hubSystem', Hub_System_Adder_drive()) if with_3pt_drive: assembly.add('nacelle', Drive3pt()) else: assembly.add('nacelle', Drive4pt()) else: assembly.add('nacelle', DriveWPACT()) assembly.add('hub', HubWPACT()) assembly.driver.workflow.add(['hub', 'nacelle']) if with_new_nacelle: assembly.driver.workflow.add(['hubSystem']) # connections to hub and hub system assembly.connect('blade_design.blade_mass', 'hub.blade_mass') assembly.connect('loads.blade_root_flap_max', 'hub.rotor_bending_moment') assembly.connect('rotor_diameter', ['hub.rotor_diameter']) assembly.connect('blade_design.blade_root_diameter', 'hub.blade_root_diameter') assembly.add('blade_number', Int(3, iotype='in', desc='number of blades', group='Aero')) assembly.connect('blade_number', 'hub.blade_number') if with_new_nacelle: assembly.connect('rated_power', '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.add('rotor_tilt', Float(5.0, iotype='in', desc='rotor tilt', group='Rotor')) 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 * aep_calc.rated_torque', 'nacelle.rotor_torque') assembly.connect('loads.max_thrust', 'nacelle.rotor_thrust') assembly.connect('aep_calc.rated_speed', 'nacelle.rotor_speed') assembly.connect('rated_power', 'nacelle.machine_rating') assembly.add('generator_speed', Float(1173.7, iotype='in', units='rpm', desc='speed of generator', group='Drivetrain')) # - should be in nacelle assembly.connect('generator_speed/aep_calc.rated_speed', 'nacelle.gear_ratio') assembly.connect('tower_top_diameter', 'nacelle.tower_top_diameter') assembly.connect( 'blade_number * blade_design.blade_mass + 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('blade_number', 'nacelle.blade_number') assembly.connect('rotor_tilt', 'nacelle.shaft_angle') assembly.connect('333.3 * rated_power / 1000.0', 'nacelle.shrink_disc_mass') assembly.connect('blade_design.blade_root_diameter', 'nacelle.blade_root_diameter') #moments - ignoring for now (nacelle will use internal defaults) #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('1.5 * aep_calc.rated_torque', '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 - ignoring for now (nacelle will use internal defaults) #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('loads.max_thrust', 'nacelle.rotor_force_x')
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')