From 280d43e3f2eff67f41932acaa2edbbea9bd22ed3 Mon Sep 17 00:00:00 2001 From: Wyatt Sieminski Date: Fri, 31 Jul 2026 13:42:50 -0400 Subject: [PATCH 1/2] Added spatialhash.describe to spatialhash.py and associated spatialhash_describe to _reprs.py --- src/parcels/_core/spatialhash.py | 21 ++++++++++++++++++++ src/parcels/_reprs.py | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/parcels/_core/spatialhash.py b/src/parcels/_core/spatialhash.py index bcb11914a..39d69e26f 100644 --- a/src/parcels/_core/spatialhash.py +++ b/src/parcels/_core/spatialhash.py @@ -1,5 +1,8 @@ import warnings +import sys +from typing import IO + import numpy as np from parcels._core.index_search import ( @@ -10,6 +13,7 @@ ) from parcels._core.warnings import FieldSetWarning from parcels._python import isinstance_noimport +from parcels._reprs import spatialhash_describe # Budget on the total number of (face, hash cell) pairs in the hash table: # max(_HASH_ENTRIES_PER_FACE * nfaces, _HASH_ENTRY_BUDGET_MIN). @@ -524,6 +528,23 @@ def query(self, y, x): coords_best.reshape((num_queries, coordinates.shape[1])), ) + def describe(self, buf: IO | None = None) -> None: + """ + Summary of the SpatialHash's hash-table statistics (resolution, occupancy, + entry counts). + + Parameters + ---------- + buf : file-like, default: sys.stdout + writable buffer + """ + if buf is None: + buf = sys.stdout + assert buf is not None + + buf.write(spatialhash_describe(self)) + + def _dilate_bits(n): """ diff --git a/src/parcels/_reprs.py b/src/parcels/_reprs.py index 5a6ae2944..a8b1c55f1 100644 --- a/src/parcels/_reprs.py +++ b/src/parcels/_reprs.py @@ -18,6 +18,7 @@ from parcels import Field, FieldSet, ParticleSet from parcels._core.field import VectorField from parcels._core.model import ModelData + from parcels._core.spatialhash import SpatialHash from parcels._core.utils.time import TimeInterval @@ -280,6 +281,38 @@ def fieldset_describe(fieldset: FieldSet) -> str: ) +def spatialhash_describe(spatialhash: SpatialHash) -> str: + grid = spatialhash._source_grid + hash_table = spatialhash._hash_table + counts = hash_table["counts"] + + n_faces = int(np.size(spatialhash._xlow)) + n_entries = int(hash_table["faces"].size) + n_occupied_cells = int(hash_table["keys"].size) + n_total_cells = (spatialhash._bitwidth + 1) ** 3 + + rows = { + "Grid type": type(grid).__name__, + "Mesh": "spherical" if grid._mesh.is_spherical() else "flat", + "Total Mesh Faces": str(n_faces), + "Bitwidth (current / max)": f"{spatialhash._bitwidth} / 1023 (higher = finer resolution hash grid)", + "Total hash cells": str(n_total_cells), + "Occupied hash cells": str(n_occupied_cells), + "Total (cell --> face) entries": str(n_entries), + "Entries per occupied cell (avg)": f"{n_entries / n_occupied_cells:.2f}" if n_occupied_cells else "-", + "Entries per face (avg)": f"{n_entries / n_faces:.2f}" if n_faces else "-", + "Faces per occupied cell (min / mean / max)": ( + f"{counts.min()} / {counts.mean():.2f} / {counts.max()}" if n_occupied_cells else "-" + ), + } + key_width = max(len(k) for k in rows) + table = "\n".join(f"{k.ljust(key_width)} : {v}" for k, v in rows.items()) + + return ( + "Spatial Hash Grid Statistics" + "\n" + + table + "\n" + ) + def _get_parent_model(field: Field | VectorField) -> ModelData: if isinstance_noimport(field, "Field"): return field.model # type:ignore[union-attr] From 7b204ca7dc865bfdfd6491456d36185f358ca2cc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 17:49:36 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/parcels/_core/spatialhash.py | 4 +--- src/parcels/_reprs.py | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/parcels/_core/spatialhash.py b/src/parcels/_core/spatialhash.py index 39d69e26f..18f8d4801 100644 --- a/src/parcels/_core/spatialhash.py +++ b/src/parcels/_core/spatialhash.py @@ -1,6 +1,5 @@ -import warnings - import sys +import warnings from typing import IO import numpy as np @@ -545,7 +544,6 @@ def describe(self, buf: IO | None = None) -> None: buf.write(spatialhash_describe(self)) - def _dilate_bits(n): """ Takes a 10-bit integer n, in range [0,1023], and "dilates" its bits so that diff --git a/src/parcels/_reprs.py b/src/parcels/_reprs.py index a8b1c55f1..1eb1bde0d 100644 --- a/src/parcels/_reprs.py +++ b/src/parcels/_reprs.py @@ -308,10 +308,8 @@ def spatialhash_describe(spatialhash: SpatialHash) -> str: key_width = max(len(k) for k in rows) table = "\n".join(f"{k.ljust(key_width)} : {v}" for k, v in rows.items()) - return ( - "Spatial Hash Grid Statistics" + "\n" - + table + "\n" - ) + return "Spatial Hash Grid Statistics" + "\n" + table + "\n" + def _get_parent_model(field: Field | VectorField) -> ModelData: if isinstance_noimport(field, "Field"):