Exemple #1
0
 def nabla_grad(self, o, a):
     sh = a.ufl_shape
     if sh == ():
         return Grad(a)
     else:
         j = Index()
         ii = tuple(indices(len(sh)))
         return as_tensor(a[ii].dx(j), (j, ) + ii)
Exemple #2
0
    def grad(self, o):
        "Represent grad(grad(f)) as Grad(Grad(f))."

        # Check that o is a "differential terminal"
        if not isinstance(o.ufl_operands[0], (Grad, Terminal)):
            error("Expecting only grads applied to a terminal.")

        return Grad(o)
Exemple #3
0
 def argument(self, o):
     # TODO: Enable this after fixing issue#13, unless we move
     # simplificat ion to a separate stage?
     # if is_cellwise_constant(o):
     #     # Collapse gradient of cellwise constant function to zero
     #     # TODO: Missing this type
     #     return AnnotatedZero(o.ufl_shape + self._var_shape, arguments=(o,))
     return Grad(o)
Exemple #4
0
 def geometric_quantity(self, o):
     """Default for geometric quantities is dg/dx = 0 if piecewise constant, otherwise keep Grad(g).
     Override for specific types if other behaviour is needed."""
     if is_cellwise_constant(o):
         return self.independent_terminal(o)
     else:
         # TODO: Which types does this involve? I don't think the
         # form compilers will handle this.
         return Grad(o)
Exemple #5
0
 def apply_grads(f):
     if not isinstance(f, FormArgument):
         print((',' * 60))
         print(f)
         print(o)
         print(g)
         print((',' * 60))
         error("What?")
     for i in range(ngrads):
         f = Grad(f)
     return f
Exemple #6
0
 def apply_grads(f):
     for i in range(ngrads):
         f = Grad(f)
     return f
Exemple #7
0
 def coefficient(self, o):
     if is_cellwise_constant(o):
         return self.independent_terminal(o)
     return Grad(o)
Exemple #8
0
def generate_ref_tensor(element: FiniteElement = None):
    def monkey_patch_ufl():
        from ufl.referencevalue import ReferenceValue
        oldinit = ReferenceValue.__init__

        def newinit(self, f):
            if isinstance(f, ReferenceValue):
                f = f.ufl_operands[0]
            oldinit(self, f)

        ReferenceValue.__init__ = newinit

    monkey_patch_ufl()

    def generate_reference_tetrahedron_mesh():
        vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]],
                            dtype=np.float64)

        cells = np.array([[0, 1, 2, 3]], dtype=np.int32)

        mesh = Mesh(MPI.comm_world, CellType.Type.tetrahedron, vertices, cells,
                    [], cpp.mesh.GhostMode.none)

        return mesh

    mesh = generate_reference_tetrahedron_mesh()

    if element is None:
        element = FiniteElement("P", tetrahedron, 1)
    V = FunctionSpace(mesh, element)

    dofmap = V.dofmap().cell_dofs(0)
    dofmap_inverse = np.argsort(dofmap)

    u, v = TrialFunction(V), TestFunction(V)
    detJ = JacobianDeterminant(SpatialCoordinate(mesh))

    A0 = np.zeros(
        (dofmap.size, dofmap.size, mesh.topology.dim, mesh.topology.dim),
        dtype=np.double)

    for i in range(mesh.topology.dim):
        for j in range(mesh.topology.dim):
            jit_result = jit.jit.ffc_jit(
                outer(Grad(Val(u)), Grad(Val(v)))[i, j] / detJ * dx)
            ufc_form = cpp.fem.make_ufc_form(jit_result[0])
            a = cpp.fem.Form(ufc_form, [V._cpp_object, V._cpp_object])

            assembler = cpp.fem.Assembler([[a]], [], [])
            A_scp = PETScMatrix()
            assembler.assemble(A_scp, cpp.fem.Assembler.BlockType.monolithic)

            A = utils.scipy2numpy(A_scp)
            A0[:, :, i, j] = A[dofmap_inverse].transpose()

            #print(79 * '=')
            #print("dphi_i/dX({})*dphi_j/dX({})".format(i, j))
            #print(A[dofmap_inverse])

    A0 = A0[dofmap_inverse, :, :, :]
    return A0
Exemple #9
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