예제 #1
0
    def advective_flux(self, **kwargs):
        keys = ('energy', 'velocity', 'vertical_velocity', 'thickness',
                'energy_inflow', 'energy_surface')
        keys_alt = ('E', 'u', 'w', 'h', 'E_inflow', 'E_surface')
        E, u, w, h, E_inflow, E_surface = get_kwargs_alt(
            kwargs, keys, keys_alt)

        Q = E.function_space()
        ψ = firedrake.TestFunction(Q)

        U = firedrake.as_vector((u[0], u[1], w))
        flux_cells = -E * inner(U, grad(ψ)) * h * dx

        mesh = Q.mesh()
        ν = facet_normal_2(mesh)
        outflow = firedrake.max_value(inner(u, ν), 0)
        inflow = firedrake.min_value(inner(u, ν), 0)

        flux_outflow = (E * outflow * ψ * h * ds_v +
                        E * firedrake.max_value(-w, 0) * ψ * h * ds_b +
                        E * firedrake.max_value(+w, 0) * ψ * h * ds_t)

        flux_inflow = (E_inflow * inflow * ψ * h * ds_v +
                       E_surface * firedrake.min_value(-w, 0) * ψ * h * ds_b +
                       E_surface * firedrake.min_value(+w, 0) * ψ * h * ds_t)

        return flux_cells + flux_outflow + flux_inflow
예제 #2
0
def side_friction(**kwargs):
    r"""Return the side wall friction part of the action functional

    The component of the action functional due to friction along the side
    walls of the domain is

    .. math::
       E(u) = -\frac{m}{m + 1}\int_\Gamma h\tau(u, C_s)\cdot u\; ds

    where :math:`\tau(u, C_s)` is the side wall shear stress, :math:`ds`
    is the element of surface area and :math:`\Gamma` are the side walls.
    Side wall friction is relevant for glaciers that flow through a fjord
    with rock walls on either side.
    """
    u, h = get_kwargs_alt(kwargs, ('velocity', 'thickness'), ('u', 'h'))
    Cs = kwargs.get('side_friction', kwargs.get('Cs', firedrake.Constant(0.)))

    mesh = u.ufl_domain()
    if mesh.geometric_dimension() == 2:
        ν = firedrake.FacetNormal(mesh)
    else:
        ν = facet_normal_2(mesh)

    u_t = u - inner(u, ν) * ν
    τ = friction_stress(u_t, Cs)
    return -m / (m + 1) * h * inner(τ, u_t)
예제 #3
0
def normal_flow_penalty(**kwargs):
    r"""Return the penalty for flow normal to the domain boundary

    For problems where a glacier flows along some boundary, e.g. a fjord
    wall, the velocity has to be parallel to this boundary. Rather than
    enforce this boundary condition directly, we add a penalty for normal
    flow to the action functional.
    """
    u, = get_kwargs_alt(kwargs, ('velocity', ), ('u', ))
    scale = kwargs.get('scale', firedrake.Constant(1.))

    mesh = u.ufl_domain()
    if mesh.geometric_dimension() == 2:
        ν = firedrake.FacetNormal(mesh)
    elif mesh.geometric_dimension() == 3:
        ν = facet_normal_2(mesh)

    L = diameter(mesh)
    δx = firedrake.FacetArea(mesh)

    # Get the polynomial degree in the horizontal direction of the velocity
    # field -- if extruded, the element degree is a tuple of the horizontal
    # and vertical degrees.
    degree = u.ufl_function_space().ufl_element().degree()
    if isinstance(degree, tuple):
        d = degree[0]
    else:
        d = degree
    exponent = kwargs.get('exponent', d + 1)

    penalty = scale * (L / δx)**exponent
    return 0.5 * penalty * inner(u, ν)**2
예제 #4
0
def terminus(**kwargs):
    r"""Return the terminal stress part of the ice stream action functional

    The power exerted due to stress at the ice calving terminus :math:`\Gamma`
    is

    .. math::
       E(u) = \frac{1}{2}\int_\Gamma\left(\rho_Igh^2 - \rho_Wgd^2\right)
       u\cdot \nu\, ds

    where :math:`d` is the water depth at the terminus. We assume that sea
    level is at :math:`z = 0` for purposes of calculating the water depth.

    Parameters
    ----------
    velocity : firedrake.Function
    thickness : firedrake.Function
    surface : firedrake.Function
    """
    keys = ('velocity', 'thickness', 'surface')
    keys_alt = ('u', 'h', 's')
    u, h, s = get_kwargs_alt(kwargs, keys, keys_alt)

    d = firedrake.min_value(s - h, 0)
    τ_I = ρ_I * g * h**2 / 2
    τ_W = ρ_W * g * d**2 / 2

    ν = firedrake.FacetNormal(u.ufl_domain())
    return (τ_I - τ_W) * inner(u, ν)
예제 #5
0
    def sources(self, **kwargs):
        keys = ('energy', 'thickness', 'heat', 'heat_bed')
        keys_alt = ('E', 'h', 'q', 'q_bed')
        E, h, q, q_bed = get_kwargs_alt(kwargs, keys, keys_alt)

        Q = E.function_space()
        ψ = firedrake.TestFunction(Q)

        internal_sources = q * ψ * h * dx
        boundary_sources = q_bed * ψ * ds_b

        return internal_sources + boundary_sources
예제 #6
0
    def diffusive_flux(self, **kwargs):
        keys = ('energy', 'thickness', 'energy_surface')
        keys_alt = ('E', 'h', 'E_surface')
        E, h, E_surface = get_kwargs_alt(kwargs, keys, keys_alt)

        Q = E.function_space()
        ψ = firedrake.TestFunction(Q)

        κ = self.surface_exchange_coefficient
        cell_flux = α * E.dx(2) * ψ.dx(2) / h * dx
        surface_flux = κ * α * (E - E_surface) * ψ / h * ds_t

        return cell_flux + surface_flux
예제 #7
0
    def __call__(self, dt, **kwargs):
        keys = ('thickness', 'velocity', 'accumulation')
        keys_alt = ('h', 'u', 'a')
        h, u, a = utilities.get_kwargs_alt(kwargs, keys, keys_alt)
        h_inflow = kwargs.get('thickness_inflow', kwargs.get('h_inflow', h))

        Q = h.function_space()
        q = firedrake.TestFunction(Q)

        grad, ds, n = self.grad, self.ds, self.facet_normal(Q.mesh())
        u_n = inner(u, n)
        flux_cells = -inner(h * u, grad(q)) * dx
        flux_out = h * firedrake.max_value(u_n, 0) * q * ds
        flux_in = h_inflow * firedrake.min_value(u_n, 0) * q * ds
        accumulation = a * q * dx
        return accumulation - (flux_in + flux_out + flux_cells)
예제 #8
0
def terminus(**kwargs):
    r"""Return the terminus stress part of the ice shelf action functional

    The power exerted due to stress at the calving terminus :math:`\Gamma` is

    .. math::
       E(u) = \int_\Gamma\varrho gh^2u\cdot\nu\; ds

    We assume that sea level is at :math:`z = 0` for calculating the water
    depth.
    """
    u, h = get_kwargs_alt(kwargs, ('velocity', 'thickness'), ('u', 'h'))

    mesh = u.ufl_domain()
    ν = firedrake.FacetNormal(mesh)
    ρ = ρ_I * (1 - ρ_I / ρ_W)
    return 0.5 * ρ * g * h**2 * inner(u, ν)
예제 #9
0
    def sources(self, **kwargs):
        keys = ('damage', 'velocity', 'strain_rate', 'membrane_stress')
        keys_alt = ('D', 'u', 'ε', 'M')
        D, u, ε, M = get_kwargs_alt(kwargs, keys, keys_alt)

        # Increase/decrease damage depending on stress and strain rates
        ε_1 = eigenvalues(ε)[0]
        σ_e = sqrt(inner(M, M) - det(M))

        ε_h = firedrake.Constant(self.healing_strain_rate)
        σ_d = firedrake.Constant(self.damage_stress)
        γ_h = firedrake.Constant(self.healing_rate)
        γ_d = firedrake.Constant(self.damage_rate)

        healing = γ_h * min_value(ε_1 - ε_h, 0)
        fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.) * (1 - D)

        return healing + fracture
예제 #10
0
    def flux(self, **kwargs):
        keys = ('damage', 'velocity', 'damage_inflow')
        keys_alt = ('D', 'u', 'D_inflow')
        D, u, D_inflow = get_kwargs_alt(kwargs, keys, keys_alt)

        Q = D.function_space()
        φ = firedrake.TestFunction(Q)

        mesh = Q.mesh()
        n = firedrake.FacetNormal(mesh)

        u_n = max_value(0, inner(u, n))
        f = D * u_n
        flux_faces = (f('+') - f('-')) * (φ('+') - φ('-')) * dS
        flux_cells = -D * div(u * φ) * dx
        flux_out = D * max_value(0, inner(u, n)) * φ * ds
        flux_in = D_inflow * min_value(0, inner(u, n)) * φ * ds

        return flux_faces + flux_cells + flux_out + flux_in
예제 #11
0
def penalty(**kwargs):
    r"""Return the penalty of the shallow ice action functional

    The penalty for the shallow ice action functional is

    .. math::
        E(u) = \frac{1}{2}\int_\Omega l^2\nabla u\cdot \nabla u\; dx

    Parameters
    ----------
    velocity : firedrake.Function
    thickness : firedrake.Function

    Returns
    -------
    firedrake.Form
    """
    u, h = get_kwargs_alt(kwargs, ('velocity', 'thickness'), ('u', 'h'))
    l = 2 * firedrake.max_value(firedrake.CellDiameter(u.ufl_domain()), 5 * h)
    return .5 * l**2 * inner(grad(u), grad(u))
예제 #12
0
    def sources(self, **kwargs):
        keys = ('damage', 'velocity', 'fluidity')
        keys_alt = ('D', 'u', 'A')
        D, u, A = get_kwargs_alt(kwargs, keys, keys_alt)

        # Increase/decrease damage depending on stress and strain rates
        ε = sym(grad(u))
        ε_1 = eigenvalues(ε)[0]

        σ = M(ε, A)
        σ_e = sqrt(inner(σ, σ) - det(σ))

        ε_h = firedrake.Constant(self.healing_strain_rate)
        σ_d = firedrake.Constant(self.damage_stress)
        γ_h = firedrake.Constant(self.healing_rate)
        γ_d = firedrake.Constant(self.damage_rate)

        healing = γ_h * min_value(ε_1 - ε_h, 0)
        fracture = γ_d * conditional(σ_e - σ_d > 0, ε_1, 0.) * (1 - D)

        return healing + fracture
예제 #13
0
def terminus(**kwargs):
    r"""Return the terminal stress part of the hybrid model action functional

    The power exerted due to stress at the calving terminus :math:`\Gamma` is

    .. math::
        E(u) = \int_\Gamma\int_0^1\left(\rho_Ig(1 - \zeta) -
        \rho_Wg(\zeta_{\text{sl}} - \zeta)_+\right)u\cdot\nu\; h\, d\zeta\; ds

    where :math:`\zeta_\text{sl}` is the relative depth to sea level and the
    :math:`(\zeta_\text{sl} - \zeta)_+` denotes only the positive part.

    Parameters
    ----------
    u : firedrake.Function
        ice velocity
    h : firedrake.Function
        ice thickness
    s : firedrake.Function
        ice surface elevation
    ice_front_ids : list of int
        numeric IDs of the parts of the boundary corresponding to the
        calving front
    """
    keys = ('velocity', 'thickness', 'surface')
    keys_alt = ('u', 'h', 's')
    u, h, s = get_kwargs_alt(kwargs, keys, keys_alt)

    mesh = u.ufl_domain()
    zdegree = u.ufl_element().degree()[1]

    ζ = firedrake.SpatialCoordinate(mesh)[2]
    b = s - h
    ζ_sl = firedrake.max_value(-b, 0) / h
    p_W = ρ_W * g * h * _pressure_approx(zdegree + 1)(ζ, ζ_sl)
    p_I = ρ_I * g * h * (1 - ζ)

    ν = facet_normal_2(mesh)
    return (p_I - p_W) * inner(u, ν) * h
예제 #14
0
def gravity(**kwargs):
    r"""Return the gravitational part of the ice stream action functional

    The gravitational part of the hybrid model action functional is

    .. math::
       E(u) = -\int_\Omega\int_0^1\rho_Ig\nabla s\cdot u\; h\, d\zeta\; dx

    Parameters
    ----------
    u : firedrake.Function
        ice velocity
    h : firedrake.Function
        ice thickness
    s : firedrake.Function
        ice surface elevation
    """
    keys = ('velocity', 'thickness', 'surface')
    keys_alt = ('u', 'h', 's')
    u, h, s = get_kwargs_alt(kwargs, keys, keys_alt)

    return -ρ_I * g * inner(grad_2(s), u) * h
예제 #15
0
def gravity(**kwargs):
    r"""Return the gravitational part of the ice shelf action functional

    The gravitational part of the ice shelf action functional is

    .. math::
        E(u) = -\frac{1}{2}\int_\Omega\varrho g\nabla h^2\cdot u\; dx

    Parameters
    ----------
    u : firedrake.Function
        ice velocity
    h : firedrake.Function
        ice thickness

    Returns
    -------
    firedrake.Form
    """
    u, h = get_kwargs_alt(kwargs, ('velocity', 'thickness'), ('u', 'h'))

    ρ = ρ_I * (1 - ρ_I / ρ_W)
    return -0.5 * ρ * g * inner(grad(h**2), u)
예제 #16
0
def viscosity(**kwargs):
    r"""Return the viscous part of the hybrid model action functional

    The viscous component of the action for the hybrid model is

    .. math::
        E(u) = \frac{n}{n + 1}\int_\Omega\int_0^1\left(
        M : \dot\varepsilon_x + \tau_z\cdot\varepsilon_z\right)h\, d\zeta\; dx

    where :math:`M(\dot\varepsilon, A)` is the membrane stress tensor and
    :math:`\tau_z` is the vertical shear stress vector.

    This form assumes that we're using the fluidity parameter instead
    the rheology parameter, the temperature, etc. To use a different
    variable, you can implement your own viscosity functional and pass it
    as an argument when initializing model objects to use your functional
    instead.

    Keyword arguments
    -----------------
    velocity : firedrake.Function
    surface : firedrake.Function
    thickness : firedrake.Function
    fluidity : firedrake.Function
        `A` in Glen's flow law

    Returns
    -------
    firedrake.Form
    """
    keys = ('velocity', 'thickness', 'surface', 'fluidity')
    keys_alt = ('u', 'h', 's', 'A')
    u, h, s, A = get_kwargs_alt(kwargs, keys, keys_alt)

    ε_x, ε_z = horizontal_strain(u, s, h), vertical_strain(u, h)
    M, τ_z = stresses(ε_x, ε_z, A)
    return n / (n + 1) * (inner(M, ε_x) + inner(τ_z, ε_z)) * h
예제 #17
0
def gravity(**kwargs):
    r"""Return the gravity term for the shallow ice action functional

    The gravity function for the shallow ice action functional is

    .. math::
        E(u) = \int_\Omega\frac{2A(\varrho_I g)**n}{n+2} (\nabla h^2\cdot u) h^{n+1} \nabla s^{n-1}\; dx

    Parameters
    ----------
    velocity : firedrake.Function
    thickness : firedrake.Function
    surface : firedrake.Function
    fluidity : firedrake.Function or firedrake.Constant

    Returns
    -------
    firedrake.Form
    """
    keys = ('velocity', 'thickness', 'surface', 'fluidity')
    keys_alt = ('u', 'h', 's', 'A')
    u, h, s, A = get_kwargs_alt(kwargs, keys, keys_alt)

    return (2 * A * (ρ_I * g)**n / (n + 2)) * h**(n + 1) * grad(s)**(n - 1) * inner(grad(s), u)