VAPoR  0.1
vapor_wrf.py
Go to the documentation of this file.
1 ''' vapor_wrf module includes following WRF-based utilities:
2  CTT - cloud-top temperature (2D)
3  DBZ - radar reflectivity
4  DBZ_MAX - max radar reflectivity over vertical column
5  ETH - equivalent potential temperature
6  RH - relative humidity
7  PV - potential vorticity
8  SHEAR - horizontal wind shear
9  SLP - sea-level pressure (2D)
10  TD - dewpoint temperature
11  TK - temperature in degrees Kelvin.
12  CTHGT - cloud-top height
13  wrf_deriv_findiff - 6th order finite-difference derivative wrf_curl_findiff - finite-difference curl
14  wrf_grad_findiff - finite-difference gradient
15  wrf_div_findiff - finite-difference divergence'''
16 
17 import numpy
18 import vapor_utils
19 import vapor
20 def CTT(P,PB,T,QCLOUD,QICE):
21  '''Calculate cloud-top temperature using WRF variables.
22  Calling sequence: VAL=CTT(P,PB,T,QCLOUD,QICE)
23  Where P,PB,T,QCLOUD,QICE are 3D WRF variables.
24  (Replace QICE by 0 if not in data)
25  Result VAL is a 2D variable.'''
26 #Copied (and adapted) from RIP4 fortran code cttcalc.f
27 #constants:
28 #iice should be 1 if QSNOW and QICE is present
29  iice = (vapor.VariableExists(vapor.TIMESTEP,"QSNOW") and vapor.VariableExists(vapor.TIMESTEP,"QICE"))
30  grav=9.81
31  celkel=273.15 #celsius to kelvin difference
32  c = 2.0/7.0
33  abscoefi = 0.272
34  abscoef = 0.145
35 #calculate TK:
36  pf = P+PB
37  tmk = (T+300.0)*numpy.power(pf*.00001,c)
38  s = numpy.shape(P) #size of the input array
39  ss = [s[1],s[2]] # shape of 2d arrays
40 #initialize with value at bottom:
41  WRF_CTT = tmk[0,:,:]-celkel
42  opdepthd = numpy.zeros(ss,numpy.float32) #next value
43  opdepthu = numpy.zeros(ss,numpy.float32) #previous value
44 #Sweep array from top to bottom, accumulating optical depth
45  if (iice == 1):
46  for k in range(s[0]-2,-1,-1): #start at top-1, end at bottom (k=0) accumulate opacity
47  dp =100.*(pf[k,:,:]-pf[k+1,:,:])
48  opdepthd=opdepthu+(abscoef*QCLOUD[k,:,:]+abscoefi*QICE[k,:,:])*dp/grav
49  logArray= numpy.logical_and(opdepthd > 1.0,opdepthu <= 1.0)
50  #identify level when opac=1 is reached
51  WRF_CTT = numpy.where(logArray,tmk[k,:,:]-celkel,WRF_CTT[:,:])
52  opdepthu = opdepthd
53  else:
54  for k in range(s[0]-2,-1,-1): #start at top-1, end at bottom (k=0) accumulate opacity
55  dp =100.*(pf[k,:,:]-pf[k+1,:,:])
56  logArray1 = tmk[k,:,:]<celkel
57  opdepthd= numpy.where(logArray1,opdepthu+abscoefi*QCLOUD[k,:,:]*dp/grav,opdepthu+abscoef*QCLOUD[k,:,:]*dp/grav)
58  logArray= numpy.logical_and(opdepthd > 1.0,opdepthu <= 1.0)
59  #identify level when opac=1 is reached
60  WRF_CTT = numpy.where(logArray,tmk[k,:,:]-celkel,WRF_CTT[:,:])
61  opdepthu = opdepthd
62  return WRF_CTT
63 
64 def CTHGT(P,PB,T,QCLOUD,QICE,ELEVATION):
65  '''Calculate cloud-top height using WRF variables.
66  Calling sequence: VAL=CTHGT(P,PB,T,QCLOUD,QICE,ELEVATION)
67  Where P,PB,T,QCLOUD,QICE are 3D WRF variables.
68  (Replace QICE by 0 if not in data)
69  Result VAL is a 2D variable.'''
70 #Copied (and adapted) from RIP4 fortran code cttcalc.f
71 #constants:
72 #iice should be 1 if QSNOW and QICE is present
73  iice = (vapor.VariableExists(vapor.TIMESTEP,"QSNOW") and vapor.VariableExists(vapor.TIMESTEP,"QICE"))
74  # if iice is 0, need to use T, otherwise not.
75  grav=9.81
76  celkel=273.15 #celsius to kelvin difference
77  c = 2.0/7.0
78  abscoefi = 0.272
79  abscoef = 0.145
80 #calculate TK:
81  pf = P+PB
82  tmk = (T+300.0)*numpy.power(pf*.00001,c)
83  s = numpy.shape(P) #size of the input array
84  ss = [s[1],s[2]] # shape of 2d arrays
85 #initialize with value at bottom:
86  CTHT = numpy.zeros(ss,numpy.float32)
87  opdepthd = numpy.zeros(ss,numpy.float32) #next value
88  opdepthu = numpy.zeros(ss,numpy.float32) #previous value
89 #Sweep array from top to bottom, accumulating optical depth
90  if (iice == 1):
91  for k in range(s[0]-2,-1,-1): #start at top-1, end at bottom (k=0) accumulate opacity
92  dp =100.*(pf[k,:,:]-pf[k+1,:,:])
93  opdepthd=opdepthu+(abscoef*QCLOUD[k,:,:]+abscoefi*QICE[k,:,:])*dp/grav
94  logArray= numpy.logical_and(opdepthd > 1.0,opdepthu <= 1.0)
95  #identify level when opac=1 is reached
96  CTHT = numpy.where(logArray,ELEVATION[k,:,:],CTHT[:,:])
97  opdepthu = opdepthd
98  else:
99  for k in range(s[0]-2,-1,-1): #start at top-1, end at bottom (k=0) accumulate opacity
100  dp =100.*(pf[k,:,:]-pf[k+1,:,:])
101  logArray1 = tmk[k,:,:]<celkel
102  opdepthd= numpy.where(logArray1,opdepthu+abscoefi*QCLOUD[k,:,:]*dp/grav,opdepthu+abscoef*QCLOUD[k,:,:]*dp/grav)
103  logArray= numpy.logical_and(opdepthd > 1.0,opdepthu <= 1.0)
104  #identify level when opac=1 is reached
105  CTHT = numpy.where(logArray,ELEVATION[k,:,:],CTHT[:,:])
106  opdepthu = opdepthd
107  return CTHT
108 
109 def DBZ(P,PB,QRAIN,QGRAUP,QSNOW,T,QVAPOR,iliqskin=0,ivarint=0):
110  ''' Calculates 3D radar reflectivity based on WRF variables.
111  Calling sequence:
112  VAL = DBZ(P,PB,QRAIN,QGRAUP,QSNOW,T,QVAPOR,iliqskin=0,ivarint=0)
113  Where P,PB,QRAIN,QGRAUP,QSNOW,T,and QVAPOR are WRF 3D variables.
114  Optional arguments iliqskin and ivarint default to 0
115  if iliqskin=1, then frozen particles above freezing are
116  assumed to scatter as a liquid particle. If ivarint = 1 then
117  intercept parameters are calculated based on Thompson, Rasmussen
118  and Manning, as described in 2004 Monthly Weather Review.
119  Result VAL is 3D variable on same grid as WRF variables.
120  If QGRAUP or QSNOW are not available then replace them by 0.'''
121 #Copied from NCL/Fortran source code wrf_user_dbz.f
122 #Based on work by Mark Stoellinga, U. of Washington
123 #parameters ivarint and iliqskin defined as in original code, either 0 or 1.
124 #set to 0 by default.
125 #If iliqskin=1, frozen particles above freezing are assumed to scatter as a liquid particle
126 #If ivarint=0, the intercept parameters are assumed constant with values of
127 # 8*10^6, 2*10^7, and 4*10^6, for rain, snow, and graupel respectively.
128 #If ivarint=1, intercept parameters are used as calculated in Thompson, Rasmussen, and Manning,
129 #2004 Monthly Weather Review, Vol 132, No. 2, pp.519-542
130  c = 2.0/7.0
131  R1=1.e-15
132  RON = 8.e6
133  RON2 = 1.e10
134  SON = 2.e7
135  GON = 5.37
136  RON_MIN = 8.e6
137  RON_QR0 = 0.0001
138  RON_DELQR0 = 0.25*RON_QR0
139  RON_CONST1R = (RON2-RON_MIN)*0.5
140  RON_CONST2R = (RON2+RON_MIN)*0.5
141  RN0_R = 8.e6
142  RN0_S = 2.e7
143  RN0_G = 4.e6
144  GAMMA_SEVEN =720.
145  RHOWAT = 1000.
146  RHO_R = RHOWAT
147  RHO_S = 100.
148  RHO_G = 400.
149  ALPHA = 0.224
150  CELKEL = 273.15
151  pi = 3.141592653589793
152  RD = 287.04
153  FACTOR_R = GAMMA_SEVEN*1.e18*numpy.power((1./(pi*RHO_R)),1.75)
154  FACTOR_S = GAMMA_SEVEN*1.e18*numpy.power((1./(pi*RHO_S)),1.75)*numpy.power((RHO_S/RHOWAT),2.*ALPHA)
155  FACTOR_G = GAMMA_SEVEN*1.e18*numpy.power((1./(pi*RHO_G)),1.75)*numpy.power((RHO_G/RHOWAT),2.*ALPHA)
156 #calculate Temp. in Kelvin
157  PRESS = P+PB
158  TK = (T+300.)*numpy.power(PRESS*.00001,c)
159 #Force Q arrays to be nonnegative:
160  QVAPOR = numpy.maximum(QVAPOR,0.0)
161  QSNOW = numpy.maximum(QSNOW,0.0)
162  QRAIN = numpy.maximum(QRAIN,0.0)
163  if (vapor.VariableExists(vapor.TIMESTEP,"QGRAUP")):
164  QGRAUP = numpy.maximum(QGRAUP,0.0)
165  else:
166 #Avoid divide by zero if QGRAUP is not present:
167  QGRAUP = 1.e-30
168  TestT = numpy.less(TK,CELKEL)
169  QSNOW = numpy.where(TestT,QRAIN, QSNOW)
170  QRAIN = numpy.where(TestT,0.0, QRAIN)
171  VIRTUAL_T = TK*(0.622 + QVAPOR)/(0.622*(1.+QVAPOR))
172  RHOAIR = PRESS/(RD*VIRTUAL_T)
173  FACTORB_S = FACTOR_S
174  FACTORB_G = FACTOR_G
175  if (iliqskin == 1):
176  FACTORB_S = numpy.float32(numpy.where(TestT,FACTOR_S,FACTOR_S/ALPHA))
177  FACTORB_G = numpy.float32(numpy.where(TestT,FACTOR_G, FACTOR_G/ALPHA))
178  if (ivarint == 1):
179  TEMP_C = numpy.minimum(-.001, TK-CELKEL)
180  SONV = numpy.minimum(2.e8,2.e6*numpy.exp(-.12*TEMP_C))
181  TestG = numpy.less(R1, QGRAUP)
182  GONV = numpy.where(TestG,2.38*numpy.power(pi*RHO_G/(RHOAIR*QGRAUP),0.92),GON)
183  GONV = numpy.where(TestG,numpy.maximum(1.e4,numpy.minimum(GONV,GON)),GONV)
184  GONV = RN0_G
185  RONV = numpy.where(numpy.greater(QRAIN,R1),RON_CONST1R*numpy.tanh((RON_QR0-QRAIN)/RON_DELQR0) + RON_CONST2R,RON2)
186  else:
187  GONV = RN0_G
188  RONV = RN0_R
189  SONV = RN0_S
190  Z_E = FACTOR_R*numpy.power(RHOAIR*QRAIN,1.75)/numpy.power(RONV,0.75)
191  Z_E = Z_E+FACTORB_S*numpy.power(RHOAIR*QSNOW,1.75)/numpy.power(SONV,0.75)
192  Z_E = Z_E+FACTORB_G*numpy.power(RHOAIR*QGRAUP,1.75)/numpy.power(GONV,0.75)
193  Z_E = numpy.maximum(Z_E, 0.001)
194 
195  WRF_DBZ = 10.0*numpy.log10(Z_E)
196  return WRF_DBZ
197 
198 def DBZ_MAX(P,PB,QRAIN,QGRAUP,QSNOW,T,QVAPOR,iliqskin=0,ivarint=0):
199  ''' Calculates 2D radar reflectivity based on WRF variables.
200  Calling sequence: VAL = DBZ_MAX(P,PB,QRAIN,QGRAUP,QSNOW,T,QVAPOR)
201  Where P,PB,QRAIN,QGRAUP,QSNOW,T,and QVAPOR are WRF 3D variables.
202  Optional arguments iliqskin and ivarint default to 0, as
203  described in help(DBZ)
204  Result VAL is 2D variable on 2D grid of WRF variables.
205  VAL is the maximum over a vertical column of DBZ.
206  If QGRAUP or QSNOW are not available then replace them by 0.'''
207  WRF_DBZ = DBZ(P,PB,QRAIN,QGRAUP,QSNOW,T,QVAPOR)
208  WRF_DBZ_MAX = numpy.amax(WRF_DBZ,axis=0)
209  return WRF_DBZ_MAX
210 
211 
212 def ETH(P,PB,T,QVAPOR):
213  ''' Program to calculate equivalent potential temperature using WRF
214  variables P, PB, T, QVAPOR.
215  Calling sequence: WRF_ETH = ETH(P,PB,T,QVAPOR)
216  Result WRF_ETH is a 3D variable on same grid as P,PB,T,QVAPOR.'''
217 #Copied from NCL/Fortran source code DEQTHECALC in eqthecalc.f
218  c = 2.0/7.0
219  EPS = 0.622
220  GAMMA = 287.04/1004.0
221  GAMMAMD = 0.608 -0.887
222  TLCLC1 = 2840.0
223  TLCLC2 = 3.5
224  TLCLC3 = 4.805
225  TLCLC4 = 55.0
226  THTECON1 = 3376.0
227  THTECON2 = 2.54
228  THTECON3 = 0.81
229  TH = T+300.0
230 #calculate Temp. in Kelvin
231  PRESS = 0.01*(P+PB)
232  TK = TH*numpy.power(PRESS*.001,c)
233  Q = numpy.maximum(QVAPOR, 1.e-15)
234  E = Q*PRESS/(EPS+Q)
235  TLCL = TLCLC4+ TLCLC1/(numpy.log(numpy.power(TK,TLCLC2)/E)-TLCLC3)
236  EXPNT = (THTECON1/TLCL - THTECON2)*Q*(1.0+THTECON3*Q)
237  WRF_ETH = TK*numpy.power(1000.0/PRESS,GAMMA*(1.0+GAMMAMD*Q))*numpy.exp(EXPNT)
238  return WRF_ETH
239 
240 def PV(T,P,PB,U,V,ELEV,F):
241  ''' Routine that calculates potential vorticity using WRF variables.
242  Calling sequence: WRF_PV = PV(T,P,PB,U,V,ELEV,F)
243  Where T,P,PB,U,V are WRF 3D variables, F is WRF 2D variable.
244  ELEV is the VAPOR ELEVATION variable (PH+PHB)/g
245  Result is 3D variable WRF_PV.'''
246 # Based on wrf_pvo.f in NCL WRF library
247  from vapor_utils import deriv_var_findiff
248  PR = 0.01*(P+PB)
249  DTHDP = deriv_var_findiff(T,PR,3)
250  DTHDX = wrf_deriv_findiff(T,ELEV,1)
251  DTHDY = wrf_deriv_findiff(T,ELEV,2)
252  DUDP = deriv_var_findiff(U,PR,3)
253  DVDP = deriv_var_findiff(V,PR,3)
254  DUDY = wrf_deriv_findiff(U,ELEV,2)
255  DVDX = wrf_deriv_findiff(V,ELEV,1)
256  AVORT = DVDX - DUDY + F
257  WRF_PVO = numpy.float32(-9.81*(DTHDP*AVORT-DVDP*DTHDX+DUDP*DTHDY)*10000.)
258  return WRF_PVO
259 
260 def RH(P,PB,T,QVAPOR):
261  ''' Calculation of relative humidity.
262  Calling sequence WRF_RH = RH(P,PB,T,QVAPOR),
263  where P,PB,T,QVAPOR are standard WRF 3D variables,
264  result WRF_RH is 3D variable on same grid as inputs.'''
265 #Formula is from wrf_user.f
266  c = 2.0/7.0
267  SVP1 = 0.6112
268  SVP2 = 17.67
269  SVPT0 = 273.15
270  SVP3 = 29.65
271  EP_3 = 0.622
272  TH = T+300.0
273  PRESS = P+PB
274  TK = TH*numpy.power(PRESS*.00001,c)
275  ES = 10*SVP1*numpy.exp(SVP2*(TK-SVPT0)/(TK-SVP3))
276  QVS = EP_3*ES/(0.01*PRESS - (1.-EP_3)*ES)
277  WRF_RH = 100.0*numpy.maximum(numpy.minimum(QVAPOR/QVS,1.0),0)
278  return WRF_RH
279 
280 
281 def SHEAR(U,V,P,PB,level1=200.,level2=850.):
282  '''Program calculates horizontal wind shear
283  Calling sequence: SHR = SHEAR(U,V,P,PB,level1,level2)
284  where U and V are 3D wind velocity components, and
285  result SHR is 3D wind shear.
286  Shear is defined as the RMS difference between the horizontal
287  velocity interpolated to the specified pressure levels,
288  level1 and level2 (in millibars) which default to 200 and 850.'''
289  from numpy import sqrt
290  PR = 0.01*(P+PB)
291  uinterp1 = vapor_utils.interp3d(U,PR,level1)
292  uinterp2 = vapor_utils.interp3d(U,PR,level2)
293  vinterp1 = vapor_utils.interp3d(V,PR,level1)
294  vinterp2 = vapor_utils.interp3d(V,PR,level2)
295  result = (uinterp1-uinterp2)*(uinterp1-uinterp2)+(vinterp1-vinterp2)*(vinterp1-vinterp2)
296  result = sqrt(result)
297  return result
298 
299 def SLP(P,PB,T,QVAPOR,ELEVATION):
300  '''Calculation of Sea-level pressure.
301  Calling sequence: WRF_SLP = SLP(P,PB,T,QVAPOR,ELEVATION)
302  where P,PB,T,QVAPOR are WRF 3D variables and ELEVATION is
303  the VAPOR variable indicating the elevation in meters above sea level.
304  Result is a 2D variable with same horizonal extents as input variables.'''
305 #Copied (and adapted) from NCL fortran source code wrf_user.f
306 #constants:
307  R=287.04
308  G=9.81
309  GAMMA=0.0065
310  TC=273.16+17.05
311  PCONST=10000
312  c = 2.0/7.0
313 #calculate TK:
314  TH = T+300.0
315  PR = P+PB
316  TK = (T+300.0)*numpy.power(PR*.00001,c)
317 #Find least z that is PCONST Pa above the surface
318 #Sweep array from bottom to top
319  s = numpy.shape(P) #size of the input array
320  ss = [s[1],s[2]] # shape of 2d arrays
321  WRF_SLP = numpy.empty(ss,numpy.float32)
322  LEVEL = numpy.empty(ss,numpy.int32)
323  # Ridiculous MM5 test:
324  RIDTEST = numpy.empty(ss,numpy.int32)
325  PLO = numpy.empty(ss, numpy.float32)
326  ZLO = numpy.empty(ss,numpy.float32)
327  TLO = numpy.empty(ss,numpy.float32)
328  PHI = numpy.empty(ss,numpy.float32)
329  ZHI = numpy.empty(ss,numpy.float32)
330  THI = numpy.empty(ss,numpy.float32)
331  LEVEL[:,:] = -1
332  for K in range(s[0]):
333  KHI = numpy.minimum(K+1, s[0]-1)
334  LEVNEED = numpy.logical_and(numpy.less(LEVEL,0), numpy.less(PR[K,:,:] , PR[0,:,:] - PCONST))
335  LEVEL[LEVNEED]=K
336  PLO=numpy.where(LEVNEED,PR[K,:,:],PLO[:,:])
337  TLO=numpy.where(LEVNEED,TK[K,:,:]*(1.+0.608*QVAPOR[K,:,:]), TLO[:,:])
338  ZLO=numpy.where(LEVNEED,ELEVATION[K,:,:],ZLO[:,:])
339  PHI=numpy.where(LEVNEED,PR[KHI,:,:],PHI[:,:])
340  THI=numpy.where(LEVNEED,TK[KHI,:,:]*(1.+0.608*QVAPOR[KHI,:,:]), THI[:,:])
341  ZHI=numpy.where(LEVNEED,ELEVATION[KHI,:,:],ZHI[:,:])
342  P_AT_PCONST = PR[0,:,:]-PCONST
343  T_AT_PCONST = THI - (THI-TLO)*numpy.log(P_AT_PCONST/PHI)*numpy.log(PLO/PHI)
344  Z_AT_PCONST = ZHI - (ZHI-ZLO)*numpy.log(P_AT_PCONST/PHI)*numpy.log(PLO/PHI)
345  T_SURF = T_AT_PCONST*numpy.power((PR[0,:,:]/P_AT_PCONST),(GAMMA*R/G))
346  T_SEA_LEVEL = T_AT_PCONST + GAMMA*Z_AT_PCONST
347  RIDTEST = numpy.logical_and(T_SURF <= TC, T_SEA_LEVEL >= TC)
348  T_SEA_LEVEL = numpy.where(RIDTEST, TC, TC - .005*(T_SURF -TC)**2)
349  Z_HALF_LOWEST=ELEVATION[0,:,:]
350  WRF_SLP = 0.01*(PR[0,:,:]*numpy.exp(2.*G*Z_HALF_LOWEST/(R*(T_SEA_LEVEL+T_SURF))))
351  return WRF_SLP
352 
353 def TD(P,PB,QVAPOR):
354  ''' Calculation of dewpoint temperature based on WRF variables.
355  Calling sequence: WRFTD = TD(P,PB,QVAPOR)
356  where P,PB,QVAPOR are WRF 3D variables, and result WRFTD
357  is a 3D variable on the same grid.'''
358 #Let PR = 0.1*(P+PB) (pressure in hPa)
359 #and QV = MAX(QVAPOR,0)
360 #Where TDC = QV*PR/(0.622+QV)
361 # TDC = MAX(TDC,0.001)
362 #Formula is (243.5*log(TDC) - 440.8)/(19.48-log(TDC))
363  QV = numpy.maximum(QVAPOR,0.0)
364  TDC = 0.01*QV*(P+PB)/(0.622+QV)
365  TDC = numpy.maximum(TDC,0.001)
366  WRF_TD =(243.5*numpy.log(TDC) - 440.8)/(19.48 - numpy.log(TDC))
367  return WRF_TD
368 
369 
370 def TK(P,PB,T):
371  ''' Calculation of temperature in degrees kelvin using WRF variables.
372  Calling sequence: TMP = TK(P,PB,T)
373  Where P,PB,T are WRF 3D variables, result TMP is a 3D variable
374  indicating the temperature in degrees Kelvin.'''
375 #Formula is (T+300)*((P+PB)*10**(-5))**c,
376 #Where c is 287/(7*287*.5) = 2/7
377  c = 2.0/7.0
378  TH = T+300.0
379  WRF_TK = TH*numpy.power((P+PB)*.00001,c)
380  return WRF_TK
381 
382 def wrf_deriv_findiff(A,ELEV,dir):
383  ''' Operator that calculates the derivative of a WRF (or layered) variable A
384  in the direction dir (user coordinates; in Python the direction is reversed)
385  ELEV is the ELEVATION variable. '''
386  import vapor
387  import vapor_utils
388  if (dir == 3):
389  return vapor_utils.deriv_var_findiff(A,ELEV,3)
390 
391  ext = (vapor.BOUNDS[3]-vapor.BOUNDS[0], vapor.BOUNDS[4]-vapor.BOUNDS[1],vapor.BOUNDS[5]-vapor.BOUNDS[2])
392  usrmax = vapor.MapVoxToUser([vapor.BOUNDS[3],vapor.BOUNDS[4],vapor.BOUNDS[5]],vapor.REFINEMENT,vapor.LOD)
393  usrmin = vapor.MapVoxToUser([vapor.BOUNDS[0],vapor.BOUNDS[1],vapor.BOUNDS[2]],vapor.REFINEMENT,vapor.LOD)
394  dx = (usrmax[2]-usrmin[2])/ext[2]
395  dy = (usrmax[1]-usrmin[1])/ext[1]
396 
397  if (dir == 1):
398  dadx_eta = vapor_utils.deriv_findiff(A,1,dx)
399  dadz = vapor_utils.deriv_var_findiff(A,ELEV,3)
400  dzdx_eta = vapor_utils.deriv_findiff(ELEV,1,dx)
401  ans = dadx_eta -dadz*dzdx_eta
402  return ans
403 
404  if (dir == 2):
405  # dA/dy is (dA/dy)_eta - (dA/dz)*(dZ/dy)_eta
406  dady_eta = vapor_utils.deriv_findiff(A,2,dy)
407  dadz = vapor_utils.deriv_var_findiff(A,ELEV,3)
408  dzdy_eta = vapor_utils.deriv_findiff(ELEV,2,dy)
409  ans = dady_eta - dadz*dzdy_eta
410  return ans
411 
412 def wrf_grad_findiff(A,ELEV):
413  ''' Operator that calculates the gradient of a scalar field
414  using 6th order finite differences on a WRF (layered) grid
415  Calling sequence: GRD = grad_findiff(A,ELEV)
416  Where:
417  A is a float32 array defining a scalar field.
418  ELEV is the corresponding ELEVATION array
419  Result GRD is a triple of 3 3-dimensional float3d arrays consisting of
420  the gradient of A.'''
421 
422  aux1 = wrf_deriv_findiff(A,ELEV,3) #x component of gradient (in python coords)
423  aux2 = wrf_deriv_findiff(A,ELEV,2)
424  aux3 = wrf_deriv_findiff(A,ELEV,1)
425  return aux1,aux2,aux3 # return in user coordinate (x,y,z) order
426 
427 # Calculate divergence for WRF (layered) grid
428 def wrf_div_findiff(A,B,C,ELEV):
429  ''' Operator that calculates the divergence of a vector field
430  using 6th order finite differences.
431  Calling sequence: DIV = wrf_div_findiff(A,B,C,ELEV)
432  Where:
433  A, B, and C are 3-dimensional float32 arrays defining a vector field.
434  A is the x-component, B is y, C is z (in user coordinates)
435  ELEV is the ELEVATION variable
436  Resulting DIV is a 3-dimensional float3d array consisting of
437  the divergence of the triple (A,B,C).'''
438 
439  return wrf_deriv_findiff(A,ELEV,1)+wrf_deriv_findiff(B,ELEV,2)+wrf_deriv_findiff(C,ELEV,3)
440 
441 
442 
443 def wrf_curl_findiff(A,B,C,ELEV):
444  ''' Operator that calculates the curl of a vector field
445  using 6th order finite differences, on a layered (e.g. WRF) grid.
446  Calling sequence: curlfield = wrf_curl_findiff(A,B,C,ELEV)
447  Where:
448  A,B,C are three 3-dimensional float32 arrays that define a
449  vector field on a layered grid
450  ELEV is the ELEVATION variable for the layered grid.
451  curlfield is a 3-tuple of 3-dimensional float32 arrays that is
452  returned by this operator.'''
453  import vapor
454  import vapor_utils
455  ext = (vapor.BOUNDS[3]-vapor.BOUNDS[0], vapor.BOUNDS[4]-vapor.BOUNDS[1],vapor.BOUNDS[5]-vapor.BOUNDS[2])
456  usrmax = vapor.MapVoxToUser([vapor.BOUNDS[3],vapor.BOUNDS[4],vapor.BOUNDS[5]],vapor.REFINEMENT,vapor.LOD)
457  usrmin = vapor.MapVoxToUser([vapor.BOUNDS[0],vapor.BOUNDS[1],vapor.BOUNDS[2]],vapor.REFINEMENT,vapor.LOD)
458  dx = (usrmax[2]-usrmin[2])/ext[2] #user x coordinate, python z coordinate
459  dy = (usrmax[1]-usrmin[1])/ext[1]
460  dz = (usrmax[0]-usrmin[0])/ext[0]
461 
462 # x component is dC/dy - dB/dz [y,z are user coordinates]
463 # dC/dy is calc by (dC/dy)_eta - (dC/dz)*(dZ/dy)_eta
464 # where _eta indicates the derivative calculated in the WRF grid coordinates
465 # as is performed by deriv_findiff.pro;
466 # Z is ELEVATION and dC/dz is deriv wrt Elevation
467 # dB/dz is deriv wrt ELEV
468 
469  dcdy_eta = vapor_utils.deriv_findiff(C, 2, dy)
470  dcdz = vapor_utils.deriv_var_findiff(C,ELEV,3)
471  dzdy_eta = vapor_utils.deriv_findiff(ELEV,2,dy)
472  dbdz = vapor_utils.deriv_var_findiff(B,ELEV,3)
473 
474  outx = dcdy_eta - dcdz*dzdy_eta -dbdz
475 
476 # y component is dA/dz - dC/dx
477 # dC/dx is (dC/dx)_eta -(dC/dz)*(dZ/dx)_eta)
478 
479  dadz = vapor_utils.deriv_var_findiff(A,ELEV,3)
480  dcdx_eta = vapor_utils.deriv_findiff(C,1,dx)
481  dzdx_eta = vapor_utils.deriv_findiff(ELEV,1,dx)
482 
483  outy = dadz - dcdx_eta + dcdz*dzdx_eta
484 
485 # z component is dB/dx - dA/dy
486 # dB/dx is (dB/dx)_eta - (dB/dz)*(dZ/dx)_eta
487 # dA/dy is (dA/dy)_eta - (dA/dz)*(dZ/dy)_eta
488 
489  dbdx_eta = vapor_utils.deriv_findiff(B,1,dx)
490  dady_eta = vapor_utils.deriv_findiff(A,2,dy)
491 
492  outz = dbdx_eta - dbdz*dzdx_eta -dady_eta + dadz*dzdy_eta
493 
494  return outx, outy, outz #return results in user coordinate order
495 
496 
def SLP(P, PB, T, QVAPOR, ELEVATION)
Definition: vapor_wrf.py:299
def MapVoxToUser(voxcoord, refinementLevel, lod)
Definition: vapor.py:20
def TK(P, PB, T)
Definition: vapor_wrf.py:370
def SHEAR
Definition: vapor_wrf.py:281
def deriv_findiff
Definition: vapor_utils.py:151
def PV(T, P, PB, U, V, ELEV, F)
Definition: vapor_wrf.py:240
def ETH(P, PB, T, QVAPOR)
Definition: vapor_wrf.py:212
def CTHGT(P, PB, T, QCLOUD, QICE, ELEVATION)
Definition: vapor_wrf.py:64
def CTT(P, PB, T, QCLOUD, QICE)
Definition: vapor_wrf.py:20
def wrf_deriv_findiff(A, ELEV, dir)
Definition: vapor_wrf.py:382
def TD(P, PB, QVAPOR)
Definition: vapor_wrf.py:353
def wrf_div_findiff(A, B, C, ELEV)
Definition: vapor_wrf.py:428
def RH(P, PB, T, QVAPOR)
Definition: vapor_wrf.py:260
def VariableExists(timestep, varname, refinement, lod)
Definition: vapor.py:72
def interp3d(A, PR, val)
Definition: vapor_utils.py:532
def wrf_grad_findiff(A, ELEV)
Definition: vapor_wrf.py:412
def wrf_curl_findiff(A, B, C, ELEV)
Definition: vapor_wrf.py:443
def deriv_var_findiff
Definition: vapor_utils.py:359
def DBZ_MAX
Definition: vapor_wrf.py:198