• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FEniCS / ffcx / 28736460040

05 Jul 2026 09:36AM UTC coverage: 84.747% (+0.06%) from 84.685%
28736460040

Pull #846

github

schnellerhase
Use core.types everywhere
Pull Request #846: Support `numba>=0.66.0` and tidy optional dependency

5 of 10 new or added lines in 1 file covered. (50.0%)

4206 of 4963 relevant lines covered (84.75%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.58
/ffcx/codegeneration/utils.py
1
# Copyright (C) 2020-2026 Michal Habera, Chris Richardson, Garth N. Wells and Paul T. Kühner
2
#
3
# This file is part of FFCx.(https://www.fenicsproject.org)
4
#
5
# SPDX-License-Identifier:    LGPL-3.0-or-later
6
"""Utilities."""
7

8
from importlib.util import find_spec
1✔
9

10
import numpy as np
1✔
11
import numpy.typing as npt
1✔
12

13

14
def dtype_to_c_type(dtype: npt.DTypeLike | str) -> str:
1✔
15
    """For a NumPy dtype, return the corresponding C type.
16

17
    Args:
18
        dtype: Numpy data type,
19

20
    Returns:
21
        Corresponding C type.
22
    """
23
    # Note: Possible aliases, e.g. numpy.longdouble, should test against char ID
24
    if np.dtype(dtype).char == "g":
1✔
25
        return "long double"
×
26
    if np.dtype(dtype) == np.intc:
1✔
27
        return "int"
1✔
28
    elif np.dtype(dtype).char == "f":
1✔
29
        return "float"
1✔
30
    elif np.dtype(dtype).char == "d":
1✔
31
        return "double"
1✔
32
    elif np.dtype(dtype) == np.complex64:
1✔
33
        return "float _Complex"
1✔
34
    elif np.dtype(dtype) == np.complex128:
1✔
35
        return "double _Complex"
1✔
36
    else:
37
        raise RuntimeError(f"Unknown NumPy type for: {dtype}")
×
38

39

40
def dtype_to_scalar_dtype(dtype: npt.DTypeLike | str) -> np.dtype:
1✔
41
    """For a NumPy dtype, return the corresponding real dtype.
42

43
    Args:
44
        dtype: Numpy data type
45

46
    Returns:
47
        ``numpy.dtype`` for the real component of ``dtype``.
48
    """
49
    if np.issubdtype(dtype, np.floating):
1✔
50
        return np.dtype(dtype)
1✔
51
    elif np.issubdtype(dtype, np.complexfloating):
1✔
52
        return np.dtype(dtype).type(0).real.dtype
1✔
53
    elif np.issubdtype(dtype, np.integer):
1✔
54
        return np.dtype(dtype)
1✔
55
    else:
56
        raise RuntimeError(f"Cannot get value dtype for '{dtype}'. ")
×
57

58

59
if find_spec("numba") is not None:
1✔
60
    import numba
1✔
61
    from numba.core import types
1✔
62

63
    def numba_ufcx_kernel_signature(dtype: npt.DTypeLike, xdtype: npt.DTypeLike):
1✔
64
        """Return a Numba C signature for the UFCx ``tabulate_tensor`` interface.
65

66
        Args:
67
            dtype: The scalar type for the finite element data.
68
            xdtype: The geometry float type.
69

70
        Returns:
71
            A Numba signature (``numba.core.typing.templates.Signature``).
72
        """
73
        return types.void(
1✔
74
            types.CPointer(numba.from_dtype(dtype)),
75
            types.CPointer(numba.from_dtype(dtype)),
76
            types.CPointer(numba.from_dtype(dtype)),
77
            types.CPointer(numba.from_dtype(xdtype)),
78
            types.CPointer(types.intc),
79
            types.CPointer(types.uint8),
80
            types.CPointer(types.void),
81
        )
82

83
    @numba.extending.intrinsic
1✔
84
    def empty_void_pointer(typingctx):
1✔
85
        """Custom intrinsic to return an empty void* pointer.
86

87
        This function creates a void pointer initialized to null (0).
88
        This is used to pass a nullptr to the UFCx tabulate_tensor interface.
89

90
        Args:
91
            typingctx: The typing context.
92

93
        Returns:
94
            A Numba signature and a code generation function that returns a void pointer.
95
        """
96

97
        def codegen(context, builder, signature, args):
×
NEW
98
            null_ptr = context.get_constant(types.voidptr, 0)
×
99
            return null_ptr
×
100

NEW
101
        sig = types.voidptr()
×
102
        return sig, codegen
×
103

104
    @numba.extending.intrinsic
1✔
105
    def get_void_pointer(typingctx, arr):
1✔
106
        """Custom intrinsic to get a void* pointer from a NumPy array.
107

108
        This function takes a NumPy array and returns a void pointer to the array's data.
109
        This is used to pass custom data organised in a NumPy array
110
        to the UFCx tabulate_tensor interface.
111

112
        Args:
113
            typingctx: The typing context.
114
            arr: The NumPy array to get the void pointer to the first element from.
115
            In a multi-dimensional NumPy array, the memory is laid out in a contiguous
116
            block of memory, see
117
            https://numpy.org/doc/stable/reference/arrays.ndarray.html#internal-memory-layout-of-an-ndarray
118

119
        Returns:
120
            sig: A Numba signature, which specifies the numba type (here voidptr),
121
            codegen: A code generation function, which returns the LLVM IR to cast
122
            the raw data pointer to the first element of the of the contiguous block of memory
123
            of the NumPy array to void*.
124
        """
NEW
125
        if not isinstance(arr, types.Array):
×
126
            raise TypeError("Expected a NumPy array")
×
127

128
        def codegen(context, builder, signature, args):
×
129
            """Generate LLVM IR code to convert a NumPy array to a void* pointer.
130

131
            This function generates the necessary LLVM IR instructions to:
132
            1. Allocate memory for the array on the stack.
133
            2. Cast the allocated memory to a void* pointer.
134

135
            Args:
136
                context: The LLVM context.
137
                builder: The LLVM IR builder.
138
                signature: The function signature.
139
                args: The input arguments (NumPy array).
140

141
            Returns:
142
                A void* pointer to the array's data.
143
            """
144
            [arr] = args
×
145
            raw_ptr = numba.core.cgutils.alloca_once_value(builder, arr)
×
NEW
146
            void_ptr = builder.bitcast(raw_ptr, context.get_value_type(types.voidptr))
×
147
            return void_ptr
×
148

NEW
149
        sig = types.voidptr(arr)
×
150
        return sig, codegen
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc