Example #1
0
def flotationMask(s, zF, Q, rhoI=rhoI, rhoW=rhoW):
    """Using flotation height, create masks for floating and grounded ice.

    Parameters
    ----------
    zF firedrake interp function
        Flotation height (m)
    Q : firedrake function space
        function space
    rhoI : [type], optional
        [description], by default rhoI
    rhoW : [type], optional
        [description], by default rhoW
    Returns
    -------
    floating firedrake interp function
         ice shelf mask 1 floating, 0 grounded
    grounded firedrake interp function
        Grounded mask 1 grounded, 0 floating
    """
    # smooth to avoid isolated points dipping below flotation.
    zAbove = firedrakeSmooth(icepack.interpolate(s - zF, Q), alpha=100)
    floating = icepack.interpolate(zAbove < 0, Q)
    grounded = icepack.interpolate(zAbove > 0, Q)
    return floating, grounded
Example #2
0
def mapPlots(plotData, t, melt, floating, h, hLast, deltaT, Q):
    ''' Plot melt, floating/grounded, thinning in map view
    '''
    setupMapPlots(plotData)
    axes = plotData['axesM'].flatten()
    meltC = icepack.plot.tricontourf(icepack.interpolate(melt, Q),
                                     levels=np.linspace(-150, 0, 151),
                                     extend='both',
                                     axes=axes[0])
    floatC = icepack.plot.tricontourf(floating,
                                      axes=axes[1],
                                      extend='both',
                                      levels=np.linspace(0, 1, 106))

    thin = icepack.interpolate((h - hLast) / deltaT, Q)
    thinC = icepack.plot.tricontourf(thin,
                                     levels=np.linspace(-8, 8, 161),
                                     axes=axes[2],
                                     extend='both',
                                     cmap=plt.get_cmap('bwr_r'))
    plotData['figM'].suptitle(f'Simulation Year: {t:0.1f}')
    if plotData['figMColorbar']:
        titles = ['melt (m/yr)', 'floating', 'dH/dt (m/yr)']
        for ax, cont, title in zip(axes, [meltC, floatC, thinC], titles):
            myColorBar(plotData['figM'], ax, cont)
            ax.set_title(title)
        plotData['figMColorbar'] = False
        plotData['figM'].tight_layout(rect=[0, 0, 1, 0.95])
    if plotData['plotResult']:
        plotData['figM'].canvas.draw()
Example #3
0
def forceFloat(floatingMask, bedElevation, sufaceElevation, Q, headRoom=50):
    """Adjust bed as needed to force flotation
    Parameters
    ----------
    floatingMask : firedrake function
        Mask where 1 indicates ice should be afloati
    bedElevation : firedrake function
        Original bed elevation
    sufaceElevation : firedrake function
        Surface elevation ice equivalent
    Q : firedrake function space
        Domain
    """
    nItMax = 20
    newBed = bedElevation.copy(deepcopy=True)
    dZ = 15
    i = 0
    print('start')
    while i < nItMax:
        zF = flotationHeight(newBed, Q, rhoI=rhoI, rhoW=rhoW)
        currentFlotation, _ = flotationMask(sufaceElevation,
                                            zF,
                                            Q,
                                            rhoI=rhoI,
                                            rhoW=rhoW)
        notFloating = firedrake.And(currentFlotation < firedrake.Constant(0.5),
                                    floatingMask > 0.5)
        area = firedrake.assemble(notFloating * firedrake.dx)
        newBed = icepack.interpolate(newBed - dZ * notFloating, Q)
        print(i, area / 1e6)
        if area < 1:
            break
        i = i + 1
    newBed = icepack.interpolate(newBed - headRoom * floatingMask, Q)
    return newBed
Example #4
0
def divMelt(h, floating, meltParams, u, Q):
    """ Melt function that is a scaled version of the flux divergence
    h : firedrake function
        ice thickness
    u : firedrake vector function
        surface elevation
    floating : firedrake function
        floating mask
    V : firedrake vector space
        vector space for velocity
    meltParams : dict
        parameters for melt function
    Returns
    -------
    firedrake function
        melt rates
    """

    flux = u * h
    fluxDiv = icepack.interpolate(firedrake.div(flux), Q)
    fluxDivS = firedrakeSmooth(fluxDiv, alpha=8000)
    fluxDivS = firedrake.min_value(
        fluxDivS * floating * meltParams['meltMask'], 0)
    intFluxDiv = firedrake.assemble(fluxDivS * firedrake.dx)
    scale = -1.0 * float(meltParams['intMelt']) / float(intFluxDiv)
    scale = firedrake.Constant(scale)
    melt = icepack.interpolate(
        firedrake.min_value(fluxDivS * scale, meltParams['maxMelt']), Q)

    return melt
Example #5
0
def test_ice_shelf():
    ice_shelf = icepack.IceShelf({0})

    h = icepack.interpolate(discretization, thickness)
    u0 = icepack.interpolate(discretization, velocity, lambda x: 0.0)
    theta = icepack.interpolate(discretization, temperature)

    u = ice_shelf.solve(h, theta, u0)
Example #6
0
def piecewiseWithDepth(h, floating, meltParams, Q, *argv, **kwargs):
    """ Melt function that is described piecewise by set of polynomials
    Melt is in units of m/yr w.e.
    Parameters
    ----------
    h : firedrake function
        ice thickness
    floating : firedrake function
        floating mask
    meltParams : dict
        parameters for melt function
    Returns
    -------
    firedrake function
        melt rates
    """
    # compute depth
    melt = firedrake.Constant(0)
    for i in range(1, meltParams['numberOfPolynomials'] + 1):
        poly = meltParams[f'poly{i}']
        tmpMelt = firedrake.Constant(poly['coeff'][0])
        for j in range(1, poly['deg'] + 1):
            tmpMelt = tmpMelt + poly['coeff'][j] * h**j
        # Apply melt to all shelf ice (ice > 30 m)
        melt = melt + tmpMelt * \
            (h > max(poly['min'], 30.1)) * (h < poly['max'])
    # Smooth result
    alpha = 4000  # Default
    if 'alpha' in meltParams:
        alpha = meltParams['alpha']
    #
    # if filterWithFloatMask apply float mask before filter, which will shift
    # melt distribution up in the column. If filter applied afterwards, it
    # will be concentrated nearer the GL.
    filterWithFloatMask = False
    if 'filterWithFloatMask' in meltParams:
        filterWithFloatMask = meltParams['filterWithFloatMask']
    if filterWithFloatMask:
        # Changed to avoid petsc memory issue on store
        # melt1 = icepack.interpolate(melt * floating, Q)
        melt1 = icepack.interpolate(melt, Q)
        melt1 = icepack.interpolate(floating * melt1, Q)
    else:
        melt1 = icepack.interpolate(melt, Q)
    melt1 = firedrakeSmooth(melt1, alpha=alpha)
    # 'totalMelt' given renormalize melt to produce this value
    if 'totalMelt' in meltParams.keys():
        trend = 0.
        if 'trend' in kwargs.keys():
            trend = kwargs['trend']
        intMelt = firedrake.assemble(melt1 * floating * firedrake.dx)
        total = float(meltParams['totalMelt']) + trend
        scale = firedrake.Constant(-1.0 * total / float(intMelt))
    else:
        scale = firedrake.Constant(1.)
    #
    melt = icepack.interpolate(melt1 * scale * floating, Q)
    return melt
Example #7
0
def test_algebra():
    u = icepack.interpolate(discretization, lambda x: x[0] - x[1])
    v = icepack.interpolate(discretization, lambda x: x[0] * x[1])

    w = icepack.interpolate(discretization,
                            lambda x: x[0] - x[1] + x[0] * x[1])
    assert icepack.dist(u + v, w) / icepack.norm(w) < 1.0e-8

    w = icepack.interpolate(discretization,
                            lambda x: x[0] - x[1] - x[0] * x[1])
    assert icepack.dist(u - v, w) / icepack.norm(w) < 1.0e-8

    w = icepack.interpolate(discretization, lambda x: 2 * x[0] * x[1])
    assert icepack.dist(2.0 * v, w) / icepack.norm(w) < 1.0e-8

    assert abs(icepack.inner_product(u, v)) < 1.0e-8
Example #8
0
def test_interpolating_function():
    nx, ny = 32, 32
    mesh = firedrake.UnitSquareMesh(nx, ny)
    x = firedrake.SpatialCoordinate(mesh)
    Q = firedrake.FunctionSpace(mesh, "CG", 2)
    q = icepack.interpolate(x[0] ** 2 - x[1] ** 2, Q)
    assert abs(firedrake.assemble(q * dx)) < 1e-6
Example #9
0
def test_interpolating_vector_field():
    n = 32
    array_vx = np.array([[(i + j) / n for j in range(n + 1)]
                         for i in range(n + 1)])
    missing = -9999.0
    array_vx[0, 0] = missing
    array_vx = np.flipud(array_vx)

    array_vy = np.array([[(j - i) / n for j in range(n + 1)]
                         for i in range(n + 1)])
    array_vy[-1, -1] = -9999.0
    array_vy = np.flipud(array_vy)

    vx = make_rio_dataset(array_vx, missing)
    vy = make_rio_dataset(array_vy, missing)

    mesh = make_domain(48,
                       48,
                       xmin=1 / 4,
                       ymin=1 / 4,
                       width=1 / 2,
                       height=1 / 2)
    x, y = firedrake.SpatialCoordinate(mesh)
    V = firedrake.VectorFunctionSpace(mesh, family='CG', degree=1)
    u = firedrake.interpolate(firedrake.as_vector((x + y, x - y)), V)
    v = icepack.interpolate((vx, vy), V)

    assert firedrake.norm(u - v) / firedrake.norm(u) < 1e-10
Example #10
0
def initSummary(grounded0,
                floating0,
                h0,
                u0,
                meltModel,
                meltParams,
                SMB,
                Q,
                mesh,
                forwardParams,
                restart=False):
    ''' Compute initial areas and summary data
        if restart, try reload restart data. If not go with clean slate, which
        should be a legacy case (from when intermediates steps were not saved)
    '''
    if forwardParams['restart']:
        summaryData = reinitSummary(forwardParams)
        if summaryData is not None:
            return summaryData
        # No summary.tmp from a prior run so reset restart
        forwardParams['restart'] = False
    # start from scratch
    area = firedrake.assemble(firedrake.Constant(1) * firedrake.dx(mesh))
    gArea0 = firedrake.assemble(grounded0 * firedrake.dx(mesh))
    fArea0 = area - gArea0
    melt = meltModel(h0, floating0, meltParams, Q, u0)
    meltTot = firedrake.assemble(
        icepack.interpolate(floating0 * melt, Q) * firedrake.dx(mesh))
    SMBfloating = firedrake.assemble(
        icepack.interpolate(floating0 * SMB, Q) * firedrake.dx(mesh))
    SMBgrounded = firedrake.assemble(
        icepack.interpolate(grounded0 * SMB, Q) * firedrake.dx(mesh))
    summaryData = {
        'year': [0],
        'DVG': [0, 0],
        'DVF': [0, 0],
        'deltaVF': [0, 0],
        'deltaVG': [0, 0],
        'gArea': [float(gArea0)],
        'fArea': [float(fArea0)],
        'meltTot': [float(meltTot)],
        'area': float(area),
        'SMBgrounded': [float(SMBgrounded)],
        'SMBfloating': [float(SMBfloating)],
        'dTsum': 1.
    }  # dTsum fixed - code modes needed to change
    return summaryData
Example #11
0
def computeSummaryData(SD, h, s, u, a, melt, SMB, grounded, floating, year, Q,
                       mesh, deltaT, beginTime):
    ''' Compute summary results and sort in summaryData
        Save all as float for yaml output
    '''
    deltaVF, deltaVG = \
        volumeChange(grounded, floating, h, u, a, mesh)
    SD['deltaVF'][-1] += deltaVF * deltaT * iceToWater
    SD['deltaVG'][-1] += deltaVG * deltaT * iceToWater
    SD['DVF'][-1] += deltaVF * deltaT * iceToWater
    SD['DVG'][-1] += deltaVG * deltaT * iceToWater
    print(f"++{year:0.3f} {SD['deltaVF'][-1]/1e9:0.3f} "
          f"{SD['deltaVG'][-1]/1e9:0.3f} {SD['DVF'][-1]/1e9:0.3f} "
          f"{SD['DVG'][-1]/1e9:0.3f}")
    #
    # If not with half a time step of year return
    # Need to update this for different update interval (~=1)
    dTint = abs(year - round(year, 0))  # difference from int year
    # if before first year or not with half time step of int year return
    if year < (1. - deltaT * 0.5) or not (dTint < deltaT * 0.5):
        return False
    print(f'year {year} runtime {datetime.now() - beginTime}')
    #
    gArea = firedrake.assemble(grounded * firedrake.dx(mesh))
    SD['year'].append(float(year))
    SD['gArea'].append(gArea)
    SD['fArea'].append(SD['area'] - gArea)
    # append a new zero value to start incrementing
    SD['deltaVF'].append(0)
    SD['deltaVG'].append(0)
    # append current value to start incrementing
    SD['DVF'].append(SD['DVF'][-1])
    SD['DVG'].append(SD['DVG'][-1])
    #
    meltTot = firedrake.assemble(
        icepack.interpolate(floating * melt, Q) * firedrake.dx(mesh))
    SD['meltTot'].append(float(meltTot))
    SMBfloating = firedrake.assemble(
        icepack.interpolate(floating * SMB, Q) * firedrake.dx(mesh))
    SD['SMBfloating'].append(float(SMBfloating))
    SMBgrounded = firedrake.assemble(
        icepack.interpolate(grounded * SMB, Q) * firedrake.dx(mesh))
    SD['SMBgrounded'].append(float(SMBgrounded))
    #
    print(f'{year}: Initial melt {SD["meltTot"][0] / 1e9:.2f} current melt '
          f' {meltTot / 1e9:.2f}')
    return True
Example #12
0
def getRateFactor(rateFile, Q):
    """Read rate factor as B and convert to A
    Parameters
    ----------
    rateFile : str
        File with rate factor data
    Q : firedrake function space
        function space
    Returns
    -------
    A : firedrake function
        A Glenns flow law parameter
    """
    Bras = rasterio.open(rateFile)
    B = icepack.interpolate(Bras, Q)
    convFactor = 1e-6 * (86400 * 365.25)**(-1. / 3.)
    A = icepack.interpolate((B * convFactor)**-3, Q)
    return A
Example #13
0
def test_close_to_edge():
    n = 32
    array = np.array([[(i + j) / n for j in range(n + 1)] for i in range(n + 1)])
    missing = -9999.0
    array = np.flipud(array)
    dataset = make_rio_dataset(array, missing)

    xmin, ymin = 1 / (2 * n), 3 / (4 * n)
    mesh = make_domain(48, 48, xmin=xmin, ymin=ymin, width=1 / 2, height=1 / 2)
    Q = firedrake.FunctionSpace(mesh, "CG", 1)
    q = icepack.interpolate(dataset, Q)
Example #14
0
def piecewiseWithDepth(h, floating, meltParams, Q, *argv):
    """ Melt function that is described piecewise by set of polynomials

    Parameters
    ----------
    h : firedrake function
        ice thickness
    floating : firedrake function
        floating mask
    meltParams : dict
        parameters for melt function
    Returns
    -------
    firedrake function
        melt rates
    """
    # compute depth
    melt = firedrake.Constant(0)
    for i in range(1, meltParams['numberOfPolynomials'] + 1):
        poly = meltParams[f'poly{i}']
        tmpMelt = firedrake.Constant(poly['coeff'][0])
        for j in range(1, poly['deg'] + 1):
            tmpMelt = tmpMelt + poly['coeff'][j] * h**j
        melt = melt + tmpMelt * (h > poly['min']) * (h < poly['max'])
    # Smooth result
    # melt1 = icepack.interpolate(melt * floating, Q)
    alpha = 4000  # Default
    if 'alpha' in meltParams:
        alpha = meltParams['alpha']
    melt1 = icepack.interpolate(melt, Q)
    melt1 = firedrakeSmooth(melt1, alpha=alpha)
    # 'totalMelt' given renormalize melt to produce this value
    if 'totalMelt' in meltParams.keys():
        intMelt = firedrake.assemble(melt1 * floating * firedrake.dx)
        scale = firedrake.Constant(-1.0 * float(meltParams['totalMelt']) /
                                   float(intMelt))
    else:
        scale = firedrake.Constant(1.)
    #
    melt = icepack.interpolate(melt1 * scale * floating, Q)
    return melt
Example #15
0
def getModelVelocity(baseName, Q, V, minSigma=5, maxSigma=100):
    """Read in a tiff velocity data set and return
    firedrake interpolate functions.

    Parameters
    ----------
    baseName : str
        baseName should be of the form pattern.*.abc or pattern
        The wildcard (*) will be filled with the suffixes (vx, vy.)
        e.g.,pattern.vx.abc.tif, pattern.vy.abc.tif.
    Q : firedrake function space
        function space
    V : firedrake vector space
        vector space
    Returns
    -------
    uObs firedrake interp function on V
        velocity (m/yr)
    speed firedrake interp function on Q
        speed in (m)
    sigmaX firedrake interp function on Q
        vx error (m)
    sigmaY firedrake interp function on Q
        vy error (m)
    """
    # suffixes for products used
    suffixes = ['vx', 'vy', 'ex', 'ey']
    rasters = {}
    # prep baseName - baseName.*.xyz.tif or baseName.*
    if '*' not in baseName:
        baseName += '.*'
    if '.tif' not in baseName:
        baseName += '.tif'
    # read data
    for suffix in suffixes:
        myBand = baseName.replace('*', suffix)
        if not os.path.exists(myBand):
            u.myerror(f'Velocity/error file - {myBand} - does not exist')
        rasters[suffix] = rasterio.open(myBand, 'r')
    # Firedrake interpolators
    uObs = icepack.interpolate((rasters['vx'], rasters['vy']), V)
    # force error to be at least 1 to avoid 0 or negatives.
    sigmaX = icepack.interpolate(rasters['ex'], Q)
    sigmaX = icepack.interpolate(firedrake.max_value(sigmaX, minSigma), Q)
    sigmaX = icepack.interpolate(firedrake.min_value(sigmaX, maxSigma), Q)
    sigmaY = icepack.interpolate(rasters['ey'], Q)
    sigmaY = icepack.interpolate(firedrake.max_value(sigmaY, minSigma), Q)
    sigmaY = icepack.interpolate(firedrake.min_value(sigmaY, maxSigma), Q)
    speed = icepack.interpolate(firedrake.sqrt(inner(uObs, uObs)), Q)
    # return results
    return uObs, speed, sigmaX, sigmaY
Example #16
0
def readSMB(SMBfile, Q):
    ''' Read SMB file an limit values to +/- 6 to avoid no data values

    Returns water equivalent values.
    '''
    if not os.path.exists:
        myerror(f'readSMB: SMB file  ({SMBfile}) does not exist')
    SMB = mf.getModelVarFromTiff(SMBfile, Q)
    # avoid any unreasonably large value
    SMB = icepack.interpolate(
        firedrake.max_value(firedrake.min_value(SMB, 6), -6), Q)
    return SMB
Example #17
0
def test_interpolating_scalar_field():
    n = 32
    array = np.array([[(i + j) / n for j in range(n + 1)] for i in range(n + 1)])
    missing = -9999.0
    array[0, 0] = missing
    array = np.flipud(array)
    dataset = make_rio_dataset(array, missing)

    mesh = make_domain(48, 48, xmin=1 / 4, ymin=1 / 4, width=1 / 2, height=1 / 2)
    x, y = firedrake.SpatialCoordinate(mesh)
    Q = firedrake.FunctionSpace(mesh, "CG", 1)
    p = firedrake.interpolate(x + y, Q)
    q = icepack.interpolate(dataset, Q)

    assert firedrake.norm(p - q) / firedrake.norm(p) < 1e-10
Example #18
0
def test_nearest_neighbor_interpolation():
    n = 32
    array = np.array([[(i + j) / n for j in range(n + 1)] for i in range(n + 1)])
    missing = -9999.0
    array[0, 0] = missing
    array = np.flipud(array)
    dataset = make_rio_dataset(array, missing)

    mesh = make_domain(48, 48, xmin=1 / 4, ymin=1 / 4, width=1 / 2, height=1 / 2)
    x, y = firedrake.SpatialCoordinate(mesh)
    Q = firedrake.FunctionSpace(mesh, "CG", 1)
    p = firedrake.interpolate(x + y, Q)
    q = icepack.interpolate(dataset, Q, method="nearest")

    relative_error = firedrake.norm(p - q) / firedrake.norm(p)
    assert (relative_error > 1e-10) and (relative_error < 1 / n)
Example #19
0
def getModelVarFromTiff(myTiff, Q):
    """Read a model variable from a tiff file using rasterio
    Parameters
    ----------
    myTiff : str
        tiff file with a scalar variable
    Q : firedrake function space
        function space
    Returns
    -------
    firedrake function
        Data from tiff
    """
    if not os.path.exists(myTiff):
        myerror(f'Geometry file {myTiff} does not exist')
    x = rasterio.open(myTiff)
    return icepack.interpolate(x, Q)
Example #20
0
def reduceNearGLBeta(s, sOrig, zF, grounded, Q, thresh, limit=False):
    """Compute beta reduction in area near grounding line where the height
    above floation is less than thresh.

    Parameters
    ----------
    s : firedrake function
        Current surface.
    sOrig : firedrake function
        Original surface.
    zF : firedrake function
        Flotation height.
    grounded : firedrake function
        grounde mask
    Q : firedrake function space
        scaler function space for model
    thresh : float
        Threshold to determine where to reduce beta (zAbove < thresh)
    """
    # compute original height above flotation for grounded region
    sAboveOrig = (sOrig - zF) * grounded
    # avoid negative/zero values
    sAboveOrig = firedrake.max_value(sAboveOrig, 0.0)
    # Current height above flotation with negative values zeroed out.
    sAbove = firedrake.max_value((s - zF) * grounded, 0)
    # mask so only areas less than thresh but grounded
    sMask = (sAbove < thresh) * grounded
    # print(f'{sAbove.dat.data_ro.min()}, {sAbove.dat.data_ro.max()} {thresh}')
    # Inverse mask
    sMaskInv = sMask < 1
    # scale = fraction of original height above flotation
    # Use 5 to avoid potentially large ratio at small values.
    scaleBeta = sAbove / \
        firedrake.max_value(firedrake.min_value(thresh, sAboveOrig), 3)
    if limit:
        scaleBeta = firedrake.min_value(3, scaleBeta)
    scaleBeta = scaleBeta * sMask + sMaskInv
    # scaleBeta = icepack.interpolate(firedrake.min_value(scaleBeta,1.),Q)
    # sqrt so tau = scale * beta^2
    # scaleBeta = icepack.interpolate(firedrake.sqrt(scaleBeta) * grounded, Q)
    # Removed grounded above because grounded is always applied in friction
    scaleBeta = icepack.interpolate(firedrake.sqrt(scaleBeta), Q)
    # print(f'{scaleBeta.dat.data_ro.min()}, {scaleBeta.dat.data_ro.max()}')
    return scaleBeta
Example #21
0
def betaInit(s, h, speed, V, Q, Q1, grounded, inversionParams):
    """Compute intitial beta using 0.5 taud.
    Parameters
    ----------
    s : firedrake function
        model surface elevation
    h : firedrake function
        model thickness
    speed : firedrake function
        modelled speed
    V : firedrake vector function space
        vector function space
    Q : firedrake function space
        scalar function space
    grounded : firedrake function
        Mask with 1s for grounded 0 for floating.
    """
    # Use a result from prior inversion
    checkFile = inversionParams['initFile']
    Quse = Q
    if inversionParams['initWithDeg1']:
        checkFile = f'{inversionParams["inversionResult"]}.deg1'
        Quse = Q1
    if checkFile is not None:
        betaTemp = mf.getCheckPointVars(checkFile, 'betaInv', Quse)['betaInv']
        beta1 = icepack.interpolate(betaTemp, Q)
        return beta1
    # No prior result, so use fraction of taud
    tauD = firedrake.project(-rhoI * g * h * grad(s), V)
    #
    stress = firedrake.sqrt(firedrake.inner(tauD, tauD))
    Print('stress', firedrake.assemble(stress * firedrake.dx))
    fraction = firedrake.Constant(0.95)
    U = max_value(speed, 1)
    C = fraction * stress / U**(1/m)
    if inversionParams['friction'] == 'schoof':
        mExp = 1/m + 1
        U0 = firedrake.Constant(inversionParams['uThresh'])
        C = C * (m/(m+1)) * (U0**mExp + U**mExp)**(1/(m+1))
    beta = firedrake.interpolate(firedrake.sqrt(C) * grounded, Q)
    return beta
Example #22
0
def reduceNearGLBeta(s, sOrig, zF, grounded, Q, thresh, limit=False):
    """Compute beta reduction in area near grounding line where the height
    above floation is less than thresh.

    Parameters
    ----------
    s : firedrake function
        Current surface.
    sOrig : firedrake function
        Original surface.
    zF : firedrake function
        Flotation height.
    grounded : firedrake function
        grounde mask
    Q : firedrake function space
        scaler function space for model
    thresh : float
        Threshold to determine where to reduce beta (zAbove < thresh)
    """
    # compute original height above flotation for grounded region
    sAboveOrig = (sOrig - zF) * grounded
    # avoid negative/zero values
    sAboveOrig = firedrake.max_value(sAboveOrig, 0.001)
    # Current height above flotation with negative values zeroed out.
    sAbove = firedrake.max_value((s - zF) * grounded, 0)
    # mask so only areas less than thresh but grounded
    sMask = (sAbove <= thresh) * grounded
    # Inverse mask
    sMaskInv = sMask < 1
    # scale = fraction of of original height above flotation
    scaleBeta = sAbove / \
        firedrake.max_value(firedrake.min_value(thresh, sAboveOrig), 5)
    if limit:
        scaleBeta = firedrake.min_value(3, scaleBeta)
    scaleBeta = scaleBeta * sMask + sMaskInv
    # scaleBeta = icepack.interpolate(firedrake.min_value(scaleBeta,1.),Q)
    # sqrt so tau = scale * beta^2
    scaleBeta = icepack.interpolate(firedrake.sqrt(scaleBeta) * grounded, Q)
    return scaleBeta
Example #23
0
def thetaInit(Ainit, Q, Q1, grounded, floating, inversionParams):
    """Compute intitial theta on the ice shelf (not grounded).
    Parameters
    ----------
    Ainit : firedrake function
        A Glens flow law A
    Q : firedrake function space
        scalar function space
    Q1 : firedrake function space
        1 deg scalar function space used with 'initWithDeg1'
    grounded : firedrake function
        Mask with 1s for grounded 0 for floating.
    floating : firedrake function
        Mask with 1s for floating 0 for grounded.
    Returns
    -------
    theta : firedrake function
        theta for floating ice
    """
    # Get initial file if there is one to init inversion
    checkFile = inversionParams['initFile']
    Quse = Q
    # Use degree 1 solution if prompted
    if inversionParams['initWithDeg1']:
        checkFile = f'{inversionParams["inversionResult"]}.deg1'
        Quse = Q1
    # Now check if there is a file specificed, and if so, init with that
    if checkFile is not None:
        Print(f'Init. with theta: {checkFile}')
        thetaTemp = mf.getCheckPointVars(checkFile,
                                         'thetaInv', Quse)['thetaInv']
        thetaInit = icepack.interpolate(thetaTemp, Q)
        return thetaInit
    # No initial theta, so use initial A to init inversion
    Atheta = mf.firedrakeSmooth(Ainit, alpha=1000)
    theta = firedrake.ln(Atheta)
    theta = firedrake.interpolate(theta, Q)
    return theta
Example #24
0
def getModelGeometry(geometryFile,
                     Q,
                     smooth=False,
                     alpha=2e3,
                     zFirn=0.,
                     rhoI=rhoI,
                     rhoW=rhoW):
    """Load geometry data for model and create firedrake interpolators
    Parameters
    ----------
    geometryFile : str
        Path to a yaml file with bed, surface, thickness, and floatMask
    Q : firedrake function space
        function space
    smooth: bool, optional
        apply firedrakeSmooth to the result
    alpha : float, optional
        parameter that controls the amount of smoothing, which is approximately
        the smoothing lengthscale in m, by default 2e3
    zFirn : float, optional
        Correct elevation for firn thickness (m), by default 14 m
    rhoI : [type], optional
        [description], by default rhoI
    rhoW : [type], optional
        [description], by default rhoW
    Returns
    -------
    zb firedrake interp function
        bed elevation (m)
    s firedrake interp function
        surface elevation (m)
    h firedrake interp function
        ice thickness (m)
    floatMask firedrake interp function
        mask with 1 for floating 0 for grounded
    """
    # load geometry files
    try:
        with open(geometryFile) as fp:
            geom = yaml.load(fp, Loader=yaml.FullLoader)
    except Exception:
        myerror(f'Could not open geomtery file: {geometryFile}')
    # Load and convert to firedrake
    fd = {'bed': None, 'surface': None, 'thickness': None, 'floatMask': None}
    # Read and process data
    for myVar in geom:
        print(myVar, geom[myVar])
        fd[myVar] = getModelVarFromTiff(geom[myVar], Q)
        if smooth and alpha > 1 and myVar != 'floatMask':
            fd[myVar] = firedrakeSmooth(fd[myVar], alpha=alpha)
        if myVar == 'surface':
            fd[myVar] = icepack.interpolate(fd[myVar] - zFirn, Q)
    # If data are smoothed, regenerate a new mask from smoothed results.
    if smooth and alpha > 1:
        zF = flotationHeight(fd['bed'], Q, rhoI=rhoI, rhoW=rhoW)
        fd['floatMask'], g = flotationMask(fd['surface'],
                                           zF,
                                           Q,
                                           rhoI=rhoI,
                                           rhoW=rhoW)
    else:
        g = icepack.interpolate(fd['floatMask'] < 1, Q)
    # Don't allow negative values
    for myVar in ['surface', 'thickness']:
        fd[myVar] = icepack.interpolate(firedrake.max_value(10, fd[myVar]), Q)
    for myVar in geom:
        print(f'{myVar} min/max {fd[myVar].dat.data_ro.min():10.2f} '
              f'{fd[myVar].dat.data_ro.max():10.2f}')
    return fd['bed'], fd['surface'], fd['thickness'], fd['floatMask'], g
Example #25
0
def test_interpolating():
    u = icepack.interpolate(discretization, lambda x: x[0] * x[1])
    assert u.discretization is discretization
    assert icepack.max(u) <= 1.0
from icepack import rho_ice, rho_water, gravity

# All of this is similar to example 1.
import make_mesh
length, width = 20.0e3, 20.0e3
make_mesh.main(length, width, "rectangle")

mesh = icepack.read_msh("rectangle.msh")
mesh.refine_global(3)
discretization = icepack.make_discretization(mesh, 1)

h0, dh = 500.0, 250.0
def thickness(x):
    return h0 - dh * x[0] / length

h = icepack.interpolate(discretization, thickness)
u0, du = 200.0, 200.0
v = icepack.interpolate(discretization,
                        lambda x: u0 + du * x[0] / length, lambda x: 0.0)
theta = icepack.interpolate(discretization, lambda x: 254.15)


# For a grounded ice stream, we also need to pick the surface elevation (or
# equivalently the bed elevation). Make the surface elevation at 50m above
# flotation.
def surface(x):
    return (1 - rho_ice / rho_water) * thickness(x) + 20
s = icepack.interpolate(discretization, surface)

# We also need to set the friction coefficient, which we'll choose to be a low
# value throughout but with a jump in the center of the domain.
Example #27
0
def test_interpolating_to_mesh():
    # Make the mesh the square `[1/4, 3/4] x [1/4, 3/4]`
    nx, ny = 32, 32
    mesh = firedrake.UnitSquareMesh(nx, ny)
    x, y = firedrake.SpatialCoordinate(mesh)
    Vc = mesh.coordinates.function_space()
    f = firedrake.interpolate(
        firedrake.as_vector((x / 2 + 1 / 4, y / 2 + 1 / 4)), Vc)
    mesh.coordinates.assign(f)

    # Set up the geometry of the gridded data set
    x0 = (0, 0)
    n = 32
    dx = 1.0 / n
    transform = rasterio.transform.from_origin(west=0.0,
                                               north=1.0,
                                               xsize=dx,
                                               ysize=dx)

    # Interpolate a scalar field
    array = np.array([[dx * (i + j) for j in range(n + 1)]
                      for i in range(n + 1)])
    missing = -9999.0
    array[0, 0] = missing
    array = np.flipud(array)

    memfile = rasterio.MemoryFile(ext='.tif')
    opts = {
        'driver': 'GTiff',
        'count': 1,
        'width': n,
        'height': n,
        'transform': transform,
        'nodata': -9999
    }

    with memfile.open(**opts) as dataset:
        dataset.write(array, indexes=1)
    dataset = memfile.open()

    Q = firedrake.FunctionSpace(mesh, family='CG', degree=1)
    p = firedrake.interpolate(x + y, Q)
    q = icepack.interpolate(dataset, Q)

    assert firedrake.norm(p - q) / firedrake.norm(p) < 1 / n

    # Interpolate a vector field
    array_vx = np.copy(array)
    array_vy = np.array([[dx * (j - i) for j in range(n + 1)]
                         for i in range(n + 1)])
    array_vy[-1, -1] = -9999.0
    array_vy = np.flipud(array_vy)

    memfile_vx, memfile_vy = rasterio.MemoryFile(), rasterio.MemoryFile()
    with memfile_vx.open(**opts) as vx, memfile_vy.open(**opts) as vy:
        vx.write(array_vx, indexes=1)
        vy.write(array_vy, indexes=1)
    vx, vy = memfile_vx.open(), memfile_vy.open()

    V = firedrake.VectorFunctionSpace(mesh, family='CG', degree=1)
    u = firedrake.interpolate(firedrake.as_vector((x + y, x - y)), V)
    v = icepack.interpolate((vx, vy), V)

    assert firedrake.norm(u - v) / firedrake.norm(u) < 1 / n
def velocity(x):
    from icepack import rho_ice, rho_water, gravity, rate_factor
    u0 = 100.0
    rho = rho_ice * (1 - rho_ice / rho_water)
    A = (rho * gravity * h0 / 4)**3 * rate_factor(temp)
    q = 1 - (1 - (dh / h0) * (x[0] / length))**4
    return u0 + 0.25 * A * q * length * h0 / dh


# Read the mesh from a file, refine it a bit, and make a discretization.
mesh = icepack.read_msh("rectangle.msh")
mesh.refine_global(3)
discretization = icepack.make_discretization(mesh, 1)

# Interpolate all the exact data to the discretization we just made.
h = icepack.interpolate(discretization, thickness)
u0 = icepack.interpolate(discretization, velocity, lambda x: 0.0)
theta = icepack.interpolate(discretization, temperature)


# --- New stuff! ---

# The boundary segments of the mesh have different numeric IDs in order to help
# set where Dirichlet or Neumann boundary conditions apply. We can check what
# they are by plotting the mesh.
fig, ax = plt.subplots()
ax.set_aspect('equal')
icepack.plot.plot_mesh(ax, mesh)
plt.show(fig)

# From this figure we can see that boundary region 1 is where we want Dirichlet
Example #29
0
def main():
    ''' Main for foward model simulation '''
    forwardParams, inversionParams = parsePigForwardArgs()
    print(forwardParams)
    #
    # Read mesh and setup function spaces
    mesh, Q, V, meshOpts = \
        mf.setupMesh(forwardParams['mesh'], degree=forwardParams['degree'],
                     meshOversample=inversionParams['meshOversample'])
    beta0, theta0, A0, s0, h0, zb, floating0, grounded0, uInv, uObs = \
        mf.getInversionData(forwardParams['inversionResult'], Q, V)
    # Compute masks for combining A0 with theta0
    groundedSmooth, floatingSmooth = setupTaperedMasks(inversionParams,
                                                       grounded0, floating0)
    SMB = readSMB(forwardParams['SMB'], Q)
    #
    meltModel, meltParams = setupMelt(forwardParams)
    # Setup ice stream model
    frictionLaw = setupFriction(forwardParams)
    #
    forwardModel = icepack.models.IceStream(friction=frictionLaw,
                                            viscosity=taperedViscosity)
    opts = {
        'dirichlet_ids': meshOpts['dirichlet_ids'],
        'diagnostic_solver_parameters': {
            'max_iterations': 150
        }
    }
    forwardSolver = icepack.solvers.FlowSolver(forwardModel, **opts)
    # initial solve
    uThresh = firedrake.Constant(forwardParams['uThresh'])
    u0 = forwardSolver.diagnostic_solve(velocity=uObs,
                                        thickness=h0,
                                        surface=s0,
                                        fluidity=A0,
                                        beta=beta0,
                                        theta=theta0,
                                        grounded=grounded0,
                                        floating=floating0,
                                        groundedSmooth=groundedSmooth,
                                        floatingSmooth=floatingSmooth,
                                        uThresh=uThresh)
    # Get fresh or reloaded summary data - reset restart if not data
    summaryData = initSummary(grounded0, floating0, h0, u0, meltModel,
                              meltParams, SMB, Q, mesh, forwardParams)
    #
    chk = setupOutputs(forwardParams, inversionParams, meltParams)
    deltaT = forwardParams['deltaT']
    # copy original state
    if not forwardParams['restart']:
        startYear = 0
        h, hLast, s, u, zF, grounded, floating = \
            initialState(h0, s0, u0, zb, grounded0, floating0, Q)
    else:  # load state to restart
        startYear, h, hLast, s, u, zF, grounded, floating = \
            doRestart(forwardParams, zb, deltaT, chk, Q, V)
    # Sanity/consistency check
    print(f'area {summaryData["area"]}')
    mf.velocityError(u0, uInv, summaryData['area'], 'Difference with uInv')
    mf.velocityError(u0, uObs, summaryData['area'], 'Difference with uObs')
    mf.velocityError(uInv, uObs, summaryData['area'],
                     'Difference with uInv/uObs')
    # setup plots
    plotData = {
        'plotResult': forwardParams['plotResult'],
        'mapPlotLimits': forwardParams['mapPlotLimits'],
        'figM': None,
        'axesM': None
    }
    setupTimesSeriesPlots(plotData, forwardParams)
    setupProfilePlots(plotData, forwardParams, h)
    profilePlots(-1e-12, plotData, uObs, s0, h0, zb, zF, None, Q, first=True)
    #
    beginTime = datetime.now()
    betaScale = grounded * 1
    beta = beta0
    print('Loop')
    if startYear > forwardParams['nYears']:
        myerror(f'startYear ({startYear}) is greater than nYears '
                f'({forwardParams["nYears"]}). Restart '
                f'{forwardParams["nYears"]} so sim may be done')
    times = np.arange(startYear, forwardParams['nYears'] + deltaT, deltaT)
    for t in np.around(times, decimals=6):
        #
        hLast = h.copy(deepcopy=True)  # Save for next summary calc
        trend = meltTrend(t, forwardParams)
        melt = meltModel(h, floating, meltParams, Q, u, trend=trend) * \
            meltAnomaly(t, forwardParams)
        a = icepack.interpolate((SMB + melt) * waterToIce, Q)
        #
        h = forwardSolver.prognostic_solve(forwardParams['deltaT'],
                                           thickness=h,
                                           velocity=u,
                                           accumulation=a,
                                           thickness_inflow=h0)
        # Don't allow to go too thin.
        h = checkThickness(h, 30, Q, t, h0)
        # Compute surface and masks
        s = computeSurface(h, zb, Q)
        floating, grounded = mf.flotationMask(s, zF, Q)
        # Scale beta near gl
        if t > forwardParams['tBetaScale']:
            betaScale = mf.reduceNearGLBeta(s, s0, zF, grounded, Q,
                                            forwardParams['GLThresh'])
            beta = icepack.interpolate(beta0 * betaScale, Q)
        else:
            beta = beta0
        uThresh = firedrake.Constant(forwardParams['uThresh'])
        u = forwardSolver.diagnostic_solve(velocity=u,
                                           thickness=h,
                                           surface=s,
                                           fluidity=A0,
                                           beta=beta,
                                           theta=theta0,
                                           uThresh=uThresh,
                                           floating=floating,
                                           grounded=grounded,
                                           groundedSmooth=groundedSmooth,
                                           floatingSmooth=floatingSmooth)
        print('.', end='', flush=True)
        #
        # Compute summary data and plot if indicated
        if computeSummaryData(summaryData, h, s, u, a, melt, SMB, grounded,
                              floating, t, Q, mesh, deltaT, beginTime):
            if plotData['plotResult']:  # Only do final plot (below)
                mapPlots(plotData, t, melt, betaScale, h, hLast, deltaT, Q)
            # For now ouput fields at same interval as summary data
            outputTimeStep(t,
                           chk,
                           h=h,
                           s=s,
                           u=u,
                           grounded=grounded,
                           floating=floating)
            saveSummaryData(forwardParams, summaryData, tmp=True)
        #
        timeSeriesPlots(t, plotData, summaryData)
        profilePlots(t, plotData, u, s, h, zb, zF, melt, Q)
    #
    # End Simulation so save results
    mapPlots(plotData, t, melt, betaScale, h, hLast, deltaT, Q)
    saveSummaryData(forwardParams, summaryData)
    savePlots(plotData, forwardParams)
    # Show final result if requested
    if plotData['plotResult']:
        print('Show Plot')
        plt.show()
Example #30
0
def checkThickness(h, thresh, Q, t, h0):
    ''' Do not let ice get too thin
    '''
    #
    h = icepack.interpolate(firedrake.max_value(thresh, h), Q)
    return h
Example #31
0
def computeSurface(h, zb, Q):
    '''Hack of icepack version to uses different rhoI/rhoW
    '''
    s = firedrake.max_value(h + zb, h * (1 - rhoI / rhoW))
    return icepack.interpolate(s, Q)
Example #32
0
plt.show(fig)

# This mesh is too coarse. We can refine all the cells for better resolution.
mesh.refine_global(4)
print("Number of vertices, cells: {0} {1}"
      .format(mesh.n_vertices(), mesh.n_active_cells()))

# To represent fields defined over this domain, we first need to create a
# finite element discretization. The second argument is the polynomial degree.
discretization = icepack.make_discretization(mesh, 1)

# To test this out, we'll make a random Fourier series.
def f(x):
    k1 = (2.0, 3.0)
    k2 = (-5.0, 1.0)
    phi1 = 2 * np.pi * (k1[0] * x[0] / length + k1[1] * x[1] / width)
    phi2 = 2 * np.pi * (k2[0] * x[0] / length + k2[1] * x[1] / width)
    return np.sin(phi1) + np.sin(phi2)

# We'll be using this function a lot. It takes an analytically defined field
# `f` and interpolates it to a finite element discretization. The fields we'll
# be interpolating are input data, either defined by hand or from observations.
u = icepack.interpolate(discretization, f)

# Finally, to make sure it's all working right, we can plot it.
import icepack.plot
fig, ax = plt.subplots()
icepack.plot.plot_field(ax, u)
plt.show(fig)

preprocess.main()

# Read in the observational data.
vx_obs = icepack.read_arc_ascii_grid(open("ross-vx.txt", "r"))
vy_obs = icepack.read_arc_ascii_grid(open("ross-vy.txt", "r"))
h_obs = icepack.read_arc_ascii_grid(open("ross-h.txt", "r"))

mesh = icepack.read_msh("ross.msh")
fig, ax = plt.subplots()
ax.set_aspect('equal')
icepack.plot.plot_mesh(ax, mesh)
plt.show(fig)

discretization = icepack.make_discretization(mesh, 1)

v = icepack.interpolate(discretization, vx_obs, vy_obs)
h = icepack.interpolate(discretization, h_obs)

# Make a dumb guess for the ice temperature. In "real life", you would want to
# use an inverse method that would tune the temperature to fit observations.
theta = icepack.interpolate(discretization, lambda x: 253.0)

# Solve for the ice velocity, assuming this guess for the temperature.
dirichlet_boundary_ids = {2, 3, 4, 5}
ice_shelf = icepack.IceShelf(dirichlet_boundary_ids)
u = ice_shelf.solve(h, theta, v)

print("Misfit between computed and observed velocities: {}"
      .format(icepack.dist(u, v) / icepack.norm(v)))

fig, axes = plt.subplots(ncols=2, sharey=True)
import numpy as np
import matplotlib.pyplot as plt
import icepack, icepack.plot

import preprocess
preprocess.main()

# All of this is the same as example 3.
vx_obs = icepack.read_arc_ascii_grid(open("ross-vx.txt", "r"))
vy_obs = icepack.read_arc_ascii_grid(open("ross-vy.txt", "r"))
h_obs = icepack.read_arc_ascii_grid(open("ross-h.txt", "r"))

mesh = icepack.read_msh("ross.msh")
discretization = icepack.make_discretization(mesh, 1)

v = icepack.interpolate(discretization, vx_obs, vy_obs)
h0 = icepack.interpolate(discretization, h_obs)
theta = icepack.interpolate(discretization, lambda x: 253.0)

dirichlet_boundary_ids = {2, 3, 4, 5}
ice_shelf = icepack.IceShelf(dirichlet_boundary_ids);
u0 = ice_shelf.solve(h0, theta, v)

# And this should be familiar from example 2.
dt = min(1.0, icepack.compute_timestep(0.5, u0))

# Make a steady-state accumulation rate field.
a0 = icepack.interpolate(discretization, lambda x: 0.0)
a0 = (ice_shelf.solve(dt, h0, a0, u0, h0) - h0) / dt

# Really hacky way to compute the average of a field.