Пример #1
0
    def modified_terminal(self, o):
        mt = analyse_modified_terminal(o)
        terminal = mt.terminal

        if not isinstance(terminal, Coefficient):
            # Only split coefficients
            return o

        if type(terminal.ufl_element()) != MixedElement:
            # Only split mixed coefficients
            return o

        # Reference value expected
        assert mt.reference_value

        # Derivative indices
        beta = indices(mt.local_derivatives)

        components = []
        for subcoeff in self._split[terminal]:
            # Apply terminal modifiers onto the subcoefficient
            component = construct_modified_terminal(mt, subcoeff)
            # Collect components of the subcoefficient
            for alpha in numpy.ndindex(subcoeff.ufl_element().reference_value_shape()):
                # New modified terminal: component[alpha + beta]
                components.append(component[alpha + beta])
        # Repack derivative indices to shape
        c, = indices(1)
        return ComponentTensor(as_tensor(components)[c], MultiIndex((c,) + beta))
Пример #2
0
 def hashdatas():
     for i in range(3):
         for ii in ((i,), (i, 0), (1, i)):
             jj = tuple(FixedIndex(j) for j in ii)
             expr = MultiIndex(jj)
             reprs.add(repr(expr))
             hashes.add(hash(expr))
             yield compute_multiindex_hashdata(expr, {})
Пример #3
0
def test_index_simplification_reference_grad(self):
    mesh = Mesh(VectorElement("P", quadrilateral, 1))
    i, = indices(1)
    A = as_tensor(Indexed(Jacobian(mesh), MultiIndex((i, i))), (i,))
    expr = apply_derivatives(apply_geometry_lowering(
        apply_algebra_lowering(A[0])))
    assert expr == ReferenceGrad(SpatialCoordinate(mesh))[0, 0]
    assert expr.ufl_free_indices == ()
    assert expr.ufl_shape == ()
Пример #4
0
    def indexed(self, o, expr, multiindex):
        indices = list(multiindex)
        while indices and isinstance(expr, ListTensor) and isinstance(indices[0], FixedIndex):
            index = indices.pop(0)
            expr = expr.ufl_operands[int(index)]

        if indices:
            return Indexed(expr, MultiIndex(tuple(indices)))
        else:
            return expr
Пример #5
0
def count_flops(n):
    mesh = Mesh(VectorElement('CG', interval, 1))
    tfs = FunctionSpace(mesh, TensorElement('DG', interval, 1, shape=(n, n)))
    vfs = FunctionSpace(mesh, VectorElement('DG', interval, 1, dim=n))

    ensemble_f = Coefficient(vfs)
    ensemble2_f = Coefficient(vfs)
    phi = TestFunction(tfs)

    i, j = indices(2)
    nc = 42  # magic number
    L = ((IndexSum(
        IndexSum(
            Product(nc * phi[i, j], Product(ensemble_f[i], ensemble_f[i])),
            MultiIndex((i, ))), MultiIndex((j, ))) * dx) +
         (IndexSum(
             IndexSum(
                 Product(nc * phi[i, j], Product(
                     ensemble2_f[j], ensemble2_f[j])), MultiIndex(
                         (i, ))), MultiIndex((j, ))) * dx) -
         (IndexSum(
             IndexSum(
                 2 * nc *
                 Product(phi[i, j], Product(ensemble_f[i], ensemble2_f[j])),
                 MultiIndex((i, ))), MultiIndex((j, ))) * dx))

    kernel, = compile_form(L, parameters=dict(mode='spectral'))
    return EstimateFlops().visit(kernel.ast)
Пример #6
0
 def hashdatas():
     ijs = []
     iind = indices(3)
     jind = indices(3)
     for i in iind:
         ijs.append((i,))
         for j in jind:
             ijs.append((i, j))
             ijs.append((j, i))
     for ij in ijs:
         expr = MultiIndex(ij)
         reprs.add(repr(expr))
         hashes.add(hash(expr))
         yield compute_multiindex_hashdata(expr, {})
Пример #7
0
def _split_indexed(o, self):
    aggregate, multiindex = o.ufl_operands
    indices = multiindex.indices()
    result = []
    for agg in self(aggregate):
        ncmp = len(agg.ufl_shape)
        idx = indices[:ncmp]
        indices = indices[ncmp:]
        if ncmp == 0:
            result.append(agg)
        else:
            mi = multiindex if multiindex.indices() == idx else MultiIndex(idx)
            result.append(ufl_reuse_if_untouched(o, agg, mi))
    return tuple(result)
Пример #8
0
def test_index_simplification_handles_repeated_indices(self):
    mesh = Mesh(VectorElement("P", quadrilateral, 1))
    V = FunctionSpace(mesh, TensorElement("DQ", quadrilateral, 0))
    K = JacobianInverse(mesh)
    G = outer(Identity(2), Identity(2))
    i, j, k, l, m, n = indices(6)
    A = as_tensor(K[m, i] * K[n, j] * G[i, j, k, l], (m, n, k, l))
    i, j = indices(2)
    # Can't use A[i, i, j, j] because UFL automagically index-sums
    # repeated indices in the __getitem__ call.
    Adiag = Indexed(A, MultiIndex((i, i, j, j)))
    A = as_tensor(Adiag, (i, j))
    v = TestFunction(V)
    f = inner(A, v)*dx
    fd = compute_form_data(f, do_apply_geometry_lowering=True)
    integral, = fd.preprocessed_form.integrals()
    assert integral.integrand().ufl_free_indices == ()
Пример #9
0
 def hashdatas():
     for rep in range(nrep):
         # Resetting index_numbering for each repetition,
         # resulting in hashdata staying the same for
         # each repetition but repr and hashes changing
         # because new indices are created each repetition.
         index_numbering = {}
         i, j, k, l = indices(4)
         for expr in (MultiIndex((i,)),
                      MultiIndex((i,)),  # r
                      MultiIndex((i, j)),
                      MultiIndex((j, i)),
                      MultiIndex((i, j)),  # r
                      MultiIndex((i, j, k)),
                      MultiIndex((k, j, i)),
                      MultiIndex((j, i))):  # r
             reprs.add(repr(expr))
             hashes.add(hash(expr))
             yield compute_multiindex_hashdata(expr, index_numbering)
Пример #10
0
def _split_indexed(o, self, inct):
    aggregate, multiindex = o.ufl_operands
    indices = multiindex.indices()
    result = []
    for agg in self(aggregate, False):
        ncmp = len(agg.ufl_shape)
        if ncmp == 0:
            result.append(agg)
        elif not inct:
            idx = indices[:ncmp]
            indices = indices[ncmp:]
            mi = multiindex if multiindex.indices() == idx else MultiIndex(idx)
            result.append(ufl_reuse_if_untouched(o, agg, mi))
        else:
            # shape and inct
            aggshape = (flatten(agg.ufl_shape)
                        + tuple(itertools.repeat(1, len(aggregate.ufl_shape) - 1)))
            agg = reshape(agg, aggshape)
            result.append(ufl_reuse_if_untouched(o, agg, multiindex))
    return tuple(result)
Пример #11
0
def apply_mapping(expression, mapping, domain):
    """
    This applies the appropriate transformation to the
    given expression for interpolation to a specific
    element, according to the manner in which it maps
    from the reference cell.

    The following is borrowed from the UFC documentation:

    Let g be a field defined on a physical domain T with physical
    coordinates x. Let T_0 be a reference domain with coordinates
    X. Assume that F: T_0 -> T such that

      x = F(X)

    Let J be the Jacobian of F, i.e J = dx/dX and let K denote the
    inverse of the Jacobian K = J^{-1}. Then we (currently) have the
    following four types of mappings:

    'affine' mapping for g:

      G(X) = g(x)

    For vector fields g:

    'contravariant piola' mapping for g:

      G(X) = det(J) K g(x)   i.e  G_i(X) = det(J) K_ij g_j(x)

    'covariant piola' mapping for g:

      G(X) = J^T g(x)          i.e  G_i(X) = J^T_ij g(x) = J_ji g_j(x)

    'double covariant piola' mapping for g:

      G(X) = J^T g(x) J     i.e. G_il(X) = J_ji g_jk(x) J_kl

    'double contravariant piola' mapping for g:

      G(X) = det(J)^2 K g(x) K^T  i.e. G_il(X)=(detJ)^2 K_ij g_jk K_lk

    If 'contravariant piola' or 'covariant piola' are applied to a
    matrix-valued function, the appropriate mappings are applied row-by-row.

    :arg expression: UFL expression
    :arg mapping: a string indicating the mapping to apply
    """

    mesh = expression.ufl_domain()
    if mesh is None:
        mesh = domain
    if domain is not None and mesh != domain:
        raise NotImplementedError("Multiple domains not supported")
    rank = len(expression.ufl_shape)
    if mapping == "affine":
        return expression
    elif mapping == "covariant piola":
        J = Jacobian(mesh)
        *i, j, k = indices(len(expression.ufl_shape) + 1)
        expression = Indexed(expression, MultiIndex((*i, k)))
        return as_tensor(J.T[j, k] * expression, (*i, j))
    elif mapping == "contravariant piola":
        K = JacobianInverse(mesh)
        detJ = JacobianDeterminant(mesh)
        *i, j, k = indices(len(expression.ufl_shape) + 1)
        expression = Indexed(expression, MultiIndex((*i, k)))
        return as_tensor(detJ * K[j, k] * expression, (*i, j))
    elif mapping == "double covariant piola" and rank == 2:
        J = Jacobian(mesh)
        return J.T * expression * J
    elif mapping == "double contravariant piola" and rank == 2:
        K = JacobianInverse(mesh)
        detJ = JacobianDeterminant(mesh)
        return (detJ)**2 * K * expression * K.T
    else:
        raise NotImplementedError("Don't know how to handle mapping type %s for expression of rank %d" % (mapping, rank))
Пример #12
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