예제 #1
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
예제 #2
0
def norm(u, norm_type="L2"):
    r"""Compute the norm of a field

    Computes one of any number of norms of a scalar or vector field. The
    available options are:

    - ``L2``: :math:`\|u\|^2 = \int_\Omega|u|^2dx`

    - ``H01``: :math:`\|u\|^2 = \int_\Omega|\nabla u|^2dx`

    - ``H1``: :math:`\|u\|^2 = \int_\Omega\left(|u|^2 + L^2|\nabla u|^2\right)dx`

    - ``L1``: :math:`\|u\| = \int_\Omega|u|dx`

    - ``TV``: :math:`\|u\| = \int_\Omega|\nabla u|dx`

    - ``Linfty``: :math:`\|u\| = \max_{x\in\Omega}|u(x)|`

    The extra factor :math:`L` in the :math:`H^1` norm is the diameter of
    the domain in the infinity metric. This extra factor is included to
    make the norm scale appropriately with the size of the domain.
    """
    if norm_type == "L2":
        form, p = inner(u, u) * dx, 2

    if norm_type == "H01":
        form, p = inner(grad(u), grad(u)) * dx, 2

    if norm_type == "H1":
        L = utilities.diameter(u.ufl_domain())
        form, p = inner(u, u) * dx + L**2 * inner(grad(u), grad(u)) * dx, 2

    if norm_type == "L1":
        form, p = sqrt(inner(u, u)) * dx, 1

    if norm_type == "TV":
        form, p = sqrt(inner(grad(u), grad(u))) * dx, 1

    if norm_type == "Linfty":
        data = u.dat.data_ro
        if len(data.shape) == 1:
            local_max = np.max(np.abs(data))
        elif len(data.shape) == 2:
            local_max = np.max(np.sqrt(np.sum(data**2, 1)))

        return u.comm.allreduce(local_max, op=max)

    return assemble(form)**(1 / p)
예제 #3
0
def normal_flow_penalty(u, scale=1.0, exponent=None, side_wall_ids=()):
    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.
    """
    mesh = u.ufl_domain()
    ν = firedrake.FacetNormal(mesh)
    L = utilities.diameter(mesh)
    δx = firedrake.CellSize(mesh)
    d = u.ufl_function_space().ufl_element().degree()
    exponent = d + 1 if exponent is None else exponent
    penalty = scale * (L / δx)**exponent
    return 0.5 * penalty * inner(u, ν)**2 * ds(tuple(side_wall_ids))
예제 #4
0
def normal_flow_penalty(u, h, scale=1.0, exponent=None, side_wall_ids=()):
    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.
    """
    mesh = u.ufl_domain()
    ν = facet_normal_2(mesh)

    # Note that this quantity has units of [length] x [dimensionless] because
    # the mesh has a "thickness" of 1! If it had dimensions of physical
    # thickness, we would instead use the square root of the facet area.
    δx = firedrake.FacetArea(mesh)
    L = diameter(mesh)

    d = u.ufl_function_space().ufl_element().degree()[0]
    exponent = d + 1 if (exponent is None) else exponent
    penalty = scale * (L / δx)**exponent
    return 0.5 * penalty * inner(u, ν)**2 * h * ds_v(tuple(side_wall_ids))