def test_change_unmapped_form_arguments_to_reference_frame():
    U = FiniteElement("CG", triangle, 1)
    V = VectorElement("CG", triangle, 1)
    T = TensorElement("CG", triangle, 1)

    expr = Coefficient(U)
    assert change_to_reference_frame(expr) == ReferenceValue(expr)
    expr = Coefficient(V)
    assert change_to_reference_frame(expr) == ReferenceValue(expr)
    expr = Coefficient(T)
    assert change_to_reference_frame(expr) == ReferenceValue(expr)
예제 #2
0
def construct_modified_terminal(mt, terminal):
    """Construct a modified terminal given terminal modifiers from an
    analysed modified terminal and a terminal."""
    expr = terminal

    if mt.reference_value:
        expr = ReferenceValue(expr)

    dim = expr.ufl_domain().topological_dimension()
    for n in range(mt.local_derivatives):
        # Return zero if expression is trivially constant. This has to
        # happen here because ReferenceGrad has no access to the
        # topological dimension of a literal zero.
        if is_cellwise_constant(expr):
            expr = Zero(expr.ufl_shape + (dim,), expr.ufl_free_indices,
                        expr.ufl_index_dimensions)
        else:
            expr = ReferenceGrad(expr)

    if mt.averaged == "cell":
        expr = CellAvg(expr)
    elif mt.averaged == "facet":
        expr = FacetAvg(expr)

    # No need to apply restrictions to ConstantValue terminals
    if not isinstance(expr, ConstantValue):
        if mt.restriction == '+':
            expr = PositiveRestricted(expr)
        elif mt.restriction == '-':
            expr = NegativeRestricted(expr)

    return expr
예제 #3
0
def construct_modified_terminal(mt, terminal):
    """Construct a modified terminal given terminal modifiers from an
    analysed modified terminal and a terminal."""
    expr = terminal

    if mt.reference_value:
        expr = ReferenceValue(expr)

    dim = expr.ufl_domain().topological_dimension()
    for n in range(mt.local_derivatives):
        # Return zero if expression is trivially constant. This has to
        # happen here because ReferenceGrad has no access to the
        # topological dimension of a literal zero.
        if is_cellwise_constant(expr):
            expr = Zero(expr.ufl_shape + (dim, ), expr.ufl_free_indices,
                        expr.ufl_index_dimensions)
        else:
            expr = ReferenceGrad(expr)

    # No need to apply restrictions to ConstantValue terminals
    if not isinstance(expr, ConstantValue):
        if mt.restriction == '+':
            expr = PositiveRestricted(expr)
        elif mt.restriction == '-':
            expr = NegativeRestricted(expr)

    return expr
예제 #4
0
def check_single_function_pullback(g, mappings):
    expected = mappings[g]
    actual = apply_single_function_pullbacks(ReferenceValue(g), g.ufl_element())
    assert expected.ufl_shape == actual.ufl_shape
    for idx in numpy.ndindex(actual.ufl_shape):
        rexp = renumber_indices(expected[idx])
        ract = renumber_indices(actual[idx])
        if not rexp == ract:
            print()
            print("In check_single_function_pullback:")
            print("input:")
            print(repr(g))
            print("expected:")
            print(str(rexp))
            print("actual:")
            print(str(ract))
            print("signatures:")
            print((expected**2*dx).signature())
            print((actual**2*dx).signature())
            print()
        assert ract == rexp
예제 #5
0
def construct_modified_terminal(mt, terminal):
    """Construct a modified terminal given terminal modifiers from an
    analysed modified terminal and a terminal."""
    expr = terminal

    if mt.reference_value:
        expr = ReferenceValue(expr)

    for n in range(mt.local_derivatives):
        expr = ReferenceGrad(expr)

    if mt.averaged == "cell":
        expr = CellAvg(expr)
    elif mt.averaged == "facet":
        expr = FacetAvg(expr)

    # No need to apply restrictions to ConstantValue terminals
    if not isinstance(expr, ConstantValue):
        if mt.restriction == '+':
            expr = PositiveRestricted(expr)
        elif mt.restriction == '-':
            expr = NegativeRestricted(expr)

    return expr
def test_apply_single_function_pullbacks_triangle3d():
    triangle3d = Cell("triangle", geometric_dimension=3)
    cell = triangle3d
    domain = as_domain(cell)

    UL2 = FiniteElement("DG L2", cell, 1)
    U0 = FiniteElement("DG", cell, 0)
    U = FiniteElement("CG", cell, 1)
    V = VectorElement("CG", cell, 1)
    Vd = FiniteElement("RT", cell, 1)
    Vc = FiniteElement("N1curl", cell, 1)
    T = TensorElement("CG", cell, 1)
    S = TensorElement("CG", cell, 1, symmetry=True)
    COV2T = FiniteElement("Regge", cell, 0)  # (0, 2)-symmetric tensors
    CONTRA2T = FiniteElement("HHJ", cell, 0)  # (2, 0)-symmetric tensors

    Uml2 = UL2 * UL2
    Um = U * U
    Vm = U * V
    Vdm = V * Vd
    Vcm = Vd * Vc
    Tm = Vc * T
    Sm = T * S

    Vd0 = Vd * U0  # case from failing ffc demo

    W = S * T * Vc * Vd * V * U

    ul2 = Coefficient(UL2)
    u = Coefficient(U)
    v = Coefficient(V)
    vd = Coefficient(Vd)
    vc = Coefficient(Vc)
    t = Coefficient(T)
    s = Coefficient(S)
    cov2t = Coefficient(COV2T)
    contra2t = Coefficient(CONTRA2T)

    uml2 = Coefficient(Uml2)
    um = Coefficient(Um)
    vm = Coefficient(Vm)
    vdm = Coefficient(Vdm)
    vcm = Coefficient(Vcm)
    tm = Coefficient(Tm)
    sm = Coefficient(Sm)

    vd0m = Coefficient(Vd0)  # case from failing ffc demo

    w = Coefficient(W)

    rul2 = ReferenceValue(ul2)
    ru = ReferenceValue(u)
    rv = ReferenceValue(v)
    rvd = ReferenceValue(vd)
    rvc = ReferenceValue(vc)
    rt = ReferenceValue(t)
    rs = ReferenceValue(s)
    rcov2t = ReferenceValue(cov2t)
    rcontra2t = ReferenceValue(contra2t)

    ruml2 = ReferenceValue(uml2)
    rum = ReferenceValue(um)
    rvm = ReferenceValue(vm)
    rvdm = ReferenceValue(vdm)
    rvcm = ReferenceValue(vcm)
    rtm = ReferenceValue(tm)
    rsm = ReferenceValue(sm)

    rvd0m = ReferenceValue(vd0m)

    rw = ReferenceValue(w)
    assert len(w) == 9 + 9 + 3 + 3 + 3 + 1
    assert len(rw) == 6 + 9 + 2 + 2 + 3 + 1
    assert len(w) == 28
    assert len(rw) == 23

    assert len(vd0m) == 4
    assert len(rvd0m) == 3

    # Geometric quantities we need:
    J = Jacobian(domain)
    detJ = JacobianDeterminant(domain)
    Jinv = JacobianInverse(domain)
    # o = CellOrientation(domain)
    i, j, k, l = indices(4)

    # Contravariant H(div) Piola mapping:
    M_hdiv = ((1.0 / detJ) * J)  # Not applying cell orientation here
    # Covariant H(curl) Piola mapping: Jinv.T

    mappings = {
        # Simple elements should get a simple representation
        ul2:
        rul2 / detJ,
        u:
        ru,
        v:
        rv,
        vd:
        as_vector(M_hdiv[i, j] * rvd[j], i),
        vc:
        as_vector(Jinv[j, i] * rvc[j], i),
        t:
        rt,
        s:
        as_tensor([[rs[0], rs[1], rs[2]], [rs[1], rs[3], rs[4]],
                   [rs[2], rs[4], rs[5]]]),
        cov2t:
        as_tensor(Jinv[k, i] * rcov2t[k, l] * Jinv[l, j], (i, j)),
        contra2t:
        as_tensor(
            (1.0 / detJ) * (1.0 / detJ) * J[i, k] * rcontra2t[k, l] * J[j, l],
            (i, j)),
        # Mixed elements become a bit more complicated
        uml2:
        as_vector([ruml2[0] / detJ, ruml2[1] / detJ]),
        um:
        rum,
        vm:
        rvm,
        vdm:
        as_vector([
            # V
            rvdm[0],
            rvdm[1],
            rvdm[2],
            # Vd
            M_hdiv[0, j] * as_vector([rvdm[3], rvdm[4]])[j],
            M_hdiv[1, j] * as_vector([rvdm[3], rvdm[4]])[j],
            M_hdiv[2, j] * as_vector([rvdm[3], rvdm[4]])[j],
        ]),
        vcm:
        as_vector([
            # Vd
            M_hdiv[0, j] * as_vector([rvcm[0], rvcm[1]])[j],
            M_hdiv[1, j] * as_vector([rvcm[0], rvcm[1]])[j],
            M_hdiv[2, j] * as_vector([rvcm[0], rvcm[1]])[j],
            # Vc
            Jinv[i, 0] * as_vector([rvcm[2], rvcm[3]])[i],
            Jinv[i, 1] * as_vector([rvcm[2], rvcm[3]])[i],
            Jinv[i, 2] * as_vector([rvcm[2], rvcm[3]])[i],
        ]),
        tm:
        as_vector([
            # Vc
            Jinv[i, 0] * as_vector([rtm[0], rtm[1]])[i],
            Jinv[i, 1] * as_vector([rtm[0], rtm[1]])[i],
            Jinv[i, 2] * as_vector([rtm[0], rtm[1]])[i],
            # T
            rtm[2],
            rtm[3],
            rtm[4],
            rtm[5],
            rtm[6],
            rtm[7],
            rtm[8],
            rtm[9],
            rtm[10],
        ]),
        sm:
        as_vector([
            # T
            rsm[0],
            rsm[1],
            rsm[2],
            rsm[3],
            rsm[4],
            rsm[5],
            rsm[6],
            rsm[7],
            rsm[8],
            # S
            rsm[9],
            rsm[10],
            rsm[11],
            rsm[10],
            rsm[12],
            rsm[13],
            rsm[11],
            rsm[13],
            rsm[14],
        ]),
        # Case from failing ffc demo:
        vd0m:
        as_vector([
            M_hdiv[0, j] * as_vector([rvd0m[0], rvd0m[1]])[j],
            M_hdiv[1, j] * as_vector([rvd0m[0], rvd0m[1]])[j],
            M_hdiv[2, j] * as_vector([rvd0m[0], rvd0m[1]])[j], rvd0m[2]
        ]),
        # This combines it all:
        w:
        as_vector([
            # S
            rw[0],
            rw[1],
            rw[2],
            rw[1],
            rw[3],
            rw[4],
            rw[2],
            rw[4],
            rw[5],
            # T
            rw[6],
            rw[7],
            rw[8],
            rw[9],
            rw[10],
            rw[11],
            rw[12],
            rw[13],
            rw[14],
            # Vc
            Jinv[i, 0] * as_vector([rw[15], rw[16]])[i],
            Jinv[i, 1] * as_vector([rw[15], rw[16]])[i],
            Jinv[i, 2] * as_vector([rw[15], rw[16]])[i],
            # Vd
            M_hdiv[0, j] * as_vector([rw[17], rw[18]])[j],
            M_hdiv[1, j] * as_vector([rw[17], rw[18]])[j],
            M_hdiv[2, j] * as_vector([rw[17], rw[18]])[j],
            # V
            rw[19],
            rw[20],
            rw[21],
            # U
            rw[22],
        ]),
    }

    # Check functions of various elements outside a mixed context
    check_single_function_pullback(ul2, mappings)
    check_single_function_pullback(u, mappings)
    check_single_function_pullback(v, mappings)
    check_single_function_pullback(vd, mappings)
    check_single_function_pullback(vc, mappings)
    check_single_function_pullback(t, mappings)
    check_single_function_pullback(s, mappings)
    check_single_function_pullback(cov2t, mappings)
    check_single_function_pullback(contra2t, mappings)

    # Check functions of various elements inside a mixed context
    check_single_function_pullback(uml2, mappings)
    check_single_function_pullback(um, mappings)
    check_single_function_pullback(vm, mappings)
    check_single_function_pullback(vdm, mappings)
    check_single_function_pullback(vcm, mappings)
    check_single_function_pullback(tm, mappings)
    check_single_function_pullback(sm, mappings)

    # Check the ridiculous mixed element W combining it all
    check_single_function_pullback(w, mappings)
def test_apply_single_function_pullbacks_triangle():
    cell = triangle
    domain = as_domain(cell)

    Ul2 = FiniteElement("DG L2", cell, 1)
    U = FiniteElement("CG", cell, 1)
    V = VectorElement("CG", cell, 1)
    Vd = FiniteElement("RT", cell, 1)
    Vc = FiniteElement("N1curl", cell, 1)
    T = TensorElement("CG", cell, 1)
    S = TensorElement("CG", cell, 1, symmetry=True)

    Uml2 = Ul2 * Ul2
    Um = U * U
    Vm = U * V
    Vdm = V * Vd
    Vcm = Vd * Vc
    Tm = Vc * T
    Sm = T * S

    W = S * T * Vc * Vd * V * U

    ul2 = Coefficient(Ul2)
    u = Coefficient(U)
    v = Coefficient(V)
    vd = Coefficient(Vd)
    vc = Coefficient(Vc)
    t = Coefficient(T)
    s = Coefficient(S)

    uml2 = Coefficient(Uml2)
    um = Coefficient(Um)
    vm = Coefficient(Vm)
    vdm = Coefficient(Vdm)
    vcm = Coefficient(Vcm)
    tm = Coefficient(Tm)
    sm = Coefficient(Sm)

    w = Coefficient(W)

    rul2 = ReferenceValue(ul2)
    ru = ReferenceValue(u)
    rv = ReferenceValue(v)
    rvd = ReferenceValue(vd)
    rvc = ReferenceValue(vc)
    rt = ReferenceValue(t)
    rs = ReferenceValue(s)

    ruml2 = ReferenceValue(uml2)
    rum = ReferenceValue(um)
    rvm = ReferenceValue(vm)
    rvdm = ReferenceValue(vdm)
    rvcm = ReferenceValue(vcm)
    rtm = ReferenceValue(tm)
    rsm = ReferenceValue(sm)

    rw = ReferenceValue(w)

    assert len(w) == 4 + 4 + 2 + 2 + 2 + 1
    assert len(rw) == 3 + 4 + 2 + 2 + 2 + 1
    assert len(w) == 15
    assert len(rw) == 14

    # Geometric quantities we need:
    J = Jacobian(domain)
    detJ = JacobianDeterminant(domain)
    Jinv = JacobianInverse(domain)
    i, j, k, l = indices(4)

    # Contravariant H(div) Piola mapping:
    M_hdiv = (1.0 / detJ) * J
    # Covariant H(curl) Piola mapping: Jinv.T

    mappings = {
        # Simple elements should get a simple representation
        ul2:
        rul2 / detJ,
        u:
        ru,
        v:
        rv,
        vd:
        as_vector(M_hdiv[i, j] * rvd[j], i),
        vc:
        as_vector(Jinv[j, i] * rvc[j], i),
        t:
        rt,
        s:
        as_tensor([[rs[0], rs[1]], [rs[1], rs[2]]]),
        # Mixed elements become a bit more complicated
        uml2:
        as_vector([ruml2[0] / detJ, ruml2[1] / detJ]),
        um:
        rum,
        vm:
        rvm,
        vdm:
        as_vector([
            # V
            rvdm[0],
            rvdm[1],
            # Vd
            M_hdiv[0, j] * as_vector([rvdm[2], rvdm[3]])[j],
            M_hdiv[1, j] * as_vector([rvdm[2], rvdm[3]])[j],
        ]),
        vcm:
        as_vector([
            # Vd
            M_hdiv[0, j] * as_vector([rvcm[0], rvcm[1]])[j],
            M_hdiv[1, j] * as_vector([rvcm[0], rvcm[1]])[j],
            # Vc
            Jinv[i, 0] * as_vector([rvcm[2], rvcm[3]])[i],
            Jinv[i, 1] * as_vector([rvcm[2], rvcm[3]])[i],
        ]),
        tm:
        as_vector([
            # Vc
            Jinv[i, 0] * as_vector([rtm[0], rtm[1]])[i],
            Jinv[i, 1] * as_vector([rtm[0], rtm[1]])[i],
            # T
            rtm[2],
            rtm[3],
            rtm[4],
            rtm[5],
        ]),
        sm:
        as_vector([
            # T
            rsm[0],
            rsm[1],
            rsm[2],
            rsm[3],
            # S
            rsm[4],
            rsm[5],
            rsm[5],
            rsm[6],
        ]),
        # This combines it all:
        w:
        as_vector([
            # S
            rw[0],
            rw[1],
            rw[1],
            rw[2],
            # T
            rw[3],
            rw[4],
            rw[5],
            rw[6],
            # Vc
            Jinv[i, 0] * as_vector([rw[7], rw[8]])[i],
            Jinv[i, 1] * as_vector([rw[7], rw[8]])[i],
            # Vd
            M_hdiv[0, j] * as_vector([rw[9], rw[10]])[j],
            M_hdiv[1, j] * as_vector([rw[9], rw[10]])[j],
            # V
            rw[11],
            rw[12],
            # U
            rw[13],
        ]),
    }

    # Check functions of various elements outside a mixed context
    check_single_function_pullback(ul2, mappings)
    check_single_function_pullback(u, mappings)
    check_single_function_pullback(v, mappings)
    check_single_function_pullback(vd, mappings)
    check_single_function_pullback(vc, mappings)
    check_single_function_pullback(t, mappings)
    check_single_function_pullback(s, mappings)

    # Check functions of various elements inside a mixed context
    check_single_function_pullback(uml2, mappings)
    check_single_function_pullback(um, mappings)
    check_single_function_pullback(vm, mappings)
    check_single_function_pullback(vdm, mappings)
    check_single_function_pullback(vcm, mappings)
    check_single_function_pullback(tm, mappings)
    check_single_function_pullback(sm, mappings)

    # Check the ridiculous mixed element W combining it all
    check_single_function_pullback(w, mappings)
예제 #8
0
def apply_single_function_pullbacks(g):
    element = g.ufl_element()
    mapping = element.mapping()

    r = ReferenceValue(g)
    gsh = g.ufl_shape
    rsh = r.ufl_shape

    if mapping == "physical":
        # TODO: Is this right for immersed things
        assert gsh == rsh
        return r

    # Shortcut the "identity" case which includes Expression and
    # Constant from dolfin that may be ill-formed without a domain
    # (until we get that fixed)
    if mapping == "identity":
        assert rsh == gsh
        return r

    gsize = product(gsh)
    rsize = product(rsh)

    # Create some geometric objects for reuse
    domain = g.ufl_domain()
    J = Jacobian(domain)
    detJ = JacobianDeterminant(domain)
    Jinv = JacobianInverse(domain)

    # Create contravariant transform for reuse (note that detJ is the
    # _signed_ (pseudo-)determinant)
    transform_hdiv = (1.0 / detJ) * J

    # Shortcut simple cases for a more efficient representation,
    # including directly Piola-mapped elements and mixed elements of
    # any combination of affinely mapped elements without symmetries
    if mapping == "symmetries":
        fcm = element.flattened_sub_element_mapping()
        assert gsize >= rsize
        assert len(fcm) == gsize
        assert sorted(set(fcm)) == sorted(range(rsize))
        g_components = [r[fcm[i]] for i in range(gsize)]
        g_components = reshape_to_nested_list(g_components, gsh)
        f = as_tensor(g_components)
        assert f.ufl_shape == g.ufl_shape
        return f
    elif mapping == "contravariant Piola":
        assert transform_hdiv.ufl_shape == (gsize, rsize)
        i, j = indices(2)
        f = as_vector(transform_hdiv[i, j] * r[j], i)
        # f = as_tensor(transform_hdiv[i, j]*r[k,j], (k,i)) # FIXME: Handle Vector(Piola) here?
        assert f.ufl_shape == g.ufl_shape
        return f
    elif mapping == "covariant Piola":
        assert Jinv.ufl_shape == (rsize, gsize)
        i, j = indices(2)
        f = as_vector(Jinv[j, i] * r[j], i)
        # f = as_tensor(Jinv[j, i]*r[k,j], (k,i)) # FIXME: Handle Vector(Piola) here?
        assert f.ufl_shape == g.ufl_shape
        return f
    elif mapping == "double covariant Piola":
        i, j, m, n = indices(4)
        f = as_tensor(Jinv[m, i] * r[m, n] * Jinv[n, j], (i, j))
        assert f.ufl_shape == g.ufl_shape
        return f
    elif mapping == "double contravariant Piola":
        i, j, m, n = indices(4)
        f = as_tensor(
            (1.0 / detJ) * (1.0 / detJ) * J[i, m] * r[m, n] * J[j, n], (i, j))
        assert f.ufl_shape == g.ufl_shape
        return f
    elif mapping == "L2 Piola":
        assert rsh == gsh
        return r / detJ

    # By placing components in a list and using as_vector at the end,
    # we're assuming below that both global function g and its
    # reference value r have vector shape, which is the case for most
    # elements with the exceptions:
    # - TensorElements
    #   - All cases with scalar subelements and without symmetries
    #     are covered by the shortcut above
    #     (ONLY IF REFERENCE VALUE SHAPE PRESERVES TENSOR RANK)
    #   - All cases with scalar subelements and without symmetries are
    #     covered by the shortcut above

    g_components = [None] * gsize
    gpos = 0
    rpos = 0

    r = as_vector([r[idx] for idx in numpy.ndindex(r.ufl_shape)])
    for subelm in sub_elements_with_mappings(element):
        gm = product(subelm.value_shape())
        rm = product(subelm.reference_value_shape())

        mp = subelm.mapping()
        if mp == "identity":
            assert gm == rm
            for i in range(gm):
                g_components[gpos + i] = r[rpos + i]

        elif mp == "symmetries":
            """
            tensor_element.value_shape() == (2,2)
            tensor_element.reference_value_shape() == (3,)
            tensor_element.symmetry() == { (1,0): (0,1) }
            tensor_element.component_mapping() == { (0,0): 0, (0,1): 1, (1,0): 1, (1,1): 2 }
            tensor_element.flattened_component_mapping() == { 0: 0, 1: 1, 2: 1, 3: 2 }
            """
            fcm = subelm.flattened_sub_element_mapping()
            assert gm >= rm
            assert len(fcm) == gm
            assert sorted(set(fcm)) == sorted(range(rm))
            for i in range(gm):
                g_components[gpos + i] = r[rpos + fcm[i]]

        elif mp == "contravariant Piola":
            assert transform_hdiv.ufl_shape == (gm, rm)
            # Get reference value vector corresponding to this subelement:
            rv = as_vector([r[rpos + k] for k in range(rm)])
            # Apply transform with IndexSum over j for each row
            j = Index()
            for i in range(gm):
                g_components[gpos + i] = transform_hdiv[i, j] * rv[j]

        elif mp == "covariant Piola":
            assert Jinv.ufl_shape == (rm, gm)
            # Get reference value vector corresponding to this subelement:
            rv = as_vector([r[rpos + k] for k in range(rm)])
            # Apply transform with IndexSum over j for each row
            j = Index()
            for i in range(gm):
                g_components[gpos + i] = Jinv[j, i] * rv[j]

        elif mp == "double covariant Piola":
            # components are flatten, map accordingly
            rv = as_vector([r[rpos + k] for k in range(rm)])
            (gdim, _) = subelm.value_shape()
            (rdim, _) = subelm.reference_value_shape()
            for i in range(gdim):
                for j in range(gdim):
                    gv = 0
                    # int times Index is not allowed. so sum by hand
                    for m in range(rdim):
                        for n in range(rdim):
                            gv += Jinv[m, i] * rv[m * rdim + n] * Jinv[n, j]
                    g_components[gpos + i * gdim + j] = gv

        elif mp == "double contravariant Piola":
            # components are flatten, map accordingly
            rv = as_vector([r[rpos + k] for k in range(rm)])
            (gdim, _) = subelm.value_shape()
            (rdim, _) = subelm.reference_value_shape()
            for i in range(gdim):
                for j in range(gdim):
                    gv = 0
                    # int times Index is not allowed. so sum by hand
                    for m in range(rdim):
                        for n in range(rdim):
                            gv += ((1.0 / detJ) * (1.0 / detJ) * J[i, m] *
                                   rv[m * rdim + n] * J[j, n])
                    g_components[gpos + i * gdim + j] = gv

        elif mp == "L2 Piola":
            assert gm == rm
            for i in range(gm):
                g_components[gpos + i] = r[rpos + i] / detJ

        else:
            error("Unknown subelement mapping type %s for element %s." %
                  (mp, str(subelm)))

        gpos += gm
        rpos += rm

    # Wrap up components in a vector, must return same shape as input
    # function g
    f = as_tensor(numpy.asarray(g_components).reshape(gsh))
    assert f.ufl_shape == g.ufl_shape
    return f
예제 #9
0
 def form_argument(self, o):
     # Represent 0-derivatives of form arguments on reference
     # element
     f = apply_single_function_pullbacks(ReferenceValue(o), o.ufl_element())
     assert f.ufl_shape == o.ufl_shape
     return f
def test_change_hcurl_form_arguments_to_reference_frame():
    V = FiniteElement("RT", triangle, 1)

    expr = Coefficient(V)
    assert change_to_reference_frame(expr) == ReferenceValue(expr)
    '''
def change_expr_to_reference_frame(expr):
    expr = ReferenceValue(expr)
    return expr
예제 #12
0
 def spatial_coordinate(self, o):
     assert o.ufl_domain().ufl_coordinate_element().mapping() == "identity"
     return ReferenceValue(self.coordinates)
예제 #13
0
    def grad(self, o):
        # Peel off the Grads and count them, and get restriction if
        # it's between the grad and the terminal
        ngrads = 0
        restricted = ''
        rv = False
        while not o._ufl_is_terminal_:
            if isinstance(o, Grad):
                o, = o.ufl_operands
                ngrads += 1
            elif isinstance(o, Restricted):
                restricted = o.side()
                o, = o.ufl_operands
            elif isinstance(o, ReferenceValue):
                rv = True
                o, = o.ufl_operands
            else:
                error("Invalid type %s" % o._ufl_class_.__name__)
        f = o
        if rv:
            f = ReferenceValue(f)

        # Get domain and create Jacobian inverse object
        domain = o.ufl_domain()
        Jinv = JacobianInverse(domain)

        if is_cellwise_constant(Jinv):
            # Optimise slightly by turning Grad(Grad(...)) into
            # J^(-T)J^(-T)RefGrad(RefGrad(...))
            # rather than J^(-T)RefGrad(J^(-T)RefGrad(...))

            # Create some new indices
            ii = indices(len(f.ufl_shape))  # Indices to get to the scalar component of f
            jj = indices(ngrads)  # Indices to sum over the local gradient axes with the inverse Jacobian
            kk = indices(ngrads)  # Indices for the leftover inverse Jacobian axes

            # Preserve restricted property
            if restricted:
                Jinv = Jinv(restricted)
                f = f(restricted)

            # Apply the same number of ReferenceGrad without mappings
            lgrad = f
            for i in range(ngrads):
                lgrad = ReferenceGrad(lgrad)

            # Apply mappings with scalar indexing operations (assumes
            # ReferenceGrad(Jinv) is zero)
            jinv_lgrad_f = lgrad[ii + jj]
            for j, k in zip(jj, kk):
                jinv_lgrad_f = Jinv[j, k] * jinv_lgrad_f

            # Wrap back in tensor shape, derivative axes at the end
            jinv_lgrad_f = as_tensor(jinv_lgrad_f, ii + kk)

        else:
            # J^(-T)RefGrad(J^(-T)RefGrad(...))

            # Preserve restricted property
            if restricted:
                Jinv = Jinv(restricted)
                f = f(restricted)

            jinv_lgrad_f = f
            for foo in range(ngrads):
                ii = indices(len(jinv_lgrad_f.ufl_shape))  # Indices to get to the scalar component of f
                j, k = indices(2)

                lgrad = ReferenceGrad(jinv_lgrad_f)
                jinv_lgrad_f = Jinv[j, k] * lgrad[ii + (j,)]

                # Wrap back in tensor shape, derivative axes at the end
                jinv_lgrad_f = as_tensor(jinv_lgrad_f, ii + (k,))

        return jinv_lgrad_f
예제 #14
0
    def _mapped(self, t):
        # Check that we have a valid input object
        if not isinstance(t, Terminal):
            error("Expecting a Terminal.")

        # Get modifiers accumulated by previous handler calls
        ngrads = self._ngrads
        restricted = self._restricted
        avg = self._avg
        if avg != "":
            error("Averaging not implemented.")  # FIXME

        # These are the global (g) and reference (r) values
        if isinstance(t, FormArgument):
            g = t
            r = ReferenceValue(g)
        elif isinstance(t, GeometricQuantity):
            g = t
            r = g
        else:
            error("Unexpected type {0}.".format(type(t).__name__))

        # Some geometry mapping objects we may need multiple times below
        domain = t.ufl_domain()
        J = Jacobian(domain)
        detJ = JacobianDeterminant(domain)
        K = JacobianInverse(domain)

        # Restrict geometry objects if applicable
        if restricted:
            J = J(restricted)
            detJ = detJ(restricted)
            K = K(restricted)

        # Create Hdiv mapping from possibly restricted geometry objects
        Mdiv = (1.0 / detJ) * J

        # Get component indices of global and reference terminal objects
        gtsh = g.ufl_shape
        # rtsh = r.ufl_shape
        gtcomponents = compute_indices(gtsh)
        # rtcomponents = compute_indices(rtsh)

        # Create core modified terminal, with eventual
        # layers of grad applied directly to the terminal,
        # then eventual restriction applied last
        for i in range(ngrads):
            g = Grad(g)
            r = ReferenceGrad(r)
        if restricted:
            g = g(restricted)
            r = r(restricted)

        # Get component indices of global and reference objects with
        # grads applied
        gsh = g.ufl_shape
        # rsh = r.ufl_shape
        # gcomponents = compute_indices(gsh)
        # rcomponents = compute_indices(rsh)

        # Get derivative component indices
        dsh = gsh[len(gtsh):]
        dcomponents = compute_indices(dsh)

        # Create nested array to hold expressions for global
        # components mapped from reference values
        def ndarray(shape):
            if len(shape) == 0:
                return [None]
            elif len(shape) == 1:
                return [None] * shape[-1]
            else:
                return [ndarray(shape[1:]) for i in range(shape[0])]
        global_components = ndarray(gsh)

        # Compute mapping from reference values for each global component
        for gtc in gtcomponents:

            if isinstance(t, FormArgument):

                # Find basic subelement and element-local component
                # ec, element, eoffset = t.ufl_element().extract_component2(gtc) # FIXME: Translate this correctly
                eoffset = 0
                ec, element = t.ufl_element().extract_reference_component(gtc)

                # Select mapping M from element, pick row emapping =
                # M[ec,:], or emapping = [] if no mapping
                if isinstance(element, MixedElement):
                    error("Expecting a basic element here.")
                mapping = element.mapping()
                if mapping == "contravariant Piola":  # S == HDiv:
                    # Handle HDiv elements with contravariant piola
                    # mapping contravariant_hdiv_mapping = (1/det J) *
                    # J * PullbackOf(o)
                    ec, = ec
                    emapping = Mdiv[ec, :]
                elif mapping == "covariant Piola":  # S == HCurl:
                    # Handle HCurl elements with covariant piola mapping
                    # covariant_hcurl_mapping = JinvT * PullbackOf(o)
                    ec, = ec
                    emapping = K[:, ec]  # Column of K is row of K.T
                elif mapping == "identity":
                    emapping = None
                else:
                    error("Unknown mapping {0}".format(mapping))

            elif isinstance(t, GeometricQuantity):
                eoffset = 0
                emapping = None

            else:
                error("Unexpected type {0}.".format(type(t).__name__))

            # Create indices
            # if rtsh:
            #     i = Index()
            if len(dsh) != ngrads:
                error("Mismatch between derivative shape and ngrads.")
            if ngrads:
                ii = indices(ngrads)
            else:
                ii = ()

            # Apply mapping row to reference object
            if emapping:  # Mapped, always nonscalar terminal Not
                # using IndexSum for the mapping row dot product to
                # keep it simple, because we don't have a slice type
                emapped_ops = [emapping[s] * Indexed(r, MultiIndex((FixedIndex(eoffset + s),) + ii))
                               for s in range(len(emapping))]
                emapped = sum(emapped_ops[1:], emapped_ops[0])
            elif gtc:  # Nonscalar terminal, unmapped
                emapped = Indexed(r, MultiIndex((FixedIndex(eoffset),) + ii))
            elif ngrads:  # Scalar terminal, unmapped, with derivatives
                emapped = Indexed(r, MultiIndex(ii))
            else:  # Scalar terminal, unmapped, no derivatives
                emapped = r

            for di in dcomponents:
                # Multiply derivative mapping rows, parameterized by
                # free column indices
                dmapping = as_ufl(1)
                for j in range(ngrads):
                    dmapping *= K[ii[j], di[j]]  # Row of K is column of JinvT

                # Compute mapping from reference values for this
                # particular global component
                global_value = dmapping * emapped

                # Apply index sums
                # if rtsh:
                #     global_value = IndexSum(global_value, MultiIndex((i,)))
                # for j in range(ngrads): # Applied implicitly in the dmapping * emapped above
                #     global_value = IndexSum(global_value, MultiIndex((ii[j],)))

                # This is the component index into the full object
                # with grads applied
                gc = gtc + di

                # Insert in nested list
                comp = global_components
                for i in gc[:-1]:
                    comp = comp[i]
                comp[0 if gc == () else gc[-1]] = global_value

        # Wrap nested list in as_tensor unless we have a scalar
        # expression
        if gsh:
            tensor = as_tensor(global_components)
        else:
            tensor, = global_components
        return tensor