Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
158 commits
Select commit Hold shift + click to select a range
1accc33
use rstar capi for cell location
leo-collins Feb 17, 2026
6b5eea5
add logging
leo-collins Feb 17, 2026
06da607
remove allgather logs
leo-collins Feb 17, 2026
4709136
update comments
leo-collins Feb 23, 2026
0ce05f9
fix cached property
leo-collins Feb 23, 2026
793a92d
merge logging
leo-collins Feb 24, 2026
ff062ff
more logs
leo-collins Feb 25, 2026
1dd92d4
more logging
leo-collins Feb 25, 2026
2fc20a6
adapt to new API
leo-collins Mar 4, 2026
ea48fb6
rebase
leo-collins Mar 10, 2026
f413029
partial fix
leo-collins Mar 10, 2026
d792583
tidy up cython
leo-collins Mar 10, 2026
923db26
fixes
leo-collins Mar 12, 2026
cb25eb6
renaming and use `firedrake_rtree` package
leo-collins Mar 20, 2026
7418224
firedrake-rtree fixes
leo-collins Mar 20, 2026
a66d16d
remove unused stuff from rtree cython
leo-collins Mar 20, 2026
ac08113
remove unnecessary stuff from petschdr
leo-collins Mar 20, 2026
44863a6
misc tidying
leo-collins Mar 20, 2026
5a60847
fixes
leo-collins Mar 20, 2026
df6df0b
fixup mesh.py
leo-collins Mar 20, 2026
789b486
add rtree libspatialindex back in
leo-collins Mar 20, 2026
088e8c7
add spatialindex to supermesh extension
leo-collins Mar 24, 2026
a0be450
add extra runtime path
leo-collins Mar 24, 2026
431daec
lowercase r
leo-collins Mar 24, 2026
aae03f4
fix
leo-collins Mar 25, 2026
6719b40
libsupermesh fix
leo-collins Mar 25, 2026
4cfd969
remove library
leo-collins Mar 26, 2026
17cdaa4
remove rtree import from setup.py
leo-collins Mar 26, 2026
db7972b
use libsupermesh branch for docs
leo-collins Mar 26, 2026
bf7037e
installation and workflow
leo-collins Mar 26, 2026
859032e
review suggestions
leo-collins Apr 2, 2026
9f6ebd8
fix docstrings
leo-collins Apr 2, 2026
f852bc7
use rstar capi for cell location
leo-collins Feb 17, 2026
841af86
renaming and use `firedrake_rtree` package
leo-collins Mar 20, 2026
2f2e450
misc tidying
leo-collins Mar 20, 2026
ed91eaf
add node interface
leo-collins Mar 5, 2026
e8ee003
add bounding boxes tree traverser
leo-collins Mar 5, 2026
6bf2a79
add bounding_boxes_total_volume method and partition_volume method
leo-collins Mar 5, 2026
cb714a1
WIP: distributed RTree
leo-collins Mar 5, 2026
47b282e
build distributed rtree method
leo-collins Mar 6, 2026
eaa3cae
remove partition_volume method
leo-collins Mar 6, 2026
4d8fcf0
edit docstrings
leo-collins Mar 9, 2026
1f055bd
temporarily remove exclude_halos
leo-collins Mar 12, 2026
7147a71
WIP
leo-collins Mar 13, 2026
e6b5613
WIP
leo-collins Mar 16, 2026
d52bd1f
don't skip tests
leo-collins Mar 16, 2026
31e7b6c
WIP
leo-collins Mar 16, 2026
0c3a195
WIP: remove old code
leo-collins Mar 16, 2026
df61091
tidy
leo-collins Mar 16, 2026
7a4ac42
some tidying
leo-collins Mar 17, 2026
7b78a8e
DROPME: debug tests
leo-collins Mar 17, 2026
c0c53ea
fixes
leo-collins Mar 24, 2026
e527389
WIP
leo-collins Mar 24, 2026
21d6c3b
WIP
leo-collins Mar 25, 2026
c62aed6
tidy
leo-collins Mar 25, 2026
53e8559
small fixes
leo-collins Mar 25, 2026
ae38341
use correct MPI type
leo-collins Mar 25, 2026
134df37
WIP fixes
leo-collins Mar 25, 2026
a763304
WIP
leo-collins Apr 1, 2026
d9b504c
tidy
leo-collins Apr 1, 2026
4afb92f
tidying
leo-collins Apr 1, 2026
c08a2bd
renaming and tidying
leo-collins Apr 2, 2026
25a1931
add comments
leo-collins Apr 2, 2026
35a4da5
tidy
leo-collins Apr 2, 2026
0c9b497
fixes
leo-collins Apr 2, 2026
c8ef52e
add comments
leo-collins Apr 7, 2026
7da726b
comments
leo-collins Apr 8, 2026
287de23
remove prints
leo-collins Apr 16, 2026
42e8043
update docstring
leo-collins Apr 20, 2026
7d6a839
tidy
leo-collins Apr 21, 2026
d9da160
use correct MPI op
leo-collins Apr 29, 2026
19a2975
tidy
leo-collins May 15, 2026
87a1cfc
bounding box tolerance
leo-collins May 20, 2026
3287edf
fix merge conflict
leo-collins May 20, 2026
834f029
tidy remote array construction
leo-collins May 28, 2026
2ddefde
tidy
leo-collins May 28, 2026
9441b00
order points robustly now that we are not allgathering
leo-collins May 28, 2026
18e1ccd
cache distributed rtree
leo-collins May 29, 2026
94acf88
cache bboxes in non-extruded case
leo-collins Jun 15, 2026
9821b28
fixes to caching
leo-collins Jun 15, 2026
d0f5bf8
wrap `rtree_collect_bounding_boxes` in cython
leo-collins Jun 16, 2026
163d599
add cython wrapper for bounding box collection
leo-collins Jun 17, 2026
652ff63
fixes
leo-collins Jun 17, 2026
15e6046
moved node stuff to firedrake-rtree
leo-collins Jun 17, 2026
3847d7b
type fixing
leo-collins Jun 17, 2026
fe30274
fix type
leo-collins Jun 17, 2026
4766a33
fix
leo-collins Jun 17, 2026
a492db8
better `discover_ranks`
leo-collins Jun 17, 2026
d31cf38
tidy
leo-collins Jun 17, 2026
2328530
merge bulk-query
leo-collins Jun 18, 2026
0b6e605
use correct types
leo-collins Jun 18, 2026
85f6b88
tidy
leo-collins Jul 7, 2026
bb51164
fixes
leo-collins Jul 7, 2026
785fdc5
fix
leo-collins Jul 7, 2026
38f9dca
type fixes
leo-collins Jul 7, 2026
98fadff
remove unused exception
leo-collins Jul 7, 2026
89b1dcc
remove missing import
leo-collins Jul 13, 2026
2edaed8
Merge branch 'main' into leo/distributed-rtree
leo-collins Aug 6, 2026
5100474
lint and fixup
leo-collins Aug 6, 2026
a1ae81e
introduce VOM sf class
leo-collins Aug 7, 2026
3c23260
WIP
leo-collins Aug 10, 2026
774cbed
update pyproject & requirements-build
leo-collins Aug 10, 2026
9b31432
rewrite discover_ranks
leo-collins Aug 10, 2026
fe3a64d
move remote construction to cython
leo-collins Aug 10, 2026
c28e6e3
WIP
leo-collins Aug 10, 2026
90e358e
add broadcast/reduce methods
leo-collins Aug 11, 2026
5110928
tidy parent_mesh_embedding
leo-collins Aug 11, 2026
efa91cf
tidy pic_swarm_in_mesh partially
leo-collins Aug 11, 2026
7686278
create embedded leaf sf
leo-collins Aug 11, 2026
539cc47
rtree.pyx tidy
leo-collins Aug 11, 2026
52987d3
remove retry loop
leo-collins Aug 12, 2026
31d4cdc
tidy up parent_mesh_embedding
leo-collins Aug 12, 2026
88c795b
fix deadlock
leo-collins Aug 13, 2026
e011c7d
add todo
leo-collins Aug 13, 2026
c70e6cb
clean up creation of dmswarm
leo-collins Aug 13, 2026
3926344
tidy
leo-collins Aug 14, 2026
ba78ddb
more tidying
leo-collins Aug 14, 2026
1641137
generalise _mpi_unit
leo-collins Aug 14, 2026
ebb9aed
create SF on correct comm
leo-collins Aug 15, 2026
093b2b5
tidy up cython code
leo-collins Aug 19, 2026
75479a8
add some todos
leo-collins Aug 19, 2026
f952270
more tidying
leo-collins Aug 21, 2026
3b36b89
WIP
leo-collins Aug 24, 2026
86a675d
use new firedrake-rtree routine
leo-collins Aug 25, 2026
6a651da
tidying
leo-collins Aug 25, 2026
103c14b
more tidying
leo-collins Aug 25, 2026
4df098d
fix
leo-collins Aug 25, 2026
106414b
tidy
leo-collins Aug 26, 2026
0f92a05
don't do exact floating point comparisons
leo-collins Aug 26, 2026
4b046b3
Merge branch 'main' into leo/distributed-rtree-refactor
leo-collins Aug 27, 2026
e1f2800
add comments
leo-collins Aug 27, 2026
0827193
fixes
leo-collins Aug 27, 2026
cfed258
lint cython
leo-collins Aug 27, 2026
54a9f2b
maturin & puccinialin
leo-collins Aug 27, 2026
a6fc0a7
do exact floating point equality
leo-collins Aug 27, 2026
425390b
rename test
leo-collins Aug 27, 2026
39b7b1b
Merge branch 'main' into leo/distributed-rtree-refactor
leo-collins Aug 27, 2026
3d7c6f6
int64 fix
leo-collins Aug 28, 2026
c321012
Merge branch 'main' into leo/distributed-rtree-refactor
leo-collins Aug 29, 2026
e7cac8c
add comments to parallel algorithm
leo-collins Sep 2, 2026
d99abf5
duplicate comm inside of collective function
leo-collins Sep 2, 2026
e209f8f
lint
leo-collins Sep 2, 2026
b1de9fd
move docstring
leo-collins Sep 3, 2026
c211427
inherit
leo-collins Sep 3, 2026
5570933
add docstring
leo-collins Sep 3, 2026
875f4c3
tidy up VertexOnlyMeshSF
leo-collins Sep 3, 2026
9e3407e
final review suggestions
leo-collins Sep 3, 2026
d39ac1e
tidy
leo-collins Sep 3, 2026
2ad2709
Apply suggestion from @connorjward
leo-collins Sep 3, 2026
4ed302b
remove init
leo-collins Sep 3, 2026
9f10b94
add comment
leo-collins Sep 7, 2026
fde4af2
add comment about NULL values in locate.c
leo-collins Sep 7, 2026
62253a1
Update firedrake/cython/rtree.pyx
leo-collins Sep 7, 2026
b9dafee
Merge branch 'main' into leo/distributed-rtree-refactor
leo-collins Sep 9, 2026
b10bd41
add comment
leo-collins Sep 14, 2026
0442911
complex fixes
leo-collins Sep 14, 2026
f28763e
Merge branch 'main' into leo/distributed-rtree-refactor
leo-collins Sep 17, 2026
e1af963
Merge branch 'main' into leo/distributed-rtree-refactor
leo-collins Sep 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 228 additions & 0 deletions firedrake/cython/rtree.pyx
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
# cython: language_level=3

from firedrake.utils import IntType
cimport numpy as np
import numpy as np
import ctypes
import cython
from libc.stddef cimport size_t
from libc.stdint cimport uintptr_t, uint32_t, int64_t
from libc.stdlib cimport free, malloc

cimport mpi4py.MPI as MPI
from mpi4py.libmpi cimport (
MPI_ANY_SOURCE,
MPI_REQUEST_NULL,
MPI_STATUS_IGNORE,
MPI_STATUSES_IGNORE,
MPI_TYPECLASS_INTEGER,
MPI_Datatype,
MPI_Get_count,
MPI_Ibarrier,
MPI_Iprobe,
MPI_Issend,
MPI_Recv,
MPI_Request,
MPI_Status,
MPI_Test,
MPI_Testall,
MPI_Type_match_size,
)

include "petschdr.pxi"

cdef extern from "rtree-capi.h":
ctypedef enum RTreeError:
Expand All @@ -27,6 +51,38 @@ cdef extern from "rtree-capi.h":

RTreeError rtree_free(RTreeH *tree)

RTreeError rtree_free_ids(int64_t *ids, size_t n)

RTreeError rtree_free_offsets(size_t *offsets, size_t n)

RTreeError rtree_free_point_indices(size_t *point_indices, size_t n)

RTreeError rtree_locate_points_grouped_by_id_unique(
const RTreeH *tree,
const double *points,
size_t n_points,
int64_t **ids_out,
size_t **offsets_out,
size_t **point_indices_out,
size_t *n_ids_out
)

RTreeError rtree_depth(const RTreeH *tree, size_t *depth_out)

RTreeError rtree_collect_bounding_boxes(
const RTreeH *tree,
size_t level,
double **mins_out,
double **maxs_out,
size_t *nboxes_out
)

RTreeError rtree_free_bounding_boxes(
double *mins,
double *maxs,
size_t nboxes,
uint32_t dim
)

cdef class RTree(object):
"""Python class for holding an Rtree."""
Expand Down Expand Up @@ -101,3 +157,175 @@ def build_from_aabb(np.ndarray[np.float64_t, ndim=2, mode="c"] coords_min,
raise RuntimeError("rtree_bulk_load failed")

return RTree(<uintptr_t>rtree)


@cython.boundscheck(False)
@cython.wraparound(False)
def discover_remote_roots(
RTree rtree,
np.ndarray[np.float64_t, ndim=2, mode="c"] points,
MPI.Comm comm):
"""Build the remote array for a candidate star forest. Collective.

This implements the non-blocking consensus algorithm from Hoefler et al.
'Scalable communication protocols for dynamic sparse data exchange'.

This routine duplicates the given comm since we send tag-0 messages
and listen with MPI_IProbe(MPI_ANY_SOURCE).

Parameters
----------
rtree : RTree
The distributed Rtree built by :func:`build_from_aabb` with rank
numbers as leaf ids.
points : (n_points, gdim) float64 array
Local point coordinates.
comm : mpi4py.MPI.Comm
The MPI communicator.

Returns
-------
remote : (nleaves, 2) IntType array
For every local candidate leaf, the MPI rank and local index of its
remote root point.
"""
cdef:
MPI.Comm dup_comm = comm.Dup()
MPI.MPI_Comm mpi_comm = dup_comm.ob_mpi
MPI_Request *send_requests = NULL
MPI_Request barrier_request = MPI_REQUEST_NULL
MPI_Status status
MPI_Datatype point_index_type
int count, source_rank, message_ready, sends_complete = 0
int barrier_complete = 0
Py_ssize_t nleaves = 0, recv_offset = 0
int64_t *send_ranks = NULL
size_t *point_indices = NULL
size_t *send_offsets = NULL
size_t n_points = points.shape[0], nranks_to = 0
np.ndarray[np.uintp_t, ndim=1, mode="c"] received
np.ndarray[PetscInt, ndim=2, mode="c"] remote
list recv_messages = []

try:
# MPI does not have a builtin type for size_t
CHKERRMPI(MPI_Type_match_size(MPI_TYPECLASS_INTEGER, sizeof(size_t), &point_index_type))

if rtree_locate_points_grouped_by_id_unique(
rtree.tree,
<const double *>points.data,
n_points,
&send_ranks, # unique ranks I am sending to
&send_offsets, # offsets into `point_indices` of points I need to send
&point_indices, # the points I need to send
&nranks_to, # number of ranks I am sending to (len(send_ranks))
) != Success:
raise RuntimeError("rtree_locate_points_grouped_by_id_unique failed")

# Each rank knows where to send to, but not where it is going to receive from.
# The following algorithm is the 'non-blocking consensus' algorithm (Hoefler et al.)
# which is a sparse alternative to MPI_Alltoallv
if nranks_to != 0:
send_requests = <MPI_Request *>malloc(nranks_to * sizeof(MPI_Request))

# Post non-blocking synchronous sends. 'Synchronous' means that the send is not
# considered as complete by MPI_Test until the destination starts the matching receive.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this important?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment

# This is so that a rank cannot hit the barrier while any of its outgoing messages remain unmatched.
for k in range(nranks_to):
count = send_offsets[k + 1] - send_offsets[k]
CHKERRMPI(MPI_Issend(
<const void *>&point_indices[send_offsets[k]],
count, point_index_type,
<int>send_ranks[k],
0,
mpi_comm,
&send_requests[k],
))

# MPI_Ibarrier is a non-blocking barrier. It posts into `barrier_request`. This request is
# not considered complete until all ranks on the comm post the barrier request.
# This is used to know when a rank has sent all of its messages.
# In the case we are sending no messages, we do this now.
if nranks_to == 0:
CHKERRMPI(MPI_Ibarrier(mpi_comm, &barrier_request))

# Enter a loop where we continuously probe for incoming messages.
# `barrier_complete` is true when all ranks have hit the barrier.
while not barrier_complete:
Comment thread
connorjward marked this conversation as resolved.
# We don't know where we are going to receive from, so we use MPI_ANY_SOURCE. If we're
# about to receive a message, then `message_ready` is true.
CHKERRMPI(MPI_Iprobe(MPI_ANY_SOURCE, 0, mpi_comm, &message_ready, &status))

# We're receiving a message: determine the number of entries, and do the blocking receive.
if message_ready:
CHKERRMPI(MPI_Get_count(&status, point_index_type, &count))
source_rank = status.MPI_SOURCE
received = np.empty(count, dtype=np.uintp)
CHKERRMPI(MPI_Recv(<void *>received.data, count, point_index_type, source_rank, 0, mpi_comm, MPI_STATUS_IGNORE))
recv_messages.append((source_rank, received))
nleaves += count

if barrier_request == MPI_REQUEST_NULL:
# This rank has not hit the barrier. Test if all the sends have been complete. If they
# have, then this ranks hits the barrier to mark that its sends have completed.
CHKERRMPI(MPI_Testall(nranks_to, send_requests, &sends_complete, MPI_STATUSES_IGNORE))
if sends_complete:
CHKERRMPI(MPI_Ibarrier(mpi_comm, &barrier_request))
else:
# This rank has hit the barrier and has posted `barrier_request`. This request completes
# when _all_ other ranks send barrier_request. Then MPI_Test will set `barrier_complete`
# to true which ends the loop.
CHKERRMPI(MPI_Test(&barrier_request, &barrier_complete, MPI_STATUS_IGNORE))
finally:
dup_comm.Free()
if send_requests != NULL:
free(send_requests)
if rtree_free_ids(send_ranks, nranks_to) != Success:
raise RuntimeError("rtree_free_ids failed")
if rtree_free_point_indices(point_indices, send_offsets[nranks_to]) != Success:
raise RuntimeError("rtree_free_point_indices failed")
if rtree_free_offsets(send_offsets, nranks_to + 1) != Success:
raise RuntimeError("rtree_free_offsets failed")

# create remote array for candidate star forest
remote = np.empty((nleaves, 2), dtype=IntType)
for source_rank, received in recv_messages:
count = received.shape[0]
remote[recv_offset:recv_offset + count, 0] = source_rank
remote[recv_offset:recv_offset + count, 1] = received
recv_offset += count

return remote


def bounding_boxes_at_level(RTree rtree, size_t level, uint32_t dim):
"""Return all bounding boxes at the specified level of the Rtree."""
cdef:
double *mins = NULL
double *maxs = NULL
size_t n_boxes = 0
np.ndarray[np.float64_t, ndim=3, mode="c"] boxes

if rtree_collect_bounding_boxes(rtree.tree, level, &mins, &maxs, &n_boxes) != Success:
raise RuntimeError("rtree_bounding_boxes failed")

boxes = np.empty((n_boxes, 2, dim), dtype=np.float64)

for i in range(n_boxes):
for j in range(dim):
boxes[i, 0, j] = mins[i * dim + j]
boxes[i, 1, j] = maxs[i * dim + j]

rtree_free_bounding_boxes(mins, maxs, n_boxes, dim)

return boxes


def tree_depth(RTree rtree):
"""Return the depth of the Rtree."""
cdef:
size_t depth = 0

if rtree_depth(rtree.tree, &depth) != Success:
raise RuntimeError("rtree_depth failed")
return depth
24 changes: 13 additions & 11 deletions firedrake/evaluate.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,19 @@ typedef PetscReal (*ref_cell_l1_dist_xtr)(void *data_,
double *x);

extern PetscErrorCode locate_cell_from_candidates(struct Function *f,
double *x,
ref_cell_l1_dist try_candidate,
ref_cell_l1_dist_xtr try_candidate_xtr,
void *temp_ref_coords,
void *found_ref_coords,
PetscReal *found_ref_cell_dist_l1,
size_t nids,
const int64_t *ids,
size_t ncells_ignore,
const PetscInt *cells_ignore,
PetscInt *cell_out);
double *x,
ref_cell_l1_dist try_candidate,
ref_cell_l1_dist_xtr try_candidate_xtr,
void *temp_ref_coords,
void *found_ref_coords,
PetscReal *found_ref_cell_dist_l1,
size_t nids,
const int64_t *ids,
size_t ncells_ignore,
const PetscInt *cells_ignore,
const PetscInt *cell_owner_ranks,
PetscInt *cell_out,
PetscInt *owner_out);

extern int evaluate(struct Function *f,
double *x,
Expand Down
50 changes: 30 additions & 20 deletions firedrake/locate.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ PetscErrorCode locate_cell_from_candidates(struct Function *f,
const int64_t *ids,
size_t ncells_ignore,
const PetscInt *cells_ignore,
PetscInt *cell_out)
const PetscInt *cell_owner_ranks,
PetscInt *cell_out,
PetscInt *owner_out)
{
bool cell_ignore_found = false;
/* NOTE: temp_ref_coords and found_ref_coords are actually of type
Expand All @@ -21,13 +23,20 @@ PetscErrorCode locate_cell_from_candidates(struct Function *f,
surrounds this is declared in pointquery_utils.py. We cast when we use the
ref_coords_copy function and trust that the underlying memory which the
pointers refer to is updated as necessary. */
PetscReal ref_cell_dist_l1 = PETSC_MAX_REAL;
PetscReal current_ref_cell_dist_l1 = -0.5;
PetscReal best_distance = PETSC_MAX_REAL;
PetscInt best_owner = -1;
PetscInt best_cell = -1;
/* NOTE: `tolerance`, which is used throughout this function, is a static
variable defined outside this function when putting together all the C
code that needs to be compiled - see pointquery_utils.py */

/* NOTE: `cell_owner_ranks` and `owner_out` may be NULL. In this case, every
candidate is treated as having owner rank 0. This is for backwards compatibility
with the `Function.at` code path which is being deprecated soon. */
*cell_out = -1;
if (owner_out) {
*owner_out = -1;
}
for (size_t i = 0; i < nids; ++i) {
/* Check that casting the ids from int64 to PetscInt is safe (for 32 bit petsc builds).
Since the ids are mesh cell ids this *should* always be safe, but better to check
Expand All @@ -47,33 +56,34 @@ PetscErrorCode locate_cell_from_candidates(struct Function *f,
continue;
}

PetscReal distance;
PetscInt owner;
if (f->extruded) {
PetscInt nlayers = f->n_layers;
PetscInt c = candidate / nlayers;
PetscInt l = candidate % nlayers;
current_ref_cell_dist_l1 = (*try_candidate_xtr)(temp_ref_coords, f, c, l, x);
distance = (*try_candidate_xtr)(temp_ref_coords, f, c, l, x);
owner = cell_owner_ranks ? cell_owner_ranks[c] : 0;
}
else {
current_ref_cell_dist_l1 = (*try_candidate)(temp_ref_coords, f, candidate, x);
distance = (*try_candidate)(temp_ref_coords, f, candidate, x);
owner = cell_owner_ranks ? cell_owner_ranks[candidate] : 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a backwards compatibility thing? (cell_owner_ranks may be undefined?) If so a comment wouldn't go amiss.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Added a comment

}

if (current_ref_cell_dist_l1 <= 0.0) {
/* Found cell! */
*cell_out = candidate;
/* Select owning cell by minimum L1 distance, with ties broken by highest owning rank. */
if (distance < best_distance || (distance == best_distance && owner > best_owner)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still worry about this. Consider an interval mesh like

global:
x-----x-----x
      o

rank 0:
x-----x
      o

rank 1:
      x-----x
      o

(which is allowed since we don't always need a full cell of overlap)

If o is the point we want to locate then rank 0 and rank 1 both have one entry in cell_owner_ranks - they will each think that they own the point.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A rank doesn't decide at this point that they own the point. locate.c just determines whether the point lies in one of their owned cells (and L^1 distances and ref coords, etc.).

The 'global' selection in _parent_mesh_embedding is what determines the owning rank. In this case the points both have a zero L^1 distance, so the owner is going to be rank 1 since we break ties by choosing the highest owning rank.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it work if both ranks think that the other rank is the owner?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading your example correctly, rank 0 can see no cells of rank 1 and vice-versa. So I can't see how a rank could think the point lived in a cell owned by the other rank in this case.

If we do have halos then this can happen, but by selecting the single highest owning rank we can never end up that situation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't apply to the example I gave earlier. Only if there are halos.

I guess my concern comes down to my mental model of floating point in parallel. Can we be sure that two ranks will compute the distance of a point on the cell boundary as exactly zero under any circumstance?

best_distance = distance;
best_owner = owner;
best_cell = candidate;
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_out = candidate;
memcpy(found_ref_coords, temp_ref_coords, sizeof(struct ReferenceCoords));
found_ref_cell_dist_l1[0] = ref_cell_dist_l1;
}
}

if (best_cell != -1 && (best_distance <= 0.0 || best_distance < tolerance)) {
*cell_out = best_cell;
if (owner_out) {
*owner_out = best_owner;
}
*found_ref_cell_dist_l1 = best_distance;
}
return PETSC_SUCCESS;
}
Loading
Loading