From 9463fcb8918e7e9e422221f0c20c7a4fae153ecd Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Mon, 15 Jun 2026 17:51:33 +0100 Subject: [PATCH 01/11] add `locate_cell_from_candidates` --- firedrake/evaluate.h | 4 +++- firedrake/locate.c | 14 +++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/firedrake/evaluate.h b/firedrake/evaluate.h index 47bf93c23f..aadbb568ba 100644 --- a/firedrake/evaluate.h +++ b/firedrake/evaluate.h @@ -45,7 +45,7 @@ typedef PetscReal (*ref_cell_l1_dist_xtr)(void *data_, int layer, double *x); -extern int locate_cell(struct Function *f, +extern int locate_cell_from_candidates(struct Function *f, double *x, int dim, ref_cell_l1_dist try_candidate, @@ -53,6 +53,8 @@ extern int locate_cell(struct Function *f, void *temp_ref_coords, void *found_ref_coords, double *found_ref_cell_dist_l1, + size_t nids, + size_t *ids, size_t ncells_ignore, int* cells_ignore); diff --git a/firedrake/locate.c b/firedrake/locate.c index f1fa6856a3..0e13f08e8f 100644 --- a/firedrake/locate.c +++ b/firedrake/locate.c @@ -4,7 +4,7 @@ #include #include -int locate_cell(struct Function *f, +int locate_cell_from_candidates(struct Function *f, double *x, int dim, ref_cell_l1_dist try_candidate, @@ -12,10 +12,11 @@ int locate_cell(struct Function *f, void *temp_ref_coords, void *found_ref_coords, double *found_ref_cell_dist_l1, + size_t nids, + size_t *ids, size_t ncells_ignore, int* cells_ignore) { - RTreeError err; int cell = -1; int cell_ignore_found = 0; /* NOTE: temp_ref_coords and found_ref_coords are actually of type @@ -31,14 +32,6 @@ int locate_cell(struct Function *f, variable defined outside this function when putting together all the C code that needs to be compiled - see pointquery_utils.py */ - size_t *ids = NULL; - size_t nids = 0; - err = rtree_locate_all_at_point((const struct RTreeH *)f->rtree, x, &ids, &nids); - if (err != Success) { - fputs("ERROR: rtree_locate_all_at_point failed.\n", stderr); - rtree_free_ids(ids, nids); - return -1; - } if (f->extruded == 0) { for (size_t i = 0; i < nids; i++) { current_ref_cell_dist_l1 = (*try_candidate)(temp_ref_coords, f, ids[i], x); @@ -106,6 +99,5 @@ int locate_cell(struct Function *f, } } } - rtree_free_ids(ids, nids); return cell; } From 81f8045ae773ebc957e8c6b9ac01a0b38d139b72 Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Mon, 15 Jun 2026 17:51:44 +0100 Subject: [PATCH 02/11] use in c locator --- firedrake/mesh.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/firedrake/mesh.py b/firedrake/mesh.py index 8e6ebed99e..048901b447 100644 --- a/firedrake/mesh.py +++ b/firedrake/mesh.py @@ -2748,6 +2748,15 @@ def _c_locator(self, tolerance=None): src += dedent(f""" int locator(struct Function *f, double *x, double *X, double *ref_cell_dists_l1, {IntTypeC} *cells, {IntTypeC} npoints, size_t ncells_ignore, int* cells_ignore) {{ + size_t *candidate_ids = NULL; + size_t *candidate_offsets = NULL; + RTreeError rtree_err = rtree_locate_all_at_points( + (const struct RTreeH *)f->rtree, x, npoints, &candidate_ids, &candidate_offsets); + if (rtree_err != Success) {{ + fputs("ERROR: rtree_locate_all_at_points failed.\\n", stderr); + return -1; + }} + {IntTypeC} j = 0; /* index into x and X */ for({IntTypeC} i=0; i Date: Mon, 15 Jun 2026 17:51:52 +0100 Subject: [PATCH 03/11] fix for Function.at --- firedrake/pointeval_utils.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/firedrake/pointeval_utils.py b/firedrake/pointeval_utils.py index f6c24f8b30..fe077eb3c4 100644 --- a/firedrake/pointeval_utils.py +++ b/firedrake/pointeval_utils.py @@ -180,7 +180,19 @@ def predicate(index): double found_ref_cell_dist_l1 = DBL_MAX; struct ReferenceCoords temp_reference_coords, found_reference_coords; int cells_ignore[1] = {-1}; - %(IntType)s cell = locate_cell(f, x, %(geometric_dimension)d, &to_reference_coords, &to_reference_coords_xtr, &temp_reference_coords, &found_reference_coords, &found_ref_cell_dist_l1, 1, cells_ignore); + RTreeError err; + size_t *ids = NULL; + size_t nids = 0; + err = rtree_locate_all_at_point((const struct RTreeH *)f->rtree, x, &ids, &nids); + if (err != Success) { + fputs("ERROR: rtree_locate_all_at_point failed.\\n", stderr); + rtree_free_ids(ids, nids); + return -1; + } + %(IntType)s cell = locate_cell_from_candidates(f, x, %(geometric_dimension)d, &to_reference_coords, &to_reference_coords_xtr, + &temp_reference_coords, &found_reference_coords, &found_ref_cell_dist_l1, + nids, ids, 1, cells_ignore); + rtree_free_ids(ids, nids); if (cell == -1) { return -1; } From aeba6397fbb8281c450a8700077ef8fc600eb0e1 Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Wed, 17 Jun 2026 14:32:28 +0100 Subject: [PATCH 04/11] update to new types --- firedrake/cython/rtree.pyx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/firedrake/cython/rtree.pyx b/firedrake/cython/rtree.pyx index 346e03bb4b..44a8409c0f 100644 --- a/firedrake/cython/rtree.pyx +++ b/firedrake/cython/rtree.pyx @@ -5,7 +5,7 @@ import numpy as np import ctypes import cython from libc.stddef cimport size_t -from libc.stdint cimport uintptr_t, uint32_t +from libc.stdint cimport uintptr_t, uint32_t, int64_t cdef extern from "rtree-capi.h": ctypedef enum RTreeError: @@ -20,7 +20,7 @@ cdef extern from "rtree-capi.h": RTreeH **tree, const double *mins, const double *maxs, - const size_t *ids, + const int64_t *ids, size_t n, uint32_t dim ) @@ -53,7 +53,7 @@ cdef class RTree(object): @cython.wraparound(False) def build_from_aabb(np.ndarray[np.float64_t, ndim=2, mode="c"] coords_min, np.ndarray[np.float64_t, ndim=2, mode="c"] coords_max, - np.ndarray[np.npy_uintp, ndim=1, mode="c"] ids = None): + np.ndarray[np.int64_t, ndim=1, mode="c"] ids = None): """Builds rtree from two arrays of shape (n, dim) containing the coordinates of the lower and upper corners of n axis-aligned bounding boxes, and an optional array of shape (n,) containing integer ids for each box. @@ -76,24 +76,24 @@ def build_from_aabb(np.ndarray[np.float64_t, ndim=2, mode="c"] coords_min, cdef: RTreeH* rtree size_t n - size_t dim + uint32_t dim RTreeError err if coords_min.shape[0] != coords_max.shape[0] or coords_min.shape[1] != coords_max.shape[1]: raise ValueError("coords_min and coords_max must have the same shape") - n = coords_min.shape[0] - dim = coords_min.shape[1] + n = coords_min.shape[0] + dim = coords_min.shape[1] if ids is None: - ids = np.arange(n, dtype=np.uintp) - elif ids.shape[0] != n: + ids = np.arange(n, dtype=np.int64) + elif ids.shape[0] != n: raise ValueError("Mismatch between number of boxes and number of ids") err = rtree_bulk_load( &rtree, coords_min.data, coords_max.data, - ids.data, + ids.data, n, dim ) From ead8117af939a3a3dd6183d903be44ecfd9727fa Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Wed, 17 Jun 2026 14:33:08 +0100 Subject: [PATCH 05/11] specify minimum version --- pyproject.toml | 4 ++-- requirements-build.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 74d38ccf8e..063133c4e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ dependencies = [ # TODO RELEASE "firedrake-fiat @ git+https://github.com/firedrakeproject/fiat.git@main", "h5py>3.12.1", - "firedrake-rtree", + "firedrake-rtree>=2026.2.0", "immutabledict", "libsupermesh>=2026.0", "loopy>2024.1", @@ -156,7 +156,7 @@ docker = [ # Used in firedrake-vanilla container [build-system] requires = [ "Cython>=3.0", - "firedrake-rtree", + "firedrake-rtree>=2026.2.0", "libsupermesh>=2026.0", "mpi4py>3; python_version >= '3.13'", "mpi4py; python_version < '3.13'", diff --git a/requirements-build.txt b/requirements-build.txt index 7916a00db7..5e6ffbef0f 100644 --- a/requirements-build.txt +++ b/requirements-build.txt @@ -1,6 +1,6 @@ # Core build dependencies (adapted from pyproject.toml) Cython>=3.0 -firedrake-rtree +firedrake-rtree>=2026.2.0 libsupermesh>=2026.0 mpi4py>3; python_version >= '3.13' mpi4py; python_version < '3.13' From bcf754176c708ffdacdb4b644c17afdd5c24c253 Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Tue, 14 Jul 2026 13:09:40 +0100 Subject: [PATCH 06/11] DROP BEFORE MERGE use main branch firedrake-rtree --- pyproject.toml | 4 ++-- requirements-build.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 063133c4e1..dedb532f9e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ dependencies = [ # TODO RELEASE "firedrake-fiat @ git+https://github.com/firedrakeproject/fiat.git@main", "h5py>3.12.1", - "firedrake-rtree>=2026.2.0", + "firedrake-rtree @ git+https://github.com/firedrakeproject/firedrake-rtree.git@main", "immutabledict", "libsupermesh>=2026.0", "loopy>2024.1", @@ -156,7 +156,7 @@ docker = [ # Used in firedrake-vanilla container [build-system] requires = [ "Cython>=3.0", - "firedrake-rtree>=2026.2.0", + "firedrake-rtree @ git+https://github.com/firedrakeproject/firedrake-rtree.git@main", "libsupermesh>=2026.0", "mpi4py>3; python_version >= '3.13'", "mpi4py; python_version < '3.13'", diff --git a/requirements-build.txt b/requirements-build.txt index 5e6ffbef0f..17d9178e65 100644 --- a/requirements-build.txt +++ b/requirements-build.txt @@ -1,6 +1,6 @@ # Core build dependencies (adapted from pyproject.toml) Cython>=3.0 -firedrake-rtree>=2026.2.0 +firedrake-rtree @ git+https://github.com/firedrakeproject/firedrake-rtree.git@main libsupermesh>=2026.0 mpi4py>3; python_version >= '3.13' mpi4py; python_version < '3.13' From f9b825fcf3b38075fa917e2a878d69de82295c60 Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Tue, 14 Jul 2026 13:25:47 +0100 Subject: [PATCH 07/11] maturin puccinialin --- requirements-build.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements-build.txt b/requirements-build.txt index 17d9178e65..6c8f71e67f 100644 --- a/requirements-build.txt +++ b/requirements-build.txt @@ -14,3 +14,5 @@ setuptools>=77.0.3 hatchling meson-python scikit_build_core +maturin>=1.12,<2.0 +puccinialin From 92b9d50439b5ed5572110d6f13548be0983350a0 Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Tue, 14 Jul 2026 15:19:15 +0100 Subject: [PATCH 08/11] use correct function --- firedrake/mesh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firedrake/mesh.py b/firedrake/mesh.py index 048901b447..37cc7e2e4f 100644 --- a/firedrake/mesh.py +++ b/firedrake/mesh.py @@ -2781,7 +2781,7 @@ def _c_locator(self, tolerance=None): }} }} rtree_free_ids(candidate_ids, candidate_offsets[npoints]); - rtree_free_ids(candidate_offsets, npoints + 1); + rtree_free_offsets(candidate_offsets, npoints + 1); return 0; }} """) From 2d88a18da7a1c9b1f590f2544e5023364486a548 Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Tue, 14 Jul 2026 15:34:21 +0100 Subject: [PATCH 09/11] use correct types --- firedrake/evaluate.h | 3 ++- firedrake/locate.c | 2 +- firedrake/mesh.py | 4 ++-- firedrake/pointeval_utils.py | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/firedrake/evaluate.h b/firedrake/evaluate.h index aadbb568ba..360db5bbb8 100644 --- a/firedrake/evaluate.h +++ b/firedrake/evaluate.h @@ -2,6 +2,7 @@ #define _EVALUATE_H #include +#include #ifdef __cplusplus extern "C" { @@ -54,7 +55,7 @@ extern int locate_cell_from_candidates(struct Function *f, void *found_ref_coords, double *found_ref_cell_dist_l1, size_t nids, - size_t *ids, + int64_t *ids, size_t ncells_ignore, int* cells_ignore); diff --git a/firedrake/locate.c b/firedrake/locate.c index 0e13f08e8f..f636e5d2fb 100644 --- a/firedrake/locate.c +++ b/firedrake/locate.c @@ -13,7 +13,7 @@ int locate_cell_from_candidates(struct Function *f, void *found_ref_coords, double *found_ref_cell_dist_l1, size_t nids, - size_t *ids, + int64_t *ids, size_t ncells_ignore, int* cells_ignore) { diff --git a/firedrake/mesh.py b/firedrake/mesh.py index 37cc7e2e4f..61fdb474e6 100644 --- a/firedrake/mesh.py +++ b/firedrake/mesh.py @@ -2748,7 +2748,7 @@ def _c_locator(self, tolerance=None): src += dedent(f""" int locator(struct Function *f, double *x, double *X, double *ref_cell_dists_l1, {IntTypeC} *cells, {IntTypeC} npoints, size_t ncells_ignore, int* cells_ignore) {{ - size_t *candidate_ids = NULL; + int64_t *candidate_ids = NULL; size_t *candidate_offsets = NULL; RTreeError rtree_err = rtree_locate_all_at_points( (const struct RTreeH *)f->rtree, x, npoints, &candidate_ids, &candidate_offsets); @@ -2766,7 +2766,7 @@ def _c_locator(self, tolerance=None): struct ReferenceCoords temp_reference_coords, found_reference_coords; size_t nids_i = candidate_offsets[i + 1] - candidate_offsets[i]; - size_t *ids_i = candidate_ids + candidate_offsets[i]; + int64_t *ids_i = candidate_ids + candidate_offsets[i]; /* to_reference_coords and to_reference_coords_xtr are defined in pointquery_utils.py. If they contain python calls, this loop will diff --git a/firedrake/pointeval_utils.py b/firedrake/pointeval_utils.py index fe077eb3c4..e5f80abc6f 100644 --- a/firedrake/pointeval_utils.py +++ b/firedrake/pointeval_utils.py @@ -181,7 +181,7 @@ def predicate(index): struct ReferenceCoords temp_reference_coords, found_reference_coords; int cells_ignore[1] = {-1}; RTreeError err; - size_t *ids = NULL; + int64_t *ids = NULL; size_t nids = 0; err = rtree_locate_all_at_point((const struct RTreeH *)f->rtree, x, &ids, &nids); if (err != Success) { From efded77df25fe7a23ef28052c340c900d2eee945 Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Tue, 14 Jul 2026 15:56:04 +0100 Subject: [PATCH 10/11] remove unused `dim` argument from locate_cell_from_candidates --- firedrake/evaluate.h | 1 - firedrake/locate.c | 1 - firedrake/mesh.py | 2 +- firedrake/pointeval_utils.py | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/firedrake/evaluate.h b/firedrake/evaluate.h index 360db5bbb8..33c07eba5c 100644 --- a/firedrake/evaluate.h +++ b/firedrake/evaluate.h @@ -48,7 +48,6 @@ typedef PetscReal (*ref_cell_l1_dist_xtr)(void *data_, extern int locate_cell_from_candidates(struct Function *f, double *x, - int dim, ref_cell_l1_dist try_candidate, ref_cell_l1_dist_xtr try_candidate_xtr, void *temp_ref_coords, diff --git a/firedrake/locate.c b/firedrake/locate.c index f636e5d2fb..185630b2f2 100644 --- a/firedrake/locate.c +++ b/firedrake/locate.c @@ -6,7 +6,6 @@ int locate_cell_from_candidates(struct Function *f, double *x, - int dim, ref_cell_l1_dist try_candidate, ref_cell_l1_dist_xtr try_candidate_xtr, void *temp_ref_coords, diff --git a/firedrake/mesh.py b/firedrake/mesh.py index 61fdb474e6..6e71046c99 100644 --- a/firedrake/mesh.py +++ b/firedrake/mesh.py @@ -2773,7 +2773,7 @@ def _c_locator(self, tolerance=None): not run at c-loop speed. */ /* cells_ignore has shape (npoints, ncells_ignore) - find the ith row */ int *cells_ignore_i = cells_ignore + i*ncells_ignore; - cells[i] = locate_cell_from_candidates(f, &x[j], {self.geometric_dimension}, &to_reference_coords, &to_reference_coords_xtr, &temp_reference_coords, &found_reference_coords, &ref_cell_dists_l1[i], nids_i, ids_i, ncells_ignore, cells_ignore_i); + cells[i] = locate_cell_from_candidates(f, &x[j], &to_reference_coords, &to_reference_coords_xtr, &temp_reference_coords, &found_reference_coords, &ref_cell_dists_l1[i], nids_i, ids_i, ncells_ignore, cells_ignore_i); for (int k = 0; k < {self.geometric_dimension}; k++) {{ X[j] = found_reference_coords.X[k]; diff --git a/firedrake/pointeval_utils.py b/firedrake/pointeval_utils.py index e5f80abc6f..d6b087cbaf 100644 --- a/firedrake/pointeval_utils.py +++ b/firedrake/pointeval_utils.py @@ -189,7 +189,7 @@ def predicate(index): rtree_free_ids(ids, nids); return -1; } - %(IntType)s cell = locate_cell_from_candidates(f, x, %(geometric_dimension)d, &to_reference_coords, &to_reference_coords_xtr, + %(IntType)s cell = locate_cell_from_candidates(f, x, &to_reference_coords, &to_reference_coords_xtr, &temp_reference_coords, &found_reference_coords, &found_ref_cell_dist_l1, nids, ids, 1, cells_ignore); rtree_free_ids(ids, nids); From d8355c5cf858d64c1ba21944a00ba1113a8afc9a Mon Sep 17 00:00:00 2001 From: Leo Collins Date: Tue, 14 Jul 2026 16:25:54 +0100 Subject: [PATCH 11/11] refactor locate.c - Check cells ignore list before computing reference coordinates - Reduce code duplication --- firedrake/locate.c | 83 ++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/firedrake/locate.c b/firedrake/locate.c index 185630b2f2..9327ec8805 100644 --- a/firedrake/locate.c +++ b/firedrake/locate.c @@ -31,70 +31,43 @@ int locate_cell_from_candidates(struct Function *f, variable defined outside this function when putting together all the C code that needs to be compiled - see pointquery_utils.py */ - if (f->extruded == 0) { - for (size_t i = 0; i < nids; i++) { - current_ref_cell_dist_l1 = (*try_candidate)(temp_ref_coords, f, ids[i], x); - for (size_t j = 0; j < ncells_ignore; j++) { - if (ids[i] == cells_ignore[j]) { - cell_ignore_found = 1; - break; - } - } - if (cell_ignore_found) { - cell_ignore_found = 0; - continue; - } - if (current_ref_cell_dist_l1 <= 0.0) { - /* Found cell! */ - cell = ids[i]; - memcpy(found_ref_coords, temp_ref_coords, sizeof(struct ReferenceCoords)); - found_ref_cell_dist_l1[0] = current_ref_cell_dist_l1; + for (size_t i = 0; i < nids; ++i) { + for (size_t j = 0; j < ncells_ignore; j++) { + if (ids[i] == cells_ignore[j]) { + cell_ignore_found = 1; break; } - else if (current_ref_cell_dist_l1 < ref_cell_dist_l1) { - /* getting closer... */ - ref_cell_dist_l1 = current_ref_cell_dist_l1; - if (ref_cell_dist_l1 < tolerance) { - /* Close to cell within tolerance so could be this cell */ - cell = ids[i]; - memcpy(found_ref_coords, temp_ref_coords, sizeof(struct ReferenceCoords)); - found_ref_cell_dist_l1[0] = ref_cell_dist_l1; - } - } } - } - else { - for (size_t i = 0; i < nids; i++) { + if (cell_ignore_found) { + cell_ignore_found = 0; + continue; + } + + if (f->extruded == 0) { + current_ref_cell_dist_l1 = (*try_candidate)(temp_ref_coords, f, ids[i], x); + } + else { int nlayers = f->n_layers; int c = ids[i] / nlayers; int l = ids[i] % nlayers; current_ref_cell_dist_l1 = (*try_candidate_xtr)(temp_ref_coords, f, c, l, x); - for (size_t j = 0; j < ncells_ignore; j++) { - if (ids[i] == cells_ignore[j]) { - cell_ignore_found = 1; - break; - } - } - if (cell_ignore_found) { - cell_ignore_found = 0; - continue; - } - if (current_ref_cell_dist_l1 <= 0.0) { - /* Found cell! */ + } + + if (current_ref_cell_dist_l1 <= 0.0) { + /* Found cell! */ + cell = ids[i]; + memcpy(found_ref_coords, temp_ref_coords, sizeof(struct ReferenceCoords)); + found_ref_cell_dist_l1[0] = current_ref_cell_dist_l1; + break; + } + else if (current_ref_cell_dist_l1 < ref_cell_dist_l1) { + /* getting closer... */ + ref_cell_dist_l1 = current_ref_cell_dist_l1; + if (ref_cell_dist_l1 < tolerance) { + /* Close to cell within tolerance so could be this cell */ cell = ids[i]; memcpy(found_ref_coords, temp_ref_coords, sizeof(struct ReferenceCoords)); - found_ref_cell_dist_l1[0] = current_ref_cell_dist_l1; - break; - } - else if (current_ref_cell_dist_l1 < ref_cell_dist_l1) { - /* getting closer... */ - ref_cell_dist_l1 = current_ref_cell_dist_l1; - if (ref_cell_dist_l1 < tolerance) { - /* Close to cell within tolerance so could be this cell */ - cell = ids[i]; - memcpy(found_ref_coords, temp_ref_coords, sizeof(struct ReferenceCoords)); - found_ref_cell_dist_l1[0] = ref_cell_dist_l1; - } + found_ref_cell_dist_l1[0] = ref_cell_dist_l1; } } }