Exemplo n.º 1
0
def mv_normal(dd, ambient_dim, dim=None):
    """Exterior unit normal as a :class:`~pymbolic.geometric_algebra.MultiVector`."""

    dd = as_dofdesc(dd)

    if not dd.is_trace():
        raise ValueError("may only request normals on boundaries")

    if dim is None:
        dim = ambient_dim - 1

    # NOTE: Don't be tempted to add a sign here. As it is, it produces
    # exterior normals for positively oriented curves.

    pder = pseudoscalar(ambient_dim, dim, dd=dd) \
            / area_element(ambient_dim, dim, dd=dd)

    # Dorst Section 3.7.2
    mv = pder << pder.I.inv()

    if dim == 0:
        # NOTE: when the mesh is 0D, we do not have a clear notion of
        # `exterior normal`, so we just take the tangent of the 1D element,
        # project it to the element faces and make it signed
        tangent = parametrization_derivative(ambient_dim, dim=1, dd=DD_VOLUME)
        tangent = tangent / sqrt(tangent.norm_squared())

        from grudge.symbolic.operators import project
        project = project(DD_VOLUME, dd)
        mv = MultiVector(
            np.array(
                [mv.as_scalar() * project(t) for t in tangent.as_vector()]))

    return cse(mv, "normal", cse_scope.DISCRETIZATION)
Exemplo n.º 2
0
def int_tpair(expression, qtag=None):
    from grudge.symbolic.operators import project, OppositeInteriorFaceSwap

    i = project("vol", "int_faces")(expression)
    e = cse(OppositeInteriorFaceSwap()(i))

    if qtag is not None and qtag != QTAG_NONE:
        q_dd = DOFDesc("int_faces", qtag)
        i = cse(project("int_faces", q_dd)(i))
        e = cse(project("int_faces", q_dd)(e))
    else:
        q_dd = "int_faces"

    return TracePair(q_dd, i, e)
Exemplo n.º 3
0
def forward_metric_derivative(xyz_axis, rst_axis, dd=None):
    r"""
    Pointwise metric derivatives representing

    .. math::

        \frac{\partial x_{\mathrm{xyz\_axis}} }{\partial r_{\mathrm{rst\_axis}} }
    """
    if dd is None:
        dd = DD_VOLUME

    inner_dd = dd.with_qtag(QTAG_NONE)

    from grudge.symbolic.operators import RefDiffOperator
    diff_op = RefDiffOperator(rst_axis, inner_dd)

    result = diff_op(NodeCoordinateComponent(xyz_axis, inner_dd))

    if dd.uses_quadrature():
        from grudge.symbolic.operators import project
        result = project(inner_dd, dd)(result)

    return cse(result,
               prefix="dx%d_dr%d" % (xyz_axis, rst_axis),
               scope=cse_scope.DISCRETIZATION)
Exemplo n.º 4
0
def mv_normal(dd, ambient_dim, dim=None):
    """Exterior unit normal as a :class:`~pymbolic.geometric_algebra.MultiVector`."""
    dd = as_dofdesc(dd)
    if not dd.is_trace():
        raise ValueError("may only request normals on boundaries")

    if dim is None:
        dim = ambient_dim - 1

    if dim == ambient_dim - 1:
        return surface_normal(ambient_dim, dim=dim, dd=dd)

    # NOTE: In the case of (d - 2)-dimensional curves, we don't really have
    # enough information on the face to decide what an "exterior face normal"
    # is (e.g the "normal" to a 1D curve in 3D space is actually a
    # "normal plane")
    #
    # The trick done here is that we take the surface normal, move it to the
    # face and then take a cross product with the face tangent to get the
    # correct exterior face normal vector.
    assert dim == ambient_dim - 2

    from grudge.symbolic.operators import project
    volm_normal = (
            surface_normal(ambient_dim, dim=dim + 1, dd=DD_VOLUME)
            .map(project(DD_VOLUME, dd)))
    pder = pseudoscalar(ambient_dim, dim, dd=dd)

    mv = cse(-(volm_normal ^ pder) << volm_normal.I.inv(),
            "face_normal",
            cse_scope.DISCRETIZATION)

    return cse(mv / sqrt(mv.norm_squared()),
            "unit_face_normal",
            cse_scope.DISCRETIZATION)
Exemplo n.º 5
0
def int_tpair(expression, qtag=None, from_dd=None):
    from grudge.symbolic.operators import project, OppositeInteriorFaceSwap

    if from_dd is None:
        from_dd = DD_VOLUME
    assert not from_dd.uses_quadrature()

    trace_dd = DOFDesc(FACE_RESTR_INTERIOR, qtag)
    if from_dd.domain_tag == trace_dd.domain_tag:
        i = expression
    else:
        i = project(from_dd, trace_dd.with_qtag(None))(expression)
    e = cse(OppositeInteriorFaceSwap()(i))

    if trace_dd.uses_quadrature():
        i = cse(project(trace_dd.with_qtag(None), trace_dd)(i))
        e = cse(project(trace_dd.with_qtag(None), trace_dd)(e))

    return TracePair(trace_dd, interior=i, exterior=e)
Exemplo n.º 6
0
def forward_metric_nth_derivative(xyz_axis, ref_axes, dd=None):
    r"""
    Pointwise metric derivatives representing repeated derivatives

    .. math::

        \frac{\partial^n x_{\mathrm{xyz\_axis}} }{\partial r_{\mathrm{ref\_axes}}}

    where *ref_axes* is a multi-index description.

    :arg ref_axes: a :class:`tuple` of tuples indicating indices of
        coordinate axes of the reference element to the number of derivatives
        which will be taken. For example, the value ``((0, 2), (1, 1))``
        indicates taking the second derivative with respect to the first
        axis and the first derivative with respect to the second
        axis. Each axis must occur only once and the tuple must be sorted
        by the axis index.

        May also be a singile integer *i*, which is viewed as equivalent
        to ``((i, 1),)``.
    """

    if isinstance(ref_axes, int):
        ref_axes = ((ref_axes, 1),)

    if not isinstance(ref_axes, tuple):
        raise ValueError("ref_axes must be a tuple")

    if tuple(sorted(ref_axes)) != ref_axes:
        raise ValueError("ref_axes must be sorted")

    if len(dict(ref_axes)) != len(ref_axes):
        raise ValueError("ref_axes must not contain an axis more than once")

    if dd is None:
        dd = DD_VOLUME
    inner_dd = dd.with_qtag(QTAG_NONE)

    from pytools import flatten
    flat_ref_axes = flatten([rst_axis] * n for rst_axis, n in ref_axes)

    from grudge.symbolic.operators import RefDiffOperator
    result = NodeCoordinateComponent(xyz_axis, inner_dd)
    for rst_axis in flat_ref_axes:
        result = RefDiffOperator(rst_axis, inner_dd)(result)

    if dd.uses_quadrature():
        from grudge.symbolic.operators import project
        result = project(inner_dd, dd)(result)

    prefix = "dx%d_%s" % (
            xyz_axis,
            "_".join("%sr%d" % ("d" * n, rst_axis) for rst_axis, n in ref_axes))

    return cse(result, prefix, cse_scope.DISCRETIZATION)
Exemplo n.º 7
0
def bv_tpair(dd, interior, exterior):
    """
    :arg interior: an expression that lives in the volume
        and will be restricted to the boundary identified by
        *tag* before use.
    :arg exterior: an expression that already lives on the boundary
        representing the exterior value to be used
        for the flux.
    """
    from grudge.symbolic.operators import project
    interior = cse(project("vol", dd)(interior))
    return TracePair(dd, interior, exterior)