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 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 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 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 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)