Skip to content

Commit 08c4a6c

Browse files
[BUG FIX] Field.igrid set by reconstruct_fields() (#3018)
* move field.igrid initialization to reconstruct fields * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Remove overly defensive error messages --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent b5c39b5 commit 08c4a6c

3 files changed

Lines changed: 49 additions & 3 deletions

File tree

‎src/parcels/_core/field.py‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ def __init__(
9898
self.name = name
9999
self.model = model
100100

101-
self.igrid = -1 # Default the grid index to -1
102-
103101
@property
104102
def data(self):
105103
return self.model.field_data(self.name)
@@ -108,6 +106,14 @@ def data(self):
108106
def grid(self): # TODO PR: Remove in favour of referencing model grid directly
109107
return self.model.grid
110108

109+
@property
110+
def igrid(self):
111+
return self._igrid
112+
113+
@igrid.setter
114+
def igrid(self, value):
115+
self._igrid = value
116+
111117
@property
112118
def time_interval(self): # TODO PR: Remove in favour of referencing model time_interval directly
113119
if "time" not in self.model.data[self.name].dims:
@@ -215,7 +221,6 @@ def __init__(
215221
self.V = V
216222
self.W = W
217223
self.grid = U.grid
218-
self.igrid = U.igrid
219224

220225
if W is None:
221226
_assert_same_time_interval((U, V))
@@ -247,6 +252,10 @@ def interp_method(self, method: VectorInterpolator):
247252
raise ValueError(f"method must be a `VectorInterpolator` object. Got {type(method)=!r}")
248253
self._interp_method = method
249254

255+
@property
256+
def igrid(self):
257+
return self.U.igrid
258+
250259
def eval(self, t: datetime, z, y, x, particles=None):
251260
"""Interpolate vectorfield values in space and time.
252261

‎src/parcels/_core/fieldset.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ def reconstruct_fields(self):
106106
if self.constant_model is not None:
107107
fields += self.constant_model.construct_fields()
108108
self._fields = {f.name: f for f in fields}
109+
for field in self._fields.values():
110+
if isinstance(field, Field):
111+
field.igrid = self.gridset.index(field.grid)
109112

110113
def __getattr__(self, name):
111114
"""Get the field by name. If the field is not found, check if it's a context variable."""

‎tests/test_particleset_execute.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
Variable,
1717
)
1818
from parcels._core.mesh import FlatMesh
19+
from parcels._core.spatialhash import SpatialHash
1920
from parcels._core.statuscodes import GridSearchingError
2021
from parcels._core.utils.time import timedelta_to_float
2122
from parcels._datasets.structured.generated import simple_UV_dataset
@@ -193,6 +194,39 @@ def SampleU(particles, fieldset): # pragma: no cover
193194
pset.execute(SampleU, runtime=np.timedelta64(1, "D"), dt=np.timedelta64(1, "D"))
194195

195196

197+
def test_ei_cache_skips_spatial_hash_with_two_grids(monkeypatch):
198+
"""Each grid keeps its own cached ei, so stationary particles only go through the spatial hash on the first step."""
199+
n_hashed = []
200+
query = SpatialHash.query
201+
202+
def counting_query(self, y, x):
203+
n_hashed.append(len(y))
204+
return query(self, y, x)
205+
206+
monkeypatch.setattr(SpatialHash, "query", counting_query)
207+
208+
ds_curvilinear = datasets_structured["2d_left_rotated"][["data_g", "grid"]].rename({"data_g": "curvilinear"})
209+
ds_rectilinear = datasets_structured["ds_2d_left"][["data_g", "grid"]].rename({"data_g": "rectilinear"})
210+
fieldset = FieldSet.from_sgrid_conventions(ds_curvilinear, mesh=FlatMesh()) + FieldSet.from_sgrid_conventions(
211+
ds_rectilinear, mesh=FlatMesh()
212+
)
213+
214+
def SampleBothGrids(particles, fieldset): # pragma: no cover
215+
_ = fieldset.curvilinear[particles]
216+
_ = fieldset.rectilinear[particles]
217+
218+
npart = 50
219+
rng = np.random.default_rng(0)
220+
pset = ParticleSet(fieldset, x=rng.uniform(1, 5, npart), y=rng.uniform(1, 5, npart), z=rng.uniform(1, 80, npart))
221+
dt = np.timedelta64(1, "D")
222+
pset.execute(SampleBothGrids, runtime=dt, dt=dt)
223+
assert sum(n_hashed) == npart
224+
225+
n_hashed.clear()
226+
pset.execute(SampleBothGrids, runtime=4 * dt, dt=dt)
227+
assert sum(n_hashed) == 0
228+
229+
196230
def test_particleset_run_to_endtime(fieldset):
197231
starttime = fieldset.time_interval.left
198232
endtime = fieldset.time_interval.right

0 commit comments

Comments
 (0)