class ExtendedFinancialAnalysis_Example(Assembly): """ Extended financial analysis assembly for coupling models to get a full wind plant cost of energy estimate as well as provides a detailed cost breakdown for the plant. """ # Inputs turbine_number = Int(iotype='in', desc='number of turbines at plant') #Outputs turbine_cost = Float(iotype='out', desc='A Wind Turbine Capital _cost') bos_costs = Float(iotype='out', desc='A Wind Plant Balance of Station _cost Model') avg_annual_opex = Float(iotype='out', desc='A Wind Plant Operations Expenditures Model') net_aep = Float(iotype='out', desc='A Wind Plant Annual Energy Production Model', units='kW*h') coe = Float(iotype='out', desc='Levelized cost of energy for the wind plant') opex_breakdown = VarTree(OPEXVarTree(), iotype='out') bos_breakdown = VarTree(BOSVarTree(), iotype='out', desc='BOS cost breakdown') def configure(self): configure_extended_financial_analysis(self) self.replace('tcc_a', BaseTurbineCostModel_Example()) self.replace('aep_a', BaseAEPModel_Example()) self.replace('fin_a', BaseFinancialModel_Example()) self.replace('bos_a', ExtendedBOSCostModel_Example()) self.replace('opex_a', ExtendedOPEXModel_Example())
class ModifyBladePlanformBase(Component): """ Base for classes that modify a blade planform object """ pfIn = VarTree(BladePlanformVT(), iotype='in') pfOut = VarTree(BladePlanformVT(), iotype='out')
class FstInputBuilder(Component): """ base class for setting up HAWC2 input data add additional design variables and methods in derived classes """ fstIn = VarTree(FstModel(), iotype='in') fstS = VarTree(FstModel(), iotype='in') fstOut = VarTree(FstModel(), iotype='out') def __init__(self): super(FstInputBuilder,self).__init__() def initialize_inputs(self): self._logger.info('dublicating inputs') self.fstS = self.fstIn.copy() def execute(self): self._logger.info('updating inputs') # update outputs self.fstOut = self.fstS.copy()
class RotorAeroCode(Component): """ Wrapper for a code capable of predicting the distributed loads on a rotor """ pf = VarTree(BladePlanformVT(), iotype='in', desc='Blade geometric definition') inflow = VarTree(TurbineEnvironmentVT(), iotype='in', desc='Rotor inflow conditions') oper = VarTree(RotorOperationalData(), iotype='out', desc='Operational data') rotor_loads = VarTree(RotorLoadsVT(), iotype='out', desc='Rotor torque, power, and thrust') blade_loads = VarTree(DistributedLoadsExtVT(), iotype='out', desc='Spanwise load distributions') def execute(self): print 'perform analysis here'
class IECRunCaseBaseVT(VariableTree): # General conditions needed case_name = Str( 'IEC_case', desc='Name of the specific case passed to the aeroelastic code') simulation = VarTree( AeroElasticSimulationSetup(), desc='Basic simulation input settings' ) # 4/28/2015 kld: should move elsewhere but leaving in for debugging environment = VarTree(OffshoreTurbineEnvironmentVT(), desc='Inflow conditions to the turbine simulation') basic_turbine = VarTree( BasicTurbineVT(), desc='Basic turbine variables already defined in fusedwind') rotor = VarTree(RotorOperationalData(), desc='Rotor variables already defined in fusedwind') pitch = VarTree( FixedSpeedFixedPitch(), desc='Pitch already defined in fusedwind') # should probably move init_conditions = VarTree(FASTInitialConditions(), desc='Initial conditions needed to run FAST') simulation_specs = VarTree( FASTSimulationSpecs(), desc='Basic simulation input settings') #mb: also shouldn't be here aero_inputs = VarTree(AerodynInputs(), desc='Wind and airfoil files to run Aerodyn') fst_inputs = VarTree(FASTInputs(), desc='FAST model variables') ptfm_inputs = VarTree(PtfmInputs(), desc='Platform model variables')
class AeroelasticHAWTVT(BasicTurbineVT): tilt_angle = Float(units='deg', desc='Rotor tilt angle') cone_angle = Float(units='deg', desc='Rotor cone angle') hub_radius = Float(units='m', desc='Hub radius') blade_length = Float(units='m', desc='blade length') tower_height = Float(units='m', desc='Tower height') towertop_length = Float(units='m', desc='Nacelle Diameter') shaft_length = Float(units='m', desc='Shaft length') airfoildata = VarTree(AirfoilDatasetVT(), desc='Airfoil Aerodynamic characteristics') drivetrain_performance = VarTree(DrivetrainPerformanceVT(), desc='drivetrain performance VT') bodies = List() def add_main_body(self, name, body=None): if body is None: body = MainBody() if 'blade' in name: body.remove('geom') body.add('geom', VarTree(BladePlanformVT())) if 'tower' in name: body.remove('geom') body.add('geom', VarTree(TubularTowerGeometryVT())) self.add(name, VarTree(body)) self.bodies.append(name) return getattr(self, name) def get_main_body(self, name): return getattr(self, name) def remove_main_body(self, name): self.delete(name) def set_machine_type(self, machine_type): self.remove('controls') if machine_type == 'FixedSpeedFixedPitch': self.add('controls', VarTree(FixedSpeedFixedPitch())) if machine_type == 'FixedSpeedVarPitch': self.add('controls', VarTree(FixedSpeedVarPitch())) if machine_type == 'VarSpeedFixedPitch': self.add('controls', VarTree(VarSpeedFixedPitch())) if machine_type == 'VarSpeedVarPitch': self.add('controls', VarTree(VarSpeedVarPitch())) return self.controls
class InandOutTree(Component): ins = VarTree(InVtree(), iotype="in") outs = VarTree(OutVtree(), iotype="out") def execute(self): self.outs.x = 2 * self.ins.a self.outs.y = 2 * self.ins.a + self.ins.b
class IECRunCaseBaseVT(VariableTree): case_name = Str( 'IEC_case', desc='Name of the specific case passed to the aeroelastic code') simulation = VarTree( AeroElasticSimulationSetup(), desc='Basic simulation input settings' ) # 4/28/2015 kld: should move elsewhere but leaving in for debugging environment = VarTree(TurbineEnvironmentVT(), desc='Inflow conditions to the turbine simulation')
class RotorAeroBase(Component): """ Base class for models that can predict the power and thrust of wind turbine rotor for a single inflow case """ pf = VarTree(BladePlanformVT(), iotype='in', desc='Blade geometric definition') inflow = VarTree(TurbineEnvironmentVT(), iotype='in', desc='Rotor inflow conditions') oper = VarTree(RotorOperationalData(), iotype='out', desc='Operational data') rotor_loads = VarTree(RotorLoadsVT(), iotype='out', desc='Rotor torque, power, and thrust')
class MainBody(VariableTree): body_name = Str('body') subsystem = Enum('Tower', ('Rotor', 'Nacelle', 'Tower', 'Foundation')) beam_structure = VarTree(BeamStructureVT(), desc='Structural beam properties of the body') geom = VarTree(BeamGeometryVT(), desc='Beam geometry') mass = Float(desc='mass of the body') damping_posdef = Array(np.zeros(6)) concentrated_mass = List(Array())
class MEflows(VariableTree): """Container of variables defining the flow properties of the mixer-ejector nozzle""" # Primary and Secondary Streams pri = VarTree(Stream(), iotype='in') sec = VarTree(Stream(), iotype='in') gamma = Float(1.4, desc='Ratio of specific heats') Pstatic = Float(2116.8, units='lbf/ft**2', desc='Freestream static pressure')
class ModifyBladeStructureBase(Component): st3dIn = VarTree( BladeStructureVT3D(), iotype='in', desc='Vartree containing initial discrete definition of blade structure' ) st3dOut = VarTree( BladeStructureVT3D(), iotype='out', desc= 'Vartree containing modified discrete definition of blade structure')
class RotorAero(Component): """ Class that extends the TurbineAeroBase with distributed blade loads for a single inflow case """ pf = VarTree(BladePlanformVT(), iotype='in', desc='Blade geometric definition') inflow = VarTree(TurbineEnvironmentVT(), iotype='in', desc='Rotor inflow conditions') oper = VarTree(RotorOperationalData(), iotype='out', desc='Operational data') rotor_loads = VarTree(RotorLoadsVT(), iotype='out', desc='Rotor torque, power, and thrust') blade_loads = VarTree(DistributedLoadsExtVT(), iotype='out', desc='Spanwise load distributions')
def __init__(self, Ns): super(Failures, self).__init__() # inputs self.add('flags', VarTree(Flags(), iotype='in')) self.add('yN', Array(np.zeros(Ns + 1), iotype='in', desc='')) self.add('Finternal', Array(np.zeros((6, Ns + 1)), iotype='in', desc='')) self.add('strain', VarTree(Strain(Ns), iotype='in')) self.add('d', Array(np.zeros(Ns), iotype='in', desc='')) self.add('theta', Array(np.zeros(Ns), iotype='in', desc='')) self.add('nTube', Array(np.zeros(Ns), iotype='in', desc='')) self.add('nCap', Array(np.zeros(Ns), iotype='in', desc='')) self.add('yWire', Array([0], iotype='in', desc='')) self.add('zWire', Float(0., iotype='in', desc='')) self.add('EIxJ', Array(np.zeros(Ns), iotype='in', desc='')) self.add('EIzJ', Array(np.zeros(Ns), iotype='in', desc='')) self.add('lBiscuit', Array(np.zeros(Ns), iotype='in', desc='')) self.add('dQuad', Float(0., iotype='in', desc='')) self.add('thetaQuad', Float(0., iotype='in', desc='')) self.add('nTubeQuad', Float(0., iotype='in', desc='')) self.add('lBiscuitQuad', Float(0., iotype='in', desc='')) self.add('RQuad', Float(0., iotype='in', desc='')) self.add('hQuad', Float(0., iotype='in', desc='')) self.add('EIQuad', Array(np.zeros(Ns), iotype='in', desc='')) self.add('GJQuad', Array(np.zeros(Ns), iotype='in', desc='')) self.add('tWire', Float(0., iotype='in', desc='')) self.add('TWire', Array([0], iotype='in', desc='')) self.add('TEtension', Float(0., iotype='in', desc='')) # all this to get TQuad... maybe should be split out self.add('b', Int(0, iotype='in', desc='number of blades')) self.add('fblade', VarTree(Fblade(Ns), iotype='in')) self.add('mSpar', Array(np.zeros(Ns), iotype='in', desc='mass of spars')) self.add('mChord', Array(np.zeros(Ns), iotype='in', desc='mass of chords')) self.add('mElseRotor', Float(0., iotype='in', desc='')) # outputs self.add('fail', VarTree(Failure(Ns), iotype='out'))
class CS2Dsolver(Component): cs2d = List(CrossSectionStructureVT, iotype='in', desc='Blade cross sectional structure geometry') pf = VarTree(BladePlanformVT(), iotype='in', desc='Blade planform discretized according to' 'the structural resolution') beam_structure = VarTree(BeamStructureVT(), iotype='out', desc='Structural beam properties') def execute(self): print '' for i, cs in enumerate(self.cs2d): print 'processing cross section %i' % i
class ComputeHAWC2BeamProps(Component): """ Component that postprocesses the individual outputs from the BECAS case runs returning a BeamStructureVT, mass and mass moment. """ pf = VarTree(BladePlanformVT(), iotype='in') hub_radius = Float(iotype='in') cs2d_cases = List(iotype='in') g = Float(9.81, iotype='in') beam_structure = VarTree(BeamStructureVT(), iotype='out') mass = Float(iotype='out') mass_moment = Float(iotype='out') def execute(self): self.beam_structure = self.beam_structure.copy() ni = len(self.cs2d_cases) for name in self.beam_structure.list_vars(): var = getattr(self.beam_structure, name) if name == 'J': nname = 'K' else: nname = name if isinstance(var, np.ndarray): var = np.zeros(ni) for i, h2d in enumerate(self.cs2d_cases): try: var[i] = getattr(h2d, nname) except: pass setattr(self.beam_structure, name, var) self.beam_structure.s = self.pf.s * self.pf.smax * self.pf.blade_length self.mass = np.trapz(self.beam_structure.dm, self.beam_structure.s) self.mass_moment = np.trapz( self.g * self.beam_structure.dm * (self.beam_structure.s + self.hub_radius), self.beam_structure.s) print 'Mass: ', self.mass print 'Mass moment: ', self.mass_moment self.beam_structure.x_e += ( 0.5 - self.pf.p_le) * self.pf.chord * self.pf.blade_length self.beam_structure.x_cg += ( 0.5 - self.pf.p_le) * self.pf.chord * self.pf.blade_length self.beam_structure.x_sh += ( 0.5 - self.pf.p_le) * self.pf.chord * self.pf.blade_length
def set_machine_type(self, machine_type): self.remove('controls') if machine_type == 'FixedSpeedFixedPitch': self.add('controls', VarTree(FixedSpeedFixedPitch())) if machine_type == 'FixedSpeedVarPitch': self.add('controls', VarTree(FixedSpeedVarPitch())) if machine_type == 'VarSpeedFixedPitch': self.add('controls', VarTree(VarSpeedFixedPitch())) if machine_type == 'VarSpeedVarPitch': self.add('controls', VarTree(VarSpeedVarPitch())) return self.controls
class Failure(VariableTree): top = VarTree(MaterialFailure()) bottom = VarTree(MaterialFailure()) back = VarTree(MaterialFailure()) front = VarTree(MaterialFailure()) buckling = VarTree(BucklingFailure()) quad_buckling = Float(desc='Quad Buckling failure') quad_bend = Float(desc='Quad bending moment failure') quad_torsion = Float(desc='Quad torsional material failure') quad_torbuck = Float(desc='Quad torsional buckling failure') wire = Array(desc='Wire tensile failure')
class FUSEDAssembly(Assembly): """ Base class for all FUSED-Wind assemblies which extends OpenMDAO's Assembly with dedicated slots for I/O and methods for recording runs. """ inputs = VarTree( CaseInputsBase(), iotype='in', desc='Placeholder for FUSED-Wind inputs to a simulation code') outputs = VarTree(CaseOutputsBase(), iotype='out', desc='Placeholder for FUSED-Wind outputs generated by a' 'simulation code')
class HAWC2PostPowerCurve(Component): cases = Slot(ICaseIterator, iotype='in') rotor_loads = VarTree(RotorLoadsArrayVT(), iotype='out') nraverage = Int(200) def execute(self): wsp = [] P = [] T = [] Q = [] for case in self.cases: wsp.append(case.get_input('builder.Ps.wind.wsp')) out = case.get_output('wrapper.output') data = out.datasets[0].get_channels([10, 11, 12]) Q.append(np.average(data[-self.nraverage:, 0])) P.append(np.average(data[-self.nraverage:, 1])) T.append(np.average(data[-self.nraverage:, 2])) # sort the cases to make sure they are stored with increasing wsp zipped = zip(wsp, T, Q, P) zipped.sort() wsp, T, Q, P = zip(*zipped) self.rotor_loads.wsp = wsp self.rotor_loads.T = np.array(T) * 1000. self.rotor_loads.Q = np.array(Q) * 1000. self.rotor_loads.P = np.array(P) * 1000.
class Builder(Component): st3d = VarTree(BladeVT(), iotype='in') def execute(self): for region in self.st3d.section0.regions: # print region, getattr(self.st3d.section0, region) getattr(self.st3d.section0, region)
class SplinedRegion(Component): region = VarTree(RegionVT(), iotype='out') def execute(self): # print 'computing splines for c0 and c1' self.region.c0 = 1.0 # np.sin(np.linspace(0,1,10)) self.region.c1 = 2.0 # np.cos(np.linspace(0,1,10))
class GenericWindFarm(Component): # Inputs: wind_speed = Float(iotype='in', low=0.0, high=100.0, units='m/s', desc='Inflow wind speed at hub height') wind_direction = Float(iotype='in', low=0.0, high=360.0, units='deg', desc='Inflow wind direction at hub height') wt_layout = VarTree(GenericWindFarmTurbineLayout(), iotype='in', desc='wind turbine properties and layout') # Outputs: power = Float(iotype='out', units='kW', desc='Total wind farm power production') thrust = Float(iotype='out', units='N', desc='Total wind farm thrust') wt_power = Array([], iotype='out', desc='The power production of each wind turbine') wt_thrust = Array([], iotype='out', desc='The thrust of each wind turbine')
def add_dll(self, dll_name, b): b.dll_name = dll_name if not hasattr(self, dll_name): self.add(dll_name, VarTree(b)) else: print 'dll: %s already added' % dll_name
def add_case(self, obj, wsp=None, case_name=None): """ Add a BeamDisplacementsVT Specify either wsp or a user specified case name Parameters ---------- obj: BeamDisplacementsVT object case to be added wsp: float optional wind speed case_name: str custom case name """ if wsp == None and case_name == None: raise RuntimeError('Expected either wsp or case_name, got ' % (wsp, case_name)) if wsp is not None: name = 'loads%2.2f' % wsp elif case_name is not None: name = case_name self.add(name, VarTree(obj)) self.loads_array.append(name) return getattr(self, name)
class WTPC(GenericWindTurbinePowerCurveVT): """ A GenericWindTurbinePowerCurveVT with a name, position and wind rose """ # GenericWindTurbineVT hub_height = Float(desc='Machine hub height', units='m') rotor_diameter = Float(desc='Machine rotor diameter', units='m') power_rating = Float(desc='Machine power rating', units='W') # GenericWindTurbinePowerCurveVT c_t_curve = Array(desc='Machine thrust coefficients by wind speed at hub') power_curve = Array(desc='Machine power output [W] by wind speed at hub') cut_in_wind_speed = Float(4., desc='The cut-in wind speed of the wind turbine', units='m/s') cut_out_wind_speed = Float( 25., desc='The cut-out wind speed of the wind turbine', units='m/s') rated_wind_speed = Float(desc='The rated wind speed of the wind turbine', units='m/s') air_density = Float(desc='The air density the power curve are valid for', units='kg/(m*m*m)') # WTPC name = Str(desc='The wind turbine name') position = Array(shape=(2, ), desc='The UTM position of the turbine', units='m') wind_rose = VarTree(GenericWindRoseVT(), desc='The wind turbine wind rose') def __init__(self, **kwargs): """Initialise the variable tree with the right inputs""" super(WTPC, self).__init__() for k, v in kwargs.iteritems(): if k in self.list_vars(): setattr(self, k, v)
class BladePlanformWriter(Component): filebase = Str('blade') pf = VarTree(BladePlanformVT(), iotype='in') def execute(self): name = self.filebase + self.itername + '.pfd' try: if '-fd' in self.itername or '-fd' in self.parent.itername: name = self.filebase + '.pfd' except: pass data = np.array([ self.pf.x, self.pf.y, self.pf.z, self.pf.rot_x, self.pf.rot_y, self.pf.rot_z, self.pf.chord, self.pf.rthick, self.pf.p_le ]).T fid = open(name, 'w') header = [ 'main_axis_x', 'main_axis_y', 'main_axis_z', 'rot_x', 'rot_y', 'rot_z', 'chord', 'rthick', 'p_le' ] exp_prec = 10 # exponential precesion col_width = exp_prec + 8 # column width required for exp precision header_full = '# ' + ''.join([(hh + ' [%i]').center(col_width + 2) % i for i, hh in enumerate(header)]) + '\n' fid.write(header_full) np.savetxt(fid, data, fmt='%' + ' %i.%ie' % (col_width, exp_prec)) fid.close()
def __init__(self, Ns): super(Strains, self).__init__() # inputs self.add('yN', Array(np.zeros(Ns + 1), iotype='in', desc='')) self.add('d', Array(np.zeros(Ns), iotype='in', desc='')) self.add( 'k', Array(np.zeros((Ns + 2, Ns + 2, Ns)), iotype='in', desc='Local elastic stiffness matrix')) self.add( 'F', Array(np.zeros((6 * (Ns + 1), 1)), iotype='in', desc='global force vector')) self.add( 'q', Array(np.zeros((6 * (Ns + 1), 1)), iotype='in', desc='deformation')) # outputs self.add( 'Finternal', Array(np.zeros((6, Ns + 1)), iotype='out', desc='internal forces')) self.add('strain', VarTree(Strain(Ns), iotype='out', desc='strains'))
class RotorStructureBase(Component): """ Base class for models that can predict blade deflections based on load distribution """ blade_disps = VarTree(BeamDisplacementsVT(), iotype='out', desc='Blade deflections and rotations')
class BoxParametricGeometry(Component): """A simple parametric geometry (a box)""" height = Float(2, iotype="in") volume = Float(8, iotype="in") geom_data = VarTree(GeomData(n_point=8, n_facet=6, facet_size=4), iotype="out") def __init__(self): super(BoxParametricGeometry, self).__init__() # color array. one color per face in this case self.colors = array( [ [0, 0, 255], # v0-v1-v2-v3 [255, 0, 0], # v0-v3-v4-v5 [0, 255, 0], # v0-v5-v6-v1 [255, 255, 0], # v1-v6-v7-v2 [255, 0, 255], # v7-v4-v3-v2 [0, 255, 255], # v4-v7-v6-v5 ], dtype=float32) # index array # each face has 2 triangles self.triangles = array([0, 1, 2, 0, 2, 3], dtype=int32) self.bbox = [-1., -1., -1., 1., 1., 1.] self.geom_data.facets = array( [ [0, 1, 2, 3], #front [0, 3, 4, 5], #right [0, 5, 6, 1], #top [1, 6, 7, 2], #left [7, 4, 3, 2], #bottom [4, 7, 6, 5], #back ], dtype="int") def execute(self): h = self.height x = h / 2. self.bbox = [-1, -1, -x, 1, 1, x] self.volume = 2 * 2 * h self.geom_data.points = array( [ [1, 1, x], [-1, 1, x], [-1, -1, x], [1, -1, x], # v0, v1, v2, v3 [1, -1, -x], [1, 1, -x], [-1, 1, -x], [-1, -1, -x], # v4, v5, v6, v7 ], dtype=float32)