Skip to content

Commit 9c6ce08

Browse files
Merge pull request #2134 from OceanParcels/particle-particledata
Rework of Particle class, and Particle data creation
2 parents 00c57c3 + c43c694 commit 9c6ce08

17 files changed

+469
-231
lines changed

docs/examples/example_globcurrent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def test_globcurrent_particle_independence(rundays=5):
196196
time0 = fieldset.U.grid.time[0]
197197

198198
def DeleteP0(particle, fieldset, time): # pragma: no cover
199-
if particle.id == 0:
199+
if particle.trajectory == 0:
200200
particle.delete()
201201

202202
pset0 = parcels.ParticleSet(
@@ -244,7 +244,7 @@ def test_globcurrent_pset_fromfile(dt, pid_offset, tmpdir):
244244
pset.execute(parcels.AdvectionRK4, runtime=timedelta(days=1), dt=dt)
245245
pset_new.execute(parcels.AdvectionRK4, runtime=timedelta(days=1), dt=dt)
246246

247-
for var in ["lon", "lat", "depth", "time", "id"]:
247+
for var in ["lon", "lat", "depth", "time", "trajectory"]:
248248
assert np.allclose(
249249
[getattr(p, var) for p in pset], [getattr(p, var) for p in pset_new]
250250
)

parcels/_compat.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,24 @@
1717
from sklearn.cluster import KMeans # type: ignore[no-redef]
1818
except ModuleNotFoundError:
1919
pass
20+
21+
22+
# for compat with v3 of parcels when users provide `initial=attrgetter("lon")` to a Variable
23+
# so that particle initial state matches another variable
24+
class _AttrgetterHelper:
25+
"""
26+
Example usage
27+
28+
>>> _attrgetter_helper = _AttrgetterHelper()
29+
>>> _attrgetter_helper.some_attribute
30+
'some_attribute'
31+
>>> from operator import attrgetter
32+
>>> attrgetter('some_attribute')(_attrgetter_helper)
33+
'some_attribute'
34+
"""
35+
36+
def __getattr__(self, name):
37+
return name
38+
39+
40+
_attrgetter_helper = _AttrgetterHelper()

parcels/application_kernels/interaction.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ def NearestNeighborWithinRange(particle, fieldset, time, neighbors, mutator):
2525
# undesirable results.
2626
if dist < min_dist or min_dist < 0:
2727
min_dist = dist
28-
neighbor_id = n.id
28+
neighbor_id = n.trajectory
2929

3030
def f(p, neighbor):
3131
p.nearest_neighbor = neighbor
3232

33-
mutator[particle.id].append((f, [neighbor_id]))
33+
mutator[particle.trajectory].append((f, [neighbor_id]))
3434

3535
return StatusCode.Success
3636

@@ -54,14 +54,14 @@ def merge_with_neighbor(p, nlat, nlon, ndepth, nmass):
5454
p.mass = p.mass + nmass
5555

5656
for n in neighbors:
57-
if n.id == particle.nearest_neighbor:
58-
if n.nearest_neighbor == particle.id and particle.id < n.id:
57+
if n.trajectory == particle.nearest_neighbor:
58+
if n.nearest_neighbor == particle.trajectory and particle.trajectory < n.trajectory:
5959
# Merge particles:
6060
# Delete neighbor
61-
mutator[n.id].append((delete_particle, ()))
61+
mutator[n.trajectory].append((delete_particle, ()))
6262
# Take position at the mid point and sum of masses
6363
args = np.array([n.lat, n.lon, n.depth, n.mass])
64-
mutator[particle.id].append((merge_with_neighbor, args))
64+
mutator[particle.trajectory].append((merge_with_neighbor, args))
6565

6666
return StatusCode.Success
6767
else:
@@ -101,6 +101,6 @@ def f(n, dlat, dlon, ddepth):
101101
n.lon_nextloop += dlon
102102
n.depth_nextloop += ddepth
103103

104-
mutator[n.id].append((f, d_vec))
104+
mutator[n.trajectory].append((f, d_vec))
105105

106106
return StatusCode.Success

parcels/field.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
VectorType,
1717
assert_valid_mesh,
1818
)
19-
from parcels.particle import Particle
19+
from parcels.particle import KernelParticle
2020
from parcels.tools.converters import (
2121
UnitConverter,
2222
unitconverters_map,
@@ -37,9 +37,9 @@
3737

3838

3939
def _deal_with_errors(error, key, vector_type: VectorType):
40-
if isinstance(key, Particle):
40+
if isinstance(key, KernelParticle):
4141
key.state = AllParcelsErrorCodes[type(error)]
42-
elif isinstance(key[-1], Particle):
42+
elif isinstance(key[-1], KernelParticle):
4343
key[-1].state = AllParcelsErrorCodes[type(error)]
4444
else:
4545
raise RuntimeError(f"{error}. Error could not be handled because particle was not part of the Field Sampling.")
@@ -278,7 +278,7 @@ def eval(self, time: datetime, z, y, x, particle=None, applyConversion=True):
278278
def __getitem__(self, key):
279279
self._check_velocitysampling()
280280
try:
281-
if isinstance(key, Particle):
281+
if isinstance(key, KernelParticle):
282282
return self.eval(key.time, key.depth, key.lat, key.lon, key)
283283
else:
284284
return self.eval(*key)
@@ -373,7 +373,7 @@ def eval(self, time: datetime, z, y, x, particle=None, applyConversion=True):
373373

374374
def __getitem__(self, key):
375375
try:
376-
if isinstance(key, Particle):
376+
if isinstance(key, KernelParticle):
377377
return self.eval(key.time, key.depth, key.lat, key.lon, key)
378378
else:
379379
return self.eval(*key)

parcels/interaction/interactionkernel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def execute_python(self, pset, endtime, dt):
157157
for particle_idx in active_idx:
158158
p = pset[particle_idx]
159159
try:
160-
for mutator_func, args in mutator[p.id]:
160+
for mutator_func, args in mutator[p.trajectory]:
161161
mutator_func(p, *args)
162162
except KeyError:
163163
pass
@@ -201,7 +201,7 @@ def execute(self, pset, endtime, dt, output_file=None):
201201
pass
202202
else:
203203
warnings.warn(
204-
f"Deleting particle {p.id} because of non-recoverable error",
204+
f"Deleting particle {p.trajectory} because of non-recoverable error",
205205
RuntimeWarning,
206206
stacklevel=2,
207207
)

parcels/kernel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ def execute(self, pset, endtime, dt):
259259
pass
260260
else:
261261
warnings.warn(
262-
f"Deleting particle {p.id} because of non-recoverable error",
262+
f"Deleting particle {p.trajectory} because of non-recoverable error",
263263
RuntimeWarning,
264264
stacklevel=2,
265265
)

0 commit comments

Comments
 (0)