Skip to content

Commit 9a9b4f2

Browse files
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.
1 parent a1bfbc0 commit 9a9b4f2

1 file changed

Lines changed: 9 additions & 8 deletions

File tree

src/parcels/_core/spatialhash.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,6 @@ def _initialize_hash_table(self):
294294
# Cast the morton codes back to uint32
295295
morton_codes_sorted = packed.astype(np.uint32)
296296
del packed
297-
j_sorted, i_sorted = np.unravel_index(face_sorted, self._xlow.shape)
298297

299298
# Get a list of unique morton codes and their corresponding starts and counts (CSR format).
300299
# The codes are already sorted at this point, first by morton code, then by face_id
@@ -305,12 +304,14 @@ def _initialize_hash_table(self):
305304
# The number of faces per hash keys (morton codes) is easily calculated as the difference betwee the start values
306305
counts = np.diff(np.concatenate((starts, [morton_codes_sorted.size])))
307306

307+
# The flat face id is stored (4 bytes per entry); query() unravels the gathered
308+
# candidates to (j, i) on demand, instead of holding two precomputed int64
309+
# index arrays (16 bytes per entry) for the lifetime of the grid.
308310
hash_table = {
309311
"keys": keys,
310312
"starts": starts,
311313
"counts": counts,
312-
"i": i_sorted,
313-
"j": j_sorted,
314+
"faces": face_sorted,
314315
}
315316
return hash_table
316317

@@ -338,8 +339,7 @@ def query(self, y, x):
338339
keys = self._hash_table["keys"]
339340
starts = self._hash_table["starts"]
340341
counts = self._hash_table["counts"]
341-
i = self._hash_table["i"]
342-
j = self._hash_table["j"]
342+
faces = self._hash_table["faces"]
343343

344344
y = np.asarray(y)
345345
x = np.asarray(x)
@@ -415,9 +415,10 @@ def query(self, y, x):
415415
# use to quickly gather the (i,j) pairs for each query
416416
source_idx = starts[hash_positions].astype(np.int32) + intra
417417

418-
# Gather all candidate (j,i) pairs in one shot
419-
j_all = j[source_idx]
420-
i_all = i[source_idx]
418+
# Gather all candidate face ids in one shot and unravel them to (j, i) pairs;
419+
# only the gathered candidates are unraveled, not the whole table
420+
face_all = faces[source_idx]
421+
j_all, i_all = np.unravel_index(face_all, self._xlow.shape)
421422

422423
# Now we need to construct arrays that repeats the y and x coordinates for each candidate
423424
# to enable vectorized point-in-cell checks

0 commit comments

Comments
 (0)