# Tools for the compute of diagnostics # L. Fita, CIMA. CONICET-UBA, CNRS UMI-IFAECI, Buenos Aires, Argentina # Available general pupose diagnostics (model independent) providing (varv1, varv2, ..., dimns, dimvns) # compute_accum: Function to compute the accumulation of a variable # compute_cllmh: Function to compute cllmh: low/medium/hight cloud fraction following # newmicro.F90 from LMDZ compute_clt(cldfra, pres, dimns, dimvns) # compute_clt: Function to compute the total cloud fraction following 'newmicro.F90' from LMDZ # compute_clivi: Function to compute cloud-ice water path (clivi) # compute_clwvl: Function to compute condensed water path (clwvl) # compute_deaccum: Function to compute the deaccumulation of a variable # compute_mslp: Function to compute mslp: mean sea level pressure following p_interp.F90 from WRF # compute_OMEGAw: Function to transform OMEGA [Pas-1] to velocities [ms-1] # compute_prw: Function to compute water vapour path (prw) # compute_rh: Function to compute relative humidity following 'Tetens' equation (T,P) ...' # compute_td: Function to compute the dew point temperature # compute_turbulence: Function to compute the rubulence term of the Taylor's decomposition ...' # compute_wds: Function to compute the wind direction # compute_wss: Function to compute the wind speed # compute_WRFta: Function to compute WRF air temperature # compute_WRFtd: Function to compute WRF dew-point air temperature # compute_WRFuava: Function to compute geographical rotated WRF 3D winds # compute_WRFuasvas: Fucntion to compute geographical rotated WRF 2-meter winds # derivate_centered: Function to compute the centered derivate of a given field # def Forcompute_cllmh: Function to compute cllmh: low/medium/hight cloud fraction following newmicro.F90 from LMDZ via Fortran subroutine # Forcompute_clt: Function to compute the total cloud fraction following 'newmicro.F90' from LMDZ via a Fortran module # Others just providing variable values # var_cllmh: Fcuntion to compute cllmh on a 1D column # var_clt: Function to compute the total cloud fraction following 'newmicro.F90' from LMDZ using 1D vertical column values # var_mslp: Fcuntion to compute mean sea-level pressure # var_virtualTemp: This function returns virtual temperature in K, # var_WRFtime: Function to copmute CFtimes from WRFtime variable # rotational_z: z-component of the rotatinoal of horizontal vectorial field # turbulence_var: Function to compute the Taylor's decomposition turbulence term from a a given variable import numpy as np from netCDF4 import Dataset as NetCDFFile import os import re import nc_var_tools as ncvar import generic_tools as gen import datetime as dtime import module_ForDiag as fdin import module_ForDef as fdef main = 'diag_tools.py' errormsg = 'ERROR -- error -- ERROR -- error' warnmsg = 'WARNING -- warning -- WARNING -- warning' # Constants grav = fdef.module_definitions.grav # Gneral information ## def reduce_spaces(string): """ Function to give words of a line of text removing any extra space """ values = string.replace('\n','').split(' ') vals = [] for val in values: if len(val) > 0: vals.append(val) return vals def variable_combo(varn,combofile): """ Function to provide variables combination from a given variable name varn= name of the variable combofile= ASCII file with the combination of variables [varn] [combo] [combo]: '@' separated list of variables to use to generate [varn] [WRFdt] to get WRF time-step (from general attributes) >>> variable_combo('WRFprls','/home/lluis/PY/diagnostics.inf') deaccum@RAINNC@XTIME@prnc """ fname = 'variable_combo' if varn == 'h': print fname + '_____________________________________________________________' print variable_combo.__doc__ quit() if not os.path.isfile(combofile): print errormsg print ' ' + fname + ": file with combinations '" + combofile + \ "' does not exist!!" quit(-1) objf = open(combofile, 'r') found = False for line in objf: linevals = reduce_spaces(line) varnf = linevals[0] combo = linevals[1].replace('\n','') if varn == varnf: found = True break if not found: print errormsg print ' ' + fname + ": variable '" + varn + "' not found in '" + combofile +\ "' !!" combo='ERROR' objf.close() return combo # Mathematical operators ## def compute_accum(varv, dimns, dimvns): """ Function to compute the accumulation of a variable compute_accum(varv, dimnames, dimvns) [varv]= values to accum (assuming [t,]) [dimns]= list of the name of the dimensions of the [varv] [dimvns]= list of the name of the variables with the values of the dimensions of [varv] """ fname = 'compute_accum' deacdims = dimns[:] deacvdims = dimvns[:] slicei = [] slicee = [] Ndims = len(varv.shape) for iid in range(0,Ndims): slicei.append(slice(0,varv.shape[iid])) slicee.append(slice(0,varv.shape[iid])) slicee[0] = np.arange(varv.shape[0]) slicei[0] = np.arange(varv.shape[0]) slicei[0][1:varv.shape[0]] = np.arange(varv.shape[0]-1) vari = varv[tuple(slicei)] vare = varv[tuple(slicee)] ac = vari*0. for it in range(1,varv.shape[0]): ac[it,] = ac[it-1,] + vare[it,] return ac, deacdims, deacvdims def compute_deaccum(varv, dimns, dimvns): """ Function to compute the deaccumulation of a variable compute_deaccum(varv, dimnames, dimvns) [varv]= values to deaccum (assuming [t,]) [dimns]= list of the name of the dimensions of the [varv] [dimvns]= list of the name of the variables with the values of the dimensions of [varv] """ fname = 'compute_deaccum' deacdims = dimns[:] deacvdims = dimvns[:] slicei = [] slicee = [] Ndims = len(varv.shape) for iid in range(0,Ndims): slicei.append(slice(0,varv.shape[iid])) slicee.append(slice(0,varv.shape[iid])) slicee[0] = np.arange(varv.shape[0]) slicei[0] = np.arange(varv.shape[0]) slicei[0][1:varv.shape[0]] = np.arange(varv.shape[0]-1) vari = varv[tuple(slicei)] vare = varv[tuple(slicee)] deac = vare - vari return deac, deacdims, deacvdims def derivate_centered(var,dim,dimv): """ Function to compute the centered derivate of a given field centered derivate(n) = (var(n-1) + var(n+1))/(2*dn). [var]= variable [dim]= which dimension to compute the derivate [dimv]= dimension values (can be of different dimension of [var]) >>> derivate_centered(np.arange(16).reshape(4,4)*1.,1,1.) [[ 0. 1. 2. 0.] [ 0. 5. 6. 0.] [ 0. 9. 10. 0.] [ 0. 13. 14. 0.]] """ fname = 'derivate_centered' vark = var.dtype if hasattr(dimv, "__len__"): # Assuming that the last dimensions of var [..., N, M] are the same of dimv [N, M] if len(var.shape) != len(dimv.shape): dimvals = np.zeros((var.shape), dtype=vark) if len(var.shape) - len(dimv.shape) == 1: for iz in range(var.shape[0]): dimvals[iz,] = dimv elif len(var.shape) - len(dimv.shape) == 2: for it in range(var.shape[0]): for iz in range(var.shape[1]): dimvals[it,iz,] = dimv else: print errormsg print ' ' + fname + ': dimension difference between variable', \ var.shape,'and variable with dimension values',dimv.shape, \ ' not ready !!!' quit(-1) else: dimvals = dimv else: # dimension values are identical everywhere! # from: http://stackoverflow.com/questions/16807011/python-how-to-identify-if-a-variable-is-an-array-or-a-scalar dimvals = np.ones((var.shape), dtype=vark)*dimv derivate = np.zeros((var.shape), dtype=vark) if dim > len(var.shape) - 1: print errormsg print ' ' + fname + ': dimension',dim,' too big for given variable of ' + \ 'shape:', var.shape,'!!!' quit(-1) slicebef = [] sliceaft = [] sliceder = [] for id in range(len(var.shape)): if id == dim: slicebef.append(slice(0,var.shape[id]-2)) sliceaft.append(slice(2,var.shape[id])) sliceder.append(slice(1,var.shape[id]-1)) else: slicebef.append(slice(0,var.shape[id])) sliceaft.append(slice(0,var.shape[id])) sliceder.append(slice(0,var.shape[id])) if hasattr(dimv, "__len__"): derivate[tuple(sliceder)] = (var[tuple(slicebef)] + var[tuple(sliceaft)])/ \ ((dimvals[tuple(sliceaft)] - dimvals[tuple(slicebef)])) print (dimvals[tuple(sliceaft)] - dimvals[tuple(slicebef)]) else: derivate[tuple(sliceder)] = (var[tuple(slicebef)] + var[tuple(sliceaft)])/ \ (2.*dimv) # print 'before________' # print var[tuple(slicebef)] # print 'after________' # print var[tuple(sliceaft)] return derivate def rotational_z(Vx,Vy,pos): """ z-component of the rotatinoal of horizontal vectorial field \/ x (Vx,Vy,Vz) = \/xVy - \/yVx [Vx]= Variable component x [Vy]= Variable component y [pos]= poisition of the grid points >>> rotational_z(np.arange(16).reshape(4,4)*1., np.arange(16).reshape(4,4)*1., 1.) [[ 0. 1. 2. 0.] [ -4. 0. 0. -7.] [ -8. 0. 0. -11.] [ 0. 13. 14. 0.]] """ fname = 'rotational_z' ndims = len(Vx.shape) rot1 = derivate_centered(Vy,ndims-1,pos) rot2 = derivate_centered(Vx,ndims-2,pos) rot = rot1 - rot2 return rot # Diagnostics ## def var_clt(cfra): """ Function to compute the total cloud fraction following 'newmicro.F90' from LMDZ using 1D vertical column values [cldfra]= cloud fraction values (assuming [[t],z,y,x]) """ ZEPSEC=1.0E-12 fname = 'var_clt' zclear = 1. zcloud = 0. dz = cfra.shape[0] for iz in range(dz): zclear =zclear*(1.-np.max([cfra[iz],zcloud]))/(1.-np.min([zcloud,1.-ZEPSEC])) clt = 1. - zclear zcloud = cfra[iz] return clt def compute_clt(cldfra, dimns, dimvns): """ Function to compute the total cloud fraction following 'newmicro.F90' from LMDZ compute_clt(cldfra, dimnames) [cldfra]= cloud fraction values (assuming [[t],z,y,x]) [dimns]= list of the name of the dimensions of [cldfra] [dimvns]= list of the name of the variables with the values of the dimensions of [cldfra] """ fname = 'compute_clt' cltdims = dimns[:] cltvdims = dimvns[:] if len(cldfra.shape) == 4: clt = np.zeros((cldfra.shape[0],cldfra.shape[2],cldfra.shape[3]), \ dtype=np.float) dx = cldfra.shape[3] dy = cldfra.shape[2] dz = cldfra.shape[1] dt = cldfra.shape[0] cltdims.pop(1) cltvdims.pop(1) for it in range(dt): for ix in range(dx): for iy in range(dy): zclear = 1. zcloud = 0. gen.percendone(it*dx*dy + ix*dy + iy, dx*dy*dt, 5, 'diagnosted') clt[it,iy,ix] = var_clt(cldfra[it,:,iy,ix]) else: clt = np.zeros((cldfra.shape[1],cldfra.shape[2]), dtype=np.float) dx = cldfra.shape[2] dy = cldfra.shape[1] dy = cldfra.shape[0] cltdims.pop(0) cltvdims.pop(0) for ix in range(dx): for iy in range(dy): zclear = 1. zcloud = 0. gen.percendone(ix*dy + iy, dx*dy*dt, 5, 'diagnosted') clt[iy,ix] = var_clt(cldfra[:,iy,ix]) return clt, cltdims, cltvdims def Forcompute_clt(cldfra, dimns, dimvns): """ Function to compute the total cloud fraction following 'newmicro.F90' from LMDZ via a Fortran module compute_clt(cldfra, dimnames) [cldfra]= cloud fraction values (assuming [[t],z,y,x]) [dimns]= list of the name of the dimensions of [cldfra] [dimvns]= list of the name of the variables with the values of the dimensions of [cldfra] """ fname = 'Forcompute_clt' cltdims = dimns[:] cltvdims = dimvns[:] if len(cldfra.shape) == 4: clt = np.zeros((cldfra.shape[0],cldfra.shape[2],cldfra.shape[3]), \ dtype=np.float) dx = cldfra.shape[3] dy = cldfra.shape[2] dz = cldfra.shape[1] dt = cldfra.shape[0] cltdims.pop(1) cltvdims.pop(1) clt = fdin.module_fordiagnostics.compute_clt4d2(cldfra[:]) else: clt = np.zeros((cldfra.shape[1],cldfra.shape[2]), dtype=np.float) dx = cldfra.shape[2] dy = cldfra.shape[1] dy = cldfra.shape[0] cltdims.pop(0) cltvdims.pop(0) clt = fdin.module_fordiagnostics.compute_clt3d1(cldfra[:]) return clt, cltdims, cltvdims def var_cllmh(cfra, p): """ Fcuntion to compute cllmh on a 1D column """ fname = 'var_cllmh' ZEPSEC =1.0E-12 prmhc = 440.*100. prmlc = 680.*100. zclearl = 1. zcloudl = 0. zclearm = 1. zcloudm = 0. zclearh = 1. zcloudh = 0. dvz = cfra.shape[0] cllmh = np.ones((3), dtype=np.float) for iz in range(dvz): if p[iz] < prmhc: cllmh[2] = cllmh[2]*(1.-np.max([cfra[iz], zcloudh]))/(1.- \ np.min([zcloudh,1.-ZEPSEC])) zcloudh = cfra[iz] elif p[iz] >= prmhc and p[iz] < prmlc: cllmh[1] = cllmh[1]*(1.-np.max([cfra[iz], zcloudm]))/(1.- \ np.min([zcloudm,1.-ZEPSEC])) zcloudm = cfra[iz] elif p[iz] >= prmlc: cllmh[0] = cllmh[0]*(1.-np.max([cfra[iz], zcloudl]))/(1.- \ np.min([zcloudl,1.-ZEPSEC])) zcloudl = cfra[iz] cllmh = 1.- cllmh return cllmh def Forcompute_cllmh(cldfra, pres, dimns, dimvns): """ Function to compute cllmh: low/medium/hight cloud fraction following newmicro.F90 from LMDZ via Fortran subroutine compute_clt(cldfra, pres, dimns, dimvns) [cldfra]= cloud fraction values (assuming [[t],z,y,x]) [pres] = pressure field [dimns]= list of the name of the dimensions of [cldfra] [dimvns]= list of the name of the variables with the values of the dimensions of [cldfra] """ fname = 'Forcompute_cllmh' cllmhdims = dimns[:] cllmhvdims = dimvns[:] if len(cldfra.shape) == 4: dx = cldfra.shape[3] dy = cldfra.shape[2] dz = cldfra.shape[1] dt = cldfra.shape[0] cllmhdims.pop(1) cllmhvdims.pop(1) cllmh = fdin.module_fordiagnostics.compute_cllmh4d2(cldfra[:], pres[:]) else: dx = cldfra.shape[2] dy = cldfra.shape[1] dz = cldfra.shape[0] cllmhdims.pop(0) cllmhvdims.pop(0) cllmh = fdin.module_fordiagnostics.compute_cllmh3d1(cldfra[:], pres[:]) return cllmh, cllmhdims, cllmhvdims def compute_cllmh(cldfra, pres, dimns, dimvns): """ Function to compute cllmh: low/medium/hight cloud fraction following newmicro.F90 from LMDZ compute_clt(cldfra, pres, dimns, dimvns) [cldfra]= cloud fraction values (assuming [[t],z,y,x]) [pres] = pressure field [dimns]= list of the name of the dimensions of [cldfra] [dimvns]= list of the name of the variables with the values of the dimensions of [cldfra] """ fname = 'compute_cllmh' cllmhdims = dimns[:] cllmhvdims = dimvns[:] if len(cldfra.shape) == 4: dx = cldfra.shape[3] dy = cldfra.shape[2] dz = cldfra.shape[1] dt = cldfra.shape[0] cllmhdims.pop(1) cllmhvdims.pop(1) cllmh = np.ones(tuple([3, dt, dy, dx]), dtype=np.float) for it in range(dt): for ix in range(dx): for iy in range(dy): gen.percendone(it*dx*dy + ix*dy + iy, dx*dy*dt, 5, 'diagnosted') cllmh[:,it,iy,ix] = var_cllmh(cldfra[it,:,iy,ix], pres[it,:,iy,ix]) else: dx = cldfra.shape[2] dy = cldfra.shape[1] dz = cldfra.shape[0] cllmhdims.pop(0) cllmhvdims.pop(0) cllmh = np.ones(tuple([3, dy, dx]), dtype=np.float) for ix in range(dx): for iy in range(dy): gen.percendone(ix*dy + iy,dx*dy, 5, 'diagnosted') cllmh[:,iy,ix] = var_cllmh(cldfra[:,iy,ix], pres[:,iy,ix]) return cllmh, cllmhdims, cllmhvdims def compute_clivi(dens, qtot, dimns, dimvns): """ Function to compute cloud-ice water path (clivi) [dens] = density [in kgkg-1] (assuming [t],z,y,x) [qtot] = added mixing ratio of all cloud-ice species in [kgkg-1] (assuming [t],z,y,x) [dimns]= list of the name of the dimensions of [q] [dimvns]= list of the name of the variables with the values of the dimensions of [q] """ fname = 'compute_clivi' clividims = dimns[:] clivivdims = dimvns[:] if len(qtot.shape) == 4: clividims.pop(1) clivivdims.pop(1) else: clividims.pop(0) clivivdims.pop(0) data1 = dens*qtot clivi = np.sum(data1, axis=1) return clivi, clividims, clivivdims def compute_clwvl(dens, qtot, dimns, dimvns): """ Function to compute condensed water path (clwvl) [dens] = density [in kgkg-1] (assuming [t],z,y,x) [qtot] = added mixing ratio of all cloud-water species in [kgkg-1] (assuming [t],z,y,x) [dimns]= list of the name of the dimensions of [q] [dimvns]= list of the name of the variables with the values of the dimensions of [q] """ fname = 'compute_clwvl' clwvldims = dimns[:] clwvlvdims = dimvns[:] if len(qtot.shape) == 4: clwvldims.pop(1) clwvlvdims.pop(1) else: clwvldims.pop(0) clwvlvdims.pop(0) data1 = dens*qtot clwvl = np.sum(data1, axis=1) return clwvl, clwvldims, clwvlvdims def var_virtualTemp (temp,rmix): """ This function returns virtual temperature in K, temp: temperature [K] rmix: mixing ratio in [kgkg-1] """ fname = 'var_virtualTemp' virtual=temp*(0.622+rmix)/(0.622*(1.+rmix)) return virtual def var_mslp(pres, psfc, ter, tk, qv): """ Function to compute mslp on a 1D column """ fname = 'var_mslp' N = 1.0 expon=287.04*.0065/9.81 pref = 40000. # First find where about 400 hPa is located dz=len(pres) kref = -1 pinc = pres[0] - pres[dz-1] if pinc < 0.: for iz in range(1,dz): if pres[iz-1] >= pref and pres[iz] < pref: kref = iz break else: for iz in range(dz-1): if pres[iz] >= pref and pres[iz+1] < pref: kref = iz break if kref == -1: print errormsg print ' ' + fname + ': no reference pressure:',pref,'found!!' print ' values:',pres[:] quit(-1) mslp = 0. # We are below both the ground and the lowest data level. # First, find the model level that is closest to a "target" pressure # level, where the "target" pressure is delta-p less that the local # value of a horizontally smoothed surface pressure field. We use # delta-p = 150 hPa here. A standard lapse rate temperature profile # passing through the temperature at this model level will be used # to define the temperature profile below ground. This is similar # to the Benjamin and Miller (1990) method, using # 700 hPa everywhere for the "target" pressure. # ptarget = psfc - 15000. ptarget = 70000. dpmin=1.e4 kupper = 0 if pinc > 0.: for iz in range(dz-1,0,-1): kupper = iz dp=np.abs( pres[iz] - ptarget ) if dp < dpmin: exit dpmin = np.min([dpmin, dp]) else: for iz in range(dz): kupper = iz dp=np.abs( pres[iz] - ptarget ) if dp < dpmin: exit dpmin = np.min([dpmin, dp]) pbot=np.max([pres[0], psfc]) # zbot=0. # tbotextrap=tk(i,j,kupper,itt)*(pbot/pres_field(i,j,kupper,itt))**expon # tvbotextrap=virtual(tbotextrap,qv(i,j,1,itt)) # data_out(i,j,itt,1) = (zbot+tvbotextrap/.0065*(1.-(interp_levels(1)/pbot)**expon)) tbotextrap = tk[kupper]*(psfc/ptarget)**expon tvbotextrap = var_virtualTemp(tbotextrap, qv[kupper]) mslp = psfc*( (tvbotextrap+0.0065*ter)/tvbotextrap)**(1./expon) return mslp def compute_mslp(pressure, psurface, terrain, temperature, qvapor, dimns, dimvns): """ Function to compute mslp: mean sea level pressure following p_interp.F90 from WRF var_mslp(pres, ter, tk, qv, dimns, dimvns) [pressure]= pressure field [Pa] (assuming [[t],z,y,x]) [psurface]= surface pressure field [Pa] [terrain]= topography [m] [temperature]= temperature [K] [qvapor]= water vapour mixing ratio [kgkg-1] [dimns]= list of the name of the dimensions of [cldfra] [dimvns]= list of the name of the variables with the values of the dimensions of [pres] """ fname = 'compute_mslp' mslpdims = list(dimns[:]) mslpvdims = list(dimvns[:]) if len(pressure.shape) == 4: mslpdims.pop(1) mslpvdims.pop(1) else: mslpdims.pop(0) mslpvdims.pop(0) if len(pressure.shape) == 4: dx = pressure.shape[3] dy = pressure.shape[2] dz = pressure.shape[1] dt = pressure.shape[0] mslpv = np.zeros(tuple([dt, dy, dx]), dtype=np.float) # Terrain... to 2D ! terval = np.zeros(tuple([dy, dx]), dtype=np.float) if len(terrain.shape) == 3: terval = terrain[0,:,:] else: terval = terrain for ix in range(dx): for iy in range(dy): if terval[iy,ix] > 0.: for it in range(dt): mslpv[it,iy,ix] = var_mslp(pressure[it,:,iy,ix], \ psurface[it,iy,ix], terval[iy,ix], temperature[it,:,iy,ix],\ qvapor[it,:,iy,ix]) gen.percendone(it*dx*dy + ix*dy + iy, dx*dy*dt, 5, 'diagnosted') else: mslpv[:,iy,ix] = psurface[:,iy,ix] else: dx = pressure.shape[2] dy = pressure.shape[1] dz = pressure.shape[0] mslpv = np.zeros(tuple([dy, dx]), dtype=np.float) # Terrain... to 2D ! terval = np.zeros(tuple([dy, dx]), dtype=np.float) if len(terrain.shape) == 3: terval = terrain[0,:,:] else: terval = terrain for ix in range(dx): for iy in range(dy): gen.percendone(ix*dy + iy,dx*dy, 5, 'diagnosted') if terval[iy,ix] > 0.: mslpv[iy,ix] = var_mslp(pressure[:,iy,ix], psurface[iy,ix], \ terval[iy,ix], temperature[:,iy,ix], qvapor[:,iy,ix]) else: mslpv[iy,ix] = psfc[iy,ix] return mslpv, mslpdims, mslpvdims def compute_OMEGAw(omega, p, t, dimns, dimvns): """ Function to transform OMEGA [Pas-1] to velocities [ms-1] tacking: https://www.ncl.ucar.edu/Document/Functions/Contributed/omega_to_w.shtml [omega] = vertical velocity [in ms-1] (assuming [t],z,y,x) [p] = pressure in [Pa] (assuming [t],z,y,x) [t] = temperature in [K] (assuming [t],z,y,x) [dimns]= list of the name of the dimensions of [q] [dimvns]= list of the name of the variables with the values of the dimensions of [q] """ fname = 'compute_OMEGAw' rgas = 287.058 # J/(kg-K) => m2/(s2 K) g = 9.80665 # m/s2 wdims = dimns[:] wvdims = dimvns[:] rho = p/(rgas*t) # density => kg/m3 w = -omega/(rho*g) return w, wdims, wvdims def compute_prw(dens, q, dimns, dimvns): """ Function to compute water vapour path (prw) [dens] = density [in kgkg-1] (assuming [t],z,y,x) [q] = mixing ratio in [kgkg-1] (assuming [t],z,y,x) [dimns]= list of the name of the dimensions of [q] [dimvns]= list of the name of the variables with the values of the dimensions of [q] """ fname = 'compute_prw' prwdims = dimns[:] prwvdims = dimvns[:] if len(q.shape) == 4: prwdims.pop(1) prwvdims.pop(1) else: prwdims.pop(0) prwvdims.pop(0) data1 = dens*q prw = np.sum(data1, axis=1) return prw, prwdims, prwvdims def compute_rh(p, t, q, dimns, dimvns): """ Function to compute relative humidity following 'Tetens' equation (T,P) ...' [t]= temperature (assuming [[t],z,y,x] in [K]) [p] = pressure field (assuming in [hPa]) [q] = mixing ratio in [kgkg-1] [dimns]= list of the name of the dimensions of [t] [dimvns]= list of the name of the variables with the values of the dimensions of [t] """ fname = 'compute_rh' rhdims = dimns[:] rhvdims = dimvns[:] data1 = 10.*0.6112*np.exp(17.67*(t-273.16)/(t-29.65)) data2 = 0.622*data1/(0.01*p-(1.-0.622)*data1) rh = q/data2 return rh, rhdims, rhvdims def compute_td(p, temp, qv, dimns, dimvns): """ Function to compute the dew point temperature [p]= pressure [Pa] [temp]= temperature [C] [qv]= mixing ratio [kgkg-1] [dimns]= list of the name of the dimensions of [p] [dimvns]= list of the name of the variables with the values of the dimensions of [p] """ fname = 'compute_td' # print ' ' + fname + ': computing dew-point temperature from TS as t and Tetens...' # tacking from: http://en.wikipedia.org/wiki/Dew_point tk = temp data1 = 10.*0.6112*np.exp(17.67*(tk-273.16)/(tk-29.65)) data2 = 0.622*data1/(0.01*p-(1.-0.622)*data1) rh = qv/data2 pa = rh * data1 td = 257.44*np.log(pa/6.1121)/(18.678-np.log(pa/6.1121)) tddims = dimns[:] tdvdims = dimvns[:] return td, tddims, tdvdims def var_WRFtime(timewrfv, refdate='19491201000000', tunitsval='minutes'): """ Function to copmute CFtimes from WRFtime variable refdate= [YYYYMMDDMIHHSS] format of reference date tunitsval= CF time units timewrfv= matrix string values of WRF 'Times' variable """ fname = 'var_WRFtime' yrref=refdate[0:4] monref=refdate[4:6] dayref=refdate[6:8] horref=refdate[8:10] minref=refdate[10:12] secref=refdate[12:14] refdateS = yrref + '-' + monref + '-' + dayref + ' ' + horref + ':' + minref + \ ':' + secref dt = timewrfv.shape[0] WRFtime = np.zeros((dt), dtype=np.float) for it in range(dt): wrfdates = gen.datetimeStr_conversion(timewrfv[it,:],'WRFdatetime', 'matYmdHMS') WRFtime[it] = gen.realdatetime1_CFcompilant(wrfdates, refdate, tunitsval) tunits = tunitsval + ' since ' + refdateS return WRFtime, tunits def turbulence_var(varv, dimvn, dimn): """ Function to compute the Taylor's decomposition turbulence term from a a given variable x*=_t-(_t)^2 turbulence_var(varv,dimn) varv= values of the variable dimvn= names of the dimension of the variable dimn= names of the dimensions (as a dictionary with 'X', 'Y', 'Z', 'T') >>> turbulence_var(np.arange((27)).reshape(3,3,3),['time','y','x'],{'T':'time', 'Y':'y', 'X':'x'}) [[ 54. 54. 54.] [ 54. 54. 54.] [ 54. 54. 54.]] """ fname = 'turbulence_varv' timedimid = dimvn.index(dimn['T']) varv2 = varv*varv vartmean = np.mean(varv, axis=timedimid) var2tmean = np.mean(varv2, axis=timedimid) varvturb = var2tmean - (vartmean*vartmean) return varvturb def compute_turbulence(v, dimns, dimvns): """ Function to compute the rubulence term of the Taylor's decomposition ...' x*=_t-(_t)^2 [v]= variable (assuming [[t],z,y,x]) [dimns]= list of the name of the dimensions of [v] [dimvns]= list of the name of the variables with the values of the dimensions of [v] """ fname = 'compute_turbulence' turbdims = dimns[:] turbvdims = dimvns[:] turbdims.pop(0) turbvdims.pop(0) v2 = v*v vartmean = np.mean(v, axis=0) var2tmean = np.mean(v2, axis=0) turb = var2tmean - (vartmean*vartmean) return turb, turbdims, turbvdims def compute_wds(u, v, dimns, dimvns): """ Function to compute the wind direction [u]= W-E wind direction [ms-1, knot, ...] [v]= N-S wind direction [ms-1, knot, ...] [dimns]= list of the name of the dimensions of [u] [dimvns]= list of the name of the variables with the values of the dimensions of [u] """ fname = 'compute_wds' # print ' ' + fname + ': computing wind direction as ATAN2(v,u) ...' theta = np.arctan2(v,u) theta = np.where(theta < 0., theta + 2.*np.pi, theta) wds = 360.*theta/(2.*np.pi) wdsdims = dimns[:] wdsvdims = dimvns[:] return wds, wdsdims, wdsvdims def compute_wss(u, v, dimns, dimvns): """ Function to compute the wind speed [u]= W-E wind direction [ms-1, knot, ...] [v]= N-S wind direction [ms-1, knot, ...] [dimns]= list of the name of the dimensions of [u] [dimvns]= list of the name of the variables with the values of the dimensions of [u] """ fname = 'compute_wss' # print ' ' + fname + ': computing wind speed as SQRT(v**2 + u**2) ...' wss = np.sqrt(u*u + v*v) wssdims = dimns[:] wssvdims = dimvns[:] return wss, wssdims, wssvdims def timeunits_seconds(dtu): """ Function to transform a time units to seconds timeunits_seconds(timeuv) [dtu]= time units value to transform in seconds """ fname='timunits_seconds' if dtu == 'years': times = 365.*24.*3600. elif dtu == 'weeks': times = 7.*24.*3600. elif dtu == 'days': times = 24.*3600. elif dtu == 'hours': times = 3600. elif dtu == 'minutes': times = 60. elif dtu == 'seconds': times = 1. elif dtu == 'miliseconds': times = 1./1000. else: print errormsg print ' ' + fname + ": time units '" + dtu + "' not ready !!" quit(-1) return times def compute_WRFuava(u, v, sina, cosa, dimns, dimvns): """ Function to compute geographical rotated WRF 3D winds u= orginal WRF x-wind v= orginal WRF y-wind sina= original WRF local sinus of map rotation cosa= original WRF local cosinus of map rotation formula: ua = u*cosa-va*sina va = u*sina+va*cosa """ fname = 'compute_WRFuava' var0 = u var1 = v var2 = sina var3 = cosa # un-staggering variables unstgdims = [var0.shape[0], var0.shape[1], var0.shape[2], var0.shape[3]-1] ua = np.zeros(tuple(unstgdims), dtype=np.float) va = np.zeros(tuple(unstgdims), dtype=np.float) unstgvar0 = np.zeros(tuple(unstgdims), dtype=np.float) unstgvar1 = np.zeros(tuple(unstgdims), dtype=np.float) unstgvar0 = 0.5*(var0[:,:,:,0:var0.shape[3]-1] + var0[:,:,:,1:var0.shape[3]]) unstgvar1 = 0.5*(var1[:,:,0:var1.shape[2]-1,:] + var1[:,:,1:var1.shape[2],:]) for iz in range(var0.shape[1]): ua[:,iz,:,:] = unstgvar0[:,iz,:,:]*var3 - unstgvar1[:,iz,:,:]*var2 va[:,iz,:,:] = unstgvar0[:,iz,:,:]*var2 + unstgvar1[:,iz,:,:]*var3 dnamesvar = ['Time','bottom_top','south_north','west_east'] dvnamesvar = ncvar.var_dim_dimv(dnamesvar,dimns,dimvns) return ua, va, dnamesvar, dvnamesvar def compute_WRFuasvas(u10, v10, sina, cosa, dimns, dimvns): """ Function to compute geographical rotated WRF 2-meter winds u10= orginal WRF 10m x-wind v10= orginal WRF 10m y-wind sina= original WRF local sinus of map rotation cosa= original WRF local cosinus of map rotation formula: uas = u10*cosa-va10*sina vas = u10*sina+va10*cosa """ fname = 'compute_WRFuasvas' var0 = u10 var1 = v10 var2 = sina var3 = cosa uas = np.zeros(var0.shape, dtype=np.float) vas = np.zeros(var0.shape, dtype=np.float) uas = var0*var3 - var1*var2 vas = var0*var2 + var1*var3 dnamesvar = ['Time','south_north','west_east'] dvnamesvar = ncvar.var_dim_dimv(dnamesvar,dimns,dimvns) return uas, vas, dnamesvar, dvnamesvar def compute_WRFta(t, p, dimns, dimvns): """ Function to compute WRF air temperature t= orginal WRF temperature p= original WRF pressure (P + PB) formula: temp = theta*(p/p0)**(R/Cp) """ fname = 'compute_WRFta' ta = (t+300.)*(p/fdef.module_definitions.p0ref)**(fdef.module_definitions.rcp) dnamesvar = ['Time','bottom_top','south_north','west_east'] dvnamesvar = ncvar.var_dim_dimv(dnamesvar,dimns,dimvns) return ta, dnamesvar, dvnamesvar def compute_WRFtd(t, p, qv, dimns, dimvns): """ Function to compute WRF dew-point air temperature t= orginal WRF temperature p= original WRF pressure (P + PB) formula: temp = theta*(p/p0)**(R/Cp) """ fname = 'compute_WRFtd' tk = (t+300.)*(p/fdef.module_definitions.p0ref)**(fdef.module_definitions.rcp) data1 = 10.*0.6112*np.exp(17.67*(tk-273.16)/(tk-29.65)) data2 = 0.622*data1/(0.01*p-(1.-0.622)*data1) rh = qv/data2 pa = rh * data1 td = 257.44*np.log(pa/6.1121)/(18.678-np.log(pa/6.1121)) dnamesvar = ['Time','bottom_top','south_north','west_east'] dvnamesvar = ncvar.var_dim_dimv(dnamesvar,dimns,dimvns) return td, dnamesvar, dvnamesvar