class LoftedBladeSurfaceBase(Component): surfout = VarTree(BladeSurfaceVT(), iotype='out') surfnorot = VarTree(BladeSurfaceVT(), iotype='out')
class floris_windframe(Component): """ Calculates the locations of each turbine in the wind direction reference frame """ # original variables parameters = VarTree(FLORISParameters(), iotype='in') verbose = Bool(False, iotype='in', desc='verbosity of FLORIS, False is no output') # flow property variables wind_speed = Float(iotype='in', units='m/s', desc='free stream wind velocity') wind_direction = Float( iotype='in', units='deg', desc='wind direction using direction to, in deg. ccw from east') def __init__(self, nTurbines, resolution): print 'entering windframe __init__ - analytic' super(floris_windframe, self).__init__() # Explicitly size input arrays self.add('turbineX', Array(np.zeros(nTurbines), iotype='in', \ desc='x positions of turbines in original ref. frame')) self.add('turbineY', Array(np.zeros(nTurbines), iotype='in', \ desc='y positions of turbines in original ref. frame')) # variables for verbosity self.add('Ct', Array(np.zeros(nTurbines), iotype='in')) self.add('Cp', Array(np.zeros(nTurbines), iotype='in', \ desc='power coefficient for all turbines')) self.add('axialInduction', Array(np.zeros(nTurbines), iotype='in', dtype='float', \ desc='axial induction of all turbines')) self.add('yaw', Array(np.zeros(nTurbines), iotype='in', \ desc='yaw of each turbine')) # variables for testing wind speed at various locations self.add('ws_position', Array(np.zeros(resolution*resolution), iotype='in', units='m', \ desc='position of desired measurements in original ref. frame')) # Explicitly size output arrays self.add('wsw_position', Array(np.zeros(resolution*resolution), iotype='out', units='m', \ desc='position of desired measurements in wind ref. frame')) # for testing purposes only self.add('turbineXw', Array(np.zeros(nTurbines), iotype='out', units='m', \ desc='x coordinates of turbines in wind dir. ref. frame')) self.add('turbineYw', Array(np.zeros(nTurbines), iotype='out', units='m', \ desc='y coordinates of turbines in wind dir. ref. frame')) def execute(self): print 'entering windframe - analytic' if self.parameters.FLORISoriginal: ke = 0.065 keCorrCT = 0.0 # ignore these for now # keCorrTI = 0.0 # keCorrHR = 0.0 # keCorrHRTI = 0.0 keCorrArray = 0.0 kd = 0.15 # kdCorrYawDirection = 0.0 # ignored for now me = np.array([-0.5, 0.22, 1.0]) MU = np.array([0.5, 1.0, 5.5]) pP = 1.88 useWakeAngle = False initialWakeDisplacement = 4.5 bd = -0.01 useaUbU = True aU = 5.0 bU = 1.66 adjustInitialWakeDiamToYaw = False else: # rename inputs and outputs ke = self.parameters.ke keCorrCT = self.parameters.keCorrCT keCorrTI = self.parameters.keCorrTI keCorrHR = self.parameters.keCorrHR keCorrHRTI = self.parameters.keCorrHRTI keCorrArray = self.parameters.keCorrArray kd = self.parameters.kd kdCorrYawDirection = self.parameters.kdCorrYawDirection me = self.parameters.me MU = self.parameters.MU initialWakeDisplacement = self.parameters.initialWakeDisplacement useWakeAngle = self.parameters.useWakeAngle initialWakeAngle = self.parameters.initialWakeAngle bd = self.parameters.bd useaUbU = self.parameters.useaUbU aU = self.parameters.aU bU = self.parameters.bU adjustInitialWakeDiamToYaw = self.parameters.adjustInitialWakeDiamToYaw pP = self.parameters.pP baselineCT = self.parameters.baselineCT baselineTI = self.parameters.baselineTI keSaturation = self.parameters.keSaturation CTcorrected = self.parameters.CTcorrected CPcorrected = self.parameters.CPcorrected axialIndProvided = self.parameters.axialIndProvided Vinf = self.wind_speed windDirection = self.wind_direction * np.pi / 180.0 #variables to satisfy verbosity axialInd = self.axialInduction Cp = self.Cp Ct = self.Ct yaw = self.yaw * np.pi / 180 if self.verbose: np.set_printoptions(formatter={'float': '{: 0.3f}'.format}) print "wind direction %s deg" % [windDirection * 180.0 / np.pi] print "free-stream wind speed %s" % Vinf print "axial induction turbines %s" % axialInd print "C_P turbines %s" % Cp print "C_T turbines %s" % Ct print "yaw turbines %s" % yaw # get turbine positions and velocity sampling positions # position = self.position # turbineX = position[:, 0] # turbineY = position[:, 1] turbineX = self.turbineX turbineY = self.turbineY # print turbineX, turbineY if self.ws_position.any(): velX = self.ws_position[:, 0] velY = self.ws_position[:, 1] else: velX = np.zeros([0, 0]) velY = np.zeros([0, 0]) # convert to downwind-crosswind coordinates rotationMatrix = np.array([ (np.cos(-windDirection), -np.sin(-windDirection)), (np.sin(-windDirection), np.cos(-windDirection)) ]) # print 'rotation matrix = ', rotationMatrix turbineLocations = np.dot(rotationMatrix, np.array([turbineX, turbineY])) # print turbineLocations self.turbineXw = np.zeros(turbineX.size) self.turbineYw = np.zeros(turbineX.size) # print self.turbineXw self.turbineXw = turbineLocations[0] self.turbineYw = turbineLocations[1] #print 'windframe.turbineX = %s' %self.turbineX if velX.size > 0: locations = np.dot(rotationMatrix, np.array([velX, velY])) velX = locations[0] velY = locations[1] self.wsw_position = np.array([velX, velY]) #print 'wsw_position in windframe is:', self.wsw_position #print 'ws_position in windframe is:', self.ws_position # print self.turbineXw def list_deriv_vars(self): """specifies the inputs and outputs where derivatives are defined""" return ('turbineX', 'turbineY'), ('turbineXw', 'turbineYw') def provideJ(self): #print 'entering windframe - provideJ' n = np.size(self.turbineX) windDirection = self.wind_direction * np.pi / 180 dturbineXw_dturbineX = np.zeros([n, n]) dturbineXw_dturbineY = np.zeros([n, n]) dturbineYw_dturbineX = np.zeros([n, n]) dturbineYw_dturbineY = np.zeros([n, n]) for i in range(0, n): dturbineXw_dturbineX[i, i] = np.cos(-windDirection) dturbineXw_dturbineY[i, i] = -np.sin(-windDirection) dturbineYw_dturbineX[i, i] = np.sin(-windDirection) dturbineYw_dturbineY[i, i] = np.cos(-windDirection) JturbineXw = np.concatenate( (dturbineXw_dturbineX, dturbineXw_dturbineY), 1) JturbineYw = np.concatenate( (dturbineYw_dturbineX, dturbineYw_dturbineY), 1) J = np.concatenate((JturbineXw, JturbineYw), 0) return J
class Strains(Component): """ Computes internal forces and strains """ # inputs yN = Array(iotype='in', desc='') d = Array(iotype='in', desc='') k = Array(iotype='in', desc='Local elastic stiffness matrix') F = Array(iotype='in', desc='global force vector') q = Array(iotype='in', desc='deformation') # outputs Finternal = Array(iotype='out', desc='internal forces') strain = VarTree(Strain(), iotype='out', desc='strains') def execute(self): # short alias d = self.d Ns = len(self.yN) - 1 # number of elements dy = np.zeros((Ns, 1)) for s in range(1, Ns + 1): dy[s - 1] = self.yN[s] - self.yN[s - 1] # length of each element Ftemp = np.zeros((12, Ns)) Finternal = np.zeros((6, Ns + 1)) strain = Strain() strain.top = np.zeros((3, Ns + 1)) strain.bottom = np.zeros((3, Ns + 1)) strain.back = np.zeros((3, Ns + 1)) strain.front = np.zeros((3, Ns + 1)) strain.bending_x = np.zeros((1, Ns + 1)) strain.bending_z = np.zeros((1, Ns + 1)) strain.axial_y = np.zeros((1, Ns + 1)) strain.torsion_y = np.zeros((1, Ns + 1)) for s in range(Ns): # Determine internal forces acting at the nodes of each element Ftemp[:, s] = -(np.dot(self.k[:, :, s], self.q[s * 6:s * 6 + 12]) - self.F[s * 6:s * 6 + 12]).squeeze() Finternal[0, s] = Ftemp[0, s] # x-shear load Finternal[1, s] = Ftemp[1, s] # y-axial load Finternal[2, s] = Ftemp[2, s] # z-shear load Finternal[3, s] = Ftemp[3, s] # x-bending moment Finternal[4, s] = Ftemp[4, s] # y-torsional load Finternal[5, s] = Ftemp[5, s] # z-bending moment # Determine strains at each node x_hat = d[s] / 2 z_hat = d[s] / 2 r_hat = d[s] / 2 # Break out displacement vector for element qq = self.q[s * 6:s * 6 + 12] strain.bending_x[0, s] = np.dot( -np.array([(-(6 * x_hat) / (dy[s]**2)), ((4 * x_hat) / dy[s]), ((6 * x_hat) / (dy[s]**2)), ((2 * x_hat) / dy[s])]).reshape(1, -1), np.array([qq[0], qq[5], qq[6], qq[11]]).reshape(1, -1).T) strain.bending_z[0, s] = np.dot( -np.array([(-(6 * z_hat) / (dy[s]**2)), ((-4 * z_hat) / dy[s]), ((+6 * z_hat) / (dy[s]**2)), ((-2 * z_hat) / dy[s])]).reshape(1, -1), np.array([qq[2], qq[3], qq[8], qq[9]]).reshape(1, -1).T) strain.axial_y[0, s] = np.dot( np.array([(-1 / dy[s]), (1 / dy[s])]).reshape(1, -1), np.array([qq[1], qq[7]]).reshape(1, -1).T) strain.torsion_y[0, s] = np.dot( r_hat * np.array([(-1 / dy[s]), (1 / dy[s])]).reshape(1, -1), np.array([qq[4], qq[10]]).reshape(1, -1).T) strain.top[0, s] = strain.bending_z[0, s] + strain.axial_y[0, s] strain.top[1, s] = 0 strain.top[2, s] = strain.torsion_y[0, s] strain.bottom[0, s] = -strain.bending_z[0, s] + strain.axial_y[0, s] strain.bottom[1, s] = 0 strain.bottom[2, s] = strain.torsion_y[0, s] strain.back[0, s] = strain.bending_x[0, s] + strain.axial_y[0, s] strain.back[1, s] = 0 strain.back[2, s] = strain.torsion_y[0, s] strain.front[0, s] = -strain.bending_x[0, s] + strain.axial_y[0, s] strain.front[1, s] = 0 strain.front[2, s] = strain.torsion_y[0, s] # Loads at the tip are zero Finternal[0, Ns] = 0 # x-shear load Finternal[1, Ns] = 0 # y-axial load Finternal[2, Ns] = 0 # z-shear load Finternal[3, Ns] = 0 # x-bending moment Finternal[4, Ns] = 0 # y-torsional load Finternal[5, Ns] = 0 # z-bending moment # Strains at tip are zero strain.top[0, Ns] = 0 strain.top[1, Ns] = 0 strain.top[2, Ns] = 0 strain.bottom[0, Ns] = 0 strain.bottom[1, Ns] = 0 strain.bottom[2, Ns] = 0 strain.back[0, Ns] = 0 strain.back[1, Ns] = 0 strain.back[2, Ns] = 0 strain.front[0, Ns] = 0 strain.front[1, Ns] = 0 strain.front[2, Ns] = 0 # Strains at tip are zero strain.bending_x[0, Ns] = 0 strain.bending_z[0, Ns] = 0 strain.axial_y[0, Ns] = 0 strain.torsion_y[0, Ns] = 0 # set outputs self.Finternal = Finternal self.strain = strain
class Structures(Assembly): """ structural computation, first computes the mass of the helicopter based on the structural description of the spars and chord lengths. It then computes the deformation of the spars, the strains, and the resulting factor of safety for each of the failure modes. """ # flags flags = VarTree(Flags(), iotype='in') # inputs for spars yN = Array(iotype='in', desc='node locations for each element along the span') d = Array(iotype='in', desc='spar diameter') theta = Array(iotype='in', desc='wrap angle') nTube = Array(iotype='in', desc='number of tube layers') nCap = Array(iotype='in', desc='number of cap strips') lBiscuit = Array(iotype='in', desc='unsupported biscuit length') # joint properties Jprop = VarTree(JointProperties(), iotype='in') # inputs for chord b = Int(iotype='in', desc='number of blades') cE = Array(iotype='in', desc='chord of each element') xEA = Array(iotype='in', desc='') xtU = Array(iotype='in', desc='') # inputs for quad dQuad = Float(iotype='in', desc='diameter of quad rotor struts') thetaQuad = Float(iotype='in', desc='wrap angle of quad rotor struts') nTubeQuad = Int(iotype='in', desc='number of CFRP layers in quad rotor struts') lBiscuitQuad = Float(iotype='in', desc='') RQuad = Float( iotype='in', desc='distance from centre of helicopter to centre of quad rotors') hQuad = Float(iotype='in', desc='height of quad-rotor truss') # inputs for cover ycmax = Float(iotype='in', desc='') # inputs for wire yWire = Array(iotype='in', desc='location of wire attachment along span') zWire = Float(iotype='in', desc='depth of wire attachement') tWire = Float(iotype='in', desc='thickness of wire') TWire = Array(iotype='in', desc='') TEtension = Float(iotype='in', desc='') # inputs for 'other stuff' mElseRotor = Float(iotype='in', desc='') mElseCentre = Float(iotype='in', desc='') mElseR = Float(iotype='in', desc='') R = Float(iotype='in', desc='rotor radius') mPilot = Float(iotype='in', desc='mass of pilot') # inputs for FEM fblade = VarTree(Fblade(), iotype='in') presLoad = VarTree(PrescribedLoad(), iotype='in') def configure(self): self.add('spar', SparProperties()) self.connect('yN', 'spar.yN') self.connect('d', 'spar.d') self.connect('theta', 'spar.theta') self.connect('nTube', 'spar.nTube') self.connect('nCap', 'spar.nCap') self.connect('lBiscuit', 'spar.lBiscuit') self.connect('flags.CFRPType', 'spar.CFRPType') self.add('joint', JointSparProperties()) self.connect('flags.CFRPType', 'joint.CFRPType') self.connect('Jprop', 'joint.Jprop') self.add('chord', ChordProperties()) self.connect('yN', 'chord.yN') self.connect('cE', 'chord.c') self.connect('d', 'chord.d') self.connect('flags.GWing', 'chord.GWing') self.connect('xtU', 'chord.xtU') self.add('quad', QuadSparProperties()) self.connect('dQuad', 'quad.dQuad') self.connect('thetaQuad', 'quad.thetaQuad') self.connect('nTubeQuad', 'quad.nTubeQuad') self.connect('lBiscuitQuad', 'quad.lBiscuitQuad') self.connect('flags.CFRPType', 'quad.CFRPType') self.connect('RQuad', 'quad.RQuad') self.connect('hQuad', 'quad.hQuad') self.add('mass', MassProperties()) self.connect('flags', 'mass.flags') self.connect('b', 'mass.b') self.connect('spar.mSpar', 'mass.mSpar') self.connect('chord.mChord', 'mass.mChord') self.connect('chord.xCGChord', 'mass.xCGChord') self.connect('quad.mQuad', 'mass.mQuad') self.connect('xEA', 'mass.xEA') self.connect('ycmax', 'mass.ycmax') self.connect('zWire', 'mass.zWire') self.connect('yWire', 'mass.yWire') self.connect('tWire', 'mass.tWire') self.connect('mElseRotor', 'mass.mElseRotor') self.connect('mElseCentre', 'mass.mElseCentre') self.connect('mElseR', 'mass.mElseR') self.connect('R', 'mass.R') self.connect('mPilot', 'mass.mPilot') self.add('fem', FEM()) self.connect('flags', 'fem.flags') self.connect('yN', 'fem.yN') self.connect('spar.EIx', 'fem.EIx') self.connect('spar.EIz', 'fem.EIz') self.connect('spar.EA', 'fem.EA') self.connect('spar.GJ', 'fem.GJ') self.connect('cE', 'fem.cE') self.connect('xEA', 'fem.xEA') self.connect('spar.mSpar', 'fem.mSpar') self.connect('chord.mChord', 'fem.mChord') self.connect('mass.xCG', 'fem.xCG') self.connect('zWire', 'fem.zWire') self.connect('yWire', 'fem.yWire') self.connect('TWire', 'fem.TWire') self.connect('fblade', 'fem.fblade') self.connect('presLoad', 'fem.presLoad') self.add('strains', Strains()) self.connect('yN', 'strains.yN') self.connect('d', 'strains.d') self.connect('fem.k', 'strains.k') self.connect('fem.F', 'strains.F') self.connect('fem.q', 'strains.q') self.add('failure', Failures()) self.connect('flags', 'failure.flags') self.connect('yN', 'failure.yN') self.connect('strains.Finternal', 'failure.Finternal') self.connect('strains.strain', 'failure.strain') self.connect('d', 'failure.d') self.connect('theta', 'failure.theta') self.connect('nTube', 'failure.nTube') self.connect('nCap', 'failure.nCap') self.connect('yWire', 'failure.yWire') self.connect('zWire', 'failure.zWire') self.connect('joint.EIx', 'failure.EIxJ') self.connect('joint.EIz', 'failure.EIzJ') self.connect('lBiscuit', 'failure.lBiscuit') self.connect('dQuad', 'failure.dQuad') self.connect('thetaQuad', 'failure.thetaQuad') self.connect('nTubeQuad', 'failure.nTubeQuad') self.connect('lBiscuitQuad', 'failure.lBiscuitQuad') self.connect('RQuad', 'failure.RQuad') self.connect('hQuad', 'failure.hQuad') self.connect('quad.EIx', 'failure.EIQuad') self.connect('quad.GJ', 'failure.GJQuad') self.connect('tWire', 'failure.tWire') self.connect('TWire', 'failure.TWire') self.connect('TEtension', 'failure.TEtension') self.connect('b', 'failure.b') self.connect('fblade', 'failure.fblade') self.connect('spar.mSpar', 'failure.mSpar') self.connect('chord.mChord', 'failure.mChord') self.connect('mElseRotor', 'failure.mElseRotor') # link up the outputs self.create_passthrough('mass.Mtot') self.create_passthrough('fem.q') self.create_passthrough('strains.Finternal') self.create_passthrough('strains.strain') self.create_passthrough('failure.fail') self.driver.workflow.add('chord') self.driver.workflow.add('fem') self.driver.workflow.add('joint') self.driver.workflow.add('mass') self.driver.workflow.add('quad') self.driver.workflow.add('spar') self.driver.workflow.add('strains') self.driver.workflow.add('failure')
def __init__(self, Ns): super(LiftDrag, self).__init__() # inputs self.add('Ns', Int(0, iotype="in", desc="number of Elements")) self.add('yN', Array(np.zeros(Ns + 1), iotype="in", desc='node locations')) self.add('rho', Float(0., iotype='in', desc='air density')) self.add('visc', Float(0., iotype='in', desc='air viscosity')) self.add('vw', Float(0., iotype='in', desc='wind')) self.add('vc', Float(0., iotype='in', desc='vertical velocity')) self.add('Omega', Float(0., iotype='in', desc='Rotor angular velocity')) self.add( 'r', Array(np.zeros(Ns), iotype='in', desc='radial location of each element')) self.add( 'vi', Array(np.zeros(Ns), iotype='in', desc='induced downwash distribution')) self.add('c', Array(np.zeros(Ns), iotype='in', desc='chord distribution')) self.add( 'Cl', Array(np.zeros(Ns), iotype='in', desc='lift coefficient distribution')) self.add( 'dr', Array(np.zeros(Ns), iotype='in', desc='length of each element')) self.add( 'd', Array(np.zeros(Ns), iotype='in', desc='spar diameter distribution')) self.add( 'yWire', Array([0], iotype='in', desc='location of wire attachment along span')) self.add('zWire', Float(0., iotype='in', desc='depth of wire attachement')) self.add('tWire', Float(0., iotype='in', desc='thickness of wire')) self.add('chordFrac', Array(np.zeros(Ns), iotype='in', desc='')) self.add('Cm', Array(np.zeros(Ns), iotype='in', desc='')) self.add( 'xtU', Array(np.zeros(Ns), iotype='in', desc='fraction of laminar flow on the upper surface')) self.add( 'xtL', Array(np.zeros(Ns), iotype='in', desc='fraction of laminar flow on the lower surface')) # outputs self.add('Re', Array(np.zeros(Ns), iotype='out', desc='Reynolds number')) self.add('Cd', Array(np.zeros(Ns), iotype='out', desc='drag coefficients')) self.add('phi', Array(np.zeros(Ns), iotype='out', desc='')) self.add('Fblade', VarTree(Fblade(Ns), iotype='out', desc=''))
def add_section(self, name): self.add(name, VarTree(SectionVT()))
class openwind_assembly(Assembly): # todo: has to be assembly or manipulation and passthrough of aep in execute doesnt work """ Runs OpenWind from OpenMDAO framework """ # Inputs hub_height = Float(90.0, iotype='in', desc='turbine hub height', unit='m') rotor_diameter = Float(126.0, iotype='in', desc='turbine rotor diameter', unit='m') power_curve = Array([], iotype='in', desc='wind turbine power curve') rpm = Array([], iotype='in', desc='wind turbine rpm curve') ct = Array([], iotype='in', desc='wind turbine ct curve') machine_rating = Float(6000.0, iotype='in', desc='wind turbine rated power', unit='kW') availability = Float(0.941, iotype='in', desc='wind plant availability') wt_layout = VarTree(GenericWindFarmTurbineLayout(), iotype='in', desc='properties for each wind turbine and layout') other_losses = Float(0.0, iotype='in', desc='wind plant losses due to blade soiling, etc') dummyVbl = Float(0, iotype='in', desc='unused variable to make it easy to do DOE runs') # TODO: loss inputs # TODO: wake model option selections # Outputs # inherits output vbls net_aep and gross_aep from GenericAEPModel - NOT when using fusedwind implement_base gross_aep = Float(0.0, iotype='out', desc='Gross Output') net_aep = Float(0.0, iotype='out', desc='Net Output') #ideal_aep = Float(0.0, iotype='out', desc='Ideal Annual Energy Production before topographic, availability and loss impacts', unit='kWh') array_aep = Float(0.0, iotype='out', desc='Gross Annual Energy Production net of array impacts', unit='kWh') array_losses = Float(0.0, iotype='out', desc='Array Losses') capacity_factor = Float(0.0, iotype='out', desc='capacity factor') turbine_number = Int(100, iotype='out', desc='plant number of turbines') # ------------------- def __init__(self, openwind_executable, workbook_path, turbine_name=None, script_file=None, machine_rating=None, academic=False, debug=False): """ Creates a new LCOE Assembly object """ foundErrors = False if not os.path.isfile(openwind_executable): sys.stderr.write('\n*** ERROR: executable {:} not found\n\n'.format(openwind_executable)) foundErrors = True if not os.path.isfile(workbook_path): sys.stderr.write('\n*** ERROR: workbook {:} not found\n\n'.format(workbook_path)) foundErrors = True if foundErrors: return None # Set the location where new scripts and turbine files will be written self.workDir = os.getcwd() #self.workDir = os.path.dirname(os.path.realpath(__file__)) # location of this source file self.openwind_executable = openwind_executable self.workbook_path = workbook_path self.turbine_name = turbine_name self.script_file = script_file self.academic = academic self.debug = debug if machine_rating is not None: self.machine_rating = machine_rating super(openwind_assembly, self).__init__() # TODO: hack for now assigning turbine self.turb = GenericWindTurbinePowerCurveVT() self.turb.power_rating = self.machine_rating self.turb.hub_height = self.hub_height self.turb.power_curve = np.copy(self.power_curve) for i in xrange(0,self.turbine_number): self.wt_layout.wt_list.append(self.turb) # ------------------- def configure(self): """ Add Openwind external code component """ super(openwind_assembly, self).configure() '''if self.academic: #ow = OWACwrapped(self.openwind_executable, scriptFile=self.script_file, debug=True) sys.stderr.write('\nERROR - openwind_assembly.py not currently configured for Academic version\n') sys.stderr.write('Use ../Academic/openwindAC_assembly.py instead\n') quit() else:''' ow = OWwrapped(self.openwind_executable, scriptFile=self.script_file, debug=self.debug) self.add('ow', ow) self.driver.workflow.add(['ow']) # Inputs to OWwrapped #self.connect('rotor_diameter', 'ow.rotor_diameter') # todo: hack to force external code execution self.connect('other_losses', 'ow.other_losses') self.connect('availability', 'ow.availability') self.connect('dummyVbl', 'ow.dummyVbl') # Outputs from OWwrapped self.connect('ow.array_losses', 'array_losses') self.connect('ow.gross_aep', 'gross_aep') self.connect('ow.array_aep', 'array_aep') self.connect('ow.net_aep', 'net_aep') self.connect('ow.turbine_number', 'turbine_number') # ------------------- def execute(self): """ Set up XML and run OpenWind #This will leave OW running - use the File/Exit button to shut it down until # Nick comes up with a way to stop it from the script. # 20140326: OW now has Exit operation in scripter """ if self.debug: sys.stderr.write("In {0}.execute()...\n".format(self.__class__)) report_path = self.workDir + '/' + 'scrtest1.txt' workbook_path = self.workbook_path turbine_name = self.turbine_name # Prepare for next iteration here... # - write new scripts # - write new turbine files # - etc. #turbine_path = self.workDir + '/' + 'Turbine_Model.owtg' #self.writeNewTurbine('Turbine_Model.owtg') # write new script for execution # newScriptName = 'OpenWind_Script.xml' # self.writeNewScript(newScriptName) # self.command[1] = newScriptName # will actually run the workflow super(openwind_assembly, self).execute() # calculate capacity factor # - assumes that all turbines have the same power rating # and that self.wt_layout is correct #self.capacity_factor = ((self.net_aep) / (self.wt_layout.wt_list[0].power_rating * 8760.0 * self.turbine_number)) # 8766 hrs = 365.25 days to agree with OpenWind self.capacity_factor = ((self.net_aep) / (self.wt_layout.wt_list[0].power_rating * 8766.0 * self.turbine_number)) # ------------------- def writeNewTurbine(self, turbFileName): ''' Set up turbine to write to xml ''' rho = [1.225] vels = [float(i) for i in range(26)] # power table power = [] for i in xrange(0,4): power.append(0.0) counter = 5.0 for i in xrange(5,26): myi = min(range(self.power_curve.shape[1]), key=lambda i: abs(self.power_curve[0][i]-counter)) power.append(self.power_curve[1][myi]) counter += 1.0 power.append(self.power_curve[1][-1]) # thrust table thrust = [] for i in xrange(0,4): thrust.append(1.0) counter = 5.0 for j in xrange(5,26): myi = min(range(self.ct.shape[1]), key=lambda i: abs(self.ct[0][i]-counter)) thrust.append(self.ct[1][myi]) counter += 1.0 thrust.append(self.ct[1][0]) # RPM table rpm = [] for i in xrange(0,4): rpm.append(0.0) counter = 5.0 for j in xrange(5,26): myi = min(range(self.rpm.shape[1]), key=lambda i: abs(self.rpm[0][i]-counter)) rpm.append(self.rpm[1][myi]) counter += 1.0 rpm.append(self.rpm[1][-1]) percosts = [] cut_in_wind_speed = 4.0 cut_out_wind_speed = 25.0 blade_number = 3 turbine_cost = 2000000 foundation_cost = 100000 turbine_name = 'NewTurbine' desc = 'New Turbine' turbtree = rwTurbXML.getTurbTree(turbine_name, desc, \ vels, power, thrust, rpm, \ self.hub_height, self.rotor_diameter, rho, \ percosts, cut_in_wind_speed, cut_out_wind_speed, \ blade_number, self.machine_rating, turbine_cost, foundation_cost) turbXML = etree.tostring(turbtree, xml_declaration=True, doctype='<!DOCTYPE {:}>'.format(turbine_name), pretty_print=True) ofh = open(self.workDir + '/' + turbFileName, 'w') ofh.write(turbXML) ofh.close() # ------------------- def writeNewScript(self, scriptFileName): ''' Write a new XML script to scriptFileName and use that as the active script for OpenWind Operations are: load workbook, replace turbine, energy capture, exit ''' script_tree, operations = rwScriptXML.newScriptTree(self.report_path) # add operations to 'operations' (the 'AllOperations' tree in script_tree) rwScriptXML.makeChWkbkOp(operations,self.workbook_path) # change workbook rwScriptXML.makeRepTurbOp(operations,turbine_name,turbine_path) # replace turbine rwScriptXML.makeEnCapOp(operations) # run energy capture rwScriptXML.makeExitOp(operations) # exit script_XML = etree.tostring(script_tree, xml_declaration=True, doctype='<!DOCTYPE OpenWindScript>', pretty_print=True) self.ow.script_file = self.workDir + '/' + scriptFileName ofh = open(thisdir + '/' + self.ow.script_file, 'w') ofh.write(script_XML) ofh.close() # ------------------- def updateRptPath(self, rptPathName, newScriptName): ''' Writes a new script file and sets internal script name New script writes to 'rptPathName' rptPathName should be a full path name (if possible) ''' if not hasattr(self,'ow'): sys.stderr.write("{:}: 'ow' not defined yet (missing script file?)\n".format(self.__class__)) raise RuntimeError("OpenWind wrapped executable not defined") return e = rwScriptXML.parseScript(self.ow.script_file, debug=self.debug) rp = e.find("ReportPath") if rp is None: sys.stderr.write('Can\'t find report path in "{:}"\n'.format(self.ow.script_file)) return if self.debug: sys.stderr.write('Changing report path from "{:}" to "{:}"\n'.format(rp.get('value'),rptPathName)) rp.set('value',rptPathName) rwScriptXML.wrtScript(e, newScriptName) self.ow.script_file = self.workDir + '/' + newScriptName if self.debug: sys.stderr.write('Wrote new script file "{:}"\n'.format(self.ow.script_file))
class HAWC2VarTrees(VariableTree): sim = VarTree(HAWC2Simulation()) wind = VarTree(HAWC2Wind()) aero = VarTree(HAWC2Aero()) aerodrag = VarTree(HAWC2AeroDrag()) blade_ae = VarTree(HAWC2BladeGeometry()) blade_structure = List() airfoildata = VarTree(HAWC2AirfoilData()) output = VarTree(HAWC2OutputVT()) rotor = VarTree(RotorVT()) nacelle = VarTree(NacelleVT()) generator = VarTree(GeneratorVT()) tower = VarTree(TowerVT()) shaft = VarTree(ShaftVT()) hub = VarTree(HubVT()) body_order = List() main_bodies = VarTree(HAWC2MainBodyList()) dlls = VarTree(HAWC2Type2DLLList()) h2s = VarTree(HAWC2SVar())
from openmdao.main.api import Component, VariableTree from openmdao.lib.datatypes.api import Float, VarTree #Variable Tree definition class Gas(VariableTree): #default to helium cost = Float(6.452, desc='Cost in $USD, #/m^3, NASA Praxair Quote', units='USD/m**3') rho_stp = Float(0.1664, desc='density at Standard TP 273.15 and 1 atm', units='kg/m**3') rho_ntp = Float(0.1786, desc='density at Normal TP 293.15 K and 1 atm', units='kg/m**3') #Library Values #http://www.engineeringtoolbox.com/gas-density-d_158.html #Helium helium = VarTree(Gas(), iotype='in') helium.cost = 6.452 helium.rho_ntp = 0.1664 helium.rho_stp = 0.1786 #Hydrogen hydrogen = VarTree(Gas(), iotype='in') hydrogen.cost = 1.14 hydrogen.rho_ntp = 0.0899 hydrogen.rho_stp = 0.0899 #Air air = VarTree(Gas(), iotype='in') air.cost = 0 air.rho_ntp = 1.205 air.rho_stp = 1.293
class HAWC2GeometryBuilder(Component): bladegeom = VarTree(BladePlanformVT(), iotype='in') c12axis_init = Array(iotype='in') blade_ae = VarTree(HAWC2BladeGeometry(), iotype='out') interp_from_htc = Bool( True, iotype='in', desc= 'Interpolate blade onto the distribution defined in the htc master file' ) blade_ni_span = Int(30, iotype='in', desc='spanwise distribution of blade planform') blade_length = Float(86.366, iotype='in') hub_radius = Float(2.8, iotype='in') def execute(self): c12axis = self.calculate_c12axis() if self.interp_from_htc: cni = self.c12axis_init.shape[0] if self.c12axis_init[-1, 2] > 1.: self.c12axis_init /= self.blade_length # interpolate blade_ae distribution onto c12 distribution self.blade_ae.c12axis = np.zeros((cni, 4)) for i in range(4): tck = pchip(c12axis[:, 2], c12axis[:, i]) self.blade_ae.c12axis[:, i] = tck(self.c12axis_init[:, 2]) else: ds_root = 1. / self.blade_ni_span ds_tip = 1. / self.blade_ni_span / 3. dist = np.array([[0., ds_root, 1], [1., ds_tip, self.blade_ni_span]]) x = distfunc(dist) self.blade_ae.c12axis = np.zeros((x.shape[0], 4)) for i in range(4): tck = pchip(c12axis[:, 2], c12axis[:, i]) self.blade_ae.c12axis[:, i] = tck(x) # scale main axis according to radius self.blade_ae.c12axis[:, :3] *= self.blade_length self.blade_ae.radius = self.blade_length + self.hub_radius self.blade_ae.s = self.bladegeom.smax * self.bladegeom.s * self.blade_length self.blade_ae.rthick = self.bladegeom.rthick * 100. self.blade_ae.chord = self.bladegeom.chord * self.blade_length self.blade_ae.aeset = np.ones(len(self.blade_ae.s)) def calculate_c12axis(self): """ compute the 1/2 chord axis based on the blade axis and chordwise rotation point nb: this only works for straight blades! """ # The HAWC2 blade axis is defined using the 1/2 chord points b = self.bladegeom c12axis = np.zeros((b.x.shape[0], 4)) for i in range(b.x.shape[0]): xc12 = (0.5 - b.p_le[i]) * b.chord[i] * np.cos( b.rot_z[i] * np.pi / 180.) yc12 = -(0.5 - b.p_le[i]) * b.chord[i] * np.sin( b.rot_z[i] * np.pi / 180.) c12axis[i, 0] = -(b.x[i] + xc12) c12axis[i, 1] = b.y[i] + yc12 c12axis[i, 2] = b.z[i] c12axis[:, 3] = b.rot_z return c12axis
class FullBOSCostAggregator(Component): """ Full balance of station cost aggregator for doing some auxiliary cost calculations needed to get a full wind plant balance of station cost estimate as well as a detailed cost breakdown. """ # outputs bos_breakdown = VarTree(FullBOSVarTree(), iotype='out', desc='BOS cost breakdown') bos_costs = Float(iotype='out', desc='Output BOS cost elements')
class ExtendedBOSCostModel(Assembly): """ Extended balance of station cost assembly for coupling models to get a full wind plant balance of station cost estimate as well as a detailed cost breakdown. """ # Outputs bos_breakdown = VarTree(BOSVarTree(), iotype='out', desc='BOS cost breakdown') bos_costs = Float(iotype='out', desc='Overall wind plant balance of station/system costs up to point of comissioning')
class ExtendedBOSCostAggregator(Component): """ Extended balance of station cost aggregator for doing some auxiliary cost calculations needed to get a full wind plant balance of station cost estimate as well as a detailed cost breakdown. """ # Outputs bos_breakdown = VarTree(BOSVarTree(), iotype='out', desc='BOS cost breakdown') bos_costs = Float(iotype='out', desc='Overall wind plant balance of station/system costs up to point of comissioning')
class FullBOSCostModel(Assembly): # outputs bos_breakdown = VarTree(FullBOSVarTree(), iotype='out', desc='BOS cost breakdown') bos_costs = Float(iotype='out', desc='Output BOS cost elements')
class BladeStructureWriterBase(Component): st3d = VarTree( BladeStructureVT3D(), iotype='in', desc='Vartree containing discrete definition of blade structure')
class HAWC2Type2DLL(VariableTree): name = Str( desc='Reference name of this DLL (to be used with DLL output commands)' ) filename = Str( desc= 'Filename incl. relative path of the DLL (example ./DLL/control.dll)') dll_subroutine_init = Str( desc='Name of initialization subroutine in DLL that is addressed' '(remember to specify the name in the DLL with small letters!)') dll_subroutine_update = Str( desc='Name of subroutine in DLL that is addressed at every time step' '(remember to specify the name in the DLL with small letters!)') arraysizes_init = List( desc= 'size of array with outgoing/ingoing data in the initialization call') arraysizes_update = List( desc='size of array with outgoing/ingoing data in the update call') deltat = Float(desc='Time between dll calls.') dll_init = VarTree(HAWC2Type2DLLinit(), desc='Slot for DLL specific variable tree') output = VarTree(HAWC2Type2DLLoutput(), desc='Outputs for DLL specific variable tree') actions = VarTree(HAWC2Type2DLLoutput(), desc='Actions for DLL specific variable tree') def set_init(self, name): """ sets the parameters slot with the VariableTree corresponding to the name string defined in the type2_dll interface """ try: klass = type2_dll_dict[name] self.dll_init = klass() except: self._logger.warning( 'No init vartree available for %s, falling back on default HAWC2Type2DLLinit' % self.name) return self.dll_init def set_output(self, name): """ sets the parameters slot with the VariableTree corresponding to the name string defined in the type2_dll interface """ try: klass = type2_dll_out_dict[name] self.output = klass() except: self._logger.warning( 'No output vartree available for %s, falling back on default HAWC2Type2DLLoutput' % self.name) return self.output def set_actions(self, name): """ sets the parameters slot with the VariableTree corresponding to the name string defined in the type2_dll interface """ try: klass = type2_dll_action_dict[name] self.actions = klass() except: self._logger.warning( 'No actions vartree available for %s, falling back on default HAWC2Type2DLLoutput' % self.name) return self.actions
class BladeStructureWriter(Component): """ input file writer of BladeStructureVT3D data """ filebase = Str('blade', iotype='in') st3d = VarTree(BladeStructureVT3D(), iotype='in') def execute(self): try: if '-fd' in self.itername or '-fd' in self.parent.itername: return else: self.fbase = self.filebase + '_' + str(self.exec_count) except: self.fbase = self.filebase self.fbase = self.filebase self.write_layup_data() self.write_materials() def write_materials(self): fid = open(self.fbase + '.mat', 'w') fid.write('# %s\n' % (' '.join(self.st3d.materials.keys()))) fid.write('# E1 E2 E3 nu12 nu13 nu23 G12 G13 G23 rho\n') matdata = [] for name, mat in self.st3d.materials.iteritems(): data = np.array([ mat.E1, mat.E2, mat.E3, mat.nu12, mat.nu13, mat.nu23, mat.G12, mat.G13, mat.G23, mat.rho ]) matdata.append(data) np.savetxt(fid, np.asarray(matdata)) failcrit = dict(maximum_strain=1, maximum_stress=2, tsai_wu=3) fid = open(self.fbase + '.failmat', 'w') fid.write('# %s\n' % (' '.join(self.st3d.materials.keys()))) fid.write('# failcrit s11_t s22_t s33_t s11_c s22_c s33_c' 't12 t13 t23 e11_c e22_c e33_c e11_t e22_t e33_t g12 g13 g23' 'gM0 C1a C2a C3a C4a\n') matdata = [] for name, mat in self.st3d.materials.iteritems(): data = np.array([ failcrit[mat.failure_criterium], mat.s11_t, mat.s22_t, mat.s33_t, mat.s11_c, mat.s22_c, mat.s33_c, mat.t12, mat.t13, mat.t23, mat.e11_c, mat.e22_c, mat.e33_c, mat.e11_t, mat.e22_t, mat.e33_t, mat.g12, mat.g13, mat.g23, mat.gM0, mat.C1a, mat.C2a, mat.C3a, mat.C4a ]) matdata.append(data) fmt = '%i ' + ' '.join(23 * ['%.20e']) np.savetxt(fid, np.asarray(matdata), fmt=fmt) def write_layup_data(self): DPs = [] fid1 = open(self.fbase + '.dp3d', 'w') fid1.write('# %s\n' % (' '.join(self.st3d.webs))) for web in self.st3d.iwebs: fid1.write('# %i %i\n' % (web[0], web[1])) fid1.write('# s %s\n' % (' '.join(self.st3d.DPs))) DPs.append(self.st3d.x) for i, rname in enumerate(self.st3d.regions): self._logger.info(' writing region: %s' % rname) reg = getattr(self.st3d, rname) DP = getattr(self.st3d, 'DP%02d' % (i)) DPs.append(DP) fname = '_'.join([self.fbase, rname]) + '.st3d' fid = open(fname, 'w') lnames = ' '.join(reg.layers) fid.write('# %s\n' % rname) fid.write('# s %s\n' % lnames) data = [] data.append(self.st3d.x) for lname in reg.layers: self._logger.info(' writing layer: %s' % lname) layer = getattr(reg, lname) data.append(layer.thickness) for lname in reg.layers: self._logger.info(' writing layer: %s' % lname) layer = getattr(reg, lname) data.append(layer.angle) data = np.asarray(data).T np.savetxt(fid, data) fid.close() DPs.append(getattr(self.st3d, 'DP%02d' % (i + 1))) DPs = np.asarray(DPs).T np.savetxt(fid1, DPs) for i, wname in enumerate(self.st3d.webs): self._logger.info(' writing web: %s' % rname) reg = getattr(self.st3d, wname) fname = '_'.join([self.fbase, wname]) + '.st3d' fid = open(fname, 'w') lnames = ' '.join(reg.layers) fid.write('# %s\n' % wname) fid.write('# s %s\n' % lnames) data = [] data.append(self.st3d.x) for lname in reg.layers: self._logger.info(' writing layer: %s' % lname) layer = getattr(reg, lname) data.append(layer.thickness) for lname in reg.layers: self._logger.info(' writing layer: %s' % lname) layer = getattr(reg, lname) data.append(layer.angle) data = np.asarray(data).T np.savetxt(fid, data) fid.close()
class WeibullWindRose(Component): """Calculates the frequency_array using a weibull distribution""" wind_directions = List(iotype='in', units='deg', desc='Direction sectors angles [n_wd]') wind_speeds = List(iotype='in', units='m/s', desc='wind speeds sectors [n_ws]') wind_rose_array = Array( [], iotype='in', units='m/s', desc='Windrose array [wind_directions, frequency, weibull_A, weibull_k]' ) cut_in = Float(4.0, iotype='in', desc='The cut-in wind speed of the wind turbine') cut_out = Float(25.0, iotype='in', desc='The cut-out wind speed of the wind turbine') wind_rose = VarTree(GenericWindRoseVT(), iotype='out', desc='A wind rose VT') @property def n_wd(self): """Number of wind direction bins""" return len(self.wind_directions) @property def n_ws(self): """Number of wind speed bins""" return len(self.wind_speeds) def test_consistency_inputs(self): """Test the consistency of the inputs. This will be optimized away in production""" assert len(self.wind_rose_array) > 0,\ 'wind_rose_array is empty: %r' % self.wind_rose_array assert len(self.wind_speeds) > 0,\ 'wind_speeds is empty: %r' % self.wind_speeds assert len(self.wind_directions) > 0,\ 'wind_directions is empty: %r' % self.wind_directions assert isinstance(self.wind_rose_array, ndarray),\ 'The wind rose array is a ndarray of 4 columns' assert self.wind_rose_array.shape[1] == 4,\ 'wind_rose_array = array([wind_directions, frequency, weibull_A, weibull_k])' assert mean(self.wind_directions) > 20.0,\ 'Wind direction should be given in degrees' assert self.wind_rose_array[:, 0].mean() > 20.0,\ 'The first column of wind_rose should be in degrees' assert 1.0 - sum(self.wind_rose_array[:, 1]) < 1.0E-3,\ 'The second column of self.wind_rose_array should sum to 1.0' def test_consistency_outputs(self): """Test the consistency of the outputs. This will be optimized away in production""" assert sum(self.wind_rose.frequency_array.flatten()) <= 1.0 + 1.0E-3, \ 'The frequency array should never reach 1.0, because there are some high wind speeds not considered in the array.' def execute(self): """Calculate the new wind_rose""" if len(self.wind_rose_array) == 0: return self.test_consistency_inputs() self._directions = self.wind_rose_array[:, 0] _direction_frequency = self.wind_rose_array[:, 1] self._weibull_A = self.wind_rose_array[:, 2] self._weibull_k = self.wind_rose_array[:, 3] # Creating the interpolation functions indis = range(self.wind_rose_array.shape[0]) indis.extend([0]) _d_wd = self._directions[1] - self._directions[0] diff_dir = _direction_frequency[indis] / _d_wd directions = self._directions.tolist() + [360.0] def corr_dir(d): if d < 0.0: return d + 360.0 if d >= 360.0: return d - 360.0 return d pdf_wd = interp1d(directions, diff_dir, kind='linear') pdf_wd_ext = lambda d: pdf_wd(corr_dir(d)) weibull_A = interp1d(directions, self._weibull_A[indis], kind='linear') weibull_k = interp1d(directions, self._weibull_k[indis], kind='linear') self.wind_rose.wind_directions = self.wind_directions self.wind_rose.wind_speeds = self.wind_speeds # Statistical functions pdf_ws = lambda A, k, u: k / A * \ (u / A) ** (k - 1.0) * exp(-(u / A) ** k) #cdf_ws = lambda A,k,u, bin=1.0: exp(-(max(0.0, u-bin/2.0)/A)**k) - exp(-((u+bin/2.0)/A)**k) cdf_ws = lambda A, k, u0, u1: exp(-(u0 / A)**k) - exp(-(u1 / A)**k) # TODO: Fine tune this epsrel cdf_wd = lambda wd0, wd1: quad(pdf_wd_ext, wd0, wd1, epsrel=0.1)[0] # Create the array self.wind_rose.frequency_array = zeros([self.n_wd, self.n_ws]) for iwd, wd in enumerate(self.wind_directions): A = weibull_A(wd) k = weibull_k(wd) # We include all the wind directions between each wind directions if iwd == 0: wd0 = 0.5 * (self.wind_directions[-1] + wd + 360) else: wd0 = 0.5 * (self.wind_directions[iwd - 1] + wd) if iwd == len(self.wind_directions) - 1: wd1 = 0.5 * (self.wind_directions[0] + wd + 360) else: wd1 = 0.5 * (self.wind_directions[iwd + 1] + wd) if wd0 > wd1: # deal with the 360-0 issue P_dir = cdf_wd(wd0, 359.99) + cdf_wd(0.0, wd1) else: P_dir = cdf_wd(wd0, wd1) # print 'between', wd0, wd1, P_dir for iws, ws in enumerate(self.wind_speeds): if iws == 0: # We include all the cases from cut_in ws0 = self.cut_in else: ws0 = 0.5 * (self.wind_speeds[iws - 1] + ws) if iws == len(self.wind_speeds) - 1: ws1 = self.cut_out else: ws1 = 0.5 * (self.wind_speeds[iws + 1] + ws) ws0 = min(self.cut_out, max(self.cut_in, ws0)) ws1 = min(self.cut_out, max(self.cut_in, ws1)) self.wind_rose.frequency_array[iwd, iws] = P_dir * cdf_ws( A, k, ws0, ws1) self.test_consistency_outputs()
class BeamStructureReaderBase(Component): beamprops = VarTree(BeamStructureVT(), iotype='out')
def add_region(self, name): self.add(name, VarTree(RegionVT())) self.regions.append(name)
class SplinedBladeStructure(Assembly): """ Class for building a complete spline parameterized representation of the blade structure. Outputs a BladeStructureVT3D vartree with a discrete representation of the structural geometry. Interface with a BladeStructureBuilder class for generating code specific inputs. """ x = Array(iotype='in', desc='spanwise resolution of blade') span_ni = Int(20, iotype='in', desc='Number of discrete points along span') nC = Int(8, iotype='in', desc='Number of spline control points along span') Cx = Array(iotype='in', desc='spanwise distribution of spline control points') st3dIn = VarTree( BladeStructureVT3D(), iotype='in', desc='Vartree containing initial discrete definition of blade structure' ) st3dOut = VarTree( BladeStructureVT3D(), iotype='out', desc= 'Vartree containing re-splined discrete definition of blade structure') def __init__(self): """ initialize the blade structure parameters ----------- nsec: int total number of sections in blade """ super(SplinedBladeStructure, self).__init__() self._nsec = 0 self.add('pf', RedistributedBladePlanform()) self.driver.workflow.add('pf') self.create_passthrough('pf.pfIn') self.create_passthrough('pf.pfOut.blade_length') self.connect('x', 'pf.x') def configure_bladestructure(self): """ method for trawling through the st3dIn vartree and initializing all spline curves in the assembly """ if self.x.shape[0] == 0: self.x = np.linspace(0, 1, self.span_ni) else: self.span_ni = self.x.shape[0] if self.Cx.shape[0] == 0: self.Cx = np.linspace(0, 1, self.nC) else: self.nC = self.Cx.shape[0] self.st3dOut = self.st3dIn.copy() self.connect('x', 'st3dOut.x') sec = self.st3dIn nr = len(sec.regions) for ip in range(nr + 1): dpname = 'DP%02d' % ip # division point spline DPc = self.add(dpname, FFDSplineComponentBase(self.nC)) self.driver.workflow.add(dpname) # DPc.log_level = logging.DEBUG x = getattr(sec, 'x') DP = getattr(sec, dpname) self.connect('x', '%s.x' % dpname) self.connect('Cx', dpname + '.Cx') DPc.xinit = x DPc.Pinit = DP self.connect(dpname + '.P', '.'.join(['st3dOut', dpname])) self.create_passthrough(dpname + '.C', alias=dpname + '_C') # regions if ip < nr: rname = 'region%02d' % ip region = getattr(sec, rname) for lname in region.layers: layer = getattr(region, lname) lcname = 'r%02d%s' % (ip, lname) # thickness spline lcomp = self.add(lcname + 'T', FFDSplineComponentBase(self.nC)) self.driver.workflow.add(lcname + 'T') # lcomp.log_level = logging.DEBUG self.connect('x', '%s.x' % (lcname + 'T')) lcomp.xinit = sec.x lcomp.Pinit = layer.thickness self.connect('Cx', lcname + 'T' + '.Cx') self.connect( '%sT.P' % lcname, '.'.join(['st3dOut', rname, lname, 'thickness'])) # angle spline lcomp = self.add(lcname + 'A', FFDSplineComponentBase(self.nC)) self.driver.workflow.add(lcname + 'A') # lcomp.log_level = logging.DEBUG self.connect('x', '%s.x' % (lcname + 'A')) self.create_passthrough(lcname + 'T' + '.C', alias=lcname + 'T' + '_C') lcomp.xinit = sec.x lcomp.Pinit = layer.angle self.connect('Cx', lcname + 'A' + '.Cx') self.connect('%sA.P' % lcname, '.'.join(['st3dOut', rname, lname, 'angle'])) self.create_passthrough(lcname + 'A' + '.C', alias=lcname + 'A' + '_C') # shear webs for wname in sec.webs: web = getattr(sec, wname) for lname in web.layers: layer = getattr(web, lname) lcname = '%s%s' % (wname, lname) # thickness spline lcomp = self.add(lcname + 'T', FFDSplineComponentBase(self.nC)) # lcomp.log_level = logging.DEBUG self.driver.workflow.add(lcname + 'T') self.connect('x', '%s.x' % (lcname + 'T')) lcomp.xinit = sec.x lcomp.Pinit = layer.thickness self.connect('Cx', lcname + 'T' + '.Cx') self.connect('%sT.P' % lcname, '.'.join(['st3dOut', wname, lname, 'thickness'])) self.create_passthrough(lcname + 'T' + '.C', alias=lcname + 'T' + '_C') # angle spline lcomp = self.add(lcname + 'A', FFDSplineComponentBase(self.nC)) # lcomp.log_level = logging.DEBUG self.driver.workflow.add(lcname + 'A') self.connect('x', '%s.x' % (lcname + 'A')) lcomp.xinit = sec.x lcomp.Pinit = layer.angle self.connect('Cx', lcname + 'A' + '.Cx') self.connect('%sA.P' % lcname, '.'.join(['st3dOut', wname, lname, 'angle'])) self.create_passthrough(lcname + 'A' + '.C', alias=lcname + 'A' + '_C') # copy materials to output VT self.st3dOut.materials = self.st3dIn.materials.copy() def _post_execute(self): """ update all thicknesses and region widths """ super(SplinedBladeStructure, self)._post_execute() for i, rname in enumerate(self.st3dOut.regions): region = getattr(self.st3dOut, rname) DP0 = getattr(self.st3dOut, 'DP%02d' % i) DP1 = getattr(self.st3dOut, 'DP%02d' % (i + 1)) width = DP1 - DP0 for ix in range(width.shape[0]): if width[ix] < 0.: DPt = DP0[ix] DP0[ix] = DP1[ix] DP1[ix] = DPt width[ix] *= -1. self._logger.warning('switching DPs %i %i for section %i' % (i, i + 1, ix)) region.width = width * self.pf.pfOut.chord * self.blade_length region.thickness = np.zeros(self.st3dOut.x.shape) for layer in region.layers: region.thickness += np.maximum( 0., getattr(region, layer).thickness) for i, rname in enumerate(self.st3dOut.webs): region = getattr(self.st3dOut, rname) region.thickness = np.zeros(self.st3dOut.x.shape) for layer in region.layers: region.thickness += np.maximum( 0., getattr(region, layer).thickness)
class FEM(Component): """ Computes the deformation of the spar """ # inputs flags = VarTree(Flags(), iotype='in') yN = Array(iotype='in', desc='') EIx = Array(iotype='in', desc='') EIz = Array(iotype='in', desc='') EA = Array(iotype='in', desc='') GJ = Array(iotype='in', desc='') cE = Array(iotype='in', desc='chord of each element') xEA = Array(iotype='in', desc='') fblade = VarTree(Fblade(), iotype='in') mSpar = Array(iotype='in', desc='mass of spars') mChord = Array(iotype='in', desc='mass of chords') xCG = Array(iotype='in', desc='') yWire = Array(iotype='in', desc='location of wire attachment along span') zWire = Float(iotype='in', desc='depth of wire attachement') TWire = Array(iotype='in', desc='') presLoad = VarTree(PrescribedLoad(), iotype='in') # outputs k = Array(iotype='out', desc='local elastic stiffness matrix') K = Array(iotype='out', desc='global stiffness matrix') F = Array(iotype='out', desc='global force vector') q = Array(iotype='out', desc='deformation') def execute(self): # short aliases yN = self.yN EIx = self.EIx EIz = self.EIz EA = self.EA GJ = self.GJ xEA = self.xEA cE = self.cE mSpar = self.mSpar mChord = self.mChord xCG = self.xCG yWire = self.yWire zWire = self.zWire TWire = self.TWire fblade = self.fblade presLoad = self.presLoad Ns = len(yN) - 1 # number of elements dy = np.zeros(Ns) for s in range(Ns + 1): dy[s - 1] = yN[s] - yN[s - 1] # length of each element # FEM computation for structural deformations # ------------------------------------------- # Initialize global stiffness matrix K = np.zeros(((Ns + 1) * 6, (Ns + 1) * 6)) # global stiffness F = np.zeros(((Ns + 1) * 6, 1)) # global force vector # Create global stiffness maxtrix and force vector k = np.zeros((12, 12, Ns)) for s in range(Ns): # Local elastic stiffness matrix k[0, 0, s] = 12 * EIx[s] / (dy[s] * dy[s] * dy[s]) k[0, 5, s] = -6 * EIx[s] / (dy[s] * dy[s]) k[5, 0, s] = k[0, 5, s] k[0, 6, s] = -12 * EIx[s] / (dy[s] * dy[s] * dy[s]) k[6, 0, s] = k[0, 6, s] k[0, 11, s] = -6 * EIx[s] / (dy[s] * dy[s]) k[11, 0, s] = k[0, 11, s] k[1, 1, s] = EA[s] / dy[s] k[1, 7, s] = -EA[s] / dy[s] k[7, 1, s] = k[1, 7, s] k[2, 2, s] = 12 * EIz[s] / (dy[s] * dy[s] * dy[s]) k[2, 3, s] = 6 * EIz[s] / (dy[s] * dy[s]) k[3, 2, s] = k[2, 3, s] k[2, 8, s] = -12 * EIz[s] / (dy[s] * dy[s] * dy[s]) k[8, 2, s] = k[2, 8, s] k[2, 9, s] = 6 * EIz[s] / (dy[s] * dy[s]) k[9, 2, s] = k[2, 9, s] k[3, 3, s] = 4 * EIz[s] / dy[s] k[3, 8, s] = -6 * EIz[s] / (dy[s] * dy[s]) k[8, 3, s] = k[3, 8, s] k[3, 9, s] = 2 * EIz[s] / dy[s] k[9, 3, s] = k[3, 9, s] k[4, 4, s] = GJ[s] / dy[s] k[4, 10, s] = -GJ[s] / dy[s] k[10, 4, s] = k[4, 10, s] k[5, 5, s] = 4 * EIx[s] / dy[s] k[5, 6, s] = 6 * EIx[s] / (dy[s] * dy[s]) k[6, 5, s] = k[5, 6, s] k[5, 11, s] = 2 * EIx[s] / dy[s] k[11, 5, s] = k[5, 11, s] k[6, 6, s] = 12 * EIx[s] / (dy[s] * dy[s] * dy[s]) k[6, 11, s] = 6 * EIx[s] / (dy[s] * dy[s]) k[11, 6, s] = k[6, 11, s] k[7, 7, s] = EA[s] / dy[s] k[8, 8, s] = 12 * EIz[s] / (dy[s] * dy[s] * dy[s]) k[8, 9, s] = -6 * EIz[s] / (dy[s] * dy[s]) k[9, 8, s] = k[8, 9, s] k[9, 9, s] = 4 * EIz[s] / dy[s] k[10, 10, s] = GJ[s] / dy[s] k[11, 11, s] = 4 * EIx[s] / dy[s] # Perform dihedral and sweep rotations here if needed # Assemble global stiffness matrix K[(6*s):(6*s + 12), (6*s):(6*s + 12)] = \ K[(6*s):(6*s + 12), (6*s):(6*s + 12)] + k[:, :, s] Faero = np.zeros((6, 1)) if self.flags.Load == 0: # include aero forces # aerodynamic forces xAC = 0.25 Faero[0] = fblade.Fx[s] / 2 Faero[1] = 0 Faero[2] = fblade.Fz[s] / 2 Faero[3] = fblade.Fz[s] * dy[s] / 12 Faero[4] = fblade.My[s] / 2 + (xEA[s] - xAC) * cE[s] * fblade.Fz[s] / 2 Faero[5] = -fblade.Fx[s] * dy[s] / 12 Fg = np.zeros((6, 1)) Fwire = np.zeros((12, 1)) if (self.flags.Load == 0) or (self.flags.Load == 1): # gravitational forces g = 9.81 Fg[0] = 0 Fg[1] = 0 Fg[2] = -(mSpar[s] + mChord[s]) * g / 2 Fg[3] = -(mSpar[s] + mChord[s]) * g * dy[s] / 12 Fg[4] = (xCG[s] - xEA[s]) * cE[s] * (mSpar[s] + mChord[s]) * g / 2 Fg[5] = 0 # Wire forces (using consistent force vector) for w in range(len(yWire)): if (yWire[w] >= yN[s]) and (yWire[w] < yN[s + 1]): thetaWire = atan2(zWire, yWire[w]) a = yWire[w] - yN[s] L = dy[s] FxWire = -cos(thetaWire) * TWire[w] FzWire = -sin(thetaWire) * TWire[w] Fwire[0] = 0 Fwire[1] = FxWire * (1 - a / L) Fwire[2] = FzWire * (2 * (a / L)**3 - 3 * (a / L)**2 + 1) Fwire[3] = FzWire * a * ((a / L)**2 - 2 * (a / L) + 1) Fwire[4] = 0 Fwire[5] = 0 Fwire[6] = 0 Fwire[7] = FxWire * (a / L) Fwire[8] = FzWire * (-2 * (a / L)**3 + 3 * (a / L)**2) Fwire[9] = FzWire * a * ((a / L)**2 - (a / L)) Fwire[10] = 0 Fwire[11] = 0 else: Fwire = np.zeros((12, 1)) Fpres = np.zeros((12, 1)) if self.flags.Load == 2: # Prescribed point load (using consistent force vector) if (presLoad.y >= yN[s]) and (presLoad.y < yN[s + 1]): a = presLoad.y - yN[s] L = dy[s] Fpres[0] = 0 Fpres[1] = 0 Fpres[2] = presLoad.pointZ * (2 * (a / L)**3 - 3 * (a / L)**2 + 1) Fpres[3] = presLoad.pointZ * a * ((a / L)**2 - 2 * (a / L) + 1) Fpres[4] = presLoad.pointM * (1 - a / L) Fpres[5] = 0 Fpres[6] = 0 Fpres[7] = 0 Fpres[8] = presLoad.pointZ * (-2 * (a / L)**3 + 3 * (a / L)**2) Fpres[9] = presLoad.pointZ * a * ((a / L)**2 - (a / L)) Fpres[10] = presLoad.pointM * (a / L) Fpres[11] = 0 # Prescribed distributed load Fpres[0] = Fpres[0] + presLoad.distributedX * dy[s] / 2 Fpres[1] = Fpres[1] + 0 Fpres[2] = Fpres[2] + presLoad.distributedZ * dy[s] / 2 Fpres[ 3] = Fpres[3] + presLoad.distributedZ * dy[s] * dy[s] / 12 Fpres[4] = Fpres[4] + presLoad.distributedM * dy[s] / 2 Fpres[ 5] = Fpres[5] - presLoad.distributedX * dy[s] * dy[s] / 12 Fpres[6] = Fpres[6] + presLoad.distributedX * dy[s] / 2 Fpres[7] = Fpres[7] + 0 Fpres[8] = Fpres[8] + presLoad.distributedZ * dy[s] / 2 Fpres[ 9] = Fpres[9] - presLoad.distributedZ * dy[s] * dy[s] / 12 Fpres[10] = Fpres[10] + presLoad.distributedM * dy[s] / 2 Fpres[11] = Fpres[ 11] + presLoad.distributedX * dy[s] * dy[s] / 12 # Assemble global force vector F[(s * 6 + 0)] = F[(s * 6 + 0)] + Fpres[0] + Fwire[0] + Fg[0] + Faero[0] # x force F[(s * 6 + 1)] = F[(s * 6 + 1)] + Fpres[1] + Fwire[1] + Fg[1] + Faero[1] # y force F[(s * 6 + 2)] = F[(s * 6 + 2)] + Fpres[2] + Fwire[2] + Fg[2] + Faero[2] # z force F[(s * 6 + 3)] = F[(s * 6 + 3 )] + Fpres[3] + Fwire[3] + Fg[3] + Faero[3] # x moment F[(s * 6 + 4)] = F[(s * 6 + 4 )] + Fpres[4] + Fwire[4] + Fg[4] + Faero[4] # y moment F[(s * 6 + 5)] = F[(s * 6 + 5 )] + Fpres[5] + Fwire[5] + Fg[5] + Faero[5] # z moment F[(s * 6 + 6)] = F[(s * 6 + 6)] + Fpres[6] + Fwire[6] + Fg[0] + Faero[0] # x force F[(s * 6 + 7)] = F[(s * 6 + 7)] + Fpres[7] + Fwire[7] + Fg[1] + Faero[1] # y force F[(s * 6 + 8)] = F[(s * 6 + 8)] + Fpres[8] + Fwire[8] + Fg[2] + Faero[2] # z force F[(s * 6 + 9)] = F[(s * 6 + 9 )] + Fpres[9] + Fwire[9] - Fg[3] - Faero[3] # x moment F[(s * 6 + 10)] = F[(s * 6 + 10)] + Fpres[10] + Fwire[10] + Fg[4] + Faero[ 4] # y moment F[(s * 6 + 11)] = F[(s * 6 + 11)] + Fpres[11] + Fwire[11] - Fg[5] - Faero[ 5] # z moment # Add constraints to all 6 dof at root if self.flags.wingWarp > 0: # Also add wingWarping constraint raise Exception( 'FEM is untested and surely broken for wingWarp > 0') ii = np.array([]) for ss in range((Ns + 1) * 6 - 1): if (ss > 5) and (ss != self.flags.wingWarp * 6 + 5): ii = np.array([ii, ss]).reshape(1, -1) Fc = F[(ii - 1)] Kc = K[(ii - 1), (ii - 1)] else: Fc = F[6:] Kc = K[6:, 6:] # Solve constrained system qc, _, _, _ = np.linalg.lstsq(Kc, Fc) if self.flags.wingWarp > 0: self.q[ii, 1] = qc else: # self.q = np.array([0, 0, 0, 0, 0, 0, qc]).reshape(1, -1) self.q = np.append( np.array([0, 0, 0, 0, 0, 0]).reshape(-1, 1), qc).reshape(-1, 1) # output the stiffness and force arrays as well (for use in failure analysis) self.k = k self.K = K self.F = F
class BladeStructureReader(Component): """ input file reader of BladeStructureVT3D data """ filebase = Str(iotype='in') st3d = VarTree( BladeStructureVT3D(), iotype='out', desc='Vartree containing discrete definition of blade structure') def execute(self): self.read_layups() self.read_materials() def read_materials(self): fid = open(self.filebase + '.mat', 'r') materials = fid.readline().split()[1:] data = np.loadtxt(fid) for i, name in enumerate(materials): mat = self.st3d.add_material(name) try: d = data[i, :] except: d = data mat.E1 = d[0] mat.E2 = d[1] mat.E3 = d[2] mat.nu12 = d[3] mat.nu13 = d[4] mat.nu23 = d[5] mat.G12 = d[6] mat.G13 = d[7] mat.G23 = d[8] mat.rho = d[9] failcrit = {1: 'maximum_strain', 2: 'maximum_stress', 3: 'tsai_wu'} fid = open(self.filebase + '.failmat', 'r') materials = fid.readline().split()[1:] data = np.loadtxt(fid) for i, name in enumerate(materials): mat = self.st3d.add_material(name) try: d = data[i, :] except: d = data mat.failure_criterium = failcrit[int(d[0])] mat.s11_t = d[1] mat.s22_t = d[2] mat.s33_t = d[3] mat.s11_c = d[4] mat.s22_c = d[5] mat.s33_c = d[6] mat.t12 = d[7] mat.t13 = d[8] mat.t23 = d[9] mat.e11_c = d[10] mat.e22_c = d[11] mat.e33_c = d[12] mat.e11_t = d[13] mat.e22_t = d[14] mat.e33_t = d[15] mat.g12 = d[16] mat.g13 = d[17] mat.g23 = d[18] mat.gM0 = d[19] mat.C1a = d[20] mat.C2a = d[21] mat.C3a = d[22] mat.C4a = d[23] def read_layups(self): """ dp3d data format: # web00 web01\n <DP index0> <DP index1>\n <DP index0> <DP index0>\n # s DP00 DP01 DP02 DP03 DP04 DP05\n <float> <float> <float> <float> ... <float>\n . . . . .\n . . . . .\n . . . . .\n st3d data format:\n # region00\n # s triax uniax core uniax01 triax01 core01\n <float> <float> <float> <float> <float> <float> <float>\n . . . . . . .\n . . . . . . .\n . . . . . . .\n """ self.dp_files = glob.glob(self.filebase + '*.dp3d') self.layup_files = glob.glob(self.filebase + '*.st3d') for dpfile in self.dp_files: self._logger.info('reading dp_file: %s' % dpfile) dpfid = open(dpfile, 'r') # read webs wnames = dpfid.readline().split()[1:] iwebs = [] for w, wname in enumerate(wnames): line = dpfid.readline().split()[1:] line = [int(entry) for entry in line] iwebs.append(line) nwebs = len(iwebs) header = dpfid.readline() dpdata = np.loadtxt(dpfile) nreg = dpdata.shape[1] - 2 try: regions = header.split()[1:] assert len(regions) == nreg except: regions = ['region%02d' % i for i in range(nreg)] self.st3d.configure_regions(nreg, names=regions) self.st3d.configure_webs(len(wnames), iwebs, names=wnames) self.st3d.x = dpdata[:, 0] self.st3d.DP00 = dpdata[:, 1] for i, rname in enumerate(regions): r = getattr(self.st3d, rname) self._logger.info(' adding region: %s' % rname) dpname = 'DP%02d' % (i + 1) setattr(self.st3d, dpname, dpdata[:, i + 2]) layup_file = '_'.join([self.filebase, rname]) + '.st3d' self._logger.info(' reading layup file %s' % layup_file) fid = open(layup_file, 'r') rrname = fid.readline().split()[1] lheader = fid.readline().split()[1:] cldata = np.loadtxt(fid) layers = lheader[1:] nl = len(lheader) s = cldata[:, 0] r.thickness = np.zeros(self.st3d.x.shape[0]) for il, lname in enumerate(layers): self._logger.info(' adding layer %s' % lname) l = r.add_layer(lname) l.thickness = cldata[:, il + 1] r.thickness += l.thickness try: l.angle = cldata[:, il + 1 + nl] except: l.angle = np.zeros(s.shape[0]) for i, rname in enumerate(wnames): r = getattr(self.st3d, rname) self._logger.info(' adding web: %s' % rname) layup_file = '_'.join([self.filebase, rname]) + '.st3d' self._logger.info(' reading layup file %s' % layup_file) fid = open(layup_file, 'r') rrname = fid.readline().split()[1] lheader = fid.readline().split()[1:] cldata = np.loadtxt(fid) layers = lheader[1:] nl = len(lheader) r.thickness = np.zeros(self.st3d.x.shape[0]) # assert len(lheader) == cldata.shape[1] s = cldata[:, 0] for il, lname in enumerate(layers): self._logger.info(' adding layer %s' % lname) l = r.add_layer(lname) l.thickness = cldata[:, il + 1] r.thickness += l.thickness try: l.angle = cldata[:, il + 1 + nl] except: l.angle = np.zeros(s.shape[0])
class Failures(Component): """ Computes the factor of safety for each of the failure modes of the spar. """ # inputs flags = VarTree(Flags(), iotype='in') yN = Array(iotype='in', desc='') Finternal = Array(iotype='in', desc='') strain = VarTree(Strain(), iotype='in') d = Array(iotype='in', desc='') theta = Array(iotype='in', desc='') nTube = Array(iotype='in', desc='') nCap = Array(iotype='in', desc='') yWire = Array(iotype='in', desc='') zWire = Float(iotype='in', desc='') EIxJ = Array(iotype='in', desc='') EIzJ = Array(iotype='in', desc='') lBiscuit = Array(iotype='in', desc='') dQuad = Float(iotype='in', desc='') thetaQuad = Float(iotype='in', desc='') nTubeQuad = Float(iotype='in', desc='') lBiscuitQuad = Float(iotype='in', desc='') RQuad = Float(iotype='in', desc='') hQuad = Float(iotype='in', desc='') EIQuad = Array(iotype='in', desc='') GJQuad = Array(iotype='in', desc='') tWire = Float(iotype='in', desc='') TWire = Array(iotype='in', desc='') TEtension = Float(iotype='in', desc='') # all this to get TQuad... maybe should be split out b = Int(iotype='in', desc='number of blades') fblade = VarTree(Fblade(), iotype='in') mSpar = Array(iotype='in', desc='mass of spars') mChord = Array(iotype='in', desc='mass of chords') mElseRotor = Float(iotype='in', desc='') # outputs fail = VarTree(Failure(), iotype='out') def execute(self): # Compute factor of safety for each failure mode # ---------------------------------------------- # computes material failure, euler buckling failure and torsional # buckling failure. All failure modes are computed at the nodes. # # For material failure it looks at a sample laminate on the top, # bottom, back and front of the spar. For each side of the spar # it computes the material failure for the cap, the plus angle # plys and the minus angle plys. For each ply it computes the # fracture of failure in the fibre direction, matrix direction # and shear. Thus there are 4x3x3=36 (side x lamina x direction) # possible failure modes in the tube. # ex. fail.top.cap = 3x(Ns+1) vector # fail.top.plus = 3x(Ns+1) vector # fail.top.minus = 3x(Ns+1) vector # # Stresses and strain are given as a 3x(Ns+1) vector # ex. sigma_11, sigma_22, sigma_12 # Positive sign denotes tensile stresses, negative denotes compressive # factor of safety for each failure mode # short aliases flags = self.flags yN = self.yN Finternal = self.Finternal strain = self.strain d = self.d theta = self.theta nTube = self.nTube nCap = self.nCap yWire = self.yWire zWire = self.zWire EIxJ = self.EIxJ EIzJ = self.EIzJ lBiscuit = self.lBiscuit dQuad = self.dQuad thetaQuad = self.thetaQuad nTubeQuad = self.nTubeQuad lBiscuitQuad = self.lBiscuitQuad RQuad = self.RQuad hQuad = self.hQuad EIQuad = self.EIQuad[0] # convert single element array to scalar GJQuad = self.GJQuad[0] # convert single element array to scalar tWire = self.tWire TWire = self.TWire TEtension = self.TEtension b = self.b fblade = self.fblade mSpar = self.mSpar mChord = self.mChord mElseRotor = self.mElseRotor TQuad = np.sum(fblade.Fz) * b - (np.sum(mSpar + mChord) * b + mElseRotor / 4) * 9.81 Ns = max(yN.shape) - 1 # number of elements fail = Failure() # Material failure fail.top = self.material_failure(Ns, strain.top, theta, nCap, flags) fail.bottom = self.material_failure(Ns, strain.bottom, theta, nCap, flags) fail.back = self.material_failure(Ns, strain.back, theta, [], flags) fail.front = self.material_failure(Ns, strain.front, theta, [], flags) # Euler Buckling failure in main spar from wire force k = 0.7 # pinned-pinned = 1, fixed-pinned = 0.7 with correction factor #kk = 1.42 # correction factor kk = 1 # correction factor was in error, never saw buckling failure thetaWire = atan2(zWire, yWire) L = yWire # wire attachment provides pinned end F = TWire * cos(thetaWire) + TEtension fail.buckling.x = np.zeros(Ns + 1) fail.buckling.z = np.zeros(Ns + 1) for s in range(Ns): if yN[s] <= yWire: critical_load_x = pi**2 * EIxJ / (k * L)**2 critical_load_z = pi**2 * EIzJ / (k * L)**2 fail.buckling.x[s] = kk * F / critical_load_x fail.buckling.z[s] = kk * F / critical_load_z else: fail.buckling.x[s] = 0 fail.buckling.z[s] = 0 # no buckling at tip fail.buckling.x[Ns] = 0 fail.buckling.z[Ns] = 0 # Torsional Buckling failure fail.buckling.torsion = self.torsional_buckling_failure( Ns, Finternal, d, theta, nTube, nCap, lBiscuit, flags) # Quad Buckling failure if EIQuad != 0: k = 1 L = sqrt(RQuad**2 + hQuad**2) alpha = atan2(hQuad, RQuad) P = TQuad / sin(alpha) critical_load = pi**2 * EIQuad / (k * L)**2 fail.quad_buckling = P / critical_load else: fail.quad_buckling = 0 # Quad bending moment failure (does not include torsion since they don't occur at the same time) RotorMoment = 1400 if EIQuad != 0: TbottomWire = TQuad / tan(alpha) BM = TbottomWire * zWire + RotorMoment strainQuad = -np.array([BM * (dQuad / 2) / EIQuad, 0, 0]).reshape( 1, -1).T # strain on compression side mf = self.material_failure(1, strainQuad, [thetaQuad], [], flags) fail.quad_bend = abs( mf.plus[0, 0]) # use only compressive failure in fibre direction else: fail.quad_bend = 0 # Quad torsional material failure if GJQuad != 0: strainQuad = np.array([0, 0, dQuad / 2 * RotorMoment / GJQuad ]).reshape(1, -1).T mf = self.material_failure(1, strainQuad, [thetaQuad], [], flags) fail.quad_torsion = abs(mf.plus[0, 0]) else: fail.quad_torsion = 0 # Quad torsional buckling failure FRotorMoment = np.array([0, 0, 0, 0, RotorMoment]).reshape(1, -1).T tbf = self.torsional_buckling_failure(1, FRotorMoment, [dQuad], [thetaQuad], [nTubeQuad], [0], [lBiscuitQuad], flags) fail.quad_torbuck = tbf[0] # Wire tensile failure wire_props = wireProperties[flags.WireType] fail.wire = np.zeros(len(yWire)) for i in range(len(yWire)): stress_wire = TWire[i] / (pi * (tWire / 2)**2) fail.wire[i] = stress_wire / wire_props['ULTIMATE'] self.fail = fail def material_failure(self, Ns, strain, theta, nCap, flags): failure = MaterialFailure() failure.cap = np.zeros((3, Ns + 1)) failure.plus = np.zeros((3, Ns + 1)) failure.minus = np.zeros((3, Ns + 1)) # Material Properties tube_props = prepregProperties[flags.CFRPType] # Cap Prepreg Properties (MTM28-M46J 140 37 %RW 12") cap_props = prepregProperties[flags.CFRPType] # Populate Q matrix for tube Q_TUBE = np.zeros((3, 3)) Q_TUBE[0, 0] = tube_props['E_11'] Q_TUBE[1, 1] = tube_props['E_22'] Q_TUBE[0, 1] = tube_props['E_22'] * tube_props['V_12'] Q_TUBE[1, 0] = Q_TUBE[0, 1] Q_TUBE[2, 2] = tube_props['G_12'] # Populate Q matrix for caps Q_CAP = np.zeros((3, 3)) Q_CAP[0, 0] = cap_props['E_11'] Q_CAP[1, 1] = cap_props['E_22'] Q_CAP[0, 1] = cap_props['E_22'] * cap_props['V_12'] Q_CAP[1, 0] = Q_CAP[0, 1] Q_CAP[2, 2] = cap_props['G_12'] stress = MaterialFailure() stress.cap = np.zeros((3, Ns)) stress.plus = np.zeros((3, Ns)) stress.minus = np.zeros((3, Ns)) for s in range(Ns): # Compute stresses in structural axes for each lamina angle # Q is the matrix of elastic constants in the material axis # Q_bar is the matrix of elastic constants in the structural axes for a # lamina at a ply angle theta. # Failure is computed at each node, but using the ply angle of the # element (this shouldn't cause a large discrepency). Failure at tip is # zero, since stresses/strains at tip are zero. # Transform the elastic constants for the plus angle ply x = theta[s] # Composite angle (in radians) T_PLUS = np.array([[cos(x)**2, sin(x)**2, 2 * sin(x) * cos(x)], [sin(x)**2, cos(x)**2, -2 * sin(x) * cos(x)], [ -sin(x) * cos(x), sin(x) * cos(x), (cos(x)**2) - (sin(x)**2) ]]) # MATLAB version: Qbar_TUBE_PLUS = (T_PLUS\Q_TUBE)/T_PLUS' tmp = np.linalg.solve(T_PLUS, Q_TUBE) Qbar_TUBE_PLUS = np.linalg.solve(T_PLUS, tmp.T) # Transform the elastic constants for the minus angle ply x = -theta[s] # Composite angle (in radians) T_MINUS = np.array([[cos(x)**2, sin(x)**2, 2 * sin(x) * cos(x)], [sin(x)**2, cos(x)**2, -2 * sin(x) * cos(x)], [ -sin(x) * cos(x), sin(x) * cos(x), (cos(x)**2) - (sin(x)**2) ]]) # MATLAB version: Qbar_TUBE_MINUS = (T_MINUS\Q_TUBE)/T_MINUS' tmp = np.linalg.solve(T_MINUS, Q_TUBE) Qbar_TUBE_MINUS = np.linalg.solve(T_MINUS, tmp.T) # Compute stresses in structural coordinates stress.cap[:, s] = np.dot(Q_CAP, strain[:, s]) # using Q for the cap stress.plus[:, s] = np.dot( Qbar_TUBE_PLUS, strain[:, s]) # using Q_bar for the + angle plys stress.minus[:, s] = np.dot( Qbar_TUBE_MINUS, strain[:, s]) # using Q_bar for the - angle plys # Transform stresses to material axes for each lamina angle stress.plus[:, s] = np.dot(T_PLUS, stress.plus[:, s]) stress.minus[:, s] = np.dot(T_MINUS, stress.minus[:, s]) # Determine fraction of failure for each lamina angle # ULTIMATE_11_TENS and ULTIMATE_11_COMP are both positive values # indicating the maximum tensile and compressive stress before failure. # failure.cap[0,s] will be positive for tensile failures and negative for # compressive failures. # Cap failure if len(nCap) == 0 or (nCap == 0).all(): failure.cap[0, s] = 0 failure.cap[1, s] = 0 failure.cap[2, s] = 0 else: if stress.cap[0, s] > 0: # tensile stress in fibre failure.cap[ 0, s] = stress.cap[0, s] / cap_props['ULTIMATE_11_TENS'] else: failure.cap[ 0, s] = stress.cap[0, s] / cap_props['ULTIMATE_11_COMP'] if stress.cap[1, s] > 0: # tensile stress in matrix failure.cap[ 1, s] = stress.cap[1, s] / cap_props['ULTIMATE_22_TENS'] else: failure.cap[ 1, s] = stress.cap[1, s] / cap_props['ULTIMATE_22_COMP'] failure.cap[2, s] = stress.cap[2, s] / cap_props['ULTIMATE_12'] # Plus angle ply failure if stress.plus[0, s] > 0: # tensile stress in fibre failure.plus[ 0, s] = stress.plus[0, s] / tube_props['ULTIMATE_11_TENS'] else: failure.plus[ 0, s] = stress.plus[0, s] / tube_props['ULTIMATE_11_COMP'] if stress.plus[1, s] > 0: # tensile stress in matrix failure.plus[ 1, s] = stress.plus[1, s] / tube_props['ULTIMATE_22_TENS'] else: failure.plus[ 1, s] = stress.plus[1, s] / tube_props['ULTIMATE_22_COMP'] failure.plus[2, s] = stress.plus[2, s] / tube_props['ULTIMATE_12'] # Minus angle ply failure if stress.minus[0, s] > 0: # tensile stress in fibre failure.minus[ 0, s] = stress.minus[0, s] / tube_props['ULTIMATE_11_TENS'] else: failure.minus[ 0, s] = stress.minus[0, s] / tube_props['ULTIMATE_11_COMP'] if stress.minus[1, s] > 0: # tensile stress in matrix failure.minus[ 1, s] = stress.minus[1, s] / tube_props['ULTIMATE_22_TENS'] else: failure.minus[ 1, s] = stress.minus[1, s] / tube_props['ULTIMATE_22_COMP'] failure.minus[2, s] = stress.minus[2, s] / tube_props['ULTIMATE_12'] return failure def torsional_buckling_failure(self, Ns, Finternal, d, theta, nTube, nCap, lBiscuit, flags): # Material Properties tube_props = prepregProperties[flags.CFRPType] V_21_TUBE = tube_props['V_12'] * (tube_props['E_22'] / tube_props['E_11']) # Coordinate system: x is axial direction, theta is circumferential direction mu_prime_x = tube_props['V_12'] mu_prime_theta = V_21_TUBE Q = np.zeros((3, 3)) # Preallocate Q-matrix # Matrix of elastic constants (AER1401, Composite Lamina, slide 8) Q[0, 0] = tube_props['E_11'] / (1 - tube_props['V_12'] * V_21_TUBE) Q[1, 1] = tube_props['E_22'] / (1 - tube_props['V_12'] * V_21_TUBE) Q[0, 1] = tube_props['E_22'] * tube_props['V_12'] / ( 1 - tube_props['V_12'] * V_21_TUBE) Q[1, 0] = Q[0, 1] Q[2, 2] = tube_props['G_12'] failure = np.zeros(Ns + 1) for s in range(Ns): if nCap[s] != 0: AF_torsional_buckling = 1.25 # See "Validation - Torsional Buckling.xlsx" else: AF_torsional_buckling = 1 # Determine elastic properties of rotated tube laminate x = theta[s] # Composite angle (in radians) # Transformation matrix T = np.array( [[cos(x)**2, sin(x)**2, 2 * sin(x) * cos(x)], [sin(x)**2, cos(x)**2, -2 * sin(x) * cos(x)], [-sin(x) * cos(x), sin(x) * cos(x), cos(x)**2 - sin(x)**2]]) # Transform the elastic constants using the transformation matrix to obtain the # elastic constants at the composite angle. # MATLAB version: Qbar = (T\Q)/T' tmp = np.linalg.solve(T, Q) Qbar = np.linalg.solve(T, tmp.T) # Breakout tube elastic constants at the transformed angle E_x = Qbar[0, 0] E_theta = Qbar[1, 1] # Calculate tube geometric properties t_tube = nTube[s] * tube_props[ 'T_PLY'] # Shell thickness, CR-912 p.xxxvi R = ( d[s] + t_tube ) / 2 # Radius from axis of rotation to centroidal surface of cylinder wall, CR-912 p.xxxiv L = lBiscuit[s] # Unsupported length of cylinder, CR-912 p.xxx # Calculate tube elastic properties (CR-912 p.576) D_x = E_x * (1. / 12) * (t_tube**3) D_theta = E_theta * (1. / 12) * (t_tube**3) B_x = E_x * t_tube B_theta = E_theta * t_tube # Calculate Gamma rho = ((D_x * D_theta) / (B_x * B_theta))**(1. / 4) Gamma = 3.6125e-07 * ((R / (rho * 1000)) ** 6) + \ -1.9724e-05 * ((R / (rho * 1000)) ** 5) + \ 0.0004283 * ((R / (rho * 1000)) ** 4) + \ -0.0048315 * ((R / (rho * 1000)) ** 3) + \ 0.031801 * ((R / (rho * 1000)) ** 2) + \ -0.12975 * (R / (rho * 1000)) + \ 0.88309 # Calculate factors required in critical torque equation Z = ((B_theta * (1 - mu_prime_x * mu_prime_theta) * (L**4)) / (12 * D_x * (R**2)))**(1. / 2) Z_s = ((D_theta / D_x)**(5. / 6)) * ((B_x / B_theta)**(1. / 2)) * Z K_s = 0.89 * (Z_s**(3. / 4)) N_x_theta = (Gamma * K_s * (pi**2) * D_x) / (L**2) # Calculate critical torque critical_torque = AF_torsional_buckling * N_x_theta * 2 * pi * (R** 2) failure[s] = abs(Finternal[4, s] / critical_torque) failure[Ns] = 0 # no torsion at tip return failure
class BladeStructureCSBuilder(BladeStructureBuilderBase): """ Class that generates a series of 2D cross-sectional property vartrees (CrossSectionStructureVT) used by structural codes like BECAS """ blade_length = Float(1., iotype='in') surface = VarTree(BladeSurfaceVT(), iotype='in', desc='Stacked blade surface object') st3d = VarTree(BladeStructureVT3D(), iotype='in', desc='Blade structure definition') cs2d = List(iotype='out', desc='List of cross-sectional properties' 'vartrees') def execute(self): """ generate cross sections at every spanwise node of the st3d vartree """ # clear list of outputs! self.cs2d = [] ni = self.st3d.x.shape[0] for i in range(ni): x = self.st3d.x[i] # print 'adding section at r/R = %2.2f' % x st2d = CrossSectionStructureVT() st2d.s = x * self.blade_length st2d.DPs = [] try: airfoil = self.surface.interpolate_profile( x)[:, [0, 1]] * self.blade_length st2d.airfoil.initialize(airfoil) except: pass for ir, rname in enumerate(self.st3d.regions): reg = getattr(self.st3d, rname) if reg.thickness[i] == 0.: print 'zero thickness region!', rname # continue DP0 = getattr(self.st3d, 'DP%02d' % ir) DP1 = getattr(self.st3d, 'DP%02d' % (ir + 1)) r = st2d.add_region(rname.upper()) st2d.DPs.append(DP0[i]) r.s0 = DP0[i] r.s1 = DP1[i] for lname in reg.layers: lay = getattr(reg, lname) if lay.thickness[i] > 1.e-5: l = r.add_layer(lname) # try: lnamebase = lname.translate(None, digits) st2d.add_material(lnamebase, self.get_material(lname).copy()) # except: # raise RuntimeError('Material %s not in materials list' % lname) l.materialname = lnamebase l.thickness = max(0., lay.thickness[i]) try: l.angle = lay.angle[i] except: l.angle = 0. st2d.DPs.append(DP1[i]) for ir, rname in enumerate(self.st3d.webs): reg = getattr(self.st3d, rname) if reg.thickness[i] == 0.: continue r = st2d.add_web(rname.upper()) try: DP0 = getattr(self.st3d, 'DP%02d' % self.st3d.iwebs[ir][0]) except: DP0 = getattr( self.st3d, 'DP%02d' % (len(self.st3d.regions) + self.st3d.iwebs[ir][0] + 1)) try: DP1 = getattr(self.st3d, 'DP%02d' % self.st3d.iwebs[ir][1]) except: DP1 = getattr( self.st3d, 'DP%02d' % (len(self.st3d.regions) + self.st3d.iwebs[ir][1] + 1)) r.s0 = DP0[i] r.s1 = DP1[i] for lname in reg.layers: lay = getattr(reg, lname) if lay.thickness[i] > 1.e-5: l = r.add_layer(lname) try: lnamebase = lname.translate(None, digits) st2d.add_material(lnamebase, self.get_material(lname).copy()) except: raise RuntimeError( 'Material %s not in materials list' % lname) l.materialname = lnamebase l.thickness = max(0., lay.thickness[i]) try: l.angle = lay.angle[i] except: l.angle = 0. self.cs2d.append(st2d)
class SplinedBladePlanform(Assembly): x_dist = Array(iotype='in', desc='spanwise resolution of blade') nC = Int(8, iotype='in', desc='Number of spline control points along span') Cx = Array(iotype='in', desc='spanwise distribution of spline control points') blade_length = Float(iotype='in') blade_length_ref = Float(iotype='in') span_ni = Int(50, iotype='in') pfIn = VarTree(BladePlanformVT(), iotype='in') pfOut = VarTree(BladePlanformVT(), iotype='out') def __init__(self): super(SplinedBladePlanform, self).__init__() self.blade_length_ref = 0. def _pre_execute(self): super(SplinedBladePlanform, self)._pre_execute() # set reference length first time this comp is executed if self.blade_length_ref == 0.: self.blade_length_ref = self.blade_length def configure_splines(self): if hasattr(self, 'chord_C'): return if self.Cx.shape[0] == 0: self.Cx = np.linspace(0, 1, self.nC) else: self.nC = self.Cx.shape[0] self.connect('blade_length', 'pfOut.blade_length') self.add('compute_x', ComputeDist()) self.driver.workflow.add('compute_x') self.connect('span_ni', 'compute_x.span_ni') for vname in self.pfIn.list_vars(): if vname in ['athick', 'blade_length']: continue cIn = self.get('pfIn.' + vname) cOut = self.get('pfOut.' + vname) sname = vname.replace('.', '_') if vname == 's': self.connect('compute_x.x', 'pfOut.s') else: spl = self.add(sname, FFDSplineComponentBase(self.nC)) self.driver.workflow.add(sname) # spl.log_level = logging.DEBUG self.connect('compute_x.x', sname + '.x') self.connect('Cx', sname + '.Cx') spl.xinit = self.get('pfIn.s') spl.Pinit = cIn if vname == 'chord': self.add('scaleC', ScaleChord()) self.driver.workflow.add('scaleC') self.connect('chord.P', 'scaleC.cIn') self.connect('blade_length/blade_length_ref', 'scaleC.scaler') self.connect('scaleC.cOut', 'pfOut.chord') # self.connect(sname + '.P'+ # '*blade_length/blade_length_ref', 'pfOut.' + vname) else: self.connect(sname + '.P', 'pfOut.' + vname) self.create_passthrough(sname + '.C', alias=sname + '_C') self.create_passthrough(sname + '.dPds', alias=sname + '_dPds') self.add('athick', ComputeAthick()) self.driver.workflow.add('athick') self.connect('chord.P', 'athick.chord') self.connect('rthick.P', 'athick.rthick') self.connect('athick.athick', 'pfOut.athick')
def __init__(self, Ns): super(Structures, self).__init__() # flags self.add('flags', VarTree(Flags(), iotype='in')) # inputs for spars self.add( 'yN', Array(np.zeros(Ns + 1), iotype='in', desc='node locations for each element along the span')) self.add('d', Array(np.zeros(Ns), iotype='in', desc='spar diameter')) self.add('theta', Array(np.zeros(Ns), iotype='in', desc='wrap angle')) self.add( 'nTube', Array(np.zeros(Ns), iotype='in', desc='number of tube layers')) self.add('nCap', Array(np.zeros(Ns), iotype='in', desc='number of cap strips')) self.add( 'lBiscuit', Array(np.zeros(Ns), iotype='in', desc='unsupported biscuit length')) # joint properties self.add('Jprop', VarTree(JointProperties(), iotype='in')) # inputs for chord self.add('b', Int(0, iotype='in', desc='number of blades')) self.add( 'cE', Array(np.zeros(Ns), iotype='in', desc='chord of each element')) self.add('xEA', Array(np.zeros(Ns), iotype='in', desc='')) self.add('xtU', Array(np.zeros(Ns), iotype='in', desc='')) # inputs for quad self.add('dQuad', Float(0., iotype='in', desc='diameter of quad rotor struts')) self.add( 'thetaQuad', Float(0., iotype='in', desc='wrap angle of quad rotor struts')) self.add( 'nTubeQuad', Int(0, iotype='in', desc='number of CFRP layers in quad rotor struts')) self.add('lBiscuitQuad', Float(0., iotype='in', desc='')) self.add( 'RQuad', Float( 0., iotype='in', desc= 'distance from centre of helicopter to centre of quad rotors')) self.add('hQuad', Float(0., iotype='in', desc='height of quad-rotor truss')) # inputs for cover self.add('ycmax', Float(0., iotype='in', desc='')) # inputs for wire self.add( 'yWire', Array([0], iotype='in', desc='location of wire attachment along span')) self.add('zWire', Float(0., iotype='in', desc='depth of wire attachement')) self.add('tWire', Float(0., iotype='in', desc='thickness of wire')) self.add('TWire', Array([0], iotype='in', desc='')) self.add('TEtension', Float(0., iotype='in', desc='')) # inputs for 'other stuff' self.add('mElseRotor', Float(0., iotype='in', desc='')) self.add('mElseCentre', Float(0., iotype='in', desc='')) self.add('mElseR', Float(0., iotype='in', desc='')) self.add('R', Float(0., iotype='in', desc='rotor radius')) self.add('mPilot', Float(0., iotype='in', desc='mass of pilot')) # inputs for FEM self.add('fblade', VarTree(Fblade(Ns), iotype='in')) self.add('presLoad', VarTree(PrescribedLoad(), iotype='in')) # configure self.add('spar', SparProperties(Ns)) self.connect('yN', 'spar.yN') self.connect('d', 'spar.d') self.connect('theta', 'spar.theta') self.connect('nTube', 'spar.nTube') self.connect('nCap', 'spar.nCap') self.connect('lBiscuit', 'spar.lBiscuit') self.connect('flags.CFRPType', 'spar.CFRPType') self.add('joint', JointSparProperties(Ns)) self.connect('flags.CFRPType', 'joint.CFRPType') self.connect('Jprop', 'joint.Jprop') self.add('chord', ChordProperties(Ns)) self.connect('yN', 'chord.yN') self.connect('cE', 'chord.c') self.connect('d', 'chord.d') self.connect('flags.GWing', 'chord.GWing') self.connect('xtU', 'chord.xtU') self.add('quad', QuadSparProperties(Ns)) self.connect('dQuad', 'quad.dQuad') self.connect('thetaQuad', 'quad.thetaQuad') self.connect('nTubeQuad', 'quad.nTubeQuad') self.connect('lBiscuitQuad', 'quad.lBiscuitQuad') self.connect('flags.CFRPType', 'quad.CFRPType') self.connect('RQuad', 'quad.RQuad') self.connect('hQuad', 'quad.hQuad') self.add('mass', MassProperties(Ns)) self.connect('flags', 'mass.flags') self.connect('b', 'mass.b') self.connect('spar.mSpar', 'mass.mSpar') self.connect('chord.mChord', 'mass.mChord') self.connect('chord.xCGChord', 'mass.xCGChord') self.connect('quad.mQuad', 'mass.mQuad') self.connect('xEA', 'mass.xEA') self.connect('ycmax', 'mass.ycmax') self.connect('zWire', 'mass.zWire') self.connect('yWire', 'mass.yWire') self.connect('tWire', 'mass.tWire') self.connect('mElseRotor', 'mass.mElseRotor') self.connect('mElseCentre', 'mass.mElseCentre') self.connect('mElseR', 'mass.mElseR') self.connect('R', 'mass.R') self.connect('mPilot', 'mass.mPilot') self.add('fem', FEM(Ns)) self.connect('flags', 'fem.flags') self.connect('yN', 'fem.yN') self.connect('spar.EIx', 'fem.EIx') self.connect('spar.EIz', 'fem.EIz') self.connect('spar.EA', 'fem.EA') self.connect('spar.GJ', 'fem.GJ') self.connect('cE', 'fem.cE') self.connect('xEA', 'fem.xEA') self.connect('spar.mSpar', 'fem.mSpar') self.connect('chord.mChord', 'fem.mChord') self.connect('mass.xCG', 'fem.xCG') self.connect('zWire', 'fem.zWire') self.connect('yWire', 'fem.yWire') self.connect('TWire', 'fem.TWire') self.connect('fblade', 'fem.fblade') self.connect('presLoad', 'fem.presLoad') self.add('strains', Strains(Ns)) self.connect('yN', 'strains.yN') self.connect('d', 'strains.d') self.connect('fem.k', 'strains.k') self.connect('fem.F', 'strains.F') self.connect('fem.q', 'strains.q') self.add('failure', Failures(Ns)) self.connect('flags', 'failure.flags') self.connect('yN', 'failure.yN') self.connect('strains.Finternal', 'failure.Finternal') self.connect('strains.strain', 'failure.strain') self.connect('d', 'failure.d') self.connect('theta', 'failure.theta') self.connect('nTube', 'failure.nTube') self.connect('nCap', 'failure.nCap') self.connect('yWire', 'failure.yWire') self.connect('zWire', 'failure.zWire') self.connect('joint.EIx', 'failure.EIxJ') self.connect('joint.EIz', 'failure.EIzJ') self.connect('lBiscuit', 'failure.lBiscuit') self.connect('dQuad', 'failure.dQuad') self.connect('thetaQuad', 'failure.thetaQuad') self.connect('nTubeQuad', 'failure.nTubeQuad') self.connect('lBiscuitQuad', 'failure.lBiscuitQuad') self.connect('RQuad', 'failure.RQuad') self.connect('hQuad', 'failure.hQuad') self.connect('quad.EIx', 'failure.EIQuad') self.connect('quad.GJ', 'failure.GJQuad') self.connect('tWire', 'failure.tWire') self.connect('TWire', 'failure.TWire') self.connect('TEtension', 'failure.TEtension') self.connect('b', 'failure.b') self.connect('fblade', 'failure.fblade') self.connect('spar.mSpar', 'failure.mSpar') self.connect('chord.mChord', 'failure.mChord') self.connect('mElseRotor', 'failure.mElseRotor') # link up the outputs self.create_passthrough('mass.Mtot') self.create_passthrough('fem.q') self.create_passthrough('strains.Finternal') self.create_passthrough('strains.strain') self.create_passthrough('failure.fail') self.driver.workflow.add('chord') self.driver.workflow.add('fem') self.driver.workflow.add('joint') self.driver.workflow.add('mass') self.driver.workflow.add('quad') self.driver.workflow.add('spar') self.driver.workflow.add('strains') self.driver.workflow.add('failure')
class LoftedBladeSurface(Component): pf = VarTree(BladePlanformVT(), iotype='in') base_airfoils = List(iotype='in') blend_var = Array(iotype='in') chord_ni = Int(300, iotype='in') span_ni = Int(300, iotype='in') interp_type = Enum('rthick', ('rthick', 's'), iotype='in') surface_spline = Str('akima', iotype='in', desc='Spline') rot_order = Array(np.array([2, 1, 0]), iotype='in', desc='rotation order of airfoil sections' 'default z,y,x (twist,sweep,dihedral)') surfout = VarTree(BladeSurfaceVT(), iotype='out') surfnorot = VarTree(BladeSurfaceVT(), iotype='out') def execute(self): self.interpolator = BlendAirfoilShapes() self.interpolator.ni = self.chord_ni self.interpolator.spline = self.surface_spline self.interpolator.blend_var = self.blend_var self.interpolator.airfoil_list = self.base_airfoils self.interpolator.initialize() self.span_ni = self.pf.s.shape[0] x = np.zeros((self.chord_ni, self.span_ni, 3)) for i in range(self.span_ni): s = self.pf.s[i] pos_x = self.pf.x[i] pos_y = self.pf.y[i] pos_z = self.pf.z[i] chord = self.pf.chord[i] p_le = self.pf.p_le[i] # generate the blended airfoil shape if self.interp_type == 'rthick': rthick = self.pf.rthick[i] points = self.interpolator(rthick) else: points = self.interpolator(s) points *= chord points[:, 0] += pos_x - chord * p_le # x-coordinate needs to be inverted for clockwise rotating blades x[:, i, :] = (np.array( [-points[:, 0], points[:, 1], x.shape[0] * [pos_z]]).T) # save non-rotated blade (only really applicable for straight blades) x_norm = x.copy() x[:, :, 1] += self.pf.y x = self.rotate(x) self.surfnorot.surface = x_norm self.surfout.surface = x def rotate(self, x): """ rotate blade sections accounting for twist and main axis orientation the blade will be built with a "sheared" layout, ie no rotation around y in the case of sweep. if the main axis includes a winglet, the blade sections will be rotated accordingly. ensure that an adequate point distribution is used in this case to avoid sections colliding in the winglet junction! """ main_axis = Curve(points=np.array([self.pf.x, self.pf.y, self.pf.z]).T) rot_normals = np.zeros((3, 3)) x_rot = np.zeros(x.shape) for i in range(x.shape[1]): points = x[:, i, :] rot_center = main_axis.points[i] # rotation angles read from file angles = np.array([ self.pf.rot_x[i], self.pf.rot_y[i], self.pf.rot_z[i] ]) * np.pi / 180. # compute rotation angles of main_axis t = main_axis.dp[i] rot = np.zeros(3) rot[0] = -np.arctan(t[1] / (t[2] + 1.e-20)) v = np.array([t[2], t[1]]) vt = np.dot(v, v)**0.5 rot[1] = (np.arcsin(t[0] / vt)) angles[0] += rot[0] angles[1] += rot[1] # compute x-y-z normal vectors of rotation n_y = np.cross(t, [1, 0, 0]) n_y = n_y / norm(n_y) rot_normals[0, :] = np.array([1, 0, 0]) rot_normals[1, :] = n_y rot_normals[2, :] = t # compute final rotation matrix rotation_matrix = np.matrix([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) for n, ii in enumerate(self.rot_order): mat = np.matrix(RotMat(rot_normals[ii], angles[ii])) rotation_matrix = mat * rotation_matrix # apply rotation x_rot[:, i, :] = dotXC(rotation_matrix, points, rot_center) return x_rot
def __init__(self, Ns): super(FEM, self).__init__() # inputs self.add('flags', VarTree(Flags(), iotype='in')) self.add('yN', Array(np.zeros(Ns + 1), iotype='in', desc='')) self.add('EIx', Array(np.zeros(Ns), iotype='in', desc='')) self.add('EIz', Array(np.zeros(Ns), iotype='in', desc='')) self.add('EA', Array(np.zeros(Ns), iotype='in', desc='')) self.add('GJ', Array(np.zeros(Ns), iotype='in', desc='')) self.add( 'cE', Array(np.zeros(Ns), iotype='in', desc='chord of each element')) self.add('xEA', Array(np.zeros(Ns), iotype='in', desc='')) 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('xCG', Array(np.zeros(Ns), iotype='in', desc='')) self.add( 'yWire', Array([0], iotype='in', desc='location of wire attachment along span')) self.add('zWire', Float(0., iotype='in', desc='depth of wire attachment')) self.add('TWire', Array([0], iotype='in', desc='')) self.add('presLoad', VarTree(PrescribedLoad(), iotype='in')) # outputs self.add( 'k', Array(np.zeros((Ns + 2, Ns + 2, Ns)), iotype='out', desc='local elastic stiffness matrix')) self.add( 'K', Array(np.zeros((Ns + 2, Ns + 2, Ns)), iotype='out', desc='global stiffness matrix')) self.add( 'F', Array(np.zeros((6 * (Ns + 1), 1)), iotype='out', desc='global force vector')) self.add( 'q', Array(np.zeros((6 * (Ns + 1), 1)), iotype='out', desc='deformation'))
class dist_const(Component): parameters = VarTree(FLORISParameters(), iotype='in') def __init__(self, nTurbines): #print 'entering dist_const __init__' super(dist_const, self).__init__() # Explicitly size input arrays self.add('turbineX', Array(np.zeros(nTurbines), iotype='in', \ desc='x coordinates of turbines in wind dir. ref. frame')) self.add('turbineY', Array(np.zeros(nTurbines), iotype='in', \ desc='y coordinates of turbines in wind dir. ref. frame')) # Explicitly size output array self.add('separation', Array(np.zeros(int((nTurbines-1.)*nTurbines/2.)), iotype='out', dtype='float', \ desc='spacing of all turbines in the wind farm')) def execute(self): #print 'in dist const' turbineX = self.turbineX turbineY = self.turbineY nTurbines = turbineX.size separation = np.zeros(int((nTurbines - 1.) * nTurbines / 2.)) k = 0 for i in range(0, nTurbines): for j in range(i + 1, nTurbines): separation[k] = np.sqrt((turbineX[j] - turbineX[i])**2 + (turbineY[j] - turbineY[i])**2) k += 1 self.separation = separation def list_deriv_vars(self): return ('turbineX', 'turbineY'), ('separation', ) def provideJ(self): #print 'entering dist const - provideJ' tictot = time.time() turbineX = self.turbineX turbineY = self.turbineY nTurbines = turbineX.size J = np.zeros(((nTurbines - 1.) * nTurbines / 2., 2 * nTurbines)) k = 0 for i in range(0, nTurbines): for j in range(i + 1, nTurbines): J[k, j] = (turbineX[j] - turbineX[i]) * ( (turbineX[j] - turbineX[i])**2 + (turbineY[j] - turbineY[i])**2)**(-0.5) J[k, i] = (turbineX[i] - turbineX[j]) * ( (turbineX[j] - turbineX[i])**2 + (turbineY[j] - turbineY[i])**2)**(-0.5) J[k, j + nTurbines] = (turbineY[j] - turbineY[i]) * ( (turbineX[j] - turbineX[i])**2 + (turbineY[j] - turbineY[i])**2)**(-0.5) J[k, i + nTurbines] = (turbineY[i] - turbineY[j]) * ( (turbineX[j] - turbineX[i])**2 + (turbineY[j] - turbineY[i])**2)**(-0.5) k += 1 toctot = time.time() #print 'done %s' % (toctot-tictot) return J
class FstInputReader(FstInputBase): fst_infile = Str(desc='Master FAST file') fst_directory = Str(desc='Directory of master FAST file set') fst_file_type = Enum(0, (0, 1), desc='Fst file type, 0=old FAST, 1 = new FAST') ad_file_type = Enum( 0, (0, 1), desc='Aerodyn file type, 0=old Aerodyn, 1 = new Aerdyn') fst_vt = VarTree(FstModel(), iotype='out') def __init__(self): super(FstInputReader, self).__init__() def execute(self): self.read_input_file() def read_input_file(self): fst_file = os.path.join(self.fst_directory, self.fst_infile) f = open(fst_file) # FAST Inputs f.readline() f.readline() self.fst_vt.description = f.readline().rstrip() f.readline() f.readline() boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.Echo = False else: self.fst_vt.Echo = True ap = f.readline().split()[0] if ap == '1': self.fst_vt.ADAMSPrep = 1 elif ap == '2': self.fst_vt.ADAMSPrep = 2 else: self.fst_vt.ADAMSPrep = 3 am = f.readline().split()[0] if am == '1': self.fst_vt.AnalMode = 1 else: self.fst_vt.AnalMode = 2 self.fst_vt.NumBl = int(f.readline().split()[0]) self.fst_vt.TMax = float(f.readline().split()[0]) self.fst_vt.DT = float(f.readline().split()[0]) f.readline() ym = f.readline().split()[0] if ym == '0': self.fst_vt.YCMode = 0 elif ym == '1': self.fst_vt.YCMode = 1 else: self.fst_vt.YCMode = 2 self.fst_vt.TYCOn = float(f.readline().split()[0]) pm = f.readline().split()[0] if pm == '0': self.fst_vt.PCMode = 0 elif pm == '1': self.fst_vt.PCMode = 1 else: self.fst_vt.PCMode = 2 self.fst_vt.TPCOn = float(f.readline().split()[0]) vs = f.readline().split()[0] if vs == '0': self.fst_vt.VSContrl = 0 elif vs == '1': self.fst_vt.VSContrl = 1 elif vs == '2': self.fst_vt.VSContrl = 2 else: self.fst_vt.VSContrl = 3 self.fst_vt.VS_RtGnSp = float(f.readline().split()[0]) self.fst_vt.VS_RtTq = float(f.readline().split()[0]) self.fst_vt.VS_Rgn2K = float(f.readline().split()[0]) self.fst_vt.VS_SlPc = float(f.readline().split()[0]) gm = f.readline().split()[0] if gm == '1': self.fst_vt.GenModel = 1 elif gm == '2': self.fst_vt.GenModel = 2 else: self.fst_vt.GenModel = 3 self.fst_vt.GenTiStr = bool(f.readline().split()[0]) self.fst_vt.GenTiStp = bool(f.readline().split()[0]) self.fst_vt.SpdGenOn = float(f.readline().split()[0]) self.fst_vt.TimGenOn = float(f.readline().split()[0]) self.fst_vt.TimGenOf = float(f.readline().split()[0]) hss = f.readline().split()[0] if hss == '1': self.fst_vt.HSSBrMode = 1 else: self.fst_vt.HSSBrMode = 2 self.fst_vt.THSSBrDp = float(f.readline().split()[0]) self.fst_vt.TiDynBrk = float(f.readline().split()[0]) self.fst_vt.TTpBrDp1 = float(f.readline().split()[0]) self.fst_vt.TTpBrDp2 = float(f.readline().split()[0]) self.fst_vt.TTpBrDp3 = float(f.readline().split()[0]) self.fst_vt.TBDepISp1 = float(f.readline().split()[0]) self.fst_vt.TBDepISp2 = float(f.readline().split()[0]) self.fst_vt.TBDepISp3 = float(f.readline().split()[0]) self.fst_vt.TYawManS = float(f.readline().split()[0]) self.fst_vt.TYawManE = float(f.readline().split()[0]) self.fst_vt.NacYawF = float(f.readline().split()[0]) self.fst_vt.TPitManS1 = float(f.readline().split()[0]) self.fst_vt.TPitManS2 = float(f.readline().split()[0]) self.fst_vt.TPitManS3 = float(f.readline().split()[0]) self.fst_vt.TPitManE1 = float(f.readline().split()[0]) self.fst_vt.TPitManE2 = float(f.readline().split()[0]) self.fst_vt.TPitManE3 = float(f.readline().split()[0]) self.fst_vt.BlPitch1 = float(f.readline().split()[0]) self.fst_vt.BlPitch2 = float(f.readline().split()[0]) self.fst_vt.BlPitch3 = float(f.readline().split()[0]) self.fst_vt.B1PitchF1 = float(f.readline().split()[0]) self.fst_vt.B1PitchF2 = float(f.readline().split()[0]) self.fst_vt.B1PitchF3 = float(f.readline().split()[0]) f.readline() self.fst_vt.Gravity = float(f.readline().split()[0]) f.readline() boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.FlapDOF1 = False else: self.fst_vt.FlapDOF1 = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.FlapDOF2 = False else: self.fst_vt.FlapDOF2 = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.EdgeDOF = False else: self.fst_vt.EdgeDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.TeetDOF = False else: self.fst_vt.TeetDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.DrTrDOF = False else: self.fst_vt.DrTrDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.GenDOF = False else: self.fst_vt.GenDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.YawDOF = False else: self.fst_vt.YawDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.TwFADOF1 = False else: self.fst_vt.TwFADOF1 = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.TwFADOF2 = False else: self.fst_vt.TwFADOF2 = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.TwSSDOF1 = False else: self.fst_vt.TwSSDOF1 = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.TwSSDOF2 = False else: self.fst_vt.TwSSDOF2 = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.CompAero = False else: self.fst_vt.CompAero = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.CompNoise = False else: self.fst_vt.CompNoise = True f.readline() self.fst_vt.OoPDefl = float(f.readline().split()[0]) self.fst_vt.IPDefl = float(f.readline().split()[0]) self.fst_vt.TeetDefl = float(f.readline().split()[0]) self.fst_vt.Azimuth = float(f.readline().split()[0]) self.fst_vt.RotSpeed = float(f.readline().split()[0]) self.fst_vt.NacYaw = float(f.readline().split()[0]) self.fst_vt.TTDspFA = float(f.readline().split()[0]) self.fst_vt.TTDspSS = float(f.readline().split()[0]) f.readline() self.fst_vt.TipRad = float(f.readline().split()[0]) self.fst_vt.HubRad = float(f.readline().split()[0]) self.fst_vt.PSpnElN = int(f.readline().split()[0]) self.fst_vt.UndSling = float(f.readline().split()[0]) self.fst_vt.HubCM = float(f.readline().split()[0]) self.fst_vt.OverHang = float(f.readline().split()[0]) self.fst_vt.NacCMxn = float(f.readline().split()[0]) self.fst_vt.NacCMyn = float(f.readline().split()[0]) self.fst_vt.NacCMzn = float(f.readline().split()[0]) self.fst_vt.TowerHt = float(f.readline().split()[0]) self.fst_vt.Twr2Shft = float(f.readline().split()[0]) self.fst_vt.TwrRBHt = float(f.readline().split()[0]) self.fst_vt.ShftTilt = float(f.readline().split()[0]) self.fst_vt.Delta3 = float(f.readline().split()[0]) self.fst_vt.PreCone1 = float(f.readline().split()[0]) self.fst_vt.PreCone2 = float(f.readline().split()[0]) self.fst_vt.PreCone3 = float(f.readline().split()[0]) self.fst_vt.AzimB1Up = float(f.readline().split()[0]) f.readline() self.fst_vt.YawBrMass = float(f.readline().split()[0]) self.fst_vt.NacMass = float(f.readline().split()[0]) self.fst_vt.HubMass = float(f.readline().split()[0]) self.fst_vt.TipMass1 = float(f.readline().split()[0]) self.fst_vt.TipMass2 = float(f.readline().split()[0]) self.fst_vt.TipMass3 = float(f.readline().split()[0]) self.fst_vt.NacYIner = float(f.readline().split()[0]) self.fst_vt.GenIner = float(f.readline().split()[0]) self.fst_vt.HubIner = float(f.readline().split()[0]) f.readline() self.fst_vt.GBoxEff = float(f.readline().split()[0]) self.fst_vt.GenEff = float(f.readline().split()[0]) self.fst_vt.GBRatio = float(f.readline().split()[0]) boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.GBRevers = False else: self.fst_vt.GBRevers = True self.fst_vt.HSSBrTqF = float(f.readline().split()[0]) self.fst_vt.HSSBrDT = float(f.readline().split()[0]) self.fst_vt.DynBrkFi = f.readline().split()[0] self.fst_vt.DTTorSpr = float(f.readline().split()[0]) self.fst_vt.DTTorDmp = float(f.readline().split()[0]) f.readline() self.fst_vt.SIG_SlPc = float(f.readline().split()[0]) self.fst_vt.SIG_SySp = float(f.readline().split()[0]) self.fst_vt.SIG_RtTq = float(f.readline().split()[0]) self.fst_vt.SIG_PORt = float(f.readline().split()[0]) f.readline() self.fst_vt.TEC_Freq = float(f.readline().split()[0]) self.fst_vt.TEC_NPol = int(f.readline().split()[0]) self.fst_vt.TEC_SRes = float(f.readline().split()[0]) self.fst_vt.TEC_RRes = float(f.readline().split()[0]) self.fst_vt.TEC_VLL = float(f.readline().split()[0]) self.fst_vt.TEC_SLR = float(f.readline().split()[0]) self.fst_vt.TEC_RLR = float(f.readline().split()[0]) self.fst_vt.TEC_MR = float(f.readline().split()[0]) f.readline() pm = f.readline().split()[0] if pm == '0': self.fst_vt.PtfmModel = 0 elif pm == '1': self.fst_vt.PtfmModel = 1 elif pm == '2': self.fst_vt.PtfmModel = 2 else: self.fst_vt.PtfmModel = 3 self.fst_vt.PtfmFile = f.readline().split()[0][1:-1] f.readline() self.fst_vt.TwrNodes = int(f.readline().split()[0]) self.fst_vt.TwrFile = f.readline().split()[0][1:-1] f.readline() self.fst_vt.YawSpr = float(f.readline().split()[0]) self.fst_vt.YawDamp = float(f.readline().split()[0]) self.fst_vt.YawNeut = float(f.readline().split()[0]) f.readline() boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.Furling = False else: self.fst_vt.Furling = True self.fst_vt.FurlFile = f.readline().split()[0] f.readline() tm = f.readline().split()[0] if tm == '0': self.fst_vt.TeetMod = 0 elif tm == '1': self.fst_vt.TeetMod = 1 else: self.fst_vt.TeetMod = 2 self.fst_vt.TeetDmpP = float(f.readline().split()[0]) self.fst_vt.TeetDmp = float(f.readline().split()[0]) self.fst_vt.TeetCDmp = float(f.readline().split()[0]) self.fst_vt.TeetSStP = float(f.readline().split()[0]) self.fst_vt.TeetHStP = float(f.readline().split()[0]) self.fst_vt.TeetSSSp = float(f.readline().split()[0]) self.fst_vt.TeetHSSp = float(f.readline().split()[0]) f.readline() self.fst_vt.TBDrConN = float(f.readline().split()[0]) self.fst_vt.TBDrConD = float(f.readline().split()[0]) self.fst_vt.TpBrDT = float(f.readline().split()[0]) f.readline() self.fst_vt.BldFile1 = f.readline().split()[0][ 1:-1] # TODO - different blade files self.fst_vt.BldFile2 = f.readline().split()[0][1:-1] self.fst_vt.BldFile3 = f.readline().split()[0][1:-1] f.readline() self.fst_vt.ADFile = f.readline().split()[0][1:-1] f.readline() self.fst_vt.NoiseFile = f.readline().split()[0] f.readline() self.fst_vt.ADAMSFile = f.readline().split()[0] f.readline() self.fst_vt.LinFile = f.readline().split()[0] f.readline() boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.SumPrint = False else: self.fst_vt.SumPrint = True if self.fst_file_type == 0: ff = f.readline().split()[0] if ff == '1': self.fst_vt.OutFileFmt = 1 else: self.fst_vt.OutFileFmt = 2 boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.TabDelim = False else: self.fst_vt.TabDelim = True self.fst_vt.OutFmt = f.readline().split()[0] self.fst_vt.TStart = float(f.readline().split()[0]) self.fst_vt.DecFact = int(f.readline().split()[0]) self.fst_vt.SttsTime = float(f.readline().split()[0]) self.fst_vt.NcIMUxn = float(f.readline().split()[0]) self.fst_vt.NcIMUyn = float(f.readline().split()[0]) self.fst_vt.NcIMUzn = float(f.readline().split()[0]) self.fst_vt.ShftGagL = float(f.readline().split()[0]) self.fst_vt.NTwGages = int(f.readline().split()[0]) twrg = f.readline().split(',') for i in range(self.fst_vt.NTwGages): self.fst_vt.TwrGagNd.append(twrg[i]) self.fst_vt.TwrGagNd[-1] = self.fst_vt.TwrGagNd[-1][0:2] self.fst_vt.NBlGages = int(f.readline().split()[0]) blg = f.readline().split(',') for i in range(self.fst_vt.NBlGages): self.fst_vt.BldGagNd.append(blg[i]) self.fst_vt.BldGagNd[-1] = self.fst_vt.BldGagNd[-1][0:2] # Outlist (TODO - detailed categorization) f.readline() data = f.readline() while data.split()[0] != 'END': channels = data.split('"') channel_list = channels[1].split(',') for i in range(len(channel_list)): channel_list[i] = channel_list[i].replace(' ', '') if channel_list[ i] in self.fst_vt.fst_output_vt.wind_mot_vt.__dict__.keys( ): self.fst_vt.fst_output_vt.wind_mot_vt.__dict__[ channel_list[i]] = True for i in range(len(channel_list)): channel_list[i] = channel_list[i].replace(' ', '') if channel_list[ i] in self.fst_vt.fst_output_vt.blade_mot_vt.__dict__.keys( ): self.fst_vt.fst_output_vt.blade_mot_vt.__dict__[ channel_list[i]] = True for i in range(len(channel_list)): channel_list[i] = channel_list[i].replace(' ', '') if channel_list[ i] in self.fst_vt.fst_output_vt.hub_nacelle_mot_vt.__dict__.keys( ): self.fst_vt.fst_output_vt.hub_nacelle_mot_vt.__dict__[ channel_list[i]] = True for i in range(len(channel_list)): channel_list[i] = channel_list[i].replace(' ', '') if channel_list[ i] in self.fst_vt.fst_output_vt.tower_support_mot_vt.__dict__.keys( ): self.fst_vt.fst_output_vt.tower_support_mot_vt.__dict__[ channel_list[i]] = True for i in range(len(channel_list)): channel_list[i] = channel_list[i].replace(' ', '') if channel_list[ i] in self.fst_vt.fst_output_vt.wave_mot_vt.__dict__.keys( ): self.fst_vt.fst_output_vt.wave_mot_vt.__dict__[ channel_list[i]] = True for i in range(len(channel_list)): channel_list[i] = channel_list[i].replace(' ', '') if channel_list[ i] in self.fst_vt.fst_output_vt.blade_loads_vt.__dict__.keys( ): self.fst_vt.fst_output_vt.blade_loads_vt.__dict__[ channel_list[i]] = True for i in range(len(channel_list)): channel_list[i] = channel_list[i].replace(' ', '') if channel_list[ i] in self.fst_vt.fst_output_vt.hub_nacelle_loads_vt.__dict__.keys( ): self.fst_vt.fst_output_vt.hub_nacelle_loads_vt.__dict__[ channel_list[i]] = True for i in range(len(channel_list)): channel_list[i] = channel_list[i].replace(' ', '') if channel_list[ i] in self.fst_vt.fst_output_vt.tower_support_loads_vt.__dict__.keys( ): self.fst_vt.fst_output_vt.tower_support_loads_vt.__dict__[ channel_list[i]] = True for i in range(len(channel_list)): channel_list[i] = channel_list[i].replace(' ', '') if channel_list[ i] in self.fst_vt.fst_output_vt.dof_vt.__dict__.keys(): self.fst_vt.fst_output_vt.dof_vt.__dict__[ channel_list[i]] = True data = f.readline() self.AeroReader() if self.fst_vt.aero_vt.wind_file_type == 'hh': self.SimpleWindReader() else: print "TODO: not simple wind file" self.BladeReader() self.TowerReader() self.PlatformReader() def PlatformReader(self): platform_file = os.path.join(self.fst_directory, self.fst_vt.PtfmFile) f = open(platform_file) f.readline() f.readline() self.fst_vt.platform_vt.description = f.readline().rstrip() # FEATURE FLAGS (CONT) f.readline() boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.PtfmSgDOF = False else: self.fst_vt.PtfmSgDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.PtfmSwDOF = False else: self.fst_vt.PtfmSwDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.PtfmHvDOF = False else: self.fst_vt.PtfmHvDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.PtfmRDOF = False else: self.fst_vt.PtfmRDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.PtfmPDOF = False else: self.fst_vt.PtfmPDOF = True boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.PtfmYDOF = False else: self.fst_vt.PtfmYDOF = True # INITIAL CONDITIONS (CONT) f.readline() self.fst_vt.platform_vt.PtfmSurge = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmSway = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmHeave = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmRoll = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmPitch = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmYaw = float(f.readline().split()[0]) # TURBINE CONFIGURATION (CONT) f.readline() self.fst_vt.platform_vt.TwrDraft = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmCM = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmRef = float(f.readline().split()[0]) # MASS AND INERTIA (CONT) f.readline() self.fst_vt.platform_vt.PtfmMass = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmRIner = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmPIner = float(f.readline().split()[0]) self.fst_vt.platform_vt.PtfmYIner = float(f.readline().split()[0]) # PLATFORM (CONT) f.readline() pltmd = f.readline().split()[0] if pltmd == '0': self.fst_vt.platform_vt.PtfmLdMod = 0 else: self.fst_vt.platform_vt.PtfmLdMod = 1 # TOWER (CONT) f.readline() twrmd = f.readline().split()[0] if twrmd == '0': self.fst_vt.platform_vt.TwrLdMod = 0 elif twrmd == '1': self.fst_vt.platform_vt.TwrLdMod = 1 elif twrmd == '2': self.fst_vt.platform_vt.TwrLdMod = 3 self.fst_vt.platform_vt.TwrDiam = float(f.readline().split()[0]) self.fst_vt.platform_vt.TwrCA = float(f.readline().split()[0]) self.fst_vt.platform_vt.TwrCD = float(f.readline().split()[0]) # WAVES f.readline() self.fst_vt.platform_vt.WtrDens = float(f.readline().split()[0]) self.fst_vt.platform_vt.WtrDpth = float(f.readline().split()[0]) wavemod = f.readline().split()[0] if wavemod == '0': self.fst_vt.platform_vt.WaveMod = 0 elif wavemod == '1': self.fst_vt.platform_vt.WaveMod = 1 elif wavemod == '2': self.fst_vt.platform_vt.WaveMod = 2 elif wavemod == '3': self.fst_vt.platform_vt.WaveMod = 3 else: self.fst_vt.platform_vt.WaveMod = 4 wavestmod = f.readline().split()[0] if wavestmod == '0': self.fst_vt.platform_vt.WaveStMod = 0 elif wavestmod == '1': self.fst_vt.platform_vt.WaveStMod = 1 elif wavestmod == '2': self.fst_vt.platform_vt.WaveStMod = 2 elif wavestmod == '3': self.fst_vt.platform_vt.WaveStMod = 3 self.fst_vt.platform_vt.WaveTMax = float(f.readline().split()[0]) self.fst_vt.platform_vt.WaveDT = float(f.readline().split()[0]) self.fst_vt.platform_vt.WaveHs = float(f.readline().split()[0]) self.fst_vt.platform_vt.WaveTp = float(f.readline().split()[0]) wvpk = f.readline().split()[0] if wvpk == 'DEFAULT': self.fst_vt.platform_vt.WavePkShp = 9999.9 else: self.fst_vt.platform_vt.WavePkShp = float(wvpk) self.fst_vt.platform_vt.WaveDir = float(f.readline().split()[0]) self.fst_vt.platform_vt.WaveSeed1 = int(f.readline().split()[0]) self.fst_vt.platform_vt.WaveSeed2 = int(f.readline().split()[0]) self.fst_vt.platform_vt.GHWvFile = f.readline().split()[0] # CURRENT f.readline() currmod = float(f.readline().split()[0]) if currmod == '0': self.fst_vt.platform_vt.CurrMod = 0 elif currmod == '1': self.fst_vt.platform_vt.CurrMod = 1 elif currmod == '2': self.fst_vt.platform_vt.CurrMod = 2 self.fst_vt.platform_vt.CurrSSV0 = float(f.readline().split()[0]) currs = f.readline().split()[0] if currs == 'DEFAULT': self.fst_vt.platform_vt.CurrSSDir = 9999.9 else: self.fst_vt.platform_vt.CurrSSDir = float(currs) self.fst_vt.platform_vt.CurrNSRef = float(f.readline().split()[0]) self.fst_vt.platform_vt.CurrNSV0 = float(f.readline().split()[0]) self.fst_vt.platform_vt.CurrNSDir = float(f.readline().split()[0]) self.fst_vt.platform_vt.CurrDIV = float(f.readline().split()[0]) self.fst_vt.platform_vt.CurrDIDir = float(f.readline().split()[0]) # OUTPUT (CONT) f.readline() self.fst_vt.platform_vt.NWaveKin = int(f.readline().split()[0]) if self.fst_vt.platform_vt.NWaveKin != 0: self.fst_vt.platform_vt.WaveKinNd = str(f.readline().split()[0]) def TowerReader(self): tower_file = os.path.join(self.fst_directory, self.fst_vt.TwrFile) f = open(tower_file) f.readline() f.readline() self.fst_vt.fst_tower_vt.description = f.readline().rstrip() # General Tower Paramters f.readline() self.fst_vt.fst_tower_vt.NTwInptSt = int(f.readline().split()[0]) boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.CalcTMode = False else: self.fst_vt.CalcTMode = True self.fst_vt.fst_tower_vt.TwrFADmp1 = float(f.readline().split()[0]) self.fst_vt.fst_tower_vt.TwrFADmp2 = float(f.readline().split()[0]) self.fst_vt.fst_tower_vt.TwrSSDmp1 = float(f.readline().split()[0]) self.fst_vt.fst_tower_vt.TwrSSDmp2 = float(f.readline().split()[0]) # Tower Adjustment Factors f.readline() self.fst_vt.fst_tower_vt.FAStTunr1 = float(f.readline().split()[0]) self.fst_vt.fst_tower_vt.FAStTunr2 = float(f.readline().split()[0]) self.fst_vt.fst_tower_vt.SSStTunr1 = float(f.readline().split()[0]) self.fst_vt.fst_tower_vt.SSStTunr2 = float(f.readline().split()[0]) self.fst_vt.fst_tower_vt.AdjTwMa = float(f.readline().split()[0]) self.fst_vt.fst_tower_vt.AdjFASt = float(f.readline().split()[0]) self.fst_vt.fst_tower_vt.AdjSSSt = float(f.readline().split()[0]) # Distributed Tower Properties x = f.readline() y = f.readline() z = f.readline() self.fst_vt.fst_tower_vt.HtFract = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt self.fst_vt.fst_tower_vt.TMassDen = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt self.fst_vt.fst_tower_vt.TwFAStif = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt self.fst_vt.fst_tower_vt.TwSSStif = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt self.fst_vt.fst_tower_vt.TwGJStif = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt self.fst_vt.fst_tower_vt.TwEAStif = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt self.fst_vt.fst_tower_vt.TwFAIner = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt self.fst_vt.fst_tower_vt.TwSSIner = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt self.fst_vt.fst_tower_vt.TwFAcgOf = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt self.fst_vt.fst_tower_vt.TwSScgOf = [ None ] * self.fst_vt.fst_tower_vt.NTwInptSt for i in range(self.fst_vt.fst_tower_vt.NTwInptSt): data = f.readline().split() self.fst_vt.fst_tower_vt.HtFract[i] = float(data[0]) self.fst_vt.fst_tower_vt.TMassDen[i] = float(data[1]) self.fst_vt.fst_tower_vt.TwFAStif[i] = float(data[2]) self.fst_vt.fst_tower_vt.TwSSStif[i] = float(data[3]) self.fst_vt.fst_tower_vt.TwGJStif[i] = float(data[4]) self.fst_vt.fst_tower_vt.TwEAStif[i] = float(data[5]) self.fst_vt.fst_tower_vt.TwFAIner[i] = float(data[6]) self.fst_vt.fst_tower_vt.TwSSIner[i] = float(data[7]) self.fst_vt.fst_tower_vt.TwFAcgOf[i] = float(data[8]) self.fst_vt.fst_tower_vt.TwSScgOf[i] = float(data[9]) # Tower Mode Shapes f.readline() self.fst_vt.fst_tower_vt.TwFAM1Sh = [None] * 5 self.fst_vt.fst_tower_vt.TwFAM2Sh = [None] * 5 for i in range(5): self.fst_vt.fst_tower_vt.TwFAM1Sh[i] = float( f.readline().split()[0]) for i in range(5): self.fst_vt.fst_tower_vt.TwFAM2Sh[i] = float( f.readline().split()[0]) f.readline() self.fst_vt.fst_tower_vt.TwSSM1Sh = [None] * 5 self.fst_vt.fst_tower_vt.TwSSM2Sh = [None] * 5 for i in range(5): self.fst_vt.fst_tower_vt.TwSSM1Sh[i] = float( f.readline().split()[0]) for i in range(5): self.fst_vt.fst_tower_vt.TwSSM2Sh[i] = float( f.readline().split()[0]) def BladeReader(self): blade_file = os.path.join(self.fst_directory, self.fst_vt.BldFile1) f = open(blade_file) f.readline() f.readline() self.fst_vt.fst_blade_vt.description = f.readline().rstrip() f.readline() self.fst_vt.fst_blade_vt.NBlInpSt = int(f.readline().split()[0]) boolflag = f.readline().split()[0] if boolflag == 'False': self.fst_vt.CalcBMode = False else: self.fst_vt.CalcBMode = True self.fst_vt.fst_blade_vt.BldFlDmp1 = float(f.readline().split()[0]) self.fst_vt.fst_blade_vt.BldFlDmp2 = float(f.readline().split()[0]) self.fst_vt.fst_blade_vt.BldEdDmp1 = float(f.readline().split()[0]) f.readline() self.fst_vt.fst_blade_vt.FlStTunr1 = float(f.readline().split()[0]) self.fst_vt.fst_blade_vt.FlStTunr2 = float(f.readline().split()[0]) self.fst_vt.fst_blade_vt.AdjBlMs = float(f.readline().split()[0]) self.fst_vt.fst_blade_vt.AdjFlSt = float(f.readline().split()[0]) self.fst_vt.fst_blade_vt.AdjEdSt = float(f.readline().split()[0]) f.readline() f.readline() f.readline() self.fst_vt.fst_blade_vt.BlFract = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.AeroCent = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.StrcTwst = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.BMassDen = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.FlpStff = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.EdgStff = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.GJStff = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.EAStff = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.Alpha = [None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.FlpIner = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.EdgIner = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.PrecrvRef = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.FlpcgOf = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.Edgcgof = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.FlpEAOf = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt self.fst_vt.fst_blade_vt.EdgEAOf = [ None ] * self.fst_vt.fst_blade_vt.NBlInpSt for i in range(self.fst_vt.fst_blade_vt.NBlInpSt): data = f.readline().split() self.fst_vt.fst_blade_vt.BlFract[i] = float(data[0]) self.fst_vt.fst_blade_vt.AeroCent[i] = float(data[1]) self.fst_vt.fst_blade_vt.StrcTwst[i] = float(data[2]) self.fst_vt.fst_blade_vt.BMassDen[i] = float(data[3]) self.fst_vt.fst_blade_vt.FlpStff[i] = float(data[4]) self.fst_vt.fst_blade_vt.EdgStff[i] = float(data[5]) self.fst_vt.fst_blade_vt.GJStff[i] = float(data[6]) self.fst_vt.fst_blade_vt.EAStff[i] = float(data[7]) self.fst_vt.fst_blade_vt.Alpha[i] = float(data[8]) self.fst_vt.fst_blade_vt.FlpIner[i] = float(data[9]) self.fst_vt.fst_blade_vt.EdgIner[i] = float(data[10]) self.fst_vt.fst_blade_vt.PrecrvRef[i] = float(data[11]) self.fst_vt.fst_blade_vt.FlpcgOf[i] = float(data[12]) self.fst_vt.fst_blade_vt.Edgcgof[i] = float(data[13]) self.fst_vt.fst_blade_vt.FlpEAOf[i] = float(data[14]) self.fst_vt.fst_blade_vt.EdgEAOf[i] = float(data[15]) f.readline() self.fst_vt.fst_blade_vt.BldFl1Sh = [None] * 5 self.fst_vt.fst_blade_vt.BldFl2Sh = [None] * 5 self.fst_vt.fst_blade_vt.BldEdgSh = [None] * 5 for i in range(5): self.fst_vt.fst_blade_vt.BldFl1Sh[i] = float( f.readline().split()[0]) for i in range(5): self.fst_vt.fst_blade_vt.BldFl2Sh[i] = float( f.readline().split()[0]) for i in range(5): self.fst_vt.fst_blade_vt.BldEdgSh[i] = float( f.readline().split()[0]) def AeroReader(self): #from airfoil import PolarByRe # only if creating airfoil variable trees ad_file = os.path.join(self.fst_directory, self.fst_vt.ADFile) f = open(ad_file) # skip lines and check if nondimensional f.readline() self.fst_vt.aero_vt.SysUnits = f.readline().split()[0] self.fst_vt.aero_vt.StallMod = f.readline().split()[0] self.fst_vt.aero_vt.UseCm = f.readline().split()[0] self.fst_vt.aero_vt.InfModel = f.readline().split()[0] self.fst_vt.aero_vt.IndModel = f.readline().split()[0] self.fst_vt.aero_vt.AToler = float(f.readline().split()[0]) self.fst_vt.aero_vt.TLModel = f.readline().split()[0] self.fst_vt.aero_vt.HLModel = f.readline().split()[0] self.fst_vt.aero_vt.WindFile = f.readline().split()[0][1:-1] if self.fst_vt.aero_vt.WindFile[-1] == 'h': self.fst_vt.aero_vt.wind_file_type = 'hh' elif self.fst_vt.aero_vt.WindFile[-1] == 's': self.fst_vt.aero_vt.wind_file_type = 'bts' else: self.fst_vt.aero_vt.wind_file_type = 'wnd' self.fst_vt.aero_vt.HH = float(f.readline().split()[0]) self.fst_vt.aero_vt.TwrShad = float(f.readline().split()[0]) self.fst_vt.aero_vt.ShadHWid = float(f.readline().split()[0]) self.fst_vt.aero_vt.T_Shad_Refpt = float(f.readline().split()[0]) self.fst_vt.aero_vt.AirDens = float(f.readline().split()[0]) self.fst_vt.aero_vt.KinVisc = float(f.readline().split()[0]) self.fst_vt.aero_vt.DTAero = float(f.readline().split()[0]) self.fst_vt.aero_vt.blade_vt.NumFoil = int(f.readline().split()[0]) self.fst_vt.aero_vt.blade_vt.FoilNm = [ None ] * self.fst_vt.aero_vt.blade_vt.NumFoil for i in range(self.fst_vt.aero_vt.blade_vt.NumFoil): af_filename = f.readline().split()[0] af_filename = fix_path(af_filename) print af_filename self.fst_vt.aero_vt.blade_vt.FoilNm[i] = af_filename[1:-1] self.fst_vt.aero_vt.blade_vt.BldNodes = int(f.readline().split()[0]) f.readline() self.fst_vt.aero_vt.blade_vt.RNodes = [ None ] * self.fst_vt.aero_vt.blade_vt.BldNodes self.fst_vt.aero_vt.blade_vt.AeroTwst = [ None ] * self.fst_vt.aero_vt.blade_vt.BldNodes self.fst_vt.aero_vt.blade_vt.DRNodes = [ None ] * self.fst_vt.aero_vt.blade_vt.BldNodes self.fst_vt.aero_vt.blade_vt.Chord = [ None ] * self.fst_vt.aero_vt.blade_vt.BldNodes self.fst_vt.aero_vt.blade_vt.NFoil = [ None ] * self.fst_vt.aero_vt.blade_vt.BldNodes self.fst_vt.aero_vt.blade_vt.PrnElm = [ None ] * self.fst_vt.aero_vt.blade_vt.BldNodes for i in range(self.fst_vt.aero_vt.blade_vt.BldNodes): data = f.readline().split() self.fst_vt.aero_vt.blade_vt.RNodes[i] = float(data[0]) self.fst_vt.aero_vt.blade_vt.AeroTwst[i] = float(data[1]) self.fst_vt.aero_vt.blade_vt.DRNodes[i] = float(data[2]) self.fst_vt.aero_vt.blade_vt.Chord[i] = float(data[3]) self.fst_vt.aero_vt.blade_vt.NFoil[i] = int(data[4]) self.fst_vt.aero_vt.blade_vt.PrnElm[i] = data[5] f.close() # create airfoil objects for i in range(self.fst_vt.aero_vt.blade_vt.NumFoil): self.fst_vt.aero_vt.blade_vt.af_data.append( self.initFromAerodynFile( os.path.join(self.fst_directory, self.fst_vt.aero_vt.blade_vt.FoilNm[i]), self.ad_file_type)) def initFromAerodynFile(self, aerodynFile, mode): # kld - added for fast noise """ Construct array of polars from old-style Aerodyn file Use this method for FAST (which can't read the new format) 2012 11 12 Arguments: aerodynFile - path/name of a properly formatted old-style Aerodyn file """ # open aerodyn file f = open(aerodynFile, 'r') airfoil = ADAirfoil() # skip through header airfoil.description = f.readline().rstrip() # remove newline f.readline() if mode == 0: f.readline() airfoil.number_tables = int(f.readline().split()[0]) # loop through tables for i in range(airfoil.number_tables): polar = ADAirfoilPolar() polar.IDParam = float(f.readline().split()[0]) if mode == 0: f.readline() polar.StallAngle = float(f.readline().split()[0]) if mode == 1: f.readline() f.readline() f.readline() polar.ZeroCn = float(f.readline().split()[0]) polar.CnSlope = float(f.readline().split()[0]) polar.CnPosStall = float(f.readline().split()[0]) polar.CnNegStall = float(f.readline().split()[0]) polar.alphaCdMin = float(f.readline().split()[0]) polar.CdMin = float(f.readline().split()[0]) alpha = [] cl = [] cd = [] cm = [] # read polar information line by line while True: line = f.readline() if 'EOT' in line: break data = [float(s) for s in line.split()] if len(data) < 1: break alpha.append(data[0]) cl.append(data[1]) cd.append(data[2]) cm.append(data[3]) polar.alpha = alpha polar.cl = cl polar.cd = cd polar.cm = cm airfoil.af_tables.append(polar) f.close() return airfoil def SimpleWindReader(self): #from airfoil import PolarByRe # only if creating airfoil variable trees wind_file = os.path.join(self.fst_directory, self.fst_vt.aero_vt.WindFile) f = open(wind_file) data = [] while 1: line = f.readline() if not line: break line_split = line.split() if line_split[0] != '!': data.append(line.split()) self.fst_vt.simple_wind_vt.TimeSteps = len(data) self.fst_vt.simple_wind_vt.Time = [None] * len(data) self.fst_vt.simple_wind_vt.HorSpd = [None] * len(data) self.fst_vt.simple_wind_vt.WindDir = [None] * len(data) self.fst_vt.simple_wind_vt.VerSpd = [None] * len(data) self.fst_vt.simple_wind_vt.HorShr = [None] * len(data) self.fst_vt.simple_wind_vt.VerShr = [None] * len(data) self.fst_vt.simple_wind_vt.LnVShr = [None] * len(data) self.fst_vt.simple_wind_vt.GstSpd = [None] * len(data) for i in range(len(data)): self.fst_vt.simple_wind_vt.Time[i] = float(data[i][0]) self.fst_vt.simple_wind_vt.HorSpd[i] = float(data[i][1]) self.fst_vt.simple_wind_vt.WindDir[i] = float(data[i][2]) self.fst_vt.simple_wind_vt.VerSpd[i] = float(data[i][3]) self.fst_vt.simple_wind_vt.HorShr[i] = float(data[i][4]) self.fst_vt.simple_wind_vt.VerShr[i] = float(data[i][5]) self.fst_vt.simple_wind_vt.LnVShr[i] = float(data[i][6]) self.fst_vt.simple_wind_vt.GstSpd[i] = float(data[i][7]) f.close()