def Dewpoint(T, rh, method=None): """Computes dewpoint profile from T and rh Usage: Td = Dewpoint(T,rh,method=None) Where: T is in K rh is in % (relative humidity) method used to compute Es: 1: Hyland-Wexler formulation, polynomial coeff (absolute norm) (default) 2: Wexler formulation 3: Hyland-Wexler formulation, polynomial coeff (relative error norm) 4: classic Goff Gratch equation 5: 6.112*numpy.ma.exp(17.67*tempc/(tempc+243.5)) Assumes constant latent temperature (except over ice or water) """ To = 273.15 # K Rv = 461.53 # J/(K*kg) eo = 611 # Pa L = MV2.ones(T.shape) * 2.502E6 # J/kg L = MV2.where(MV2.less(T, To), 2.83E6, L) # J/kg es = Es(T, method=method) # in Pa e = rh * es / 100. Td = 1. / (1. / To - Rv / L * (e / eo)) Td.setAxisList(T.getAxisList()) return Td
def testMaskingFunctions(self): xouter = MV2.outerproduct(MV2.arange(5.), [1] * 10) masked = MV2.masked_greater(xouter, 1) self.assertTrue(MV2.allequal(masked.mask[2:], True)) self.assertTrue(MV2.allequal(masked.mask[:2], False)) masked = MV2.masked_greater_equal(xouter, 1) self.assertTrue(MV2.allequal(masked.mask[1:], True)) self.assertTrue(MV2.allequal(masked.mask[:1], False)) masked = MV2.masked_less(xouter, 1) self.assertTrue(MV2.allequal(masked.mask[:1], True)) self.assertTrue(MV2.allequal(masked.mask[1:], False)) masked = MV2.masked_less_equal(xouter, 1) self.assertTrue(MV2.allequal(masked.mask[:2], True)) self.assertTrue(MV2.allequal(masked.mask[2:], False)) masked = MV2.masked_not_equal(xouter, 1) self.assertTrue(MV2.allequal(masked.mask[1], False)) self.assertTrue(MV2.allequal(masked.mask[0], True)) self.assertTrue(MV2.allequal(masked.mask[2:], True)) masked = MV2.masked_equal(xouter, 1) self.assertTrue(MV2.allequal(masked.mask[1], True)) self.assertTrue(MV2.allequal(masked.mask[0], False)) self.assertTrue(MV2.allequal(masked.mask[2:], False)) masked = MV2.masked_outside(xouter, 1, 3) self.assertTrue(MV2.allequal(masked.mask[0:1], True)) self.assertTrue(MV2.allequal(masked.mask[1:4], False)) self.assertTrue(MV2.allequal(masked.mask[4:], True)) masked = MV2.masked_where( MV2.logical_or(MV2.greater(xouter, 3), MV2.less(xouter, 2)), xouter) self.assertTrue(MV2.allequal(masked.mask[0:2], True)) self.assertTrue(MV2.allequal(masked.mask[2:4], False)) self.assertTrue(MV2.allequal(masked.mask[4:], True))
def Dewpoint(T, rh, method=None): """Computes dewpoint profile from T and rh Usage: Td = Dewpoint(T,rh,method=None) Where: T is in K rh is in % (relative humidity) method used to compute Es: 1: Hyland-Wexler formulation, polynomial coeff (absolute norm) (default) 2: Wexler formulation 3: Hyland-Wexler formulation, polynomial coeff (relative error norm) 4: classic Goff Gratch equation 5: 6.112*numpy.ma.exp(17.67*tempc/(tempc+243.5)) Assumes constant latent temperature (except over ice or water) """ To = 273.15 # K Rv = 461.53 # J/(K*kg) eo = 611 # Pa L = MV2.ones(T.shape) * 2.502e6 # J/kg L = MV2.where(MV2.less(T, To), 2.83e6, L) # J/kg es = Es(T, method=method) # in Pa e = rh * es / 100.0 Td = 1.0 / (1.0 / To - Rv / L * (e / eo)) Td.setAxisList(T.getAxisList()) return Td
def myMakeMask(array, range): """Returns the input array masked where the values are not between range[0] and range[1]""" m1 = MV2.less(array, range[0]) # mask where it is less than the 1st value m2 = MV2.greater( array, range[1]) # mask where it is more than the 2nd value return MV2.logical_or(m1, m2)
## masked_not_equal(x, value) = x masked where x != value ## masked_outside(x, v1, v2) ## x with mask of all values of x that are outside [v1,v2] xmo = MV2.masked_outside(xouter, 120, 160) ## count(a, axis=None) ## Count of the non-masked elements in a, or along a certain axis. xcount = MV2.count(xmo, 0) xcount2 = MV2.count(xmo, 1) ## masked_where(condition, x, copy=1) ## Return x as an array masked where condition is true. ## Also masked where x or condition masked. xmwhere = MV2.masked_where( MV2.logical_and(MV2.greater(xouter, 120), MV2.less(xouter, 160)), xouter) ## maximum(a, b=None) ## returns maximum element of a single array, or elementwise maxval = MV2.maximum(xouter) xmax = MV2.maximum(ud, vd) xmax = MV2.maximum.reduce(ud) xmax = MV2.maximum.reduce(vd) xmax2 = numpy.ma.maximum.reduce(vd.subSlice(), axis=0) if not MV2.allclose(xmax, xmax2): markError('maximum.reduce') ## minimum(a, b=None) ## returns minimum element of a single array, or elementwise minval = MV2.minimum(xouter) xmin = MV2.minimum(ud, vd) xmin = MV2.minimum.reduce(ud)
def Es(T, method=None): """Computes saturated pressure in Pa given T in K, using the method: 1: Hyland-Wexler formulation, polynomial coeff (absolute norm) 2: Wexler formulation 3: Hyland-Wexler formulation, polynomial coeff (relative error norm) 4: classic Goff Gratch equation 5: 6.112*numpy.ma.exp(17.67*tempc/(tempc+243.5)) Default is method 1 Note: 1 and 2 use method 3 where T is not : 173.15 < T < 473.15 ref for 1, 2 and 3: Piotr Flatau and al., Journal of Applied Met., Vol 31, Dec 1992 ( http://ams.allenpress.com/perlserv/?request=get-document&doi=10.1175%2F1520-0450(1992)031%3C1507%3APFTSVP%3E2.0.CO%3B2&ct=1 ) """ if method is None: method = 1 if method == 1: ## Put in C x = T - 273.15 ## Water vapor c0 = 0.611220713E03 c1 = 0.443944344E02 c2 = 0.143195336E01 c3 = 0.263350515E-01 c4 = 0.310636053E-03 c5 = 0.185218710E-05 c6 = 0.103440324E-07 c7 = -0.468258100E-10 c8 = 0.466533033E-13 eswat = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8))))))) ## ice c0 = .611153246E03 c1 = .503261230E02 c2 = .188595709E01 c3 = .422115970E-01 c4 = .620376691E-03 c5 = .616082536E-05 c6 = .405172828E-07 c7 = .161492905E-09 c8 = .297886454E-12 esice = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8))))))) ## Combine es = MV2.where(MV2.less(T, 273.15), esice, eswat) ## Overwrite values outside valid range with method 2 mn, mx = genutil.minmax(T) if mn < 173.16 or mx > 473.15: es2 = Es(T, method=2) es = MV2.where(MV2.less(T, 173.16), es2, es) es = MV2.where(MV2.greater(T, 473.15), es2, es) elif method == 2: # over water g0 = -0.29912729E4 g1 = -0.60170128E4 g2 = 0.1887643854E2 g3 = -0.28354721E-1 g4 = 0.17838301E-4 g5 = -0.84150417E-9 g6 = 0.44412543E-12 g7 = 0.2858487E1 # over ice k0 = -0.58653696e4 k1 = 0.2224103300E2 k2 = 0.13749042E-1 k3 = -0.34031775E-4 k4 = 0.26967687E-7 k5 = 0.6918651 esice = (k0 + (k1 + k5 * MV2.log(T) + (k2 + (k3 + k4 * T) * T) * T) * T) / T # over ice eswat = (g0 + (g1 + (g2 + g7 * MV2.log(T) + (g3 + (g4 + (g5 + g6 * T) * T) * T) * T) * T) * T) / T**2 # over water es = MV2.where(MV2.less(T, 273.15), esice, eswat) es = MV2.exp(es) elif method == 3: ## Put in C x = T - 273.15 ## Water vapor c0 = 0.611213476E03 c1 = 0.444007856E02 c2 = 0.143064234E01 c3 = 0.264461437E-01 c4 = 0.305930558E-03 c5 = 0.196237241E-05 c6 = 0.892344772E-08 c7 = -0.373208410E-10 c8 = 0.209339997E-13 eswat = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8))))))) ## ice c0 = .611123516E03 c1 = .503109514E02 c2 = .1888369801E01 c3 = .420547422E-01 c4 = .614396778E-03 c5 = .602780717E-05 c6 = .387940929E-07 c7 = .149436277E-09 c8 = .262655803E-12 esice = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8))))))) ## Combine es = MV2.where(MV2.less(T, 273.15), esice, eswat) ## Overwrite values outside valid range with method 2 mn, mx = genutil.minmax(T) if mn < 173.16 or mx > 473.15: es2 = Es(T, method=2) es = MV2.where(MV2.less(T, 173.16), es2, es) es = MV2.where(MV2.greater(T, 473.15), es2, es) elif method == 4: est = 101324.6 #Pa Ts = 373.16 / T a = -7.90298 b = 5.02808 c = -1.3816E-7 d = 11.344 f = 8.1328E-3 h = -3.49149 maxexp = int(numpy.log10(numpy.finfo(numpy.float).max)) minexp = 1 - a es = a * (Ts - 1.) es = es + b * numpy.ma.log10(Ts) A = d * (1. - Ts) A = numpy.ma.masked_greater(A, maxexp) A = numpy.ma.masked_less(A, minexp) es = es + c * (numpy.ma.power(10, A) - 1.) A = h * (Ts - 1.) A = numpy.ma.masked_greater(A, maxexp) A = numpy.ma.masked_less(A, minexp) es = es + f * (numpy.ma.power(10, A) - 1.) es = est * numpy.ma.power(10, es) elif method == 5: tempc = T - 273.15 es = 611.2 * numpy.ma.exp(17.67 * tempc / (tempc + 243.5)) return es
def myMakeMask(array, range): """Returns the input array masked where the values are not between range[0] and range[1]""" m1=MV.less (array, range[0]) # mask where it is less than the 1st value m2=MV.greater(array, range[1]) # mask where it is more than the 2nd value return MV.logical_or(m1,m2)
def harmonic(data, k=3): data = data.reorder('t...') cdutil.setAxisTimeBoundsDaily(data.getTime()) axislist = data.getAxisList() dataid = data.id daily = True monthly = False timeAxis = axislist[0] N = 365. #len(timeAxis) # P = 10. # 10 year, yearly harmonic oscilation # P = 10*12 # 10 year, monthly harmonic oscilation # P = 10*365 # 10 year, daily harmonic oscilation # if P > N: # raise ValueError("P('%d') value should not exceed N(%d)" % (P,N)) if k > N/2: raise ValueError("k value should not exceed (%d) i.e. N/2 value" % (N/2)) if len(timeAxis) > 366: print 'found more than 1 year data.' # y_t = dailyClimatology(data, action='sum') else: y_t = data # end of if len(timeAxis) > 366: Y_0 = cdutil.averager(data, axis='t', action='average', weights='equal') # make memory free del data t = numpy.arange(1, N+1, dtype='float') otheraxis = list(Y_0.shape) ax_product = 1 for ax in otheraxis: ax_product *= ax otheraxis.insert(0,N) t = t.repeat(ax_product).reshape(otheraxis) angle = 2 * math.pi * t/N Y_k = 0. for i in range(1,k+1): kangle = angle*i A_k = (2./N) * cdutil.averager(y_t * numpy.cos(kangle), axis='t', action='sum') B_k = (2./N) * cdutil.averager(y_t * numpy.sin(kangle), axis='t', action='sum') C_k = MV2.sqrt((A_k*A_k) + (B_k*B_k)) # if A_k is positiv, then retain this phase_angle as it is. # phase_angle should be in degrees phase_angle = phase_arc_angle = MV2.arctan(B_k/A_k) # if A_k is zero, then replace phase_angle with pi/2 else retain same phase_angle = MV2.where(MV2.equal(A_k, 0.), math.pi/2.0, phase_arc_angle) # if A_k is negative, then add pi with phase_angle (if it is <= pi ) condition1 = MV2.logical_and(MV2.less(A_k, 0.), MV2.less_equal(phase_arc_angle, math.pi)) phase_angle = MV2.where(condition1, phase_arc_angle+math.pi, phase_arc_angle) # if A_k is negative, then subtract pi from phase_angle (if it is > pi ) condition2 = MV2.logical_and(MV2.less(A_k, 0.), MV2.greater(phase_arc_angle, math.pi)) condition3 = MV2.logical_or(condition1, condition2) phase_angle = MV2.where(condition3, phase_arc_angle-math.pi, phase_arc_angle) # make memory free del phase_arc_angle if daily and not monthly: # subtract 15 days lag to adjust phase_angle w.r.t daily print "Daily Subtraction" phase_angle -= (15.*2*math.pi)/N # end of if daily and not monthly: phase_angle = numpy.array(phase_angle) # phase_angle = numpy.tile(phase_angle, N).reshape(kangle.shape) kangle = numpy.array(kangle) Y_k += C_k * MV2.cos(kangle - phase_angle) # end of for i in range(1,k+1): # add mean to the sum of first k-th harmonic of data Y_k += Y_0 # make memory free del y_t, Y_0 sumOfMean_and_first_k_harmonic = cdms2.createVariable(Y_k, id=dataid) sumOfMean_and_first_k_harmonic.setAxisList(axislist) sumOfMean_and_first_k_harmonic.comments = 'sumOfMean_and_first_%d_harmonic' % k # make memory free del Y_k # return result return sumOfMean_and_first_k_harmonic
def Es(T, method=None): """Computes saturated pressure in Pa given T in K, using the method: 1: Hyland-Wexler formulation, polynomial coeff (absolute norm) 2: Wexler formulation 3: Hyland-Wexler formulation, polynomial coeff (relative error norm) 4: classic Goff Gratch equation 5: 6.112*numpy.ma.exp(17.67*tempc/(tempc+243.5)) Default is method 1 Note: 1 and 2 use method 3 where T is not : 173.15 < T < 473.15 ref for 1, 2 and 3: Piotr Flatau and al., Journal of Applied Met., Vol 31, Dec 1992 ( http://ams.allenpress.com/perlserv/?request=get-document&\ doi=10.1175%2F1520-0450(1992)031%3C1507%3APFTSVP%3E2.0.CO%3B2&ct=1 ) """ if method is None: method = 1 if method == 1: # Put in C x = T - 273.15 # Water vapor c0 = 0.611220713e03 c1 = 0.443944344e02 c2 = 0.143195336e01 c3 = 0.263350515e-01 c4 = 0.310636053e-03 c5 = 0.185218710e-05 c6 = 0.103440324e-07 c7 = -0.468258100e-10 c8 = 0.466533033e-13 eswat = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8))))))) # ice c0 = 0.611153246e03 c1 = 0.503261230e02 c2 = 0.188595709e01 c3 = 0.422115970e-01 c4 = 0.620376691e-03 c5 = 0.616082536e-05 c6 = 0.405172828e-07 c7 = 0.161492905e-09 c8 = 0.297886454e-12 esice = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8))))))) # Combine es = MV2.where(MV2.less(T, 273.15), esice, eswat) # Overwrite values outside valid range with method 2 mn, mx = genutil.minmax(T) if mn < 173.16 or mx > 473.15: es2 = Es(T, method=2) es = MV2.where(MV2.less(T, 173.16), es2, es) es = MV2.where(MV2.greater(T, 473.15), es2, es) elif method == 2: # over water g0 = -0.29912729e4 g1 = -0.60170128e4 g2 = 0.1887643854e2 g3 = -0.28354721e-1 g4 = 0.17838301e-4 g5 = -0.84150417e-9 g6 = 0.44412543e-12 g7 = 0.2858487e1 # over ice k0 = -0.58653696e4 k1 = 0.2224103300e2 k2 = 0.13749042e-1 k3 = -0.34031775e-4 k4 = 0.26967687e-7 k5 = 0.6918651 esice = (k0 + (k1 + k5 * MV2.log(T) + (k2 + (k3 + k4 * T) * T) * T) * T) / T # over ice eswat = ( g0 + (g1 + (g2 + g7 * MV2.log(T) + (g3 + (g4 + (g5 + g6 * T) * T) * T) * T) * T) * T ) / T ** 2 # over water es = MV2.where(MV2.less(T, 273.15), esice, eswat) es = MV2.exp(es) elif method == 3: # Put in C x = T - 273.15 # Water vapor c0 = 0.611213476e03 c1 = 0.444007856e02 c2 = 0.143064234e01 c3 = 0.264461437e-01 c4 = 0.305930558e-03 c5 = 0.196237241e-05 c6 = 0.892344772e-08 c7 = -0.373208410e-10 c8 = 0.209339997e-13 eswat = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8))))))) # ice c0 = 0.611123516e03 c1 = 0.503109514e02 c2 = 0.1888369801e01 c3 = 0.420547422e-01 c4 = 0.614396778e-03 c5 = 0.602780717e-05 c6 = 0.387940929e-07 c7 = 0.149436277e-09 c8 = 0.262655803e-12 esice = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8))))))) # Combine es = MV2.where(MV2.less(T, 273.15), esice, eswat) # Overwrite values outside valid range with method 2 mn, mx = genutil.minmax(T) if mn < 173.16 or mx > 473.15: es2 = Es(T, method=2) es = MV2.where(MV2.less(T, 173.16), es2, es) es = MV2.where(MV2.greater(T, 473.15), es2, es) elif method == 4: est = 101324.6 # Pa Ts = 373.16 / T a = -7.90298 b = 5.02808 c = -1.3816e-7 d = 11.344 f = 8.1328e-3 h = -3.49149 maxexp = int(numpy.log10(numpy.finfo(numpy.float).max)) minexp = 1 - a es = a * (Ts - 1.0) es = es + b * numpy.ma.log10(Ts) A = d * (1.0 - Ts) A = numpy.ma.masked_greater(A, maxexp) A = numpy.ma.masked_less(A, minexp) es = es + c * (numpy.ma.power(10, A) - 1.0) A = h * (Ts - 1.0) A = numpy.ma.masked_greater(A, maxexp) A = numpy.ma.masked_less(A, minexp) es = es + f * (numpy.ma.power(10, A) - 1.0) es = est * numpy.ma.power(10, es) elif method == 5: tempc = T - 273.15 es = 611.2 * numpy.ma.exp(17.67 * tempc / (tempc + 243.5)) return es
def improve(mask,navy_frac_t,threshold_1,threshold_2,UL,UC,UR,ML,MR,LL,LC,LR,regridTool='regrid2'): mask_approx = map2four(mask,mask.getGrid(),regridTool=regridTool) diff = navy_frac_t - mask_approx ## Land point conversion c1 = MV2.greater(diff,threshold_1) c2 = MV2.greater(navy_frac_t,threshold_2) c= MV2.logical_and(c1,c2) ## x.plot(c.astype("i")) ## raw_input() ## x.clear() ## Now figures out local maxima cUL,cUC,cUR,cML,cMR,cLL,cLC,cLR = create_surrounds(c) L=c.getAxis(1) bL=L.getBounds() if L.isCircular() and bL[-1][1]-bL[0][0] % L.modulo == 0: c=c[1:-1] # elimnitates north and south poles tmp = navy_frac_t[1:-1] else: c=c[1:-1,1:-1] # elimnitates north and south poles tmp = navy_frac_t[1:-1,1:-1] m = MV2.logical_and(c,MV2.greater(tmp,MV2.where(cUL,UL,0.))) m = MV2.logical_and(m,MV2.greater(tmp,MV2.where(cUC,UC,0.))) m = MV2.logical_and(m,MV2.greater(tmp,MV2.where(cUR,UR,0.))) m = MV2.logical_and(m,MV2.greater(tmp,MV2.where(cML,ML,0.))) m = MV2.logical_and(m,MV2.greater(tmp,MV2.where(cMR,MR,0.))) m = MV2.logical_and(m,MV2.greater(tmp,MV2.where(cLL,LL,0.))) m = MV2.logical_and(m,MV2.greater(tmp,MV2.where(cLC,LC,0.))) m = MV2.logical_and(m,MV2.greater(tmp,MV2.where(cLR,LR,0.))) # Ok now update the mask by setting these points to land mask2 = mask*1. if L.isCircular() and bL[-1][1]-bL[0][0] % L.modulo == 0: mask2[1:-1] = MV2.where(m,1,mask[1:-1]) else: mask2[1:-1,1:-1] = MV2.where(m,1,mask[1:-1,1:-1]) ## ocean point conversion c1 = MV2.less(diff,-threshold_1) c2 = MV2.less(navy_frac_t,1.-threshold_2) c= MV2.logical_and(c1,c2) cUL,cUC,cUR,cML,cMR,cLL,cLC,cLR = create_surrounds(c) L=c.getAxis(1) bL=L.getBounds() if L.isCircular() and bL[-1][1]-bL[0][0] % L.modulo == 0: c=c[1:-1] # elimnitates north and south poles tmp = navy_frac_t[1:-1] else: c=c[1:-1,1:-1] # elimnitates north and south poles tmp = navy_frac_t[1:-1,1:-1] ## Now figures out local maxima m = MV2.logical_and(c,MV2.less(tmp,MV2.where(cUL,UL,1.))) m = MV2.logical_and(m,MV2.less(tmp,MV2.where(cUC,UC,1.))) m = MV2.logical_and(m,MV2.less(tmp,MV2.where(cUR,UR,1.))) m = MV2.logical_and(m,MV2.less(tmp,MV2.where(cML,ML,1.))) m = MV2.logical_and(m,MV2.less(tmp,MV2.where(cMR,MR,1.))) m = MV2.logical_and(m,MV2.less(tmp,MV2.where(cLL,LL,1.))) m = MV2.logical_and(m,MV2.less(tmp,MV2.where(cLC,LC,1.))) m = MV2.logical_and(m,MV2.less(tmp,MV2.where(cLR,LR,1.))) # Ok now update the mask by setting these points to ocean if L.isCircular() and bL[-1][1]-bL[0][0] % L.modulo == 0: mask2[1:-1] = MV2.where(m,0,mask2[1:-1]) else: mask2[1:-1,1:-1] = MV2.where(m,0,mask2[1:-1,1:-1]) mask2.setAxisList(mask.getAxisList()) return mask2
def improve(mask, navy_frac_t, threshold_1, threshold_2, UL, UC, UR, ML, MR, LL, LC, LR, regridTool='regrid2'): mask_approx = map2four(mask, mask.getGrid(), regridTool=regridTool) diff = navy_frac_t - mask_approx ## Land point conversion c1 = MV2.greater(diff, threshold_1) c2 = MV2.greater(navy_frac_t, threshold_2) c = MV2.logical_and(c1, c2) ## x.plot(c.astype("i")) ## raw_input() ## x.clear() ## Now figures out local maxima cUL, cUC, cUR, cML, cMR, cLL, cLC, cLR = create_surrounds(c) L = c.getAxis(1) bL = L.getBounds() if L.isCircular() and bL[-1][1] - bL[0][0] % L.modulo == 0: c = c[1:-1] # elimnitates north and south poles tmp = navy_frac_t[1:-1] else: c = c[1:-1, 1:-1] # elimnitates north and south poles tmp = navy_frac_t[1:-1, 1:-1] m = MV2.logical_and(c, MV2.greater(tmp, MV2.where(cUL, UL, 0.))) m = MV2.logical_and(m, MV2.greater(tmp, MV2.where(cUC, UC, 0.))) m = MV2.logical_and(m, MV2.greater(tmp, MV2.where(cUR, UR, 0.))) m = MV2.logical_and(m, MV2.greater(tmp, MV2.where(cML, ML, 0.))) m = MV2.logical_and(m, MV2.greater(tmp, MV2.where(cMR, MR, 0.))) m = MV2.logical_and(m, MV2.greater(tmp, MV2.where(cLL, LL, 0.))) m = MV2.logical_and(m, MV2.greater(tmp, MV2.where(cLC, LC, 0.))) m = MV2.logical_and(m, MV2.greater(tmp, MV2.where(cLR, LR, 0.))) # Ok now update the mask by setting these points to land mask2 = mask * 1. if L.isCircular() and bL[-1][1] - bL[0][0] % L.modulo == 0: mask2[1:-1] = MV2.where(m, 1, mask[1:-1]) else: mask2[1:-1, 1:-1] = MV2.where(m, 1, mask[1:-1, 1:-1]) ## ocean point conversion c1 = MV2.less(diff, -threshold_1) c2 = MV2.less(navy_frac_t, 1. - threshold_2) c = MV2.logical_and(c1, c2) cUL, cUC, cUR, cML, cMR, cLL, cLC, cLR = create_surrounds(c) L = c.getAxis(1) bL = L.getBounds() if L.isCircular() and bL[-1][1] - bL[0][0] % L.modulo == 0: c = c[1:-1] # elimnitates north and south poles tmp = navy_frac_t[1:-1] else: c = c[1:-1, 1:-1] # elimnitates north and south poles tmp = navy_frac_t[1:-1, 1:-1] ## Now figures out local maxima m = MV2.logical_and(c, MV2.less(tmp, MV2.where(cUL, UL, 1.))) m = MV2.logical_and(m, MV2.less(tmp, MV2.where(cUC, UC, 1.))) m = MV2.logical_and(m, MV2.less(tmp, MV2.where(cUR, UR, 1.))) m = MV2.logical_and(m, MV2.less(tmp, MV2.where(cML, ML, 1.))) m = MV2.logical_and(m, MV2.less(tmp, MV2.where(cMR, MR, 1.))) m = MV2.logical_and(m, MV2.less(tmp, MV2.where(cLL, LL, 1.))) m = MV2.logical_and(m, MV2.less(tmp, MV2.where(cLC, LC, 1.))) m = MV2.logical_and(m, MV2.less(tmp, MV2.where(cLR, LR, 1.))) # Ok now update the mask by setting these points to ocean if L.isCircular() and bL[-1][1] - bL[0][0] % L.modulo == 0: mask2[1:-1] = MV2.where(m, 0, mask2[1:-1]) else: mask2[1:-1, 1:-1] = MV2.where(m, 0, mask2[1:-1, 1:-1]) mask2.setAxisList(mask.getAxisList()) return mask2
landMask.long_name = "Land Area Fraction" landMask.standard_name = "land_area_fraction" landMask.units = "%" landMask.setMissing(1.0e20) # Regrid to current obs data gridFile = "/clim_obs/obs/atm/mo/tas/JRA25/ac/tas_JRA25_000001-000012_ac.nc" f_g = cdm.open(gridFile) grid = f_g("tas").getGrid() landMask = landMask.regrid(grid, regridTool="ESMF", regridMethod="linear") f_g.close() landMask.id = "sftlf" # Rename # Deal with interpolated values landMask[mv.greater(landMask, 75)] = 100 # Fix weird ocean values landMask[mv.less(landMask, 75)] = 0 # Fix continental halos landMask[mv.less(landMask, 0)] = 0 # Fix negative values # Invert land=100, ocean=0 landMask[mv.equal(landMask, 0)] = 50 # Convert ocean landMask[mv.equal(landMask, 100)] = 0 # Convert ocean landMask[mv.equal(landMask, 50)] = 100 # Convert ocean # Create outfile and write outFile = "sftlf_pcmdi-metrics_fx_NCAR-JRA25_197901-201401.nc" # Write variables to file if os.path.isfile(outFile): os.remove(outFile) fOut = cdm.open(outFile, "w") # Use function to write standard global atts globalAttWrite(fOut, options=None)
## masked_not_equal(x, value) ## masked_not_equal(x, value) = x masked where x != value ## masked_outside(x, v1, v2) ## x with mask of all values of x that are outside [v1,v2] xmo = MV2.masked_outside(xouter, 120, 160) ## count(a, axis=None) ## Count of the non-masked elements in a, or along a certain axis. xcount = MV2.count(xmo,0) xcount2 = MV2.count(xmo,1) ## masked_where(condition, x, copy=1) ## Return x as an array masked where condition is true. ## Also masked where x or condition masked. xmwhere = MV2.masked_where(MV2.logical_and(MV2.greater(xouter,120),MV2.less(xouter,160)),xouter) ## maximum(a, b=None) ## returns maximum element of a single array, or elementwise maxval = MV2.maximum(xouter) xmax = MV2.maximum(ud,vd) xmax = MV2.maximum.reduce(ud) xmax = MV2.maximum.reduce(vd) xmax2 = numpy.ma.maximum.reduce(vd.subSlice(),axis=0) if not MV2.allclose(xmax, xmax2): markError('maximum.reduce') ## minimum(a, b=None) ## returns minimum element of a single array, or elementwise minval = MV2.minimum(xouter) xmin = MV2.minimum(ud,vd) xmin = MV2.minimum.reduce(ud)
landMask.long_name = "Land Area Fraction" landMask.standard_name = "land_area_fraction" landMask.units = "%" landMask.setMissing(1.e20) # Regrid to current obs data gridFile = '/clim_obs/obs/atm/mo/tas/JRA25/ac/tas_JRA25_000001-000012_ac.nc' f_g = cdm.open(gridFile) grid = f_g('tas').getGrid() landMask = landMask.regrid(grid, regridTool='ESMF', regridMethod='linear') f_g.close() landMask.id = 'sftlf' # Rename # Deal with interpolated values landMask[mv.greater(landMask, 75)] = 100 # Fix weird ocean values landMask[mv.less(landMask, 75)] = 0 # Fix continental halos landMask[mv.less(landMask, 0)] = 0 # Fix negative values # Invert land=100, ocean=0 landMask[mv.equal(landMask, 0)] = 50 # Convert ocean landMask[mv.equal(landMask, 100)] = 0 # Convert ocean landMask[mv.equal(landMask, 50)] = 100 # Convert ocean # Create outfile and write outFile = 'sftlf_pcmdi-metrics_fx_NCAR-JRA25_197901-201401.nc' # Write variables to file if os.path.isfile(outFile): os.remove(outFile) fOut = cdm.open(outFile, 'w') # Use function to write standard global atts globalAttWrite(fOut, options=None)
def harmonic(data, k=3, time_type='daily', phase_shift=15): """ Inputs : data : climatology data k : Integer no to compute K th harmonic. By default it takes 3. time_type : daily | monthly | full (time type of input climatology) 'daily' -> it returns 365 days harmonic, 'monthly' -> it returns 12 month harmonic, 'full' -> it retuns harmonic for full length of input data. phase_shift : Used to subtract 'phase_shift' days lag to adjust phase_angle w.r.t daily or monthly. By default it takes 15 days lag to adjust phase_angle w.r.t daily data. User can pass None disable this option. Returns : Returns "sum mean of mean and first K th harmonic" of input climatology data. Concept : Earth science data consists of a strong seasonality component as indicated by the cycles of repeated patterns in climate variables such as air pressure, temperature and precipitation. The seasonality forms the strongest signals in this data and in order to find other patterns, the seasonality is removed by subtracting the monthly mean values of the raw data for each month. However since the raw data like air temperature, pressure, etc. are constantly being generated with the help of satellite observations, the climate scientists usually use a moving reference base interval of some years of raw data to calculate the mean in order to generate the anomaly time series and study the changes with respect to that. Fourier series analysis decomposes a signal into an infinite series of harmonic components. Each of these components is comprised initially of a sine wave and a cosine wave of equal integer frequency. These two waves are then combined into a single cosine wave, which has characteristic amplitude (size of the wave) and phase angle (offset of the wave). Convergence has been established for bounded piecewise continuous functions on a closed interval, with special conditions at points of discontinuity. Its convergence has been established for other conditions as well, but these are not relevant to the analysis at hand. Reference: Daniel S Wilks, 'Statistical Methods in the Atmospheric Sciences' second Edition, page no(372-378). Written By : Arulalan.T Date : 16.05.2014 """ data = data.reorder('t...') cdutil.setAxisTimeBoundsDaily(data.getTime()) axislist = data.getAxisList() timeAxis = axislist[0] dataid = data.id if time_type in ['daily']: N = 365.0 # must be float elif time_type[:3] in ['mon']: N = 12.0 # must be float elif time_type in ['full']: N = float(len(timeAxis)) if k > N/2: raise ValueError("k value should not exceed (%d) i.e. N/2 value" % (N/2)) if len(timeAxis) > 366: print 'found more than 1 year data.' raise ValueError("Kindly pass only climatology data") else: y_t = data # end of if len(timeAxis) > 366: Y_0 = cdutil.averager(data, axis='t', action='average', weights='equal') # make memory free del data t = numpy.arange(1, N+1, dtype='float') otheraxis = list(Y_0.shape) ax_product = 1 for ax in otheraxis: ax_product *= ax otheraxis.insert(0,N) t = t.repeat(ax_product).reshape(otheraxis) angle = 2 * math.pi * t/N Y_k = 0. for i in range(1,k+1): kangle = angle*i A_k = (2./N) * cdutil.averager(y_t * numpy.cos(kangle), axis='t', action='sum') B_k = (2./N) * cdutil.averager(y_t * numpy.sin(kangle), axis='t', action='sum') C_k = MV2.sqrt((A_k*A_k) + (B_k*B_k)) # if A_k is positiv, then retain this phase_angle as it is. # phase_angle should be in degrees phase_angle = phase_arc_angle = MV2.arctan(B_k/A_k) # if A_k is zero, then replace phase_angle with pi/2 else retain same phase_angle = MV2.where(MV2.equal(A_k, 0.), math.pi/2.0, phase_arc_angle) # if A_k is negative, then add pi with phase_angle (if it is <= pi ) condition1 = MV2.logical_and(MV2.less(A_k, 0.), MV2.less_equal(phase_arc_angle, math.pi)) phase_angle = MV2.where(condition1, phase_arc_angle+math.pi, phase_arc_angle) # if A_k is negative, then subtract pi from phase_angle (if it is > pi ) condition2 = MV2.logical_and(MV2.less(A_k, 0.), MV2.greater(phase_arc_angle, math.pi)) condition3 = MV2.logical_or(condition1, condition2) phase_angle = MV2.where(condition3, phase_arc_angle-math.pi, phase_arc_angle) # make memory free del phase_arc_angle if phase_shift: # subtract 15 days lag to adjust phase_angle w.r.t daily phase_angle -= (phase_shift *2 * math.pi) / N # end of if daily and not monthly: phase_angle = numpy.array(phase_angle) kangle = numpy.array(kangle) Y_k += C_k * MV2.cos(kangle - phase_angle) # end of for i in range(1,k+1): # add mean to the sum of first k-th harmonic of data Y_k += Y_0 # make memory free del y_t, Y_0 sumOfMean_and_first_k_harmonic = cdms2.createVariable(Y_k, id=dataid) sumOfMean_and_first_k_harmonic.setAxisList(axislist) sumOfMean_and_first_k_harmonic.comments = 'sumOfMean_and_first_%d_harmonic' % k # make memory free del Y_k # return result return sumOfMean_and_first_k_harmonic
inputVarName = ['precipitable_water', 'wind_speed'] outputVarName = ['prw', 'sfcWind'] outputUnits = ['kg m-2', 'm s-1'] ### BETTER IF THE USER DOES NOT CHANGE ANYTHING BELOW THIS LINE... #%% Process variable (with time axis) # Open and read input netcdf file for fi in range(len(inputVarName)): inputFilePath = inputFilePathbgn + inputFilePathend f = cdm.open(inputFilePath + inputFileName[fi]) d = f(inputVarName[fi]) #cdutil.times.setTimeBoundsMonthly(d) if inputVarName[fi] == 'wind_speed': d = MV2.where(MV2.less(d, 0.), 1.e20, d) lat = d.getLatitude() lon = d.getLongitude() #time = d.getTime() ; # Assumes variable is named 'time', for the demo file this is named 'months' time = d.getAxis(0) # Rather use a file dimension-based load statement # Deal with problematic "months since" calendar/time axis time_bounds = time.getBounds() #time_bounds[:,0] = time[:] #time_bounds[:-1,1] = time[1:] #time_bounds[-1,1] = time_bounds[-1,0]+1 #time.setBounds(time_bounds) #del(time_bounds) ; # Cleanup