Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
def create_amount_freq_PDF(mv,
                           binedges,
                           binwidthtype=None,
                           bincentertype=None,
                           vid=None,
                           vid2=None,
                           vid3=None):
    """Takes in geospatial data (mv) with dimensions of lat, lon, and time, and 
    creates a PDF of the mv based on binedges at each lat/lon grid point. 
    binedges defines the edges of the bin, except for the bin with maximum value,
    where it is open. 
    
    binwidth option allows user to define whether the PDF is scaled by the 
    'arithmetic' bin width or the 'logarithmic' bin width. (dN/dx vs. dN/dlogx)
    default: 'logarithmic'
    
    The bincenter option allows one to use the 'geometric' 
    or the 'arithmetic' mean to define the edge. The bin with maximum value will have
    a bin center equidistant from the max bin edge as from the center of the previous bin. 
    
    PDFs will not be normalized over the histogram, but over all available data.
    For example, if there is data below the minimum bin edge, then the PDF will be 
    normalized, having included the data that lies below the minimum bin edge.
    
    vid = variable ID, which will typically be the variable name of the when output as a netcdf
    """

    #Step 1 input data and figure out the time dimensions in the data
    if vid is None:
        vid = mv.id
        vid2 = ''.join([mv.id, '2'])

    #Do get domain and find which axis corresponds to time, lat and lon
    time_index = mv.getAxisIndex('time')
    lat_index = mv.getAxisIndex('lat')
    lon_index = mv.getAxisIndex('lon')
    #obtain long_name, standard_name, typecode of the variable to eventually feed into output variables
    var_long_name = mv.long_name
    var_standard_name = mv.standard_name
    mv_typecode = mv.typecode()
    mv_lat = mv.getAxis(lat_index)
    mv_lon = mv.getAxis(lon_index)
    mv_att = mv.attributes
    mv_grid = mv.getGrid()

    #Step 2 loop over the bin widths and add up the number of data points in each bin

    #Create an array with the shape of (lat,lon,binedges,and corresponding bincenter)
    mapped_precip_freqpdf = numpy.zeros(
        (mv.shape[lat_index], mv.shape[lon_index], len(binedges)))
    mapped_precip_amntpdf = numpy.zeros(
        (mv.shape[lat_index], mv.shape[lon_index], len(binedges)))
    bincenter = numpy.zeros(len(binedges))

    #Count up total first
    counts_index = MV2.greater_equal(mv, 0.)
    logger.debug(counts_index.shape)
    data_counts = numpy.zeros((mv.shape))
    data_counts[counts_index] = 1.
    counts_total = numpy.sum(data_counts, axis=time_index)

    #specify what the binmean, bincenter, and binwidths are based on log and arith scaling
    binwidth = numpy.zeros(len(binedges))
    bincenter = numpy.zeros(len(binedges))
    binmean = numpy.zeros(len(binedges))

    #Calculate bin mean for amount PDF
    binmean[:-1] = (binedges[1:] + binedges[:-1]) / 2
    binmean[-1] = binedges[-1] + (binedges[-1] - binedges[-2]) / 2
    #Calculate bin width based on type
    if binwidthtype is 'arithmetic':
        binwidth[:-1] = binedges[1:] - binedges[:-1]
        binwidth[-1] = binedges[-1] - binedges[-2]
    elif binwidthtype is 'logarithmic' or binwidthtype is None:
        binwidth[:-1] = numpy.log10(binedges[1:] / binedges[:-1])
        binwidth[-1] = numpy.log10(binedges[-1] / binedges[-2])
    #Calculate bin center based on type
    if bincentertype is 'arithmetic' or bincentertype is None:
        bincenter = binmean
    elif bincentertype is 'geometric':
        bincenter[:-1] = numpy.sqrt(binedges[1:] * binedges[:-1])
        bincenter[-1] = binedges[-1] + (binedges[-1] - binedges[-2]) / 2

    #Count up the number of days of precip in each precip bin **Most work done here
    for i in range(len(binedges)):
        precip_index = numpy.ones(
            mv.shape
        )  #locate the index where precip rate is between the bin edges
        toolow_index = mv < binedges[i]
        precip_index[toolow_index] = 0
        if i != (len(binedges) - 1):
            toohigh_index = mv >= binedges[i + 1]
            precip_index[toohigh_index] = 0
        precip_total = numpy.sum(precip_index, axis=time_index)
        precip_fraction = numpy.divide(precip_total, counts_total)

        precip_freqpdf = precip_fraction / binwidth[i]
        precip_amntpdf = precip_fraction / binwidth[i] * binmean[i]
        mapped_precip_freqpdf[:, :, i] = precip_freqpdf
        mapped_precip_amntpdf[:, :, i] = precip_amntpdf
        precip_freqpdf = None
        precip_amntpdf = None

    #Step 3 attach all necessary attributes to data (create data as a transient variable)
    #First, specify a new axis for the PDF
    binbound_all = numpy.append(binedges, numpy.max(mv))
    binbounds = numpy.zeros((len(binedges), 2))
    binbounds[:, 0] = binbound_all[:-1]
    binbounds[:, 1] = binbound_all[1:]
    mv_hist = cdms2.createAxis(
        bincenter, bounds=binbounds,
        id='binvalue')  #mv_hist is the axes for precip rate
    ouput_mapped_precip_freqpdf = cdms2.createVariable(
        mapped_precip_freqpdf,
        typecode=mv_typecode,
        grid=mv_grid,
        axes=[mv_lat, mv_lon, mv_hist],
        attributes=mv_att,
        id=vid)

    ouput_mapped_precip_amntpdf = cdms2.createVariable(
        mapped_precip_amntpdf,
        typecode=mv_typecode,
        grid=mv_grid,
        axes=[mv_lat, mv_lon, mv_hist],
        attributes=mv_att,
        id=vid2)
    bincenter = cdms2.createVariable(bincenter,
                                     typecode=mv_typecode,
                                     axes=[mv_hist],
                                     attributes=mv_att,
                                     id=vid3)

    ouput_mapped_precip_freqpdf.units = 'frequency'
    ouput_mapped_precip_amntpdf.units = 'amount'
    ouput_mapped_precip_freqpdf.long_name = ''.join(
        ['Frequency as a function of ', var_long_name])
    ouput_mapped_precip_amntpdf.long_name = ''.join(
        ['Amount as a function of ', var_long_name])
    ouput_mapped_precip_freqpdf.standard_name = ''.join(
        [var_standard_name, '_frequency'])
    ouput_mapped_precip_amntpdf.standard_name = ''.join(
        [var_standard_name, '_amount'])
    #Step 4 output data
    return bincenter, ouput_mapped_precip_freqpdf, ouput_mapped_precip_amntpdf
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
def create_amount_freq_PDF(mv, binedges, binwidthtype=None, bincentertype=None, vid=None, vid2=None, vid3=None):
    """Takes in geospatial data (mv) with dimensions of lat, lon, and time, and 
    creates a PDF of the mv based on binedges at each lat/lon grid point. 
    binedges defines the edges of the bin, except for the bin with maximum value,
    where it is open. 
    
    binwidth option allows user to define whether the PDF is scaled by the 
    'arithmetic' bin width or the 'logarithmic' bin width. (dN/dx vs. dN/dlogx)
    default: 'logarithmic'
    
    The bincenter option allows one to use the 'geometric' 
    or the 'arithmetic' mean to define the edge. The bin with maximum value will have
    a bin center equidistant from the max bin edge as from the center of the previous bin. 
    
    PDFs will not be normalized over the histogram, but over all available data.
    For example, if there is data below the minimum bin edge, then the PDF will be 
    normalized, having included the data that lies below the minimum bin edge.
    
    vid = variable ID, which will typically be the variable name of the when output as a netcdf
    """
    
    
    #Step 1 input data and figure out the time dimensions in the data
    if vid is None:
        vid = mv.id
        vid2 = ''.join([mv.id,'2'])
    
    
        
    #Do get domain and find which axis corresponds to time, lat and lon
    time_index=mv.getAxisIndex('time')
    lat_index=mv.getAxisIndex('lat')
    lon_index=mv.getAxisIndex('lon')
    #obtain long_name, standard_name, typecode of the variable to eventually feed into output variables
    var_long_name=mv.long_name
    var_standard_name=mv.standard_name
    mv_typecode=mv.typecode()
    mv_lat=mv.getAxis(lat_index)
    mv_lon=mv.getAxis(lon_index)
    mv_att=mv.attributes
    mv_grid=mv.getGrid()
    
    
    #Step 2 loop over the bin widths and add up the number of data points in each bin
    
    #Create an array with the shape of (lat,lon,binedges,and corresponding bincenter)
    mapped_precip_freqpdf=numpy.zeros((mv.shape[lat_index],mv.shape[lon_index],len(binedges)))
    mapped_precip_amntpdf=numpy.zeros((mv.shape[lat_index],mv.shape[lon_index],len(binedges)))
    bincenter=numpy.zeros(len(binedges))
    
    #Count up total first
    counts_index=MV2.greater_equal(mv,0.)
    print counts_index.shape
    data_counts=numpy.zeros((mv.shape))
    data_counts[counts_index]=1.
    counts_total=numpy.sum(data_counts,axis=time_index)
    
    #specify what the binmean, bincenter, and binwidths are based on log and arith scaling
    binwidth=numpy.zeros(len(binedges))
    bincenter=numpy.zeros(len(binedges))
    binmean=numpy.zeros(len(binedges))
    
    #Calculate bin mean for amount PDF
    binmean[:-1]=(binedges[1:]+binedges[:-1])/2
    binmean[-1]=binedges[-1] + (binedges[-1]-binedges[-2])/2
    #Calculate bin width based on type
    if binwidthtype is 'arithmetic':
        binwidth[:-1]=binedges[1:]-binedges[:-1]
        binwidth[-1]=binedges[-1]-binedges[-2]
    elif binwidthtype is 'logarithmic' or binwidthtype is None:
        binwidth[:-1]=numpy.log10(binedges[1:]/binedges[:-1])
        binwidth[-1]=numpy.log10(binedges[-1]/binedges[-2])
    #Calculate bin center based on type
    if bincentertype is 'arithmetic' or bincentertype is None:
        bincenter=binmean
    elif bincentertype is 'geometric':
        bincenter[:-1]=numpy.sqrt(binedges[1:]*binedges[:-1])
        bincenter[-1]=binedges[-1] + (binedges[-1]-binedges[-2])/2
    
    #Count up the number of days of precip in each precip bin **Most work done here
    for i in range(len(binedges)):
        precip_index=numpy.ones(mv.shape)  #locate the index where precip rate is between the bin edges
        toolow_index=mv<binedges[i]        
        precip_index[toolow_index]=0
        if i!=(len(binedges)-1):
            toohigh_index=mv>=binedges[i+1]
            precip_index[toohigh_index]=0
        precip_total=numpy.sum(precip_index,axis=time_index)
        precip_fraction=numpy.divide(precip_total,counts_total)
        
        precip_freqpdf=precip_fraction/binwidth[i]
        precip_amntpdf=precip_fraction/binwidth[i]*binmean[i]
        mapped_precip_freqpdf[:,:,i]=precip_freqpdf
        mapped_precip_amntpdf[:,:,i]=precip_amntpdf
        precip_freqpdf=None
        precip_amntpdf=None
        
    
    
    #Step 3 attach all necessary attributes to data (create data as a transient variable)
    #First, specify a new axis for the PDF
    binbound_all=numpy.append(binedges,numpy.max(mv))
    binbounds=numpy.zeros((len(binedges),2))
    binbounds[:,0]=binbound_all[:-1]
    binbounds[:,1]=binbound_all[1:]
    mv_hist=cdms2.createAxis(bincenter,bounds=binbounds,id='binvalue') #mv_hist is the axes for precip rate
    ouput_mapped_precip_freqpdf=cdms2.createVariable(mapped_precip_freqpdf,typecode=mv_typecode,
                                             grid=mv_grid,axes=[mv_lat,mv_lon,mv_hist],attributes=mv_att,id=vid)
    
    ouput_mapped_precip_amntpdf=cdms2.createVariable(mapped_precip_amntpdf,typecode=mv_typecode,
                                             grid=mv_grid,axes=[mv_lat,mv_lon,mv_hist],attributes=mv_att,id=vid2)
    bincenter=cdms2.createVariable(bincenter,typecode=mv_typecode, axes=[mv_hist],attributes=mv_att,id=vid3)
                                       
    ouput_mapped_precip_freqpdf.units='frequency'
    ouput_mapped_precip_amntpdf.units='amount'
    ouput_mapped_precip_freqpdf.long_name=''.join(['Frequency as a function of ',var_long_name])
    ouput_mapped_precip_amntpdf.long_name=''.join(['Amount as a function of ',var_long_name])
    ouput_mapped_precip_freqpdf.standard_name=''.join([var_standard_name,'_frequency'])
    ouput_mapped_precip_amntpdf.standard_name=''.join([var_standard_name,'_amount'])
    #Step 4 output data
    return bincenter, ouput_mapped_precip_freqpdf, ouput_mapped_precip_amntpdf
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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