Esempio n. 1
0
 def testChoose(self):
     ct1 = MV2.TransientVariable([1, 1, 2, 0, 1])
     ctr = MV2.choose(ct1, [numpy.ma.masked, 10, 20, 30, 40])
     self.assertTrue(MV2.allclose(ctr, [10, 10, 20, 100, 10]))
     ctx = MV2.TransientVariable([1, 2, 3, 150, 4])
     cty = -MV2.TransientVariable([1, 2, 3, 150, 4])
     ctr = MV2.choose(MV2.greater(ctx, 100), (ctx, 100))
     self.assertTrue(MV2.allclose(ctr, [1, 2, 3, 100, 4]))
     ctr = MV2.choose(MV2.greater(ctx, 100), (ctx, cty))
     self.assertTrue(MV2.allclose(ctr, [1, 2, 3, -150, 4]))
Esempio n. 2
0
def surface_maskvariable(var, surf_mask, surf_type=None):
    """ Quick script that takes as inputs, a masked variable 
    and a surface mask to create a masked variable, where the 
    area not of interest is masked out. 
    
    Assumes that the surface mask has values with range 0 to 1.
    
    REMEMBER that the surf_mask denotes area that you want to 
    have masked out, NOT the area that you want plotted.
    
    Also note: make sure that the mask and the variable have 
    the same shape
    """
    #If no surface mask is given, create mask
    if surf_mask is None:
        surf_mask = cdutil.generateLandSeaMask(data)
        if surf_type is 'land':
            surf_mask=surf_mask/100.
        if surf_type is 'ocean':
            surf_mask=(100.-surf_mask)/100.
    
    
    #Mask the variable according to the surf_mask - assumes that surf_mask is taken from 'LANDFRAC'
    # check to see if the surface mask and variable have the same shape, otherwise regrid surf_mask
    if surf_mask.shape!=var.shape:
        var_grid=var.getGrid()
        surf_mask=surf_mask.regrid(var_grid)
    condition=MV2.greater(surf_mask,0.5)
    var_masked=MV2.masked_where(condition,var)
    return var_masked
Esempio n. 3
0
def surface_maskvariable(var, surf_mask, surf_type=None):
    """ Quick script that takes as inputs, a masked variable 
    and a surface mask to create a masked variable, where the 
    area not of interest is masked out. 
    
    Assumes that the surface mask has values with range 0 to 1.
    
    REMEMBER that the surf_mask denotes area that you want to 
    have masked out, NOT the area that you want plotted.
    
    Also note: make sure that the mask and the variable have 
    the same shape
    """
    #If no surface mask is given, create mask
    if surf_mask is None:
        surf_mask = cdutil.generateLandSeaMask(data)
        if surf_type is 'land':
            surf_mask = surf_mask / 100.
        if surf_type is 'ocean':
            surf_mask = (100. - surf_mask) / 100.

    #Mask the variable according to the surf_mask - assumes that surf_mask is taken from 'LANDFRAC'
    # check to see if the surface mask and variable have the same shape, otherwise regrid surf_mask
    if surf_mask.shape != var.shape:
        var_grid = var.getGrid()
        surf_mask = surf_mask.regrid(var_grid)
    condition = MV2.greater(surf_mask, 0.5)
    var_masked = MV2.masked_where(condition, var)
    return var_masked
Esempio n. 4
0
 def myMakeMask(array, range):
     """Returns the input array masked where the values are not between range[0] and range[1]"""
     m1 = MV2.less(array,
                   range[0])  # mask where it is less than the 1st value
     m2 = MV2.greater(
         array, range[1])  # mask where it is more than the 2nd value
     return MV2.logical_or(m1, m2)
Esempio n. 5
0
 def testMaskingFunctions(self):
     xouter = MV2.outerproduct(MV2.arange(5.), [1] * 10)
     masked = MV2.masked_greater(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[2:], True))
     self.assertTrue(MV2.allequal(masked.mask[:2], False))
     masked = MV2.masked_greater_equal(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[1:], True))
     self.assertTrue(MV2.allequal(masked.mask[:1], False))
     masked = MV2.masked_less(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[:1], True))
     self.assertTrue(MV2.allequal(masked.mask[1:], False))
     masked = MV2.masked_less_equal(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[:2], True))
     self.assertTrue(MV2.allequal(masked.mask[2:], False))
     masked = MV2.masked_not_equal(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[1], False))
     self.assertTrue(MV2.allequal(masked.mask[0], True))
     self.assertTrue(MV2.allequal(masked.mask[2:], True))
     masked = MV2.masked_equal(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[1], True))
     self.assertTrue(MV2.allequal(masked.mask[0], False))
     self.assertTrue(MV2.allequal(masked.mask[2:], False))
     masked = MV2.masked_outside(xouter, 1, 3)
     self.assertTrue(MV2.allequal(masked.mask[0:1], True))
     self.assertTrue(MV2.allequal(masked.mask[1:4], False))
     self.assertTrue(MV2.allequal(masked.mask[4:], True))
     masked = MV2.masked_where(
         MV2.logical_or(MV2.greater(xouter, 3), MV2.less(xouter, 2)),
         xouter)
     self.assertTrue(MV2.allequal(masked.mask[0:2], True))
     self.assertTrue(MV2.allequal(masked.mask[2:4], False))
     self.assertTrue(MV2.allequal(masked.mask[4:], True))
Esempio n. 6
0
def sumregions(potential_reg,potential):
    out = potential_reg[0]*1.
    wts = potential[0]*1.
    for i in range(1,potential.shape[0]):
        c   = MV2.greater(potential[i]-wts,0)
        out = MV2.where(c,potential_reg[i],out)
        wts = MV2.where(c,potential[i],wts)
    return out
Esempio n. 7
0
def generateLandSeaMask(target,
                        source=None,
                        threshold_1=.2,
                        threshold_2=.3,
                        regridTool='regrid2'):
    """
    Generates a best guess mask on any rectilinear grid, using the method described in `PCMDI's report #58`_

    .. _PCMDI's report #58: http://www-pcmdi.llnl.gov/publications/pdf/58.pdf

    :param target: either a MV2 object with a grid, or a cdms2 grid (rectilinear grid only)
    :type target: MV2 or cdms2

    :param source: A fractional (0.0 to 1.0) land sea mask, where 1 means all land
    :type source: float

    :param threshold_1: criteria 1 for detecting cells with possible increment see report for detail
                        difference threshold
    :type threshold_1: float

    :param threshold_2: criteria 2 for detecting cells with possible increment see report for detail
                        water/land content threshold
    :type threshold_2: float

    :param regridTool: which cdms2 regridder tool to use, default is regrid2
    :type regridTool:

    :returns: landsea mask on target grid
    """
    if cdms2.isVariable(target):
        target = target.getGrid()
        if target is None:
            raise Exception("Error target data passed do not have  a grid")
    if not isinstance(target, cdms2.grid.TransientRectGrid):
        raise Exception("Error: target grid must be rectilinear")

    if source is None:
        source = cdms2.open(os.path.join(egg_path, 'navy_land.nc'))('sftlf')

    try:
        # print("REGRIDDING WITH SOURCE:", source)
        navy_frac_t = source.regrid(target, regridTool='regrid2')
    except Exception as err:
        raise Exception(
            "error, cannot regrid source data to target, got error message: %s"
            % err)

    # First guess, anything greater than 50% is land
    mask = MV2.greater(navy_frac_t, .5).astype('i')
    UL, UC, UR, ML, MR, LL, LC, LR = create_surrounds(navy_frac_t)
    cont = True
    i = 0
    while cont:
        mask2 = improve(mask,
                        navy_frac_t,
                        threshold_1,
                        threshold_2,
                        UL,
                        UC,
                        UR,
                        ML,
                        MR,
                        LL,
                        LC,
                        LR,
                        regridTool=regridTool)
        if MV2.allequal(
                mask2, mask
        ) or i > 25:  # shouldn't be more than 10 at max, 25 is way safe
            cont = False
        mask = mask2.astype("i")
        i += 1
    mask.id = 'sftlf'
    return mask
Esempio n. 8
0
def Es(T, method=None):
    """Computes saturated pressure in Pa given T in K, using the method:
    1: Hyland-Wexler formulation, polynomial coeff (absolute norm)
    2: Wexler formulation
    3: Hyland-Wexler formulation, polynomial coeff (relative error norm)
    4: classic Goff Gratch equation
    5: 6.112*numpy.ma.exp(17.67*tempc/(tempc+243.5))

    Default is method 1

    Note: 1 and 2 use method 3 where T is not : 173.15 < T < 473.15
    ref for 1, 2 and 3:
    Piotr Flatau and al., Journal of Applied Met., Vol 31, Dec 1992
    ( http://ams.allenpress.com/perlserv/?request=get-document&\
doi=10.1175%2F1520-0450(1992)031%3C1507%3APFTSVP%3E2.0.CO%3B2&ct=1 )
    """
    if method is None:
        method = 1

    if method == 1:
        # Put in C
        x = T - 273.15
        # Water vapor
        c0 = 0.611220713e03
        c1 = 0.443944344e02
        c2 = 0.143195336e01
        c3 = 0.263350515e-01
        c4 = 0.310636053e-03
        c5 = 0.185218710e-05
        c6 = 0.103440324e-07
        c7 = -0.468258100e-10
        c8 = 0.466533033e-13
        eswat = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8)))))))
        # ice
        c0 = 0.611153246e03
        c1 = 0.503261230e02
        c2 = 0.188595709e01
        c3 = 0.422115970e-01
        c4 = 0.620376691e-03
        c5 = 0.616082536e-05
        c6 = 0.405172828e-07
        c7 = 0.161492905e-09
        c8 = 0.297886454e-12
        esice = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8)))))))
        # Combine
        es = MV2.where(MV2.less(T, 273.15), esice, eswat)
        # Overwrite values outside valid range with method 2
        mn, mx = genutil.minmax(T)
        if mn < 173.16 or mx > 473.15:
            es2 = Es(T, method=2)
            es = MV2.where(MV2.less(T, 173.16), es2, es)
            es = MV2.where(MV2.greater(T, 473.15), es2, es)
    elif method == 2:
        # over water
        g0 = -0.29912729e4
        g1 = -0.60170128e4
        g2 = 0.1887643854e2
        g3 = -0.28354721e-1
        g4 = 0.17838301e-4
        g5 = -0.84150417e-9
        g6 = 0.44412543e-12
        g7 = 0.2858487e1
        # over ice
        k0 = -0.58653696e4
        k1 = 0.2224103300e2
        k2 = 0.13749042e-1
        k3 = -0.34031775e-4
        k4 = 0.26967687e-7
        k5 = 0.6918651
        esice = (k0 + (k1 + k5 * MV2.log(T) + (k2 + (k3 + k4 * T) * T) * T) * T) / T  # over ice
        eswat = (
            g0 + (g1 + (g2 + g7 * MV2.log(T) + (g3 + (g4 + (g5 + g6 * T) * T) * T) * T) * T) * T
        ) / T ** 2  # over water
        es = MV2.where(MV2.less(T, 273.15), esice, eswat)
        es = MV2.exp(es)
    elif method == 3:
        # Put in C
        x = T - 273.15
        # Water vapor
        c0 = 0.611213476e03
        c1 = 0.444007856e02
        c2 = 0.143064234e01
        c3 = 0.264461437e-01
        c4 = 0.305930558e-03
        c5 = 0.196237241e-05
        c6 = 0.892344772e-08
        c7 = -0.373208410e-10
        c8 = 0.209339997e-13
        eswat = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8)))))))
        # ice
        c0 = 0.611123516e03
        c1 = 0.503109514e02
        c2 = 0.1888369801e01
        c3 = 0.420547422e-01
        c4 = 0.614396778e-03
        c5 = 0.602780717e-05
        c6 = 0.387940929e-07
        c7 = 0.149436277e-09
        c8 = 0.262655803e-12
        esice = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x * (c5 + x * (c6 + x * (c7 + x * c8)))))))
        # Combine
        es = MV2.where(MV2.less(T, 273.15), esice, eswat)
        # Overwrite values outside valid range with method 2
        mn, mx = genutil.minmax(T)
        if mn < 173.16 or mx > 473.15:
            es2 = Es(T, method=2)
            es = MV2.where(MV2.less(T, 173.16), es2, es)
            es = MV2.where(MV2.greater(T, 473.15), es2, es)
    elif method == 4:
        est = 101324.6  # Pa
        Ts = 373.16 / T
        a = -7.90298
        b = 5.02808
        c = -1.3816e-7
        d = 11.344
        f = 8.1328e-3
        h = -3.49149
        maxexp = int(numpy.log10(numpy.finfo(numpy.float).max))
        minexp = 1 - a
        es = a * (Ts - 1.0)
        es = es + b * numpy.ma.log10(Ts)
        A = d * (1.0 - Ts)
        A = numpy.ma.masked_greater(A, maxexp)
        A = numpy.ma.masked_less(A, minexp)
        es = es + c * (numpy.ma.power(10, A) - 1.0)
        A = h * (Ts - 1.0)
        A = numpy.ma.masked_greater(A, maxexp)
        A = numpy.ma.masked_less(A, minexp)
        es = es + f * (numpy.ma.power(10, A) - 1.0)
        es = est * numpy.ma.power(10, es)
    elif method == 5:
        tempc = T - 273.15
        es = 611.2 * numpy.ma.exp(17.67 * tempc / (tempc + 243.5))
    return es
Esempio n. 9
0
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
Esempio n. 10
0
       landsea maks on target grid
    """
    cdat_info.pingPCMDIdb("cdat","cdutil.generateLandSeaMask")
    if cdms2.isVariable(target):
        target = target.getGrid()
        if target is None:
            raise Exception,"Error target data passed do not have  a grid"
    if not isinstance(target,cdms2.grid.TransientRectGrid):
        raise Exception, "Error: target grid must be rectilinear"

    if source is None:
        source = cdms2.open(os.path.join(sys.prefix,'share','cdutil','navy_land.nc'))('sftlf')
        
    try:
        navy_frac_t = source.regrid(target,regridTool='regrid2')
    except Exception,err:
        raise "error, cannot regrid source data to target, got error message: %s" % err
    
    mask = MV2.greater(navy_frac_t,.5).astype('i') # First guess, anything greater than 50% is land
    UL,UC,UR,ML,MR,LL,LC,LR = create_surrounds(navy_frac_t)
    cont = True
    i=0
    while cont:
        mask2 = improve(mask,navy_frac_t,threshold_1,threshold_2,UL,UC,UR,ML,MR,LL,LC,LR,regridTool=regridTool)
        if MV2.allequal(mask2,mask) or i>25: # shouldn't be more than 10 at max, 25 is way safe
            cont=False
        mask=mask2
        i+=1
    mask.id='sftlf'
    return mask
Esempio n. 11
0
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
Esempio n. 12
0
        if target is None:
            raise Exception, "Error target data passed do not have  a grid"
    if not isinstance(target, cdms2.grid.TransientRectGrid):
        raise Exception, "Error: target grid must be rectilinear"

    if source is None:
        source = cdms2.open(
            os.path.join(sys.prefix, 'share', 'cdutil',
                         'navy_land.nc'))('sftlf')

    try:
        navy_frac_t = source.regrid(target, regridTool='regrid2')
    except Exception, err:
        raise "error, cannot regrid source data to target, got error message: %s" % err

    mask = MV2.greater(navy_frac_t, .5).astype(
        'i')  # First guess, anything greater than 50% is land
    UL, UC, UR, ML, MR, LL, LC, LR = create_surrounds(navy_frac_t)
    cont = True
    i = 0
    while cont:
        mask2 = improve(mask,
                        navy_frac_t,
                        threshold_1,
                        threshold_2,
                        UL,
                        UC,
                        UR,
                        ML,
                        MR,
                        LL,
                        LC,
inputFilePathbgn = '/p/user_pub/pmp/pmp_obs_preparation/orig/data/'
inputFilePathend = '/CMAP/'
inputFileName = ['precip.mon.mean.nc']
inputVarName = ['precip']
outputVarName = ['pr']
outputUnits = ['kg m-2 s-1']

### BETTER IF THE USER DOES NOT CHANGE ANYTHING BELOW THIS LINE...
for fi in range(len(inputVarName)):
    print(fi, inputVarName[fi])
    inputFilePath = inputFilePathbgn + inputFilePathend
    #%% Process variable (with time axis)
    # Open and read input netcdf file
    f = cdm.open(inputFilePath + inputFileName[fi])
    dtmp = f(inputVarName[fi])
    d = MV2.where(MV2.greater(dtmp, -10000.), dtmp, 1.e20)
    d.missing = 1.e20

    cdutil.times.setTimeBoundsMonthly(d)
    d = MV2.divide(d, 86400.)  # CONVERT mm/day to kg m-2 s-1
    lat = d.getLatitude()
    lon = d.getLongitude()
    print(d.shape)
    #time = d.getTime() ; # Assumes variable is named 'time', for the demo file this is named 'months'
    time = d.getAxis(0)
    # Rather use a file dimension-based load statement

    # Deal with problematic "months since" calendar/time axis
    time_bounds = time.getBounds()
    # time_bounds[:,0] = time[:]
    # time_bounds[:-1,1] = time[1:]
Esempio n. 14
0
def Es(T, method=None):
    """Computes saturated pressure in Pa given T in K, using the method:
    1: Hyland-Wexler formulation, polynomial coeff (absolute norm)
    2: Wexler formulation
    3: Hyland-Wexler formulation, polynomial coeff (relative error norm)
    4: classic Goff Gratch equation
    5: 6.112*numpy.ma.exp(17.67*tempc/(tempc+243.5))

    Default is method 1
    
    Note: 1 and 2 use method 3 where T is not : 173.15 < T < 473.15
    ref for 1, 2 and 3:
    Piotr Flatau and al., Journal of Applied Met., Vol 31, Dec 1992 ( http://ams.allenpress.com/perlserv/?request=get-document&doi=10.1175%2F1520-0450(1992)031%3C1507%3APFTSVP%3E2.0.CO%3B2&ct=1 )
    """
    if method is None:
        method = 1

    if method == 1:
        ## Put in C
        x = T - 273.15
        ## Water vapor
        c0 = 0.611220713E03
        c1 = 0.443944344E02
        c2 = 0.143195336E01
        c3 = 0.263350515E-01
        c4 = 0.310636053E-03
        c5 = 0.185218710E-05
        c6 = 0.103440324E-07
        c7 = -0.468258100E-10
        c8 = 0.466533033E-13
        eswat = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x *
                                                        (c5 + x *
                                                         (c6 + x *
                                                          (c7 + x * c8)))))))
        ## ice
        c0 = .611153246E03
        c1 = .503261230E02
        c2 = .188595709E01
        c3 = .422115970E-01
        c4 = .620376691E-03
        c5 = .616082536E-05
        c6 = .405172828E-07
        c7 = .161492905E-09
        c8 = .297886454E-12
        esice = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x *
                                                        (c5 + x *
                                                         (c6 + x *
                                                          (c7 + x * c8)))))))
        ## Combine
        es = MV2.where(MV2.less(T, 273.15), esice, eswat)
        ## Overwrite values outside valid range with method 2
        mn, mx = genutil.minmax(T)
        if mn < 173.16 or mx > 473.15:
            es2 = Es(T, method=2)
            es = MV2.where(MV2.less(T, 173.16), es2, es)
            es = MV2.where(MV2.greater(T, 473.15), es2, es)
    elif method == 2:
        # over water
        g0 = -0.29912729E4
        g1 = -0.60170128E4
        g2 = 0.1887643854E2
        g3 = -0.28354721E-1
        g4 = 0.17838301E-4
        g5 = -0.84150417E-9
        g6 = 0.44412543E-12
        g7 = 0.2858487E1
        # over ice
        k0 = -0.58653696e4
        k1 = 0.2224103300E2
        k2 = 0.13749042E-1
        k3 = -0.34031775E-4
        k4 = 0.26967687E-7
        k5 = 0.6918651
        esice = (k0 + (k1 + k5 * MV2.log(T) +
                       (k2 + (k3 + k4 * T) * T) * T) * T) / T  # over ice
        eswat = (g0 + (g1 + (g2 + g7 * MV2.log(T) +
                             (g3 + (g4 + (g5 + g6 * T) * T) * T) * T) * T) *
                 T) / T**2  # over water
        es = MV2.where(MV2.less(T, 273.15), esice, eswat)
        es = MV2.exp(es)
    elif method == 3:
        ## Put in C
        x = T - 273.15
        ## Water vapor
        c0 = 0.611213476E03
        c1 = 0.444007856E02
        c2 = 0.143064234E01
        c3 = 0.264461437E-01
        c4 = 0.305930558E-03
        c5 = 0.196237241E-05
        c6 = 0.892344772E-08
        c7 = -0.373208410E-10
        c8 = 0.209339997E-13
        eswat = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x *
                                                        (c5 + x *
                                                         (c6 + x *
                                                          (c7 + x * c8)))))))
        ## ice
        c0 = .611123516E03
        c1 = .503109514E02
        c2 = .1888369801E01
        c3 = .420547422E-01
        c4 = .614396778E-03
        c5 = .602780717E-05
        c6 = .387940929E-07
        c7 = .149436277E-09
        c8 = .262655803E-12
        esice = c0 + x * (c1 + x * (c2 + x * (c3 + x * (c4 + x *
                                                        (c5 + x *
                                                         (c6 + x *
                                                          (c7 + x * c8)))))))
        ## Combine
        es = MV2.where(MV2.less(T, 273.15), esice, eswat)
        ## Overwrite values outside valid range with method 2
        mn, mx = genutil.minmax(T)
        if mn < 173.16 or mx > 473.15:
            es2 = Es(T, method=2)
            es = MV2.where(MV2.less(T, 173.16), es2, es)
            es = MV2.where(MV2.greater(T, 473.15), es2, es)
    elif method == 4:
        est = 101324.6  #Pa
        Ts = 373.16 / T
        a = -7.90298
        b = 5.02808
        c = -1.3816E-7
        d = 11.344
        f = 8.1328E-3
        h = -3.49149
        maxexp = int(numpy.log10(numpy.finfo(numpy.float).max))
        minexp = 1 - a
        es = a * (Ts - 1.)
        es = es + b * numpy.ma.log10(Ts)
        A = d * (1. - Ts)
        A = numpy.ma.masked_greater(A, maxexp)
        A = numpy.ma.masked_less(A, minexp)
        es = es + c * (numpy.ma.power(10, A) - 1.)
        A = h * (Ts - 1.)
        A = numpy.ma.masked_greater(A, maxexp)
        A = numpy.ma.masked_less(A, minexp)
        es = es + f * (numpy.ma.power(10, A) - 1.)
        es = est * numpy.ma.power(10, es)
    elif method == 5:
        tempc = T - 273.15
        es = 611.2 * numpy.ma.exp(17.67 * tempc / (tempc + 243.5))
    return es
Esempio n. 15
0
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
Esempio n. 16
0
 def testWhere(self):
     xouter = MV2.outerproduct(MV2.arange(3), MV2.arange(3))
     xwhere = MV2.where(MV2.greater(xouter, 3), xouter, -123)
     self.assertEqual(xwhere[-1, -1], 4)
     xwhere.mask = xwhere == 4
     self.assertTrue(MV2.allequal(xwhere, -123))
Esempio n. 17
0
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
Esempio n. 18
0
##   Denominator is multiplied by 1.0 to prevent truncation for integers.
##   returned governs return of second quantity, the weights.
xav = MV2.average(xones, axis=1)
xav2 = MV2.average(ud)
xav3 = MV2.average(udat)
xav4, wav4 = MV2.average(udat, weights=MV2.ones(udat.shape, numpy.float), returned=1)

## choose(indices, t) 
##   Shaped like indices, values t[i] where at indices[i]
##   If t[j] is masked, special treatment to preserve type.
ct1 = MV2.TransientVariable([1,1,2,0,1])
ctr = MV2.choose(ct1, [numpy.ma.masked, 10,20,30,40])
if not MV2.allclose(ctr, [10, 10, 20, 100, 10]): markError('choose error 1')
ctx = MV2.TransientVariable([1,2,3,150,4])
cty = -MV2.TransientVariable([1,2,3,150,4])
ctr = MV2.choose(MV2.greater(ctx,100), (ctx, 100))
if not MV2.allclose(ctr, [1,2,3,100,4]): markError('choose error 2')
ctr = MV2.choose(MV2.greater(ctx,100), (ctx, cty))
if not MV2.allclose(ctr, [1,2,3,-150,4]): markError('choose error 3')

## concatenate(arrays, axis=0, axisid=None, axisattributes=None) 
##   Concatenate the arrays along the given axis. Give the extended axis the id and
##   attributes provided - by default, those of the first array.

try:
    xcon = MV2.concatenate((ud,vd))
except:
    markError('Concatenate error')

## isMaskedVariable(x) 
##   Is x a masked variable, that is, an instance of AbstractVariable?
Esempio n. 19
0
landMask.associated_files = "baseURL: http://rda.ucar.edu/datasets/ds625.0"
landMask.long_name = "Land Area Fraction"
landMask.standard_name = "land_area_fraction"
landMask.units = "%"
landMask.setMissing(1.e20)

# Regrid to current obs data
gridFile = '/clim_obs/obs/atm/mo/tas/JRA25/ac/tas_JRA25_000001-000012_ac.nc'
f_g = cdm.open(gridFile)
grid = f_g('tas').getGrid()
landMask = landMask.regrid(grid, regridTool='ESMF', regridMethod='linear')
f_g.close()
landMask.id = 'sftlf'  # Rename

# Deal with interpolated values
landMask[mv.greater(landMask, 75)] = 100  # Fix weird ocean values
landMask[mv.less(landMask, 75)] = 0  # Fix continental halos
landMask[mv.less(landMask, 0)] = 0  # Fix negative values

# Invert land=100, ocean=0
landMask[mv.equal(landMask, 0)] = 50  # Convert ocean
landMask[mv.equal(landMask, 100)] = 0  # Convert ocean
landMask[mv.equal(landMask, 50)] = 100  # Convert ocean

# Create outfile and write
outFile = 'sftlf_pcmdi-metrics_fx_NCAR-JRA25_197901-201401.nc'
# Write variables to file
if os.path.isfile(outFile):
    os.remove(outFile)
fOut = cdm.open(outFile, 'w')
# Use function to write standard global atts
Esempio n. 20
0
def myMakeMask(array, range):
    """Returns the input array masked where the values are not between range[0] and range[1]"""
    m1=MV.less (array, range[0]) # mask where it is less than the 1st value
    m2=MV.greater(array, range[1]) # mask where it is more than the 2nd value
    return MV.logical_or(m1,m2)
Esempio n. 21
0
 climInterp2Max = np.max(climInterp2)
 climInterp2Mean = np.mean(climInterp2)
 climInterp2Median = np.median(climInterp2)
 climInterp2Min = np.min(climInterp2)
 climInterp2Str = ''.join(['climInterp2.max():',
                           '{:{}f}'.format(climInterp2Max,precision),
                           ' mean:','{:{}f}'.format(climInterp2Mean,precision),
                           ' median:','{:{}f}'.format(climInterp2Median,precision),
                           ' min:','{:{}f}'.format(climInterp2Min,precision)])
 print(climInterp2Str)
 writeToLog(logFile,climInterp2Str)
 #print('climInterp2 created')
 #pdb.set_trace()
 # Mask invalid datapoints
 climInterp3 = mv.masked_where(mv.equal(climInterp2,1e+20),climInterp2)
 climInterp3 = mv.masked_where(mv.greater(climInterp3,1e+10),climInterp3) ; # Add great to catch fringe values, switched from 1e+20 to 1e+10
 print('climInterp3.missing:',climInterp3.missing)
 #climInterp3.setMissing(1e+20) ; # Specifically assign missing value
 #print('climInterp3 created')
 #pdb.set_trace()
 '''
 import matplotlib.pyplot as plt
 climSlice = clim[0,0,:,:] ; plt.figure(1) ; plt.contourf(clim.getLongitude().data,clim.getLatitude().data,climSlice,20) ; #clim
 plt.show()
 climInterpSlice = climInterp[0,0,:,:] ; plt.figure(2) ; plt.contourf(climInterp.getLongitude().getData(),climInterp.getLatitude().getData(),climInterpSlice,20) ; #climInterp
 plt.show()
 #climInterp2Slice = climInterp2[0,0,:,:] ; plt.figure(3) ; plt.contourf(climInterp.getLongitude().getData(),climInterp.getLatitude().getData(),climInterp2Slice,20) ; #climInterp2
 #plt.show()
 climInterp3Slice = climInterp3[0,0,:,:] ; plt.figure(4) ; plt.contourf(climInterp.getLongitude().getData(),climInterp.getLatitude().getData(),climInterp3Slice,20) ; #climInterp3
 plt.show()
 '''
Esempio n. 22
0
xav = MV2.average(xones, axis=1)
xav2 = MV2.average(ud)
xav3 = MV2.average(udat)
xav4, wav4 = MV2.average(udat,
                         weights=MV2.ones(udat.shape, numpy.float),
                         returned=1)

## choose(indices, t)
##   Shaped like indices, values t[i] where at indices[i]
##   If t[j] is masked, special treatment to preserve type.
ct1 = MV2.TransientVariable([1, 1, 2, 0, 1])
ctr = MV2.choose(ct1, [numpy.ma.masked, 10, 20, 30, 40])
if not MV2.allclose(ctr, [10, 10, 20, 100, 10]): markError('choose error 1')
ctx = MV2.TransientVariable([1, 2, 3, 150, 4])
cty = -MV2.TransientVariable([1, 2, 3, 150, 4])
ctr = MV2.choose(MV2.greater(ctx, 100), (ctx, 100))
if not MV2.allclose(ctr, [1, 2, 3, 100, 4]): markError('choose error 2')
ctr = MV2.choose(MV2.greater(ctx, 100), (ctx, cty))
if not MV2.allclose(ctr, [1, 2, 3, -150, 4]): markError('choose error 3')

## concatenate(arrays, axis=0, axisid=None, axisattributes=None)
##   Concatenate the arrays along the given axis. Give the extended axis the id and
##   attributes provided - by default, those of the first array.

try:
    xcon = MV2.concatenate((ud, vd))
except:
    markError('Concatenate error')

## isMaskedVariable(x)
##   Is x a masked variable, that is, an instance of AbstractVariable?
Esempio n. 23
0
landMask.associated_files = "baseURL: http://rda.ucar.edu/datasets/ds625.0"
landMask.long_name = "Land Area Fraction"
landMask.standard_name = "land_area_fraction"
landMask.units = "%"
landMask.setMissing(1.0e20)

# Regrid to current obs data
gridFile = "/clim_obs/obs/atm/mo/tas/JRA25/ac/tas_JRA25_000001-000012_ac.nc"
f_g = cdm.open(gridFile)
grid = f_g("tas").getGrid()
landMask = landMask.regrid(grid, regridTool="ESMF", regridMethod="linear")
f_g.close()
landMask.id = "sftlf"  # Rename

# Deal with interpolated values
landMask[mv.greater(landMask, 75)] = 100  # Fix weird ocean values
landMask[mv.less(landMask, 75)] = 0  # Fix continental halos
landMask[mv.less(landMask, 0)] = 0  # Fix negative values

# Invert land=100, ocean=0
landMask[mv.equal(landMask, 0)] = 50  # Convert ocean
landMask[mv.equal(landMask, 100)] = 0  # Convert ocean
landMask[mv.equal(landMask, 50)] = 100  # Convert ocean

# Create outfile and write
outFile = "sftlf_pcmdi-metrics_fx_NCAR-JRA25_197901-201401.nc"
# Write variables to file
if os.path.isfile(outFile):
    os.remove(outFile)
fOut = cdm.open(outFile, "w")
# Use function to write standard global atts