Skip to content

Commit 53483b8

Browse files
Support adding particlesets
1 parent 5459e0c commit 53483b8

2 files changed

Lines changed: 35 additions & 12 deletions

File tree

parcels/particleset.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,10 @@ def add(self, particles):
233233
234234
"""
235235
if isinstance(particles, type(self)):
236-
particles = particles.particledata
237-
self.particledata += particles
236+
particles.data["trajectory"] = (
237+
particles.data["trajectory"].values + self.data["trajectory"].values.max() + 1
238+
)
239+
self.data = xr.concat([self.data, particles.data], dim="trajectory")
238240
# Adding particles invalidates the neighbor search structure.
239241
self._dirty_neighbor = True
240242
return self
@@ -263,8 +265,8 @@ def remove_indices(self, indices):
263265
self.data = self.data.drop_sel(trajectory=indices)
264266

265267
def _active_particles_mask(self, time, dt):
266-
active_indices = (time - self.particledata.data["time"]) / dt >= 0
267-
non_err_indices = np.isin(self.particledata.data["state"], [StatusCode.Success, StatusCode.Evaluate])
268+
active_indices = (time - self.data["time"]) / dt >= 0
269+
non_err_indices = np.isin(self.data["state"], [StatusCode.Success, StatusCode.Evaluate])
268270
active_indices = np.logical_and(active_indices, non_err_indices)
269271
self._active_particle_idx = np.where(active_indices)[0]
270272
return active_indices
@@ -274,9 +276,9 @@ def _compute_neighbor_tree(self, time, dt):
274276

275277
self._values = np.vstack(
276278
(
277-
self.particledata.data["depth"],
278-
self.particledata.data["lat"],
279-
self.particledata.data["lon"],
279+
self.data["depth"],
280+
self.data["lat"],
281+
self.data["lon"],
280282
)
281283
)
282284
if self._dirty_neighbor:
@@ -290,14 +292,14 @@ def _neighbors_by_index(self, particle_idx):
290292
neighbor_idx = self._active_particle_idx[neighbor_idx]
291293
mask = neighbor_idx != particle_idx
292294
neighbor_idx = neighbor_idx[mask]
293-
if "horiz_dist" in self.particledata._ptype.variables:
294-
self.particledata.data["vert_dist"][neighbor_idx] = distances[0, mask]
295-
self.particledata.data["horiz_dist"][neighbor_idx] = distances[1, mask]
295+
if "horiz_dist" in self.data._ptype.variables:
296+
self.data["vert_dist"][neighbor_idx] = distances[0, mask]
297+
self.data["horiz_dist"][neighbor_idx] = distances[1, mask]
296298
return True # TODO fix for v4 ParticleDataIterator(self.particledata, subset=neighbor_idx)
297299

298300
def _neighbors_by_coor(self, coor):
299301
neighbor_idx = self._neighbor_tree.find_neighbors_by_coor(coor)
300-
neighbor_ids = self.particledata.data["id"][neighbor_idx]
302+
neighbor_ids = self.data["id"][neighbor_idx]
301303
return neighbor_ids
302304

303305
# TODO: This method is only tested in tutorial notebook. Add unit test?
@@ -725,7 +727,7 @@ def _num_error_particles(self):
725727
int
726728
Number of error particles.
727729
"""
728-
return np.sum(np.isin(self.particledata.data["state"], [StatusCode.Success, StatusCode.Evaluate], invert=True))
730+
return np.sum(np.isin(self.data["state"], [StatusCode.Success, StatusCode.Evaluate], invert=True))
729731

730732
def set_variable_write_status(self, var, write_status):
731733
"""Method to set the write status of a Variable.

tests/v4/test_particleset.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,27 @@ def test_particleset_endtime_type(fieldset, endtime, expectation):
9595
pset.execute(endtime=endtime, dt=np.timedelta64(10, "m"), pyfunc=DoNothing)
9696

9797

98+
def test_pset_add_explicit(fieldset):
99+
npart = 11
100+
lon = np.linspace(0, 1, npart)
101+
lat = np.linspace(1, 0, npart)
102+
pset = ParticleSet(fieldset, lon=lon[0], lat=lat[0], pclass=Particle)
103+
for i in range(1, npart):
104+
particle = ParticleSet(pclass=Particle, lon=lon[i], lat=lat[i], fieldset=fieldset)
105+
pset.add(particle)
106+
assert len(pset) == npart
107+
assert np.allclose(pset.data["lon"][:, 0], lon, atol=1e-12)
108+
assert np.allclose(pset.data["lat"][:, 0], lat, atol=1e-12)
109+
assert np.allclose(np.diff(pset.data.trajectory), np.ones(pset.data.trajectory.size - 1), atol=1e-12)
110+
111+
112+
def test_pset_add_implicit(fieldset):
113+
pset = ParticleSet(fieldset, lon=np.zeros(3), lat=np.ones(3), pclass=Particle)
114+
pset += ParticleSet(fieldset, lon=np.ones(4), lat=np.zeros(4), pclass=Particle)
115+
assert len(pset) == 7
116+
assert np.allclose(np.diff(pset.data.trajectory), np.ones(6), atol=1e-12)
117+
118+
98119
@pytest.mark.parametrize("verbose_progress", [True, False])
99120
def test_uxstommelgyre_pset_execute(verbose_progress):
100121
ds = datasets_unstructured["stommel_gyre_delaunay"]

0 commit comments

Comments
 (0)