def linearize(self, params, unknowns, resids): # rename rho = params['rho'] U = params['U'] d = params['d'] mu = params['mu'] beta = params['beta'] # dynamic pressure q = 0.5*rho*U**2 # Reynolds number and drag if params['cd_usr'] in [np.inf, -np.inf, None, np.nan]: cd = params['cd_usr'] Re = 1.0 dcd_dRe = 0.0 else: Re = rho*U*d/mu cd, dcd_dRe = cylinderDrag(Re) # derivatives dq_dU = rho*U const = (dq_dU*cd + q*dcd_dRe*rho*d/mu)*d dPx_dU = const*cosd(beta) dPy_dU = const*sind(beta) const = (cd + dcd_dRe*Re)*q dPx_dd = const*cosd(beta) dPy_dd = const*sind(beta) n = len(params['z']) zeron = np.zeros((n, n)) J = {} J['windLoads.Px', 'U'] = np.diag(dPx_dU) J['windLoads.Px', 'z'] = zeron J['windLoads.Px', 'd'] = np.diag(dPx_dd) J['windLoads.Py', 'U'] = np.diag(dPy_dU) J['windLoads.Py', 'z'] = zeron J['windLoads.Py', 'd'] = np.diag(dPy_dd) J['windLoads.Pz', 'U'] = zeron J['windLoads.Pz', 'z'] = zeron J['windLoads.Pz', 'd'] = zeron J['windLoads.qdyn', 'U'] = np.diag(dq_dU) J['windLoads.qdyn', 'z'] = zeron J['windLoads.qdyn', 'd'] = zeron J['windLoads.z', 'U'] = zeron J['windLoads.z', 'z'] = np.eye(n) J['windLoads.z', 'd'] = zeron return J
def solve_nonlinear(self, params, unknowns, resids): rho = params['rho'] U = params['U'] d = params['d'] mu = params['mu'] beta = params['beta'] # dynamic pressure q = 0.5*rho*U**2 # Reynolds number and drag if params['cd_usr'] in [np.inf, -np.inf, None, np.nan]: Re = rho*U*d/mu cd, dcd_dRe = cylinderDrag(Re) else: cd = params['cd_usr'] Re = 1.0 dcd_dRe = 0.0 Fp = q*cd*d # components of distributed loads Px = Fp*cosd(beta) Py = Fp*sind(beta) Pz = 0*Fp # pack data unknowns['windLoads_Px'] = Px unknowns['windLoads_Py'] = Py unknowns['windLoads_Pz'] = Pz unknowns['windLoads_qdyn'] = q unknowns['windLoads_z'] = params['z'] unknowns['windLoads_beta'] = beta
def execute(self): rho = self.rho U = self.U d = self.d mu = self.mu beta = self.beta # dynamic pressure q = 0.5*rho*U**2 # Reynolds number and drag if self.cd_usr: cd = self.cd_usr Re = 1.0 dcd_dRe = 0.0 else: Re = rho*U*d/mu cd, dcd_dRe = cylinderDrag(Re) Fp = q*cd*d # components of distributed loads Px = Fp*cosd(beta) Py = Fp*sind(beta) Pz = 0*Fp print "CommonSE Px (Wind): ", Px # pack data self.windLoads.Px = Px self.windLoads.Py = Py self.windLoads.Pz = Pz self.windLoads.qdyn = q self.windLoads.z = self.z self.windLoads.beta = beta # derivatives self.dq_dU = rho*U const = (self.dq_dU*cd + q*dcd_dRe*rho*d/mu)*d self.dPx_dU = const*cosd(beta) self.dPy_dU = const*sind(beta) const = (cd + dcd_dRe*Re)*q self.dPx_dd = const*cosd(beta) self.dPy_dd = const*sind(beta)
def provideJ(self): J = np.array([[ cosd(self.precone), sind(self.precone), (-self.Rtip * sind(self.precone) + self.precurveTip * sind(self.precone)) * pi / 180.0 ]]) return J
def execute(self): rho = self.rho U = self.U d = self.d mu = self.mu beta = self.beta # dynamic pressure q = 0.5 * rho * U**2 # Reynolds number and drag if self.cd_usr: cd = self.cd_usr Re = 1.0 dcd_dRe = 0.0 else: Re = rho * U * d / mu cd, dcd_dRe = cylinderDrag(Re) Fp = q * cd * d # components of distributed loads Px = Fp * cosd(beta) Py = Fp * sind(beta) Pz = 0 * Fp # pack data self.windLoads.Px = Px self.windLoads.Py = Py self.windLoads.Pz = Pz self.windLoads.qdyn = q self.windLoads.z = self.z self.windLoads.beta = beta # derivatives self.dq_dU = rho * U const = (self.dq_dU * cd + q * dcd_dRe * rho * d / mu) * d self.dPx_dU = const * cosd(beta) self.dPy_dU = const * sind(beta) const = (cd + dcd_dRe * Re) * q self.dPx_dd = const * cosd(beta) self.dPy_dd = const * sind(beta)
def solve_nonlinear(self, params, unknowns, resids): rho = params['rho'] U = params['U'] d = params['d'] mu = params['mu'] beta = params['beta'] if not (params['rho'] == 0. or all(params['U'] == 0.) or params['mu'] == 0.): # dynamic pressure q = 0.5*rho*U**2 # Reynolds number and drag if params['cd_usr'] in [np.inf, -np.inf, None, np.nan]: Re = rho*U*d/mu cd, dcd_dRe = cylinderDrag(Re) else: cd = params['cd_usr'] Re = 1.0 dcd_dRe = 0.0 Fp = q*cd*d # components of distributed loads Px = Fp*cosd(beta) Py = Fp*sind(beta) Pz = 0*Fp # pack data unknowns['windLoads_Px'] = Px unknowns['windLoads_Py'] = Py unknowns['windLoads_Pz'] = Pz unknowns['windLoads_qdyn'] = q unknowns['windLoads_beta'] = beta unknowns['windLoads_z'] = params['z'] unknowns['windLoads_d'] = params['d']
def execute(self): rho = self.rho U = self.U U0 = self.U0 d = self.d zrel= self.z-self.wlevel mu = self.mu beta = self.beta beta0= self.beta0 # dynamic pressure q = 0.5*rho*U**2 q0= 0.5*rho*U0**2 # Reynolds number and drag if self.cd_usr: cd = self.cd_usr*np.ones_like(self.d) Re = 1.0 dcd_dRe = 0.0 else: Re = rho*U*d/mu cd, dcd_dRe = cylinderDrag(Re) d = self.d mu = self.mu beta = self.beta # inertial and drag forces Fi = rho*self.cm*math.pi/4.0*d**2*self.A # Morrison's equation Fd = q*cd*d Fp = Fi + Fd #FORCES [N/m] AT z=0 m idx0 = np.abs(zrel).argmin() # closest index to z=0, used to find d at z=0 d0 = d[idx0] # initialize cd0 = cd[idx0] # initialize if (zrel[idx0]<0.) and (idx0< (zrel.size-1)): # point below water d0 = np.mean(d[idx0:idx0+2]) cd0 = np.mean(cd[idx0:idx0+2]) elif (zrel[idx0]>0.) and (idx0>0): # point above water d0 = np.mean(d[idx0-1:idx0+1]) cd0 = np.mean(cd[idx0-1:idx0+1]) Fi0 = rho*self.cm*math.pi/4.0*d0**2*self.A0 # Morrison's equation Fd0 = q0*cd0*d0 Fp0 = Fi0 + Fd0 # components of distributed loads Px = Fp*cosd(beta) Py = Fp*sind(beta) Pz = 0.*Fp Px0 = Fp0*cosd(beta0) Py0 = Fp0*sind(beta0) Pz0 = 0.*Fp0 #Store qties at z=0 MSL self.waveLoads.Px0 = Px0 self.waveLoads.Py0 = Py0 self.waveLoads.Pz0 = Pz0 self.waveLoads.q0 = q0 self.waveLoads.beta0 = beta0 # pack data self.waveLoads.Px = Px self.waveLoads.Py = Py self.waveLoads.Pz = Pz self.waveLoads.qdyn = q self.waveLoads.z = self.z self.waveLoads.beta = beta self.waveLoads.d = d # derivatives self.dq_dU = rho*U const = (self.dq_dU*cd + q*dcd_dRe*rho*d/mu)*d self.dPx_dU = const*cosd(beta) self.dPy_dU = const*sind(beta) const = (cd + dcd_dRe*Re)*q + rho*self.cm*math.pi/4.0*2*d*self.A self.dPx_dd = const*cosd(beta) self.dPy_dd = const*sind(beta) const = rho*self.cm*math.pi/4.0*d**2 self.dPx_dA = const*cosd(beta) self.dPy_dA = const*sind(beta)
def execute(self): #simplify nomenclature psi_wi=self.towerWindLoads.beta[0] #psi is stored in beta already, however for legs and piles it needs to be adjusted for psi psi_wa=self.towerWaveLoads.beta[0] twrZs=self.towerWindLoads.z pillegZs=self.pileLegWaveLoads.z pillegDs=self.pileLegWaveLoads.d nlegs=self.nlegs al_bat3D=self.al_bat3D VPFlag=self.VPFlag TwrRigidTop=(self.RNAinputs.CMoff[2] != 0.) and self.TwrRigidTop #This makes sure we do not have TwrRigidTop=True with CMzoff=0., no length segment that is. pilendIDs=self.pilendIDs legndIDs=self.legndIDs twrndIDs=self.twrndIDs wdepth=self.wdepth #COSINE MATRIX FROM LOCAL TO GLOBAL COORDINATE SYSTEMS DIRCOSwind=np.array([ [cosd(psi_wi) , -sind(psi_wi) ,0.], [ sind(psi_wi) , cosd(psi_wi),0.], [ 0., 0., 1.]]) DIRCOSwave=np.array([ [cosd(psi_wa) , -sind(psi_wa) ,0.], [ sind(psi_wa) , cosd(psi_wa),0.], [ 0., 0., 1.]]) #I need to get the right node IDs to be able to assign forces for Frame3DD #Get the values of the loads at the nodes of pile and leg 1 #for the other legs, the wdrag is going to be the same if nlegs== 4: #Diagonal loading condition ONLY for the time being pileidx=np.array([]) #Initialize in case empty piles if pilendIDs.size: pileidx=pilendIDs[0:pilendIDs.size/nlegs] #np.arange(Pilemems[0,0],Pilemems[-1,1]/nlegs+1)-1 #indices of pile 1 legidx=legndIDs[0:legndIDs.size/nlegs] #legidx=np.arange(Legmems[0,0],Legmems[-1,1]/nlegs+1)-1 #indices of leg 1 deltaz=((np.roll(pillegZs,-1)-pillegZs)/2)[0:-1] #these are the appropriate 1/2 deltazs for the entire pile-leg assembly deltaz=np.hstack((deltaz[0],(np.roll(deltaz,-1)+deltaz)[0:-1],deltaz[-1])) #This is the actual DeltaZ to be assigned at each node starting from the 2nd and ending at the one before last #Correct the delta z for the node just below water to avoid jumps in loading - use refined mesh however #idx_bw=np.nonzero(pillegZs<= wdepth)[0][-1] #CJB- Original code. Modified line below idx_bw=np.nonzero(pillegZs<= 0)[0][-1] #CJBe THe MSL is now at z=0, not z=wdepth #Also Attempt at using load at z=0 ###Px0=self.pileLegWaveLoads.Px_i0overd2*pillegDs[idx_bw]**2+self.pileLegWaveLoads.Px_d0overd*pillegDs[idx_bw] ###Py0=self.pileLegWaveLoads.Py_i0overd2*pillegDs[idx_bw]**2+self.pileLegWaveLoads.Py_d0overd*pillegDs[idx_bw] Px0=self.pileLegWaveLoads.Px0 Py0=self.pileLegWaveLoads.Py0 #deltaz0=(wdepth-pillegZs[idx_bw]) #CJB- Original code. Modified line below deltaz0=np.abs(0-pillegZs[idx_bw]) #CJBe #if (wdepth-pillegZs[idx_bw])> deltaz[idx_bw]/2.: #point with its deltaz entriely below surface #CJB- Original code. Modified line below if np.abs(0-pillegZs[idx_bw])> np.abs(deltaz[idx_bw]/2.): #CJBe Remove wdepth deltaz0 -= deltaz[idx_bw]/2. #note deltaz0 before deltaz as deltaz gets modified #deltaz[idx_bw]=deltaz[idx_bw]/2. -(pillegZs[idx_bw]-wdepth) else: deltaz[idx_bw]=deltaz[idx_bw]/2. waDrag0=np.sqrt(Px0**2.+Py0**2.)*deltaz0 #In case add this one to the original wDrag, or alternatively do awhat I do below, increasing Deltaz waDrag=np.sqrt(self.pileLegWaveLoads.Px**2.+self.pileLegWaveLoads.Py**2.)*deltaz #[N] forces from waves, considered normal to the sloping 1 leg. waDrag[idx_bw] += waDrag0 wiDrag=np.sqrt(self.pileLegWindLoads.Px**2.+self.pileLegWindLoads.Py**2.)*deltaz * (np.cos(al_bat3D))**2 #[N] forces from wind normal to the sloping 1 leg. Wind is horizontal, that's why cos^2 #Forces on legs 1 (and 3 though sign of Fz reversed) junk=np.zeros(waDrag.size) waDrag1_3= (np.dot(DIRCOSwave , np.vstack((waDrag*np.cos(al_bat3D),junk,waDrag*np.sin(al_bat3D))))).T #[n,3] [N] This is an approx for air drag, as it is not normal to the leg to begin with, but it makes it easier wiDrag1_3= (np.dot(DIRCOSwind , np.vstack((wiDrag*np.cos(al_bat3D),junk,wiDrag*np.sin(al_bat3D))))).T #[n,3] [N] #Forces on legs 2 (and 4), it is as if they were vertical waDrag2_4= (np.dot(DIRCOSwave ,np.vstack((waDrag,junk, waDrag*0.)))).T #[n,3] [N] wiDrag2_4= (np.dot(DIRCOSwind ,np.vstack((wiDrag,junk, wiDrag*0.)))).T #[n,3] [N] #Add them together wDrag1_3=waDrag1_3+wiDrag1_3 #[N] wDrag2_4=waDrag2_4+wiDrag2_4 #[N] wDrag=waDrag+wiDrag #[N] wl_idx=np.nonzero(wDrag)[0] #indices of the pile-leg nodes where loading is applied-- if VPFlag and pileidx: #Need to account for the cos #Forces on legs 1 (and 3 though sign of Fz reversed) wDrag1_3[pileidx]=wDrag2_4[pileidx] n_pillegLds=wl_idx.size n_loads=n_pillegLds*nlegs #Total number of wave load nodes pilleg_ndsfrc=np.zeros([n_loads,7]) nNodespile=pileidx.size #number of nodes in 1 pile nNodesleg=legidx.size #number of nodes in 1 leg for ii in range(0,nlegs): #Cycle through legs idx0=nNodespile*ii #start index for pile IDs idx1=idx0+nNodespile #stop index for pile IDs idx2=nNodesleg*ii #start index for leg IDs idx3=idx2+nNodesleg #stop index for leg IDs nd_ids=np.vstack((self.pilendIDs[idx0:idx1],self.legndIDs[idx2:idx3]))[wl_idx] if np.mod(ii,2)==0: lds=wDrag2_4[wl_idx,:] elif ii==1: lds=np.hstack((wDrag1_3[wl_idx,0:2],-wDrag1_3[wl_idx,2].reshape(-1,1))) else: lds=wDrag1_3[wl_idx,:] idx0=n_pillegLds*ii #start index in pilleg_ndsfrc idx1=idx0+n_pillegLds #stop index in pilleg_ndsfrc pilleg_ndsfrc[idx0:idx1,:-3]=np.hstack((nd_ids,lds)) #Store wave loads self.Loadouts.wdrag1_3=wDrag1_3 self.Loadouts.wdrag2_4=wDrag2_4 else: #3legged jacket in progress #TO DO THIS CASE sys.exit("nlegs <>4 not implemented yet for loading") #-----Need to add hydrostatic loading -BUOYANCY FORCE #IT is a distributed force along the non-flooded members #Still TO DO #________________________________TOWER__________________________________# #Now get the values of the loads at the nodes of Tower junk=(np.roll(twrZs,-1)-np.roll(twrZs,1))[1:-1]/2. deltaz=np.hstack(((twrZs[1]-twrZs[0])/2.,junk,(twrZs[-1]-twrZs[-2])/2.))#these are the appropriate deltazs #just wind loading for tower but wtrload perhaps in the future for tripods junk=(np.sqrt(self.towerWindLoads.Px**2+self.towerWindLoads.Py**2)*deltaz).reshape([-1,1]) #[N] forces #decompose along local x,y and add z component junk=np.hstack((junk,np.zeros([junk.size,2]))).T self.Loadouts.twr_dragf=np.dot(DIRCOSwind , junk) #*np.sin(wind_dict['psi']), junk*0.]) #Tower Loads for Frame3DD n_twrlds=(twrndIDs.shape[0]-TwrRigidTop)*(self.Loadouts.twr_dragf.any()) #distributed loads along tower+RNA node load twr_ndsfrc=np.zeros([n_twrlds,7]) twr_ndsfrc[0:n_twrlds,:-3]=np.hstack((twrndIDs[0:len(twrndIDs)-TwrRigidTop].reshape([-1,1]),self.Loadouts.twr_dragf.T)) #____________ADD CONCENTRATED RNA FORCES________________________________# #First account for moment transfer in global coordinate system as if yaw=0 RNAload=np.copy(self.RNA_F.reshape([2,3]).T)#RNAload: 1columns forces, 2nd column moments #Store yaw-rotated forces and moments at the hub still [3,2] self.Loadouts.RNAload=np.dot(DIRCOSwind,RNAload) Deltax=self.RNAinputs.Thoff[0]-self.RNAinputs.CMoff[0] Deltay=self.RNAinputs.Thoff[1]-self.RNAinputs.CMoff[1] Deltaz=self.RNAinputs.Thoff[2]-self.RNAinputs.CMoff[2] if not(TwrRigidTop): Deltax=self.RNAinputs.Thoff[0] Deltay=self.RNAinputs.Thoff[1] Deltaz=self.RNAinputs.Thoff[2] #Rotor Loads - no weight yet RNAload[0,1] += -RNAload[1,0]*Deltaz + RNAload[2,0]*Deltay #Mxx=-Fy*Deltaz +Fz*deltay RNAload[1,1] += RNAload[0,0]*Deltaz - RNAload[2,0]*Deltax #Myy= Fx*deltaz-Fz*deltax RNAload[2,1] += -RNAload[0,0]*Deltay + RNAload[1,0]*Deltax #Mzz=-Fx*Deltay +Fy*deltax #Then rotate them in the global coordinate system for PYFRAME to account for yaw RNAload=np.dot(DIRCOSwind,RNAload) #Gravity is already accounted for by Frame3DD for concentrated masses: Jacket.Twr.RNAmass*aux['g_z'],np.zeros(3))) self.RNA_F.reshape([2,3]).T if not(TwrRigidTop): twr_ndsfrc[-1,1:] += RNAload.T.flatten() else: twr_ndsfrc = np.vstack(( twr_ndsfrc,np.hstack((twrndIDs[-1],RNAload.T.flatten())) )) # If we apply this load at tower-top and not tower-top+CMzoff we need to account for different DeltaZ ## if not(TwrRigidTop): ## RNAload[0,1] -= RNAload[1,0]*ThOffset_z #*CMzoff #Mxx ## RNAload[1,1] += RNAload[0,0]*CMzoff #Myy ## twr_ndsfrc[-1,1:] += RNAload.T.flatten() ## else: #Put forces at the RNA.CM location ## RNAload[0,1] -= RNAload[1,0]*ThOffset_z #*CMzoff #Mxx ## RNAload[1,1] += RNAload[0,0]*CMzoff #Myy ## ## twr_ndsfrc[-1,:] += np.hstack((twrndIDs[-1],RNAload.T.flatten())) #STACK ALLOF THEM TOGETHER self.Loadouts.nds_frc=np.vstack((pilleg_ndsfrc, twr_ndsfrc)) #Concentrated loads
def execute(self): rho = self.rho U = self.U U0 = self.U0 d = self.d zrel = self.z - self.wlevel mu = self.mu beta = self.beta beta0 = self.beta0 # dynamic pressure q = 0.5 * rho * U**2 q0 = 0.5 * rho * U0**2 # Reynolds number and drag if self.cd_usr: cd = self.cd_usr * np.ones_like(self.d) Re = 1.0 dcd_dRe = 0.0 else: Re = rho * U * d / mu cd, dcd_dRe = cylinderDrag(Re) d = self.d mu = self.mu beta = self.beta # inertial and drag forces Fi = rho * self.cm * math.pi / 4.0 * d**2 * self.A # Morrison's equation Fd = q * cd * d Fp = Fi + Fd #FORCES [N/m] AT z=0 m idx0 = np.abs( zrel).argmin() # closest index to z=0, used to find d at z=0 d0 = d[idx0] # initialize cd0 = cd[idx0] # initialize if (zrel[idx0] < 0.) and (idx0 < (zrel.size - 1)): # point below water d0 = np.mean(d[idx0:idx0 + 2]) cd0 = np.mean(cd[idx0:idx0 + 2]) elif (zrel[idx0] > 0.) and (idx0 > 0): # point above water d0 = np.mean(d[idx0 - 1:idx0 + 1]) cd0 = np.mean(cd[idx0 - 1:idx0 + 1]) Fi0 = rho * self.cm * math.pi / 4.0 * d0**2 * self.A0 # Morrison's equation Fd0 = q0 * cd0 * d0 Fp0 = Fi0 + Fd0 # components of distributed loads Px = Fp * cosd(beta) Py = Fp * sind(beta) Pz = 0. * Fp Px0 = Fp0 * cosd(beta0) Py0 = Fp0 * sind(beta0) Pz0 = 0. * Fp0 #Store qties at z=0 MSL self.waveLoads.Px0 = Px0 self.waveLoads.Py0 = Py0 self.waveLoads.Pz0 = Pz0 self.waveLoads.q0 = q0 self.waveLoads.beta0 = beta0 # pack data self.waveLoads.Px = Px self.waveLoads.Py = Py self.waveLoads.Pz = Pz self.waveLoads.qdyn = q self.waveLoads.z = self.z self.waveLoads.beta = beta self.waveLoads.d = d # derivatives self.dq_dU = rho * U const = (self.dq_dU * cd + q * dcd_dRe * rho * d / mu) * d self.dPx_dU = const * cosd(beta) self.dPy_dU = const * sind(beta) const = (cd + dcd_dRe * Re) * q + rho * self.cm * math.pi / 4.0 * 2 * d * self.A self.dPx_dd = const * cosd(beta) self.dPy_dd = const * sind(beta) const = rho * self.cm * math.pi / 4.0 * d**2 self.dPx_dA = const * cosd(beta) self.dPy_dA = const * sind(beta)
def provideJ(self): J = np.array([[cosd(self.precone), -self.Rtip*sind(self.precone)*pi/180.0]]) return J
def execute(self): self.R = self.Rtip*cosd(self.precone) # no precurvature
def solve_nonlinear(self, params, unknowns, resids): #wlevel = params['wlevel'] #if wlevel > 0.0: wlevel *= -1.0 rho = params['rho'] U = params['U'] #U0 = params['U0'] d = params['d'] #zrel= params['z']-wlevel mu = params['mu'] beta = params['beta'] #beta0 = params['beta0'] # dynamic pressure q = 0.5*rho*U**2 #q0= 0.5*rho*U0**2 # Reynolds number and drag if params['cd_usr'] in [np.inf, -np.inf, None, np.nan]: Re = rho*U*d/mu cd, dcd_dRe = cylinderDrag(Re) else: cd = params['cd_usr']*np.ones_like(d) Re = 1.0 dcd_dRe = 0.0 # inertial and drag forces Fi = rho*params['cm']*math.pi/4.0*d**2*params['A'] # Morrison's equation Fd = q*cd*d Fp = Fi + Fd # components of distributed loads Px = Fp*cosd(beta) Py = Fp*sind(beta) Pz = 0.*Fp #FORCES [N/m] AT z=0 m #idx0 = np.abs(zrel).argmin() # closest index to z=0, used to find d at z=0 #d0 = d[idx0] # initialize #cd0 = cd[idx0] # initialize #if (zrel[idx0]<0.) and (idx0< (zrel.size-1)): # point below water # d0 = np.mean(d[idx0:idx0+2]) # cd0 = np.mean(cd[idx0:idx0+2]) #elif (zrel[idx0]>0.) and (idx0>0): # point above water # d0 = np.mean(d[idx0-1:idx0+1]) # cd0 = np.mean(cd[idx0-1:idx0+1]) #Fi0 = rho*params['cm']*math.pi/4.0*d0**2*params['A0'] # Morrison's equation #Fd0 = q0*cd0*d0 #Fp0 = Fi0 + Fd0 #Px0 = Fp0*cosd(beta0) #Py0 = Fp0*sind(beta0) #Pz0 = 0.*Fp0 #Store qties at z=0 MSL #unknowns['waveLoads_Px0'] = Px0 #unknowns['waveLoads_Py0'] = Py0 #unknowns['waveLoads_Pz0'] = Pz0 #unknowns['waveLoads_qdyn0'] = q0 #unknowns['waveLoads_beta0'] = beta0 # pack data unknowns['waveLoads_Px'] = Px unknowns['waveLoads_Py'] = Py unknowns['waveLoads_Pz'] = Pz unknowns['waveLoads_qdyn'] = q unknowns['waveLoads_pt'] = q + params['p'] unknowns['waveLoads_z'] = params['z'] unknowns['waveLoads_beta'] = beta unknowns['waveLoads_d'] = d
def execute(self): self.R = self.Rtip*cosd(self.precone) + self.precurveTip*sind(self.precone)
def execute(self): #simplify nomenclature psi_wi = self.towerWindLoads.beta[ 0] #psi is stored in beta already, however for legs and piles it needs to be adjusted for psi psi_wa = self.towerWaveLoads.beta[0] twrZs = self.towerWindLoads.z pillegZs = self.pileLegWaveLoads.z pillegDs = self.pileLegWaveLoads.d nlegs = self.nlegs al_bat3D = self.al_bat3D VPFlag = self.VPFlag TwrRigidTop = ( self.RNAinputs.CMoff[2] != 0. ) and self.TwrRigidTop #This makes sure we do not have TwrRigidTop=True with CMzoff=0., no length segment that is. pilendIDs = self.pilendIDs legndIDs = self.legndIDs twrndIDs = self.twrndIDs wdepth = self.wdepth #COSINE MATRIX FROM LOCAL TO GLOBAL COORDINATE SYSTEMS DIRCOSwind = np.array([[cosd(psi_wi), -sind(psi_wi), 0.], [sind(psi_wi), cosd(psi_wi), 0.], [0., 0., 1.]]) DIRCOSwave = np.array([[cosd(psi_wa), -sind(psi_wa), 0.], [sind(psi_wa), cosd(psi_wa), 0.], [0., 0., 1.]]) #I need to get the right node IDs to be able to assign forces for Frame3DD #Get the values of the loads at the nodes of pile and leg 1 #for the other legs, the wdrag is going to be the same if nlegs == 4: #Diagonal loading condition ONLY for the time being pileidx = np.array([]) #Initialize in case empty piles if pilendIDs.size: pileidx = pilendIDs[ 0:pilendIDs.size / nlegs] #np.arange(Pilemems[0,0],Pilemems[-1,1]/nlegs+1)-1 #indices of pile 1 legidx = legndIDs[ 0:legndIDs.size / nlegs] #legidx=np.arange(Legmems[0,0],Legmems[-1,1]/nlegs+1)-1 #indices of leg 1 deltaz = ( (np.roll(pillegZs, -1) - pillegZs) / 2 )[0: -1] #these are the appropriate 1/2 deltazs for the entire pile-leg assembly deltaz = np.hstack( (deltaz[0], (np.roll(deltaz, -1) + deltaz)[0:-1], deltaz[-1]) ) #This is the actual DeltaZ to be assigned at each node starting from the 2nd and ending at the one before last #Correct the delta z for the node just below water to avoid jumps in loading - use refined mesh however #idx_bw=np.nonzero(pillegZs<= wdepth)[0][-1] #CJB- Original code. Modified line below idx_bw = np.nonzero(pillegZs <= 0)[0][ -1] #CJBe THe MSL is now at z=0, not z=wdepth #Also Attempt at using load at z=0 ###Px0=self.pileLegWaveLoads.Px_i0overd2*pillegDs[idx_bw]**2+self.pileLegWaveLoads.Px_d0overd*pillegDs[idx_bw] ###Py0=self.pileLegWaveLoads.Py_i0overd2*pillegDs[idx_bw]**2+self.pileLegWaveLoads.Py_d0overd*pillegDs[idx_bw] Px0 = self.pileLegWaveLoads.Px0 Py0 = self.pileLegWaveLoads.Py0 #deltaz0=(wdepth-pillegZs[idx_bw]) #CJB- Original code. Modified line below deltaz0 = np.abs(0 - pillegZs[idx_bw]) #CJBe #if (wdepth-pillegZs[idx_bw])> deltaz[idx_bw]/2.: #point with its deltaz entriely below surface #CJB- Original code. Modified line below if np.abs(0 - pillegZs[idx_bw]) > np.abs( deltaz[idx_bw] / 2.): #CJBe Remove wdepth deltaz0 -= deltaz[ idx_bw] / 2. #note deltaz0 before deltaz as deltaz gets modified #deltaz[idx_bw]=deltaz[idx_bw]/2. -(pillegZs[idx_bw]-wdepth) else: deltaz[idx_bw] = deltaz[idx_bw] / 2. waDrag0 = np.sqrt( Px0**2. + Py0**2. ) * deltaz0 #In case add this one to the original wDrag, or alternatively do awhat I do below, increasing Deltaz waDrag = np.sqrt( self.pileLegWaveLoads.Px**2. + self.pileLegWaveLoads.Py**2. ) * deltaz #[N] forces from waves, considered normal to the sloping 1 leg. waDrag[idx_bw] += waDrag0 wiDrag = np.sqrt( self.pileLegWindLoads.Px**2. + self.pileLegWindLoads.Py**2. ) * deltaz * ( np.cos(al_bat3D) )**2 #[N] forces from wind normal to the sloping 1 leg. Wind is horizontal, that's why cos^2 #Forces on legs 1 (and 3 though sign of Fz reversed) junk = np.zeros(waDrag.size) waDrag1_3 = ( np.dot( DIRCOSwave, np.vstack((waDrag * np.cos(al_bat3D), junk, waDrag * np.sin(al_bat3D)))) ).T #[n,3] [N] This is an approx for air drag, as it is not normal to the leg to begin with, but it makes it easier wiDrag1_3 = (np.dot( DIRCOSwind, np.vstack((wiDrag * np.cos(al_bat3D), junk, wiDrag * np.sin(al_bat3D))))).T #[n,3] [N] #Forces on legs 2 (and 4), it is as if they were vertical waDrag2_4 = (np.dot(DIRCOSwave, np.vstack((waDrag, junk, waDrag * 0.)))).T #[n,3] [N] wiDrag2_4 = (np.dot(DIRCOSwind, np.vstack((wiDrag, junk, wiDrag * 0.)))).T #[n,3] [N] #Add them together wDrag1_3 = waDrag1_3 + wiDrag1_3 #[N] wDrag2_4 = waDrag2_4 + wiDrag2_4 #[N] wDrag = waDrag + wiDrag #[N] wl_idx = np.nonzero(wDrag)[ 0] #indices of the pile-leg nodes where loading is applied-- if VPFlag and pileidx: #Need to account for the cos #Forces on legs 1 (and 3 though sign of Fz reversed) wDrag1_3[pileidx] = wDrag2_4[pileidx] n_pillegLds = wl_idx.size n_loads = n_pillegLds * nlegs #Total number of wave load nodes pilleg_ndsfrc = np.zeros([n_loads, 7]) nNodespile = pileidx.size #number of nodes in 1 pile nNodesleg = legidx.size #number of nodes in 1 leg for ii in range(0, nlegs): #Cycle through legs idx0 = nNodespile * ii #start index for pile IDs idx1 = idx0 + nNodespile #stop index for pile IDs idx2 = nNodesleg * ii #start index for leg IDs idx3 = idx2 + nNodesleg #stop index for leg IDs nd_ids = np.vstack((self.pilendIDs[idx0:idx1], self.legndIDs[idx2:idx3]))[wl_idx] if np.mod(ii, 2) == 0: lds = wDrag2_4[wl_idx, :] elif ii == 1: lds = np.hstack( (wDrag1_3[wl_idx, 0:2], -wDrag1_3[wl_idx, 2].reshape(-1, 1))) else: lds = wDrag1_3[wl_idx, :] idx0 = n_pillegLds * ii #start index in pilleg_ndsfrc idx1 = idx0 + n_pillegLds #stop index in pilleg_ndsfrc pilleg_ndsfrc[idx0:idx1, :-3] = np.hstack((nd_ids, lds)) #Store wave loads self.Loadouts.wdrag1_3 = wDrag1_3 self.Loadouts.wdrag2_4 = wDrag2_4 else: #3legged jacket in progress #TO DO THIS CASE sys.exit("nlegs <>4 not implemented yet for loading") #-----Need to add hydrostatic loading -BUOYANCY FORCE #IT is a distributed force along the non-flooded members #Still TO DO #________________________________TOWER__________________________________# #Now get the values of the loads at the nodes of Tower junk = (np.roll(twrZs, -1) - np.roll(twrZs, 1))[1:-1] / 2. deltaz = np.hstack( ((twrZs[1] - twrZs[0]) / 2., junk, (twrZs[-1] - twrZs[-2]) / 2.)) #these are the appropriate deltazs #just wind loading for tower but wtrload perhaps in the future for tripods junk = ( np.sqrt(self.towerWindLoads.Px**2 + self.towerWindLoads.Py**2) * deltaz).reshape([-1, 1]) #[N] forces #decompose along local x,y and add z component junk = np.hstack((junk, np.zeros([junk.size, 2]))).T self.Loadouts.twr_dragf = np.dot( DIRCOSwind, junk) #*np.sin(wind_dict['psi']), junk*0.]) #Tower Loads for Frame3DD n_twrlds = (twrndIDs.shape[0] - TwrRigidTop) * ( self.Loadouts.twr_dragf.any() ) #distributed loads along tower+RNA node load twr_ndsfrc = np.zeros([n_twrlds, 7]) twr_ndsfrc[0:n_twrlds, :-3] = np.hstack( (twrndIDs[0:len(twrndIDs) - TwrRigidTop].reshape([-1, 1]), self.Loadouts.twr_dragf.T)) #____________ADD CONCENTRATED RNA FORCES________________________________# #First account for moment transfer in global coordinate system as if yaw=0 RNAload = np.copy(self.RNA_F.reshape( [2, 3]).T) #RNAload: 1columns forces, 2nd column moments #Store yaw-rotated forces and moments at the hub still [3,2] self.Loadouts.RNAload = np.dot(DIRCOSwind, RNAload) Deltax = self.RNAinputs.Thoff[0] - self.RNAinputs.CMoff[0] Deltay = self.RNAinputs.Thoff[1] - self.RNAinputs.CMoff[1] Deltaz = self.RNAinputs.Thoff[2] - self.RNAinputs.CMoff[2] if not (TwrRigidTop): Deltax = self.RNAinputs.Thoff[0] Deltay = self.RNAinputs.Thoff[1] Deltaz = self.RNAinputs.Thoff[2] #Rotor Loads - no weight yet RNAload[0, 1] += -RNAload[1, 0] * Deltaz + RNAload[ 2, 0] * Deltay #Mxx=-Fy*Deltaz +Fz*deltay RNAload[1, 1] += RNAload[0, 0] * Deltaz - RNAload[ 2, 0] * Deltax #Myy= Fx*deltaz-Fz*deltax RNAload[2, 1] += -RNAload[0, 0] * Deltay + RNAload[ 1, 0] * Deltax #Mzz=-Fx*Deltay +Fy*deltax #Then rotate them in the global coordinate system for PYFRAME to account for yaw RNAload = np.dot( DIRCOSwind, RNAload ) #Gravity is already accounted for by Frame3DD for concentrated masses: Jacket.Twr.RNAmass*aux['g_z'],np.zeros(3))) self.RNA_F.reshape([2,3]).T if not (TwrRigidTop): twr_ndsfrc[-1, 1:] += RNAload.T.flatten() else: twr_ndsfrc = np.vstack( (twr_ndsfrc, np.hstack((twrndIDs[-1], RNAload.T.flatten())))) # If we apply this load at tower-top and not tower-top+CMzoff we need to account for different DeltaZ ## if not(TwrRigidTop): ## RNAload[0,1] -= RNAload[1,0]*ThOffset_z #*CMzoff #Mxx ## RNAload[1,1] += RNAload[0,0]*CMzoff #Myy ## twr_ndsfrc[-1,1:] += RNAload.T.flatten() ## else: #Put forces at the RNA.CM location ## RNAload[0,1] -= RNAload[1,0]*ThOffset_z #*CMzoff #Mxx ## RNAload[1,1] += RNAload[0,0]*CMzoff #Myy ## ## twr_ndsfrc[-1,:] += np.hstack((twrndIDs[-1],RNAload.T.flatten())) #STACK ALLOF THEM TOGETHER self.Loadouts.nds_frc = np.vstack( (pilleg_ndsfrc, twr_ndsfrc)) #Concentrated loads
def linearize(self, params, unknowns, resids): #wlevel = params['wlevel'] #if wlevel > 0.0: wlevel *= -1.0 rho = params['rho'] U = params['U'] #U0 = params['U0'] d = params['d'] #zrel= params['z']-wlevel mu = params['mu'] beta = params['beta'] #beta0 = params['beta0'] # dynamic pressure q = 0.5*rho*U**2 #q0= 0.5*rho*U0**2 # Reynolds number and drag if params['cd_usr'] in [np.inf, -np.inf, None, np.nan]: cd = params['cd_usr']*np.ones_like(d) Re = 1.0 dcd_dRe = 0.0 else: Re = rho*U*d/mu cd, dcd_dRe = cylinderDrag(Re) # derivatives dq_dU = rho*U const = (dq_dU*cd + q*dcd_dRe*rho*d/mu)*d dPx_dU = const*cosd(beta) dPy_dU = const*sind(beta) const = (cd + dcd_dRe*Re)*q + rho*params['cm']*math.pi/4.0*2*d*params['A'] dPx_dd = const*cosd(beta) dPy_dd = const*sind(beta) const = rho*params['cm']*math.pi/4.0*d**2 dPx_dA = const*cosd(beta) dPy_dA = const*sind(beta) n = len(params['z']) zeron = np.zeros((n, n)) J = {} J['waveLoads.Px', 'U'] = np.diag(dPx_dU) J['waveLoads.Px', 'A'] = np.diag(dPx_dA) J['waveLoads.Px', 'z'] = zeron J['waveLoads.Px', 'd'] = np.diag(dPx_dd) J['waveLoads.Px', 'p'] = zeron J['waveLoads.Py', 'U'] = np.diag(dPy_dU) J['waveLoads.Py', 'A'] = np.diag(dPy_dA) J['waveLoads.Py', 'z'] = zeron J['waveLoads.Py', 'd'] = np.diag(dPy_dd) J['waveLoads.Py', 'p'] = zeron J['waveLoads.Pz', 'U'] = zeron J['waveLoads.Pz', 'A'] = zeron J['waveLoads.Pz', 'z'] = zeron J['waveLoads.Pz', 'd'] = zeron J['waveLoads.Pz', 'p'] = zeron J['waveLoads.qdyn', 'U'] = np.diag(dq_dU) J['waveLoads.qdyn', 'A'] = zeron J['waveLoads.qdyn', 'z'] = zeron J['waveLoads.qdyn', 'd'] = zeron J['waveLoads.qdyn', 'p'] = zeron J['waveLoads.pt', 'U'] = np.diag(dq_dU) J['waveLoads.pt', 'A'] = zeron J['waveLoads.pt', 'z'] = zeron J['waveLoads.pt', 'd'] = zeron J['waveLoads.pt', 'p'] = 1.0 J['waveLoads.z', 'U'] = zeron J['waveLoads.z', 'A'] = zeron J['waveLoads.z', 'z'] = np.eye(n) J['waveLoads.z', 'd'] = zeron J['waveLoads.z', 'p'] = zeron return J
def solve_nonlinear(self, params, unknowns, resids): #wlevel = params['wlevel'] #if wlevel > 0.0: wlevel *= -1.0 rho = params['rho'] U = params['U'] #U0 = params['U0'] d = params['d'] #zrel= params['z']-wlevel mu = params['mu'] beta = params['beta'] #beta0 = params['beta0'] if not (params['rho'] == 0. or all(params['U'] == 0.) or params['mu'] == 0.): # dynamic pressure q = 0.5*rho*U**2 #q0= 0.5*rho*U0**2 # Reynolds number and drag if params['cd_usr'] in [np.inf, -np.inf, None, np.nan]: Re = rho*U*d/mu cd, dcd_dRe = cylinderDrag(Re) else: cd = params['cd_usr']*np.ones_like(d) Re = 1.0 dcd_dRe = 0.0 # inertial and drag forces Fi = rho*params['cm']*math.pi/4.0*d**2*params['A'] # Morrison's equation Fd = q*cd*d Fp = Fi + Fd # components of distributed loads Px = Fp*cosd(beta) Py = Fp*sind(beta) Pz = 0.*Fp #FORCES [N/m] AT z=0 m #idx0 = np.abs(zrel).argmin() # closest index to z=0, used to find d at z=0 #d0 = d[idx0] # initialize #cd0 = cd[idx0] # initialize #if (zrel[idx0]<0.) and (idx0< (zrel.size-1)): # point below water # d0 = np.mean(d[idx0:idx0+2]) # cd0 = np.mean(cd[idx0:idx0+2]) #elif (zrel[idx0]>0.) and (idx0>0): # point above water # d0 = np.mean(d[idx0-1:idx0+1]) # cd0 = np.mean(cd[idx0-1:idx0+1]) #Fi0 = rho*params['cm']*math.pi/4.0*d0**2*params['A0'] # Morrison's equation #Fd0 = q0*cd0*d0 #Fp0 = Fi0 + Fd0 #Px0 = Fp0*cosd(beta0) #Py0 = Fp0*sind(beta0) #Pz0 = 0.*Fp0 #Store qties at z=0 MSL #unknowns['waveLoads_Px0'] = Px0 #unknowns['waveLoads_Py0'] = Py0 #unknowns['waveLoads_Pz0'] = Pz0 #unknowns['waveLoads_qdyn0'] = q0 #unknowns['waveLoads_beta0'] = beta0 # pack data unknowns['waveLoads_Px'] = Px unknowns['waveLoads_Py'] = Py unknowns['waveLoads_Pz'] = Pz unknowns['waveLoads_qdyn'] = q unknowns['waveLoads_pt'] = q + params['p'] unknowns['waveLoads_beta'] = beta unknowns['waveLoads_d'] = d unknowns['waveLoads_z'] = params['z']
def provideJ(self): J = np.array([[cosd(self.precone), sind(self.precone), (-self.Rtip*sind(self.precone) + self.precurveTip*sind(self.precone))*pi/180.0]]) return J
def execute(self): self.R = self.Rtip * cosd(self.precone) + self.precurveTip * sind( self.precone)