Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions src/parcels/_core/spatialhash.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import sys
import warnings
from typing import IO

import numpy as np

Expand All @@ -10,6 +12,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).
Expand Down Expand Up @@ -524,6 +527,22 @@ 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):
"""
Expand Down
31 changes: 31 additions & 0 deletions src/parcels/_reprs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -280,6 +281,36 @@ 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]
Expand Down
Loading