You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Tighten bounding cube for regional spherical domains
When the mesh type is spherical, we now use the actual x,y,z bounding
box rather than the unit cube. For regional runs that leverage the
spherical barycentric coordinates and built in unit conversion in the
velocity field interpolators, this reduces the hit count per hash cell
and can improve the search time in the spatialhash.query()
Note that quantize_coordinates now clips in float space before casting to uint32.
This matters now that spherical queries can fall outside the hash-grid bounds
(previously impossible with the unit cube). A negative normalized value cast to
uint32 wraps to a huge number, which would have mapped below-range queries to the
top bin (with morton code 2^32) erroneously.
For spherical grids, points outside the regional box now quantize to edge bins
rather than interior bins. In this case, they either fail the exact Morton-key
match or are rejected by the point-in-cell check; either case results in the
same outcome as before (GRID_SEARCH_ERROR)
* Add structured grid spherical spatialhash query tests
Tests for both points inside the domain and explicitly outside the domain
to confirm correct behavior for out of bounds PIC checks
* Update documentation on the unstructured grid search to note change to spherical bounding box
* Remove dead valid-face branch and identity scatter from hash table build
num_hash_per_face is never zero (quantization is monotone), so the valid
mask was always all-True and the scatter an identity permutation.
Removing them drops three entry-length temporaries (~35% peak build
memory). Accumulate entry counts in int64 to avoid overflow.
Hash table output verified byte-identical.
Co-authored-by: Claude <noreply@anthropic.com>
* Sort packed (morton code, face id) uint64 pairs in place in hash table build
Fusing each pair as (code << 32) | face_id and sorting in place replaces
argsort, its int64 permutation array, and two gather passes. Pairs are
unique so the ordering is deterministic (ties by ascending face id).
Also free decode temporaries before the sort. Peak build memory drops
17.2 GB -> 6.35 GB (with previous commit) and build time 40 s -> 32 s on
a 101M-entry spherical UxGrid table. CSR arrays verified byte-identical;
per-cell face sets verified identical.
Co-authored-by: Claude <noreply@anthropic.com>
* Replace np.unique function with a simpler set of calls that exploits sorting
The np.unique function makes no assumption about whether or not the input
is sorted. Since we've done the work to sort the list of morton codes and
face id pairings, computing the start, count, and unique keys of the hash table
can be done with just three operations:
1. Find the indices where the morton codes in the sorted list change value -
prepending this list of indices with [0] gives the starting indices for a
CSR format matrix
2. The keys for the hash table are just the unique morton code values. Once
we know the `start` indices, we can quickly index for the unique morton codes
3. The count (the number of faces per morton code / hash table key) is just the
np.diff of the `start` indices.
This results in a minor improvement in construction speed.
* Store the face id rather than i,j in the hash table to reduce memory footprint
Instead, we opt to unravel the face during the query. This cuts the
hash table size down by only storing a single uint64 array (with the start
and count) rather than two arrays. The unravel cost in the query is
small in comparison to particle in cell checks, which dominate the query
costs.
* Enforce a budget on the number of hash cells per face
Enforcing this upper bound on the number of hash cells per face helps considerably
in reducing the memory footprint of the hash table construction; this also significantly
speeds up the construction process. The max budget value was tuned to balance keeping the
number of PIC checks low while keeping the memory peak during construction small.
Claude code was used to design tests for this new feature
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* Remove erroneous test that relied on bitwidth parameter for hash table construction
I've removed the bitwidth parameter for construction and opted for this to be calculated
internally for optimal memory footprint and query cost
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Erik van Sebille <e.vansebille@uu.nl>
For spherical grids, node coordinates are converted from degrees to radians and then to Cartesian (x, y, z) on the unit sphere using `parcels._core.index_search._latlon_rad_to_xyz`:
53
53
@@ -57,7 +57,7 @@ y = sin(lon) * cos(lat)
57
57
z = sin(lat)
58
58
```
59
59
60
-
The hash grid then spans the unit cube `[-1, 1]³`. Working in Cartesian space avoids the longitude wrap-around discontinuity that would otherwise cause the bounding boxes of cells crossing the antimeridian to erroneously span the entire domain.
60
+
The hash grid then spans the axis-aligned Cartesian bounding box of the transformed grid nodes. For a global grid this is (nearly) the unit cube `[-1, 1]³`; for a regional grid it is much tighter, so the full quantization resolution (1024 bins per axis) is spent on the region actually covered by the grid rather than the whole sphere. Working in Cartesian space avoids the longitude wrap-around discontinuity that would otherwise cause the bounding boxes of cells crossing the antimeridian to erroneously span the entire domain.
61
61
62
62
For flat meshes the hash grid simply spans `[lon_min, lon_max] × [lat_min, lat_max]`, with z fixed at 0.
0 commit comments