def test1DMissing(self): yx = self.x.createyxvsx() data = """-11.14902417 -9.17390922 -7.29515002 -7.51774549 -8.63608171 -10.4827395 -9.93859485 -7.3394366 -5.39241468 -5.74825567 -6.74967902 -7.09622319 -5.93836983 -4.04592997 -2.65591499 -1.68180032 -0.86935245 -0.40114047 -0.54273785 -1.36178957 -2.67488251 -3.87524401 -4.84708491 -5.49186142 -5.28618944 -4.30557389 -2.89804038 -1.53825408 -1.84771029 -2.74948361 -2.23517037 -1.73306118 -0.71200646 0.76416785 1.51511193 -0.04018418 -1.54564706 -1.88664877 -0.43751604 0.89988184 0.33437949 -1.70341844 -3.79880014 -4.03570169 -4.7740073 -5.04626101 -3.77609961 -3.18667176 -2.21038272 -1.3666902 -0.54267951 -0.16472441 -0.52871418 -0.83520848 -0.90315403 -0.21747426 0.01922666 0.89621996 1.75691927 3.12657503 4.55749531 6.04921304 7.20744489 7.65294958""".split( ) data = numpy.array(data, dtype=numpy.float) data = MV2.array(data) data = MV2.masked_where(MV2.logical_and(data > -4, data < -2), data) self.x.plot(data, yx, bg=self.bg) fnm = "test_vcs_1d_missing.png" self.checkImage(fnm)
def loop(potential,potential_reg,c2,w3,region): nmax = potential.shape[0] c3 = MV2.not_equal(w3,0.) c = MV2.logical_and(c2,c3) thisturn = MV2.ones(c.shape) for i in range(nmax): c1 = MV2.logical_or(MV2.equal(potential_reg[i],region),MV2.equal(potential[i],-999)) c2 = MV2.logical_and(c,c1) c2 = MV2.logical_and(c2,thisturn) potential_reg[i] = MV2.where(c2,region,potential_reg[i]) thisturn = MV2.where(c2,0,thisturn) c1 = MV2.logical_and(c2,MV2.equal(potential[i],-999)) c2 = MV2.logical_and(c2,MV2.not_equal(potential[i],-999)) potential[i] = MV2.where(c1,w3,potential[i]) potential[i] = MV2.where(c2,potential[i]+w3,potential[i]) ## Ultimate test to see if more would be needed ! if not MV2.allequal(MV2.logical_and(c,thisturn),0): raise 'OOOPS WE COULD USE MORE REGIONS BUDDY !' return
-10.4827395 -9.93859485 -7.3394366 -5.39241468 -5.74825567 -6.74967902 -7.09622319 -5.93836983 -4.04592997 -2.65591499 -1.68180032 -0.86935245 -0.40114047 -0.54273785 -1.36178957 -2.67488251 -3.87524401 -4.84708491 -5.49186142 -5.28618944 -4.30557389 -2.89804038 -1.53825408 -1.84771029 -2.74948361 -2.23517037 -1.73306118 -0.71200646 0.76416785 1.51511193 -0.04018418 -1.54564706 -1.88664877 -0.43751604 0.89988184 0.33437949 -1.70341844 -3.79880014 -4.03570169 -4.7740073 -5.04626101 -3.77609961 -3.18667176 -2.21038272 -1.3666902 -0.54267951 -0.16472441 -0.52871418 -0.83520848 -0.90315403 -0.21747426 0.01922666 0.89621996 1.75691927 3.12657503 4.55749531 6.04921304 7.20744489 7.65294958""".split() data = numpy.array(data,dtype=numpy.float) data = MV2.array(data) data=MV2.masked_where(MV2.logical_and(data>-4,data<-2),data) #yx.datawc_x1 = 0 #yx.datawc_x2 = 80 ##yx.datawc_y1 =-12 #yx.datawc_y2 = 12 x.plot(data,yx,bg=1) fnm = "test_vcs_1d_missing.png" x.png(fnm) print "fnm:",fnm print "src:",src ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) sys.exit(ret)
def linearInterpolation(A, I, levels=[ 100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000 ], status=None): """ Linear interpolation to interpolate a field from some levels to another set of levels Value below "surface" are masked Input A : array to interpolate I : interpolation field (usually Pressure or depth) from TOP (level 0) to BOTTOM (last level), i.e P value going up with each level levels : levels to interplate to (same units as I), default levels are:[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000] I and levels must have same units Output array on new levels (levels) Examples: A=interpolate(A,I,levels=[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000]) """ try: nlev = len(levels) # Number of pressure levels except: nlev = 1 # if only one level len(levels) would breaks levels = [ levels, ] order = A.getOrder() A = A(order='z...') I = I(order='z...') sh = list(I.shape) nsigma = sh[0] #number of sigma levels sh[0] = nlev t = MV2.zeros(sh, typecode=MV2.float32) sh2 = I[0].shape prev = -1 for ilev in range(nlev): # loop through pressure levels if status is not None: prev = genutil.statusbar(ilev, nlev - 1., prev) lev = levels[ilev] # get value for the level Iabv = MV2.ones(sh2, MV2.float) Aabv = -1 * Iabv # Array on sigma level Above Abel = -1 * Iabv # Array on sigma level Below Ibel = -1 * Iabv # Pressure on sigma level Below Iabv = -1 * Iabv # Pressure on sigma level Above Ieq = MV2.masked_equal(Iabv, -1) # Area where Pressure == levels for i in range(1, nsigma): # loop from second sigma level to last one a = MV2.greater_equal( I[i], lev) # Where is the pressure greater than lev b = MV2.less_equal(I[i - 1], lev) # Where is the pressure less than lev # Now looks if the pressure level is in between the 2 sigma levels # If yes, sets Iabv, Ibel and Aabv, Abel a = MV2.logical_and(a, b) Iabv = MV2.where(a, I[i], Iabv) # Pressure on sigma level Above Aabv = MV2.where(a, A[i], Aabv) # Array on sigma level Above Ibel = MV2.where(a, I[i - 1], Ibel) # Pressure on sigma level Below Abel = MV2.where(a, A[i - 1], Abel) # Array on sigma level Below Ieq = MV2.where(MV2.equal(I[i], lev), A[i], Ieq) val = MV2.masked_where( MV2.equal(Ibel, -1.), numpy.ones(Ibel.shape) * lev) # set to missing value if no data below lev if there is tl = (val - Ibel) / (Iabv - Ibel) * (Aabv - Abel) + Abel # Interpolation if ((Ieq.mask is None) or (Ieq.mask is MV22.nomask)): tl = Ieq else: tl = MV2.where(1 - Ieq.mask, Ieq, tl) t[ilev] = tl.astype(MV2.float32) ax = A.getAxisList() autobnds = cdms2.getAutoBounds() cdms2.setAutoBounds('off') lvl = cdms2.createAxis(MV2.array(levels).filled()) cdms2.setAutoBounds(autobnds) try: lvl.units = I.units except: pass lvl.id = 'plev' try: t.units = I.units except: pass ax[0] = lvl t.setAxisList(ax) t.id = A.id for att in A.listattributes(): setattr(t, att, getattr(A, att)) return t(order=order)
def logLinearInterpolation(A, P, levels=[ 100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000 ], status=None): """ Log-linear interpolation to convert a field from sigma levels to pressure levels Value below surface are masked Input A : array on sigma levels P : pressure field from TOP (level 0) to BOTTOM (last level) levels : pressure levels to interplate to (same units as P), default levels are:[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000] P and levels must have same units Output array on pressure levels (levels) Examples: A=logLinearInterpolation(A,P),levels=[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000]) """ try: nlev = len(levels) # Number of pressure levels except: nlev = 1 # if only one level len(levels) would breaks levels = [ levels, ] order = A.getOrder() A = A(order='z...') P = P(order='z...') sh = list(P.shape) nsigma = sh[0] #number of sigma levels sh[0] = nlev t = MV2.zeros(sh, typecode=MV2.float32) sh2 = P[0].shape prev = -1 for ilev in range(nlev): # loop through pressure levels if status is not None: prev = genutil.statusbar(ilev, nlev - 1., prev) lev = levels[ilev] # get value for the level Pabv = MV2.ones(sh2, MV2.float) Aabv = -1 * Pabv # Array on sigma level Above Abel = -1 * Pabv # Array on sigma level Below Pbel = -1 * Pabv # Pressure on sigma level Below Pabv = -1 * Pabv # Pressure on sigma level Above Peq = MV2.masked_equal(Pabv, -1) # Area where Pressure == levels for i in range(1, nsigma): # loop from second sigma level to last one a = MV2.greater_equal( P[i], lev) # Where is the pressure greater than lev b = MV2.less_equal(P[i - 1], lev) # Where is the pressure less than lev # Now looks if the pressure level is in between the 2 sigma levels # If yes, sets Pabv, Pbel and Aabv, Abel a = MV2.logical_and(a, b) Pabv = MV2.where(a, P[i], Pabv) # Pressure on sigma level Above Aabv = MV2.where(a, A[i], Aabv) # Array on sigma level Above Pbel = MV2.where(a, P[i - 1], Pbel) # Pressure on sigma level Below Abel = MV2.where(a, A[i - 1], Abel) # Array on sigma level Below Peq = MV2.where(MV2.equal(P[i], lev), A[i], Peq) val = MV2.masked_where( MV2.equal(Pbel, -1), numpy.ones(Pbel.shape) * lev) # set to missing value if no data below lev if there is tl = MV2.log(val / Pbel) / MV2.log( Pabv / Pbel) * (Aabv - Abel) + Abel # Interpolation if ((Peq.mask is None) or (Peq.mask is MV2.nomask)): tl = Peq else: tl = MV2.where(1 - Peq.mask, Peq, tl) t[ilev] = tl.astype(MV2.float32) ax = A.getAxisList() autobnds = cdms2.getAutoBounds() cdms2.setAutoBounds('off') lvl = cdms2.createAxis(MV2.array(levels).filled()) cdms2.setAutoBounds(autobnds) try: lvl.units = P.units except: pass lvl.id = 'plev' try: t.units = P.units except: pass ax[0] = lvl t.setAxisList(ax) t.id = A.id for att in A.listattributes(): setattr(t, att, getattr(A, att)) return t(order=order)
# Create 4 ocean mask basinmask4 = basinmask[0,] ; # Trim off top layer # Try sftbyregion #mask = cdu.generateLandSeaMask(basinmask3) #sftb = cdu.sftbyrgn.generateSurfaceTypeByRegionMask(mask) # Southern Ocean # Case Atlantic lonmat = np.ma.zeros([len(latitude),len(longitude)],dtype='int16') if gridId == '1deg': lonlims = [-70.5,20.5] elif gridId == '0p25deg': lonlims = [-70.625,20.375] loninds = [np.where(longitude==np.float32(lonlims[0])),np.where(longitude==np.float32(lonlims[1]))] loninds = [loninds[0][0][0],loninds[1][0][0]] lonmat[:,loninds[0]:loninds[1]] = 1 basinmask3 = mv.where(mv.logical_and(basinmask3==10,lonmat),1,basinmask3) ; # Case Atlantic basinmask4 = mv.where(mv.logical_and(basinmask4==10,lonmat),1,basinmask4) ; # Case Atlantic # Case Indian lonmat = np.ma.zeros([len(latitude),len(longitude)],dtype='int16') if gridId == '1deg': lonlims = [20.5,147.5] elif gridId == '0p25deg': lonlims = [20.375,147.625] loninds = [np.where(longitude==np.float32(lonlims[0])),np.where(longitude==np.float32(lonlims[1]))] loninds = [loninds[0][0][0],loninds[1][0][0]] lonmat[:,loninds[0]:loninds[1]] = 1 basinmask3 = mv.where(mv.logical_and(basinmask3==10,lonmat),3,basinmask3) ; # Case Indian basinmask4 = mv.where(mv.logical_and(basinmask4==10,lonmat),3,basinmask4) ; # Case Indian # Case Pacific lonmat = np.ma.zeros([len(latitude),len(longitude)],dtype='int16') if gridId == '1deg':
def generateSurfaceTypeByRegionMask(mask, sftbyrgn=None, sftbyrgnmask=215, regions=range(201, 223), maximum_regions_per_cell=4, extend_up_to=3, verbose=True): """ Maps a "types" dataset onto a landsea mask Usage: mapped,found = generateSurfaceTypeByRegionMask(mask,sftbyrgn,sftbyrgnmask=None,regions=None,maximum_regions_per_cell=4,extend_up_to=3,verbode=True) Input: mask : land/sea mask (100/0) onto you wish to map our grid (will generate a ld/sea mask for you) sftbyrgn: mask you wish to map if None then uses our own "sftbyrgn" dataset (old ezget type) sftbyrgnmask: land/sea mask for sftbyrgn or a number specifying limit in values of sftbygrn which indicate the threshold land/sea (greater values are land) regions: Numbers from sftbyrgn array that you want to map onto mask maximum_regions_per_cell: maximum number f regions concidered in a cell extend_up_to : how many grid cells away around a cell can we extent to identify a guess verbose: prints to the screen what's going on (default is True) Output: mapped : mapped input mask found : ??? """ ## OK first determine which regions are available ## Must be integer values if isinstance(mask, cdms2.grid.TransientRectGrid): mask = cdutil.generateLandSeaMask(mask) * 100. if sftbyrgn is None: sftbyrgn = cdms2.open( os.path.join(sys.prefix, 'sample_data', 'sftbyrgn.nc'))('sftbyrgn') if regions is None: if verbose: print 'Preparing regions' ## regions = range(201,223) regions = [] for i in range(0, 10000): genutil.statusbar(i, 9999) c = float(MV2.sum(MV2.ravel(MV2.equal(sftbyrgn, i)), 0)) if c != 0: regions.append(i) if verbose: print 'Regions:', regions ## If no mask passed fr sftbyrgn, assumes everything greater 5000 is land) if isinstance(sftbyrgnmask, int): split = sftbyrgnmask n = MV2.maximum(mask) sftbyrgnmask = MV2.greater_equal(sftbyrgn, sftbyrgnmask) * n else: split = MV2.maximum(sftbyrgnmask) / 2. ## Now guess the type for each regions keys = {} ## ## Nice way to do it ## for r in regions: ## c=MV2.not_equal(sftbyrgn,r) ## c=MV2.masked_where(c,sftbyrgnmask) ## n=MV2.count(c) ## c=float(MV2.sum(MV2.ravel(c),0)/n) ## print r,c,n ## keys[r]=c ## Fast but not so "general" way to do it for r in regions: if r < split: keys[r] = 0. else: keys[r] = 100. sh = list(mask.shape) sh.insert(0, maximum_regions_per_cell) potential = MV2.ones(sh, dtype='d') * -999 potential_reg = MV2.ones(sh, dtype='d') * -999 g1 = sftbyrgn.getGrid() g2 = mask.getGrid() r1 = regrid2.Regridder(g1, g2) w = cdutil.area_weights(sftbyrgn) if verbose: print 'First pass' itmp = 0. for ireg in keys.keys(): genutil.statusbar(itmp, len(keys.keys()) - 1) itmp += 1. c = MV2.equal(sftbyrgn, ireg) w2 = 1. - c * w s2, w3 = r1(sftbyrgn, mask=w2.filled(), returnTuple=1) c2 = MV2.equal(mask, keys[ireg]) loop(potential, potential_reg, c2, w3, ireg) found = MV2.zeros(sh[1:], typecode='f') for i in range(maximum_regions_per_cell): found = found + MV2.not_equal(potential[i], -999) sh2 = list(sh) for k in range(extend_up_to): sh2[1] = sh[1] + 2 * (k + 1) sh2[2] = sh[2] + 2 * (k + 1) ## Form the possible i/j couples ! s = MV2.sum(MV2.ravel(MV2.equal(potential[0], -999)), 0) if verbose: print 'Expanding up to', k + 1, 'cells while trying to fix', s, 'cells' ## if dump: ## f=cdms2.open('tmp_'+str(k)+'.nc','w') ## f.write(sumregions(potential_reg,potential).astype('f'),id='sftbyrgn',axes=mask.getAxisList()) ## f.close() ## g=sumregions(potential_reg,potential).astype('d') ## g=MV2.masked_equal(g,-999) ## g=MV2.greater(g,4999)*100. ## g=MV2.absolute(mask-g) ## g=MV2.masked_equal(g,0.) ## print 'Number of differences:',MV2.count(g) if float(s) != 0: c0 = MV2.equal(potential[0], -999) couples = [] sft2 = MV2.zeros(sh2[1:], dtype='d') - 888. sft2[k + 1:-k - 1, k + 1:-k - 1] = mask for i in range(-k - 1, k + 2): for j in range(-k - 1, k + 2): if abs(i) > k or abs(j) > k: couples.append([i, j]) ntot = len(keys.keys()) * len(couples) - 1 itmp = 0 for ireg in keys.keys(): c = MV2.equal(sftbyrgn, ireg) w2 = 1. - c * w s2, w3 = r1(sftbyrgn, mask=w2.filled(), returnTuple=1) w4 = MV2.zeros(sh2[1:], typecode='d') w4[k + 1:-k - 1, k + 1:-k - 1] = w3 for i, j in couples: if verbose: genutil.statusbar(itmp, ntot) itmp += 1. c2 = MV2.equal( sft2[j + k + 1:j + k + 1 + sh[1], i + k + 1:i + k + 1 + sh[2]], keys[ireg]) c3 = MV2.equal( sft2[j + k + 1:j + k + 1 + sh[1], i + k + 1:i + k + 1 + sh[2]], mask) c2 = MV2.logical_and(c2, c3) c2 = MV2.logical_and(c2, c0) loop( potential, potential_reg, c2, w4[j + k + 1:j + k + 1 + sh[1], i + k + 1:i + k + 1 + sh[2]], ireg) found = MV2.where(MV2.equal(potential[0], -999), found - 1, found) out = sumregions(potential_reg, potential) out.setAxisList(mask.getAxisList()) found.setAxisList(mask.getAxisList()) found = found.astype('i') found.missing_value = -999 found.id = 'found' out.id = 'sftbyrgn' out = out.astype('i') out.missing_value = -999 del (out.name) del (found.name) return out, found
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 generateSurfaceTypeByRegionMask(mask,sftbyrgn=None,sftbyrgnmask=215,regions=range(201,223),maximum_regions_per_cell=4,extend_up_to=3,verbose=True): """ Maps a "regions" dataset onto a user provided land/sea mask or grid Usage: ----- mapped,found = generateSurfaceTypeByRegionMask(mask,sftbyrgn=None,sftbyrgnmask=None,regions=None,maximum_regions_per_cell=4,extend_up_to=3,verbose=True) Input: ----- mask User provided land/sea mask (100/0) or grid (the land/sea mask will be generated automagically) which will be mapped using the "sftbyrgn" internal dataset (will generate a land/sea mask for you) sftbyrgn Mask you wish to map onto your grid (if None uses internal "sftbyrgn" dataset (old ezget type)) sftbyrgnmask Land/sea mask for sftbyrgn (or a number specifying value limits for sftbyrgn which indicates land/sea threshold (greater values are land) - see URL below for integer region map) regions Numbers from sftbyrgn array that you want to map onto mask (integers from 201-222) maximum_regions_per_cell Maximum number of regions considered for a single cell extend_up_to How many grid cells around a cell can we extend to identify a guess verbose Prints to the screen what's going on (default is True) Output: ----- mapped Mapped input grid/mask using provided (or default) regions - sftbyrgn -> user provided grid/mask found Matrix containing number of regions matched for each output cell Notes: ----- - More detailed information, including a region map and tabulated region numbers are available from http://www-pcmdi.llnl.gov/publications/pdf/34.pdf """ cdat_info.pingPCMDIdb("cdat","cdutil.generateSurfaceTypeByRegionMask") ## OK first determine which regions are available ## Must be integer values if isinstance(mask,cdms2.grid.TransientRectGrid): mask = cdutil.generateLandSeaMask(mask)*100. if sftbyrgn is None: sftbyrgn = cdms2.open(os.path.join(cdat_info.get_prefix(),'share','cdutil','sftbyrgn.nc'))('sftbyrgn') if regions is None: if verbose: print 'Preparing regions' #regions = range(201,223) regions = [] for i in range(0,10000): genutil.statusbar(i,9999) c = float(MV2.sum(MV2.ravel(MV2.equal(sftbyrgn,i)),0)) if c != 0: regions.append(i) if verbose: print 'Regions:',regions ## If no mask passed fr sftbyrgn, assumes everything greater 5000 is land) if isinstance(sftbyrgnmask,int): split = sftbyrgnmask n = MV2.maximum(mask) sftbyrgnmask = MV2.greater_equal(sftbyrgn,sftbyrgnmask)*n else: split = MV2.maximum(sftbyrgnmask)/2. ## Now guess the type for each regions keys = {} ## ## Nice way to do it ## for r in regions: ## c=MV2.not_equal(sftbyrgn,r) ## c=MV2.masked_where(c,sftbyrgnmask) ## n=MV2.count(c) ## c=float(MV2.sum(MV2.ravel(c),0)/n) ## print r,c,n ## keys[r]=c ## Fast but not so "general" way to do it for r in regions: if r< split: keys[r] = 0. else: keys[r] = 100. sh = list(mask.shape) sh.insert(0,maximum_regions_per_cell) potential = MV2.ones(sh,dtype='d')*-999 potential_reg = MV2.ones(sh,dtype='d')*-999 g1 = sftbyrgn.getGrid() g2 = mask.getGrid() r1 = regrid2.Horizontal(g1,g2) w = cdutil.area_weights(sftbyrgn) if verbose: print 'First pass' itmp = 0. for ireg in keys.keys(): genutil.statusbar(itmp,len(keys.keys())-1) itmp += 1. c = MV2.equal(sftbyrgn,ireg) w2 = 1.-c*w s2,w3 = r1(sftbyrgn,mask=w2.filled(),returnTuple=1) c2 = MV2.equal(mask,keys[ireg]) loop(potential,potential_reg,c2,w3,ireg) found = MV2.zeros(sh[1:],typecode='f') for i in range(maximum_regions_per_cell): found = found+MV2.not_equal(potential[i],-999) sh2 = list(sh) for k in range(extend_up_to): sh2[1] = sh[1]+2*(k+1) sh2[2] = sh[2]+2*(k+1) ## Form the possible i/j couples ! s = MV2.sum(MV2.ravel(MV2.equal(potential[0],-999)),0) if verbose: print 'Expanding up to',k+1,'cells while trying to fix',s,'cells' #if dump: #f=cdms2.open('tmp_'+str(k)+'.nc','w') #f.write(sumregions(potential_reg,potential).astype('f'),id='sftbyrgn',axes=mask.getAxisList()) #f.close() #g=sumregions(potential_reg,potential).astype('d') #g=MV2.masked_equal(g,-999) #g=MV2.greater(g,4999)*100. #g=MV2.absolute(mask-g) #g=MV2.masked_equal(g,0.) #print 'Number of differences:',MV2.count(g) if float(s) != 0: c0 = MV2.equal(potential[0],-999) couples = [] sft2 = MV2.zeros(sh2[1:],dtype='d')-888. sft2[k+1:-k-1,k+1:-k-1] = mask for i in range(-k-1,k+2): for j in range(-k-1,k+2): if abs(i)>k or abs(j)>k: couples.append([i,j]) ntot = len(keys.keys())*len(couples)-1 itmp = 0 for ireg in keys.keys(): c = MV2.equal(sftbyrgn,ireg) w2 = 1.-c*w s2,w3 = r1(sftbyrgn,mask=w2.filled(),returnTuple=1) w4 = MV2.zeros(sh2[1:],typecode='d') w4[k+1:-k-1,k+1:-k-1] = w3 for i,j in couples: if verbose: genutil.statusbar(itmp,ntot) itmp += 1. c2 = MV2.equal(sft2[j+k+1:j+k+1+sh[1],i+k+1:i+k+1+sh[2]],keys[ireg]) c3 = MV2.equal(sft2[j+k+1:j+k+1+sh[1],i+k+1:i+k+1+sh[2]],mask) c2 = MV2.logical_and(c2,c3) c2 = MV2.logical_and(c2,c0) loop(potential,potential_reg,c2,w4[j+k+1:j+k+1+sh[1],i+k+1:i+k+1+sh[2]],ireg) found = MV2.where(MV2.equal(potential[0],-999),found-1,found) out = sumregions(potential_reg,potential) out.setAxisList(mask.getAxisList()) out.id = 'sftbyrgn' out = out.astype('i') out.missing_value = -999 found.setAxisList(mask.getAxisList()) found.id = 'found' found = found.astype('i') found.missing_value = -999 del(out.name) del(found.name) return out,found
#mask = cdu.generateLandSeaMask(basinmask3) #sftb = cdu.sftbyrgn.generateSurfaceTypeByRegionMask(mask) # Southern Ocean # Case Atlantic lonmat = np.ma.zeros([len(latitude), len(longitude)], dtype='int16') if gridId == '1deg': lonlims = [-70.5, 20.5] elif gridId == '0p25deg': lonlims = [-70.625, 20.375] loninds = [ np.where(longitude == np.float32(lonlims[0])), np.where(longitude == np.float32(lonlims[1])) ] loninds = [loninds[0][0][0], loninds[1][0][0]] lonmat[:, loninds[0]:loninds[1]] = 1 basinmask3 = mv.where(mv.logical_and(basinmask3 == 10, lonmat), 1, basinmask3) # Case Atlantic basinmask4 = mv.where(mv.logical_and(basinmask4 == 10, lonmat), 1, basinmask4) # Case Atlantic # Case Indian lonmat = np.ma.zeros([len(latitude), len(longitude)], dtype='int16') if gridId == '1deg': lonlims = [20.5, 147.5] elif gridId == '0p25deg': lonlims = [20.375, 147.625] loninds = [ np.where(longitude == np.float32(lonlims[0])), np.where(longitude == np.float32(lonlims[1])) ]
def getAreaOfAllClosedDomains(data, condition, **kwarg): """ Input : cdms data with proper lat, lon axis. condition : it must be MV2 or numpy.ma masked condition. eg1 : condition = MV2.masked_equal(data, 0) Using this condition, user can seperate out or distinguish between needed domains and unwanted domains. eg2: >>> condition1 = MV2.masked_less(data, 3) >>> condition2 = MV2.masked_greater(data, 5) >>> condition3 = MV2.logical_and(condition1, condition2) >>> outdict = getAllBoundaryOfClosedAreas(data, condition3) The above example2 makes clear that we are masking less than 3 and greater than 5 values. So accoring to our `condition3`, we are masking out of the range (< 3 && > 5). From this condition3 masked data, this function calls `getAllBoundaryOfClosedAreas()` to get all closed regions boundary latitudes, longitudes, its no of pixels and its weighted area in m^2. Kwarg : update_mask : Takes boolean True | False (by default) If it is True, then the data's mask will be overwrite with updated mask array out side regions other than closed boundaries pixels or (lats, lons). Return : It returns dictionary whose keys are 'region%d' % area_number starting from 1 to N (available irregular closed regions) Each key ['regionN'] contains another dictionary which contains following keys & values 'area' -> lat, lon weighted area value in m^2 of that particular closed domain/region 'unit' -> area unit is m^2 'bpixels' -> list of tuples contain (i, j) or (x, y) or (row, col) of boundary pixels of closed domain 'blatlons' -> list of tuples contain actual (lat, lon) of boundary pixels of closed domain [i.e equivalent (lats, lons) to `bpixels` (rows, cols) ] 'cpixels' -> contains dictionary whose keys are 'row' & 'col'. 'row' has (min boundary row, max boundary row) tuple, 'col' has (min boundary col, max boundary col) tuple of corner pixels of closed irregular domain/region. # Using this user can extract regular rectangle # shaped data by slicing input data. 'clatlons' -> contains dictionary whose keys are 'lat' & 'lon'. 'lat' has (min boundary lat, max boundary lat) tuple, 'lon' has (min boundary lon, max boundary lon) tuple of corner pixels of closed irregular domain/region. [i.e. equivalent to 'cpixels' (row, col)] # Using this user can extract regular rectangle # shaped data by passing argument to input cdms var # data(latitude=lat, longitude=lon). 'region' -> cdms selector variable (At this moment no use !) 'totalPixelsCount' -> total no of pixels in that particular closed domain/region eg: Input : ******* data = ([[ 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 3. 0. 0. 0.] [ 0. 0. 0. 3. 0. 0. 0.] [ 0. 0. 3. 2. 3. 0. 0.] [ 0. 4. 2. 1. 1. 2. 0.] [ 0. 1. 4. 3. 5. 4. 0.] [ 0. 2. 2. 1. 3. 5. 0.] [ 0. 0. 3. 2. 3. 0. 0.] [ 0. 0. 3. 0. 1. 0. 0.] [ 0. 0. 3. 0. 1. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0.]], mask = False, fill_value = 1e+20) >>> condition = MV2.masked_equal(data, 0) >>> outdict = getAllBoundaryOfClosedAreas(data, condition, update_mask=True) Outputs : ********* data = ([[-- -- -- -- -- -- --] [-- -- -- 3.0 -- -- --] [-- -- -- 3.0 -- -- --] [-- -- 3.0 2.0 3.0 -- --] [-- 4.0 2.0 1.0 1.0 2.0 --] [-- 1.0 4.0 3.0 5.0 4.0 --] [-- 2.0 2.0 1.0 3.0 5.0 --] [-- -- 3.0 2.0 3.0 -- --] [-- -- 3.0 -- 1.0 -- --] [-- -- 3.0 -- 1.0 -- --] [-- -- -- -- -- -- --]], mask = [[ True True True True True True True] [ True True True False True True True] [ True True True False True True True] [ True True False False False True True] [ True False False False False False True] [ True False False False False False True] [ True False False False False False True] [ True True False False False True True] [ True True False True False True True] [ True True False True False True True] [ True True True True True True True]], fill_value = 1e+20) # keys contains no of independent closed boundary pixels count >>> outdict.keys() ['region1', 'region2', 'region3', 'region4'] [40, 27, 270, 54] # eg : region2 >>> outdict['region2'].keys() ['area', 'region', 'bpixels', 'blatlons', 'cpixels', 'clatlons', 'totalPixelsCount', 'unit'] # total no of valid pixels within the irregular closed domain >>> outdict['region2']['totalPixelsCount'] 27 # weighted area of particular closed boundary region (here 27 pixels) >>> outdict['region2']['area'] 902159.07029304397 # area unit >>> outdict['region2']['unit'] 'm^2' # boundary lat, lon of particular closed boundary region >>> outdict['region2']['blatlons'] [(-87.5, -174.5), (-86.5, -174.5), (-86.5, -173.5), (-85.5, -173.5), (-85.5, -172.5), (-84.5, -172.5), (-83.5, -172.5), (-83.5, -173.5), (-82.5, -173.5), (-81.5, -173.5), (-80.5, -173.5), (-82.5, -174.5), (-82.5, -175.5), (-81.5, -175.5), (-80.5, -175.5), (-83.5, -175.5), (-83.5, -176.5), (-84.5, -176.5), (-85.5, -176.5), (-85.5, -175.5), (-86.5, -175.5), (-88.5, -174.5)] # boundary row, col of particular closed boundary region >>> outdict['region2']['bpixels'] [(2, 5), (3, 5), (3, 6), (4, 6), (4, 7), (5, 7), (6, 7), (6, 6), (7, 6), (8, 6), (9, 6), (7, 5), (7, 4), (8, 4), (9, 4), (6, 4), (6, 3), (5, 3), (4, 3), (4, 4), (3, 4), (1, 5)] # corner lat, lon of above closed irregular region >>> dic['region2']['clatlons'] {'lat': (-88.5, -80.5), 'lon': (-176.5, -172.5)} # corner row, col of above closed irregular region >>> dic['region2']['cpixels'] {'col': (3, 7), 'row': (1, 9)} # eg : region4 # total no of valid pixels within the irregular closed domain >>> outdict['region4']['totalPixelsCount'] 54 # area of 54 pixels >>> outdict['region4']['area'] 843696.5895938098 >>> outdict['region4']['blatlons'] [(-89.5, -58.5), (-89.5, -57.5), (-89.5, -56.5), (-89.5, -55.5), (-89.5, -54.5), (-89.5, -53.5), (-89.5, -52.5), (-89.5, -51.5), (-88.5, -51.5), (-87.5, -51.5), (-86.5, -51.5), (-85.5, -51.5), (-84.5, -51.5), (-84.5, -52.5), (-84.5, -53.5), (-84.5, -54.5), (-84.5, -55.5), (-84.5, -56.5), (-84.5, -57.5), (-84.5, -58.5), (-84.5, -59.5), (-85.5, -59.5), (-86.5, -59.5), (-87.5, -59.5), (-88.5, -59.5), (-89.5, -59.5)] # By comparing above Area of 'region2' (27 pixels) is greater than # Area of 'region4' (54 pixels) since its weighted area. # i.e. it is totally depends on the lat, lon positions Note : outdict 'blatlons' contains only outer boundary lat,lons only. But area will be calculated w.r.t no of pixels inside the closed boundary region and over on the boundary of region. Author : Arulalan.T <*****@*****.**> Date : 08.07.2014 """ update_mask = kwarg.get('update_mask', False) # update condition arg to kwarg dictionary kwarg['condition'] = condition dshape = data.shape # it must start with 1, since we masked out side areas/ regions with 0s. dummy = numpy.arange(1, data.size + 1, 1) dummy = dummy.reshape(dshape) # apply user passed condition and fill with our dummy data whereever mask # is false (i.e. actual data) and fill with 0s whereever mask is true # (i.e. no data in those pixels) dummy = MV2.where(condition, dummy, 0) # set missing_value as 0. so that filled() return 0s in masked pixels. dummy.missing_value = 0 # Now dummy contains zeros other than needed areas and # inside & boundar of needed areas filled with some nos. # Here set missing_value as big no & set original data mask to dummy. dummy = cdms2.createVariable(dummy.filled(), id=('dummy'), missing_value=data.fill_value, mask=data.mask) dummy.setAxisList(data.getAxisList()) area_irregular_domains = getAllBoundaryOfClosedAreas(dummy, **kwarg) if update_mask: # update input data mask with dummy mask (masked other than needed # irregular regions) along with user passed condition # apply logical_and condition with (not of dummy.mask) finalmask = MV2.logical_and(condition, MV2.logical_not(dummy.mask)) # apply original data whereever both condition and dummy's mask # becomes true, apply nan whereever false comes. data.mask = MV2.where(finalmask, data, numpy.nan).mask # end of if update_mask: # return the dictionary of area_irregular_domains return area_irregular_domains
## 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)
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
def linearInterpolation(A, Idx, levels=[ 100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000 ], status=None, axis='z'): """ Linear interpolation to interpolate a field from some levels to another set of levels Values below "surface" are masked. :param A: array to interpolate :type A: :param I: interpolation field (usually Pressure or depth) from TOP (level 0) to BOTTOM (last level) i.e P value going up with each level. :type I: :param levels: levels to interpolate to (same units as I). Default levels:[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000] :type levels: :param axis: Axis over which to do the linear interpolation. Can provide either an int representing axis index, or the axis name. Default: 'z'. :type axis: str or int .. note:: I and levels must have same units :returns: array on new levels (levels) :Examples: .. doctest:: vertical_linearInterpolation >>> A=interpolate(A,I) # interpolates A over default levels """ try: nlev = len(levels) # Number of pressure levels except BaseException: nlev = 1 # if only one level len(levels) would breaks levels = [ levels, ] order = A.getOrder() A = A(order='%s...' % axis) Idx = Idx(order='%s...' % axis) sh = list(Idx.shape) nsigma = sh[0] # number of sigma levels sh[0] = nlev t = MV2.zeros(sh, typecode=MV2.float32) sh2 = Idx[0].shape prev = -1 for ilev in range(nlev): # loop through pressure levels if status is not None: prev = genutil.statusbar(ilev, nlev - 1., prev) lev = levels[ilev] # get value for the level Iabv = MV2.ones(sh2, MV2.float) Aabv = -1 * Iabv # Array on sigma level Above Abel = -1 * Iabv # Array on sigma level Below Ibel = -1 * Iabv # Pressure on sigma level Below Iabv = -1 * Iabv # Pressure on sigma level Above Ieq = MV2.masked_equal(Iabv, -1) # Area where Pressure == levels for i in range(1, nsigma): # loop from second sigma level to last one a = MV2.greater_equal( Idx[i], lev) # Where is the pressure greater than lev b = MV2.less_equal(Idx[i - 1], lev) # Where is the pressure less than lev # Now looks if the pressure level is in between the 2 sigma levels # If yes, sets Iabv, Ibel and Aabv, Abel a = MV2.logical_and(a, b) Iabv = MV2.where(a, Idx[i], Iabv) # Pressure on sigma level Above Aabv = MV2.where(a, A[i], Aabv) # Array on sigma level Above Ibel = MV2.where(a, Idx[i - 1], Ibel) # Pressure on sigma level Below Abel = MV2.where(a, A[i - 1], Abel) # Array on sigma level Below Ieq = MV2.where(MV2.equal(Idx[i], lev), A[i], Ieq) val = MV2.masked_where(MV2.equal(Ibel, -1.), numpy.ones(Ibel.shape) * lev) # set to missing value if no data below lev if # there is tl = (val - Ibel) / (Iabv - Ibel) * \ (Aabv - Abel) + Abel # Interpolation if ((Ieq.mask is None) or (Ieq.mask is MV2.nomask)): tl = Ieq else: tl = MV2.where(1 - Ieq.mask, Ieq, tl) t[ilev] = tl.astype(MV2.float32) ax = A.getAxisList() autobnds = cdms2.getAutoBounds() cdms2.setAutoBounds('off') lvl = cdms2.createAxis(MV2.array(levels).filled()) cdms2.setAutoBounds(autobnds) try: lvl.units = Idx.units except BaseException: pass lvl.id = 'plev' try: t.units = Idx.units except BaseException: pass ax[0] = lvl t.setAxisList(ax) t.id = A.id for att in A.listattributes(): setattr(t, att, getattr(A, att)) return t(order=order)
def logLinearInterpolation(A,P,levels=[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000],status=None): """ Log-linear interpolation to convert a field from sigma levels to pressure levels Value below surface are masked Input A : array on sigma levels P : pressure field from TOP (level 0) to BOTTOM (last level) levels : pressure levels to interplate to (same units as P), default levels are:[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000] P and levels must have same units Output array on pressure levels (levels) Examples: A=logLinearInterpolation(A,P),levels=[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000]) """ try: nlev=len(levels) # Number of pressure levels except: nlev=1 # if only one level len(levels) would breaks levels=[levels,] order=A.getOrder() A=A(order='z...') P=P(order='z...') sh=list(P.shape) nsigma=sh[0] #number of sigma levels sh[0]=nlev t=MV2.zeros(sh,typecode=MV2.float32) sh2=P[0].shape prev=-1 for ilev in range(nlev): # loop through pressure levels if status is not None: prev=genutil.statusbar(ilev,nlev-1.,prev) lev=levels[ilev] # get value for the level Pabv=MV2.ones(sh2,MV2.float) Aabv=-1*Pabv # Array on sigma level Above Abel=-1*Pabv # Array on sigma level Below Pbel=-1*Pabv # Pressure on sigma level Below Pabv=-1*Pabv # Pressure on sigma level Above Peq=MV2.masked_equal(Pabv,-1) # Area where Pressure == levels for i in range(1,nsigma): # loop from second sigma level to last one a=MV2.greater_equal(P[i], lev) # Where is the pressure greater than lev b= MV2.less_equal(P[i-1],lev) # Where is the pressure less than lev # Now looks if the pressure level is in between the 2 sigma levels # If yes, sets Pabv, Pbel and Aabv, Abel a=MV2.logical_and(a,b) Pabv=MV2.where(a,P[i],Pabv) # Pressure on sigma level Above Aabv=MV2.where(a,A[i],Aabv) # Array on sigma level Above Pbel=MV2.where(a,P[i-1],Pbel) # Pressure on sigma level Below Abel=MV2.where(a,A[i-1],Abel) # Array on sigma level Below Peq= MV2.where(MV2.equal(P[i],lev),A[i],Peq) val=MV2.masked_where(MV2.equal(Pbel,-1),numpy.ones(Pbel.shape)*lev) # set to missing value if no data below lev if there is tl=MV2.log(val/Pbel)/MV2.log(Pabv/Pbel)*(Aabv-Abel)+Abel # Interpolation if ((Peq.mask is None) or (Peq.mask is MV2.nomask)): tl=Peq else: tl=MV2.where(1-Peq.mask,Peq,tl) t[ilev]=tl.astype(MV2.float32) ax=A.getAxisList() autobnds=cdms2.getAutoBounds() cdms2.setAutoBounds('off') lvl=cdms2.createAxis(MV2.array(levels).filled()) cdms2.setAutoBounds(autobnds) try: lvl.units=P.units except: pass lvl.id='plev' try: t.units=P.units except: pass ax[0]=lvl t.setAxisList(ax) t.id=A.id for att in A.listattributes(): setattr(t,att,getattr(A,att)) return t(order=order)
def linearInterpolation(A,I,levels=[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000], status=None): """ Linear interpolation to interpolate a field from some levels to another set of levels Value below "surface" are masked Input A : array to interpolate I : interpolation field (usually Pressure or depth) from TOP (level 0) to BOTTOM (last level), i.e P value going up with each level levels : levels to interplate to (same units as I), default levels are:[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000] I and levels must have same units Output array on new levels (levels) Examples: A=interpolate(A,I,levels=[100000, 92500, 85000, 70000, 60000, 50000, 40000, 30000, 25000, 20000, 15000, 10000, 7000, 5000, 3000, 2000, 1000]) """ try: nlev=len(levels) # Number of pressure levels except: nlev=1 # if only one level len(levels) would breaks levels=[levels,] order=A.getOrder() A=A(order='z...') I=I(order='z...') sh=list(I.shape) nsigma=sh[0] #number of sigma levels sh[0]=nlev t=MV2.zeros(sh,typecode=MV2.float32) sh2=I[0].shape prev=-1 for ilev in range(nlev): # loop through pressure levels if status is not None: prev=genutil.statusbar(ilev,nlev-1.,prev) lev=levels[ilev] # get value for the level Iabv=MV2.ones(sh2,MV2.float) Aabv=-1*Iabv # Array on sigma level Above Abel=-1*Iabv # Array on sigma level Below Ibel=-1*Iabv # Pressure on sigma level Below Iabv=-1*Iabv # Pressure on sigma level Above Ieq=MV2.masked_equal(Iabv,-1) # Area where Pressure == levels for i in range(1,nsigma): # loop from second sigma level to last one a = MV2.greater_equal(I[i], lev) # Where is the pressure greater than lev b = MV2.less_equal(I[i-1],lev) # Where is the pressure less than lev # Now looks if the pressure level is in between the 2 sigma levels # If yes, sets Iabv, Ibel and Aabv, Abel a=MV2.logical_and(a,b) Iabv=MV2.where(a,I[i],Iabv) # Pressure on sigma level Above Aabv=MV2.where(a,A[i],Aabv) # Array on sigma level Above Ibel=MV2.where(a,I[i-1],Ibel) # Pressure on sigma level Below Abel=MV2.where(a,A[i-1],Abel) # Array on sigma level Below Ieq= MV2.where(MV2.equal(I[i],lev),A[i],Ieq) val=MV2.masked_where(MV2.equal(Ibel,-1.),numpy.ones(Ibel.shape)*lev) # set to missing value if no data below lev if there is tl=(val-Ibel)/(Iabv-Ibel)*(Aabv-Abel)+Abel # Interpolation if ((Ieq.mask is None) or (Ieq.mask is MV22.nomask)): tl=Ieq else: tl=MV2.where(1-Ieq.mask,Ieq,tl) t[ilev]=tl.astype(MV2.float32) ax=A.getAxisList() autobnds=cdms2.getAutoBounds() cdms2.setAutoBounds('off') lvl=cdms2.createAxis(MV2.array(levels).filled()) cdms2.setAutoBounds(autobnds) try: lvl.units=I.units except: pass lvl.id='plev' try: t.units=I.units except: pass ax[0]=lvl t.setAxisList(ax) t.id=A.id for att in A.listattributes(): setattr(t,att,getattr(A,att)) return t(order=order)
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
f = cdms2.open('data/snc.nc') data = f('snc', time=slice(1), squeeze=1) print "Contions \n 1. Mask less than 100 \n 2. Mask less than 30 and greater than 70" con = input('Enter Condion Option 1 or 2 : ') if con == 1: mask_condition = MV2.masked_less(data, 100.) value = 'value equal to 100' dirname = 'outplots_eq_100' elif con == 2: c1 = MV2.masked_greater(data, 70.) c2 = MV2.masked_less(data, 30.) mask_condition = MV2.logical_and(c1, c2) value = 'value equal to within 30 to 70' dirname = 'outplots_eq_30_to_70' # end of if con == 1: if not os.path.isdir(dirname): os.mkdir(dirname) print "Output plots will be saved in '%s' directory" % dirname v = vcs.init() # Assign the variable "cf_asd" to the persistent 'ASD' isofill graphics methods. cf_asd = v.createboxfill() cf_asd.level_1 = data.min() # change to default minimum level cf_asd.level_2 = data.max() # change to default maximum level # set missing color as white
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
## 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 generateSurfaceTypeByRegionMask(mask,sftbyrgn=None,sftbyrgnmask=215,regions = range(201,223), maximum_regions_per_cell=4,extend_up_to=3,verbose=True): """ Maps a "types" dataset onto a landsea mask Usage: mapped,found = generateSurfaceTypeByRegionMask(mask,sftbyrgn,sftbyrgnmask=None,regions=None,maximum_regions_per_cell=4,extend_up_to=3,verbode=True) Input: mask : land/sea mask (100/0) onto you wish to map our grid (will generate a ld/sea mask for you) sftbyrgn: mask you wish to map if None then uses our own "sftbyrgn" dataset (old ezget type) sftbyrgnmask: land/sea mask for sftbyrgn or a number specifying limit in values of sftbygrn which indicate the threshold land/sea (greater values are land) regions: Numbers from sftbyrgn array that you want to map onto mask maximum_regions_per_cell: maximum number f regions concidered in a cell extend_up_to : how many grid cells away around a cell can we extent to identify a guess verbose: prints to the screen what's going on (default is True) Output: mapped : mapped input mask found : ??? """ ## OK first determine which regions are available ## Must be integer values if isinstance(mask, cdms2.grid.TransientRectGrid): mask = cdutil.generateLandSeaMask(mask)*100. if sftbyrgn is None: sftbyrgn = cdms2.open(os.path.join(sys.prefix,'sample_data','sftbyrgn.nc'))('sftbyrgn') if regions is None: if verbose: print 'Preparing regions' ## regions = range(201,223) regions=[] for i in range(0,10000): genutil.statusbar(i,9999) c=float(MV2.sum(MV2.ravel(MV2.equal(sftbyrgn,i)),0)) if c!=0: regions.append(i) if verbose: print 'Regions:',regions ## If no mask passed fr sftbyrgn, assumes everything greater 5000 is land) if isinstance(sftbyrgnmask,int): split = sftbyrgnmask n=MV2.maximum(mask) sftbyrgnmask=MV2.greater_equal(sftbyrgn,sftbyrgnmask)*n else: split = MV2.maximum(sftbyrgnmask)/2. ## Now guess the type for each regions keys={} ## ## Nice way to do it ## for r in regions: ## c=MV2.not_equal(sftbyrgn,r) ## c=MV2.masked_where(c,sftbyrgnmask) ## n=MV2.count(c) ## c=float(MV2.sum(MV2.ravel(c),0)/n) ## print r,c,n ## keys[r]=c ## Fast but not so "general" way to do it for r in regions: if r< split: keys[r]=0. else: keys[r]=100. sh=list(mask.shape) sh.insert(0,maximum_regions_per_cell) potential=MV2.ones(sh,dtype='d')*-999 potential_reg=MV2.ones(sh,dtype='d')*-999 g1=sftbyrgn.getGrid() g2=mask.getGrid() r1=regrid2.Regridder(g1,g2) w=cdutil.area_weights(sftbyrgn) if verbose: print 'First pass' itmp=0. for ireg in keys.keys(): genutil.statusbar(itmp,len(keys.keys())-1) itmp+=1. c=MV2.equal(sftbyrgn,ireg) w2=1.-c*w s2,w3=r1(sftbyrgn,mask=w2.filled(),returnTuple=1) c2=MV2.equal(mask,keys[ireg]) loop(potential,potential_reg,c2,w3,ireg) found=MV2.zeros(sh[1:],typecode='f') for i in range(maximum_regions_per_cell): found=found+MV2.not_equal(potential[i],-999) sh2=list(sh) for k in range(extend_up_to): sh2[1]=sh[1]+2*(k+1) sh2[2]=sh[2]+2*(k+1) ## Form the possible i/j couples ! s=MV2.sum(MV2.ravel(MV2.equal(potential[0],-999)),0) if verbose: print 'Expanding up to',k+1,'cells while trying to fix',s,'cells' ## if dump: ## f=cdms2.open('tmp_'+str(k)+'.nc','w') ## f.write(sumregions(potential_reg,potential).astype('f'),id='sftbyrgn',axes=mask.getAxisList()) ## f.close() ## g=sumregions(potential_reg,potential).astype('d') ## g=MV2.masked_equal(g,-999) ## g=MV2.greater(g,4999)*100. ## g=MV2.absolute(mask-g) ## g=MV2.masked_equal(g,0.) ## print 'Number of differences:',MV2.count(g) if float(s)!=0: c0=MV2.equal(potential[0],-999) couples=[] sft2=MV2.zeros(sh2[1:],dtype='d')-888. sft2[k+1:-k-1,k+1:-k-1]=mask for i in range(-k-1,k+2): for j in range(-k-1,k+2): if abs(i)>k or abs(j)>k: couples.append([i,j]) ntot=len(keys.keys())*len(couples)-1 itmp=0 for ireg in keys.keys(): c=MV2.equal(sftbyrgn,ireg) w2=1.-c*w s2,w3=r1(sftbyrgn,mask=w2.filled(),returnTuple=1) w4=MV2.zeros(sh2[1:],typecode='d') w4[k+1:-k-1,k+1:-k-1]=w3 for i,j in couples: if verbose: genutil.statusbar(itmp,ntot) itmp+=1. c2=MV2.equal(sft2[j+k+1:j+k+1+sh[1],i+k+1:i+k+1+sh[2]],keys[ireg]) c3=MV2.equal(sft2[j+k+1:j+k+1+sh[1],i+k+1:i+k+1+sh[2]],mask) c2=MV2.logical_and(c2,c3) c2=MV2.logical_and(c2,c0) loop(potential,potential_reg,c2,w4[j+k+1:j+k+1+sh[1],i+k+1:i+k+1+sh[2]],ireg) found=MV2.where(MV2.equal(potential[0],-999),found-1,found) out=sumregions(potential_reg,potential) out.setAxisList(mask.getAxisList()) found.setAxisList(mask.getAxisList()) found=found.astype('i') found.missing_value=-999 found.id='found' out.id='sftbyrgn' out=out.astype('i') out.missing_value=-999 del(out.name) del(found.name) return out,found