示例#1
0
def create_coordinate_map(o):
    """Return a compiled UFC coordinate_mapping object"""

    try:
        # Create a compiled coordinate map from an object with the
        # ufl_mesh attribute
        cmap_ptr = jit.ffcx_jit(o.ufl_domain())
    except AttributeError:
        # FIXME: It would be good to avoid the type check, but ffc_jit
        # supports other objects so we could get, e.g., a compiled
        # finite element
        if isinstance(o, ufl.domain.Mesh):
            cmap_ptr = jit.ffcx_jit(o)
        else:
            raise TypeError(
                "Cannot create coordinate map from an object of type: {}".
                format(type(o)))
    except Exception:
        print("Failed to create compiled coordinate map")
        raise

    # Wrap compiled coordinate map and return
    ffi = FFI()
    cmap = cpp.fem.create_coordinate_map(ffi.cast("uintptr_t", cmap_ptr))
    return cmap
示例#2
0
    def __init__(self,
                 ufl_expression: ufl.core.expr.Expr,
                 x: np.ndarray,
                 form_compiler_parameters: dict = {}, jit_parameters: dict = {}):
        """Create dolfinx Expression.

        Represents a mathematical expression evaluated at a pre-defined set of
        points on the reference cell. This class closely follows the concept of a
        UFC Expression.

        This functionality can be used to evaluate a gradient of a Function at
        the quadrature points in all cells. This evaluated gradient can then be
        used as input to a non-FEniCS function that calculates a material
        constitutive model.

        Parameters
        ----------
        ufl_expression
            Pure UFL expression
        x
            Array of points of shape (num_points, tdim) on the reference
            element.
        form_compiler_parameters
            Parameters used in FFCX compilation of this Expression. Run `ffcx
            --help` in the commandline to see all available options.
        jit_parameters
            Parameters controlling JIT compilation of C code.

        Note
        ----
        This wrapper is responsible for the FFCX compilation of the UFL Expr
        and attaching the correct data to the underlying C++ Expression.
        """
        assert x.ndim < 3
        num_points = x.shape[0] if x.ndim == 2 else 1
        x = np.reshape(x, (num_points, -1))

        mesh = ufl_expression.ufl_domain().ufl_cargo()

        # Compile UFL expression with JIT
        ufc_expression = jit.ffcx_jit(mesh.mpi_comm(), (ufl_expression, x),
                                      form_compiler_parameters=form_compiler_parameters,
                                      jit_parameters=jit_parameters)
        self._ufl_expression = ufl_expression
        self._ufc_expression = ufc_expression

        # Setup data (evaluation points, coefficients, constants, mesh, value_size).
        # Tabulation function.
        ffi = cffi.FFI()
        fn = ffi.cast("uintptr_t", ufc_expression.tabulate_expression)

        value_size = ufl.product(self.ufl_expression.ufl_shape)

        ufl_coefficients = ufl.algorithms.extract_coefficients(ufl_expression)
        coefficients = [ufl_coefficient._cpp_object for ufl_coefficient in ufl_coefficients]

        ufl_constants = ufl.algorithms.analysis.extract_constants(ufl_expression)
        constants = [ufl_constant._cpp_object for ufl_constant in ufl_constants]

        self._cpp_object = cpp.function.Expression(coefficients, constants, mesh, x, fn, value_size)
示例#3
0
文件: form.py 项目: lockyluc/dolfinx
    def __init__(self, form: ufl.Form, form_compiler_parameters: dict = {}, jit_parameters: dict = {}):
        """Create dolfinx Form

        Parameters
        ----------
        form
            Pure UFL form
        form_compiler_parameters
            See :py:func:`ffcx_jit <dolfinx.jit.ffcx_jit>`
        jit_parameters
            See :py:func:`ffcx_jit <dolfinx.jit.ffcx_jit>`

        Note
        ----
        This wrapper for UFL form is responsible for the actual FFCX compilation
        and attaching coefficients and domains specific data to the underlying
        C++ Form.
        """

        # Extract subdomain data from UFL form
        sd = form.subdomain_data()
        self._subdomains, = list(sd.values())  # Assuming single domain
        domain, = list(sd.keys())  # Assuming single domain
        mesh = domain.ufl_cargo()
        if mesh is None:
            raise RuntimeError("Expecting to find a Mesh in the form.")

        # Compile UFL form with JIT
        ufc_form = jit.ffcx_jit(
            mesh.mpi_comm(),
            form,
            form_compiler_parameters=form_compiler_parameters,
            jit_parameters=jit_parameters)

        # For every argument in form extract its function space
        function_spaces = [
            func.ufl_function_space()._cpp_object for func in form.arguments()
        ]

        # Prepare coefficients data. For every coefficient in form take
        # its C++ object.
        original_coefficients = form.coefficients()
        coeffs = [original_coefficients[ufc_form.original_coefficient_position(
            i)]._cpp_object for i in range(ufc_form.num_coefficients)]

        # Create dictionary of of subdomain markers (possible None for
        # some dimensions
        subdomains = {cpp.fem.IntegralType.cell: self._subdomains.get("cell"),
                      cpp.fem.IntegralType.exterior_facet: self._subdomains.get("exterior_facet"),
                      cpp.fem.IntegralType.interior_facet: self._subdomains.get("interior_facet"),
                      cpp.fem.IntegralType.vertex: self._subdomains.get("vertex")}

        # Prepare dolfinx.cpp.fem.Form and hold it as a member
        ffi = cffi.FFI()
        self._cpp_object = cpp.fem.create_form(ffi.cast("uintptr_t", ufc_form),
                                               function_spaces, coeffs,
                                               [c._cpp_object for c in form.constants()], subdomains, mesh)
示例#4
0
    def __init__(self,
                 mesh: Mesh,
                 element: typing.Union[ufl.FiniteElementBase, ElementMetaData],
                 cppV: typing.Optional[_cpp.fem.FunctionSpace] = None,
                 form_compiler_params: dict = {},
                 jit_params: dict = {}):
        """Create a finite element function space."""

        # Create function space from a UFL element and existing cpp
        # FunctionSpace
        if cppV is not None:
            assert mesh is None
            ufl_domain = cppV.mesh.ufl_domain()
            super().__init__(ufl_domain, element)
            self._cpp_object = cppV
            return

        # Initialise the ufl.FunctionSpace
        if isinstance(element, ufl.FiniteElementBase):
            super().__init__(mesh.ufl_domain(), element)
        else:
            e = ElementMetaData(*element)
            ufl_element = ufl.FiniteElement(e.family,
                                            mesh.ufl_cell(),
                                            e.degree,
                                            form_degree=e.form_degree)
            super().__init__(mesh.ufl_domain(), ufl_element)

        # Compile dofmap and element and create DOLFIN objects
        (self._ufcx_element, self._ufcx_dofmap), module, code = jit.ffcx_jit(
            mesh.comm,
            self.ufl_element(),
            form_compiler_params=form_compiler_params,
            jit_params=jit_params)

        ffi = cffi.FFI()
        cpp_element = _cpp.fem.FiniteElement(
            ffi.cast("uintptr_t", ffi.addressof(self._ufcx_element)))
        cpp_dofmap = _cpp.fem.create_dofmap(
            mesh.comm, ffi.cast("uintptr_t", ffi.addressof(self._ufcx_dofmap)),
            mesh.topology, cpp_element)

        # Initialize the cpp.FunctionSpace
        self._cpp_object = _cpp.fem.FunctionSpace(mesh, cpp_element,
                                                  cpp_dofmap)
示例#5
0
    def __init__(self,
                 mesh: cpp.mesh.Mesh,
                 element: typing.Union[ufl.FiniteElementBase, ElementMetaData],
                 cppV: typing.Optional[cpp.function.FunctionSpace] = None):
        """Create a finite element function space."""

        # Create function space from a UFL element and existing cpp
        # FunctionSpace
        if cppV is not None:
            assert mesh is None
            ufl_domain = cppV.mesh.ufl_domain()
            super().__init__(ufl_domain, element)
            self._cpp_object = cppV
            return

        # Initialise the ufl.FunctionSpace
        if isinstance(element, ufl.FiniteElementBase):
            super().__init__(mesh.ufl_domain(), element)
        else:
            e = ElementMetaData(*element)
            ufl_element = ufl.FiniteElement(e.family,
                                            mesh.ufl_cell(),
                                            e.degree,
                                            form_degree=e.form_degree)
            super().__init__(mesh.ufl_domain(), ufl_element)

        # Compile dofmap and element and create DOLFIN objects
        ufc_element, ufc_dofmap_ptr = jit.ffcx_jit(
            self.ufl_element(),
            form_compiler_parameters=None,
            mpi_comm=mesh.mpi_comm())

        ffi = cffi.FFI()
        ufc_element = fem.dofmap.make_ufc_finite_element(
            ffi.cast("uintptr_t", ufc_element))
        cpp_element = cpp.fem.FiniteElement(ufc_element)

        ufc_dofmap = fem.dofmap.make_ufc_dofmap(
            ffi.cast("uintptr_t", ufc_dofmap_ptr))
        cpp_dofmap = cpp.fem.create_dofmap(ufc_dofmap, mesh)

        # Initialize the cpp.FunctionSpace
        self._cpp_object = cpp.function.FunctionSpace(mesh, cpp_element,
                                                      cpp_dofmap)
示例#6
0
    def _form(form):
        """"Compile a single UFL form"""
        # Extract subdomain data from UFL form
        sd = form.subdomain_data()
        subdomains, = list(sd.values())  # Assuming single domain
        domain, = list(sd.keys())  # Assuming single domain
        mesh = domain.ufl_cargo()
        if mesh is None:
            raise RuntimeError("Expecting to find a Mesh in the form.")

        ufcx_form, module, code = jit.ffcx_jit(
            mesh.comm,
            form,
            form_compiler_params=form_compiler_params,
            jit_params=jit_params)

        # For each argument in form extract its function space
        V = [arg.ufl_function_space()._cpp_object for arg in form.arguments()]

        # Prepare coefficients data. For every coefficient in form take its
        # C++ object.
        original_coefficients = form.coefficients()
        coeffs = [
            original_coefficients[
                ufcx_form.original_coefficient_position[i]]._cpp_object
            for i in range(ufcx_form.num_coefficients)
        ]
        constants = [c._cpp_object for c in form.constants()]

        # Subdomain markers (possibly None for some dimensions)
        subdomains = {
            _cpp.fem.IntegralType.cell: subdomains.get("cell"),
            _cpp.fem.IntegralType.exterior_facet:
            subdomains.get("exterior_facet"),
            _cpp.fem.IntegralType.interior_facet:
            subdomains.get("interior_facet"),
            _cpp.fem.IntegralType.vertex: subdomains.get("vertex")
        }

        return formcls(ufcx_form, V, coeffs, constants, subdomains, mesh, code)
    eps = 0.5 * (ufl.grad(u) + ufl.grad(u).T)
    sigma = E / (1. - nu ** 2) * ((1. - nu) * eps + nu * ufl.Identity(2) * ufl.tr(eps))
    return sigma


a00 = ufl.inner(sigma, tau) * ufl.dx
a10 = - ufl.inner(sigma, ufl.grad(v)) * ufl.dx
a01 = - ufl.inner(sigma_u(u), tau) * ufl.dx

f = ufl.as_vector([0.0, 1.0 / 16])
b1 = form(- ufl.inner(f, v) * ds(1))

# JIT compile individual blocks tabulation kernels
nptype = "complex128" if np.issubdtype(PETSc.ScalarType, np.complexfloating) else "float64"
ffcxtype = "double _Complex" if np.issubdtype(PETSc.ScalarType, np.complexfloating) else "double"
ufcx_form00, _, _ = ffcx_jit(mesh.comm, a00, form_compiler_parameters={"scalar_type": ffcxtype})
kernel00 = getattr(ufcx_form00.integrals(0)[0], f"tabulate_tensor_{nptype}")
ufcx_form01, _, _ = ffcx_jit(mesh.comm, a01, form_compiler_parameters={"scalar_type": ffcxtype})
kernel01 = getattr(ufcx_form01.integrals(0)[0], f"tabulate_tensor_{nptype}")
ufcx_form10, _, _ = ffcx_jit(mesh.comm, a10, form_compiler_parameters={"scalar_type": ffcxtype})
kernel10 = getattr(ufcx_form10.integrals(0)[0], f"tabulate_tensor_{nptype}")

ffi = cffi.FFI()
cffi_support.register_type(ffi.typeof('double _Complex'), numba.types.complex128)
c_signature = numba.types.void(
    numba.types.CPointer(numba.typeof(PETSc.ScalarType())),
    numba.types.CPointer(numba.typeof(PETSc.ScalarType())),
    numba.types.CPointer(numba.typeof(PETSc.ScalarType())),
    numba.types.CPointer(numba.types.double),
    numba.types.CPointer(numba.types.int32),
    numba.types.CPointer(numba.types.uint8))
示例#8
0
    def __init__(self,
                 ufl_expression: ufl.core.expr.Expr,
                 X: np.ndarray,
                 form_compiler_params: dict = {},
                 jit_params: dict = {},
                 dtype=PETSc.ScalarType):
        """Create DOLFINx Expression.

        Represents a mathematical expression evaluated at a pre-defined
        set of points on the reference cell. This class closely follows
        the concept of a UFC Expression.

        This functionality can be used to evaluate a gradient of a
        Function at the quadrature points in all cells. This evaluated
        gradient can then be used as input to a non-FEniCS function that
        calculates a material constitutive model.

        Args:
            ufl_expression: Pure UFL expression
            X: Array of points of shape `(num_points, tdim)` on the
                reference element.
            form_compiler_params: Parameters used in FFCx compilation of
                this Expression. Run ``ffcx --help`` in the commandline
                to see all available options.
            jit_params: Parameters controlling JIT compilation of C code.

        Notes:
            This wrapper is responsible for the FFCx compilation of the
            UFL Expr and attaching the correct data to the underlying
            C++ Expression.

        """

        assert X.ndim < 3
        num_points = X.shape[0] if X.ndim == 2 else 1
        _X = np.reshape(X, (num_points, -1))

        mesh = ufl_expression.ufl_domain().ufl_cargo()

        # Compile UFL expression with JIT
        if dtype == np.float32:
            form_compiler_params["scalar_type"] = "float"
        if dtype == np.float64:
            form_compiler_params["scalar_type"] = "double"
        elif dtype == np.complex128:
            form_compiler_params["scalar_type"] = "double _Complex"
        else:
            raise RuntimeError(
                f"Unsupported scalar type {dtype} for Expression.")

        self._ufcx_expression, _, self._code = jit.ffcx_jit(
            mesh.comm, (ufl_expression, _X),
            form_compiler_params=form_compiler_params,
            jit_params=jit_params)
        self._ufl_expression = ufl_expression

        # Tabulation function.
        ffi = cffi.FFI()

        # Prepare coefficients data. For every coefficient in form take
        # its C++ object.
        original_coefficients = ufl.algorithms.extract_coefficients(
            ufl_expression)
        coeffs = [
            original_coefficients[
                self._ufcx_expression.original_coefficient_positions[i]].
            _cpp_object for i in range(self._ufcx_expression.num_coefficients)
        ]

        ufl_constants = ufl.algorithms.analysis.extract_constants(
            ufl_expression)
        constants = [constant._cpp_object for constant in ufl_constants]
        arguments = ufl.algorithms.extract_arguments(ufl_expression)
        if len(arguments) == 0:
            self._argument_function_space = None
        elif len(arguments) == 1:
            self._argument_function_space = arguments[0].ufl_function_space(
            )._cpp_object
        else:
            raise RuntimeError(
                "Expressions with more that one Argument not allowed.")

        def create_expression(dtype):
            if dtype is np.float32:
                return _cpp.fem.create_expression_float32
            elif dtype is np.float64:
                return _cpp.fem.create_expression_float64
            elif dtype is np.complex128:
                return _cpp.fem.create_expression_complex128
            else:
                raise NotImplementedError(f"Type {dtype} not supported.")

        self._cpp_object = create_expression(dtype)(
            ffi.cast("uintptr_t", ffi.addressof(self._ufcx_expression)),
            coeffs, constants, mesh, self.argument_function_space)
示例#9
0
    def __init__(self, form: ufl.Form, form_compiler_parameters: dict = {}, jit_parameters: dict = {}):
        """Create dolfinx Form

        Parameters
        ----------
        form
            Pure UFL form
        form_compiler_parameters
            Parameters used in FFCX compilation of this form. Run `ffcx --help` in the commandline
            to see all available options.
        jit_parameters
            Parameters controlling JIT compilation of C code.

        Note
        ----
        This wrapper for UFL form is responsible for the actual FFCX compilation
        and attaching coefficients and domains specific data to the underlying
        C++ Form.
        """

        # Extract subdomain data from UFL form
        sd = form.subdomain_data()
        self._subdomains, = list(sd.values())  # Assuming single domain
        domain, = list(sd.keys())  # Assuming single domain
        mesh = domain.ufl_cargo()

        # Compile UFL form with JIT
        ufc_form = jit.ffcx_jit(
            form,
            form_compiler_parameters=form_compiler_parameters,
            jit_parameters=jit_parameters,
            mpi_comm=mesh.mpi_comm())

        # For every argument in form extract its function space
        function_spaces = [
            func.ufl_function_space()._cpp_object for func in form.arguments()
        ]

        # Prepare dolfinx.Form and hold it as a member
        ffi = cffi.FFI()
        self._cpp_object = cpp.fem.create_form(ffi.cast("uintptr_t", ufc_form), function_spaces)

        # Need to fill the form with coefficients data
        # For every coefficient in form take its C++ object
        original_coefficients = form.coefficients()
        for i in range(self._cpp_object.num_coefficients()):
            j = self._cpp_object.original_coefficient_position(i)
            self._cpp_object.set_coefficient(
                i, original_coefficients[j]._cpp_object)

        # Constants are set based on their position in original form
        original_constants = [c._cpp_object for c in form.constants()]

        self._cpp_object.set_constants(original_constants)

        if mesh is None:
            raise RuntimeError("Expecting to find a Mesh in the form.")

        # Attach mesh (because function spaces and coefficients may be
        # empty lists)
        if not function_spaces:
            self._cpp_object.set_mesh(mesh)

        # Attach subdomains to C++ Form if we have them
        subdomains = self._subdomains.get("cell")
        if subdomains:
            self._cpp_object.set_cell_domains(subdomains)

        subdomains = self._subdomains.get("exterior_facet")
        if subdomains:
            self._cpp_object.set_exterior_facet_domains(subdomains)

        subdomains = self._subdomains.get("interior_facet")
        if subdomains:
            self._cpp_object.set_interior_facet_domains(subdomains)

        subdomains = self._subdomains.get("vertex")
        if subdomains:
            self._cpp_object.set_vertex_domains(subdomains)