Skip to content

Commit 84468cc

Browse files
Remove ParticleSet methods (from_line, from_field, from_list) (#2127)
* Remove ParticleSet.from_field() * Remove ParticleSet.from_line() * Remove ParticleSet.from_list()
1 parent bef8ee3 commit 84468cc

File tree

6 files changed

+6
-232
lines changed

6 files changed

+6
-232
lines changed

parcels/particleset.py

Lines changed: 1 addition & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -347,221 +347,7 @@ def populate_indices(self):
347347
self._data["ei"][:, i] = idx # assumes that we are in the surface layer (zi=0)
348348

349349
@classmethod
350-
def from_list(
351-
cls, fieldset, pclass, lon, lat, depth=None, time=None, repeatdt=None, lonlatdepth_dtype=None, **kwargs
352-
):
353-
"""Initialise the ParticleSet from lists of lon and lat.
354-
355-
Parameters
356-
----------
357-
fieldset :
358-
mod:`parcels.fieldset.FieldSet` object from which to sample velocity
359-
pclass :
360-
Particle class. May be a parcels.particle.Particle class as defined in parcels, or a subclass defining a custom particle.
361-
lon :
362-
List of initial longitude values for particles
363-
lat :
364-
List of initial latitude values for particles
365-
depth :
366-
Optional list of initial depth values for particles. Default is 0m
367-
time :
368-
Optional list of start time values for particles. Default is fieldset.U.time[0]
369-
repeatdt :
370-
Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
371-
lonlatdepth_dtype :
372-
Floating precision for lon, lat, depth particle coordinates.
373-
It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
374-
and np.float64 if the interpolation method is 'cgrid_velocity'
375-
Other Variables can be initialised using further arguments (e.g. v=... for a Variable named 'v')
376-
**kwargs :
377-
Keyword arguments passed to the particleset constructor.
378-
"""
379-
return cls(
380-
fieldset=fieldset,
381-
pclass=pclass,
382-
lon=lon,
383-
lat=lat,
384-
depth=depth,
385-
time=time,
386-
repeatdt=repeatdt,
387-
lonlatdepth_dtype=lonlatdepth_dtype,
388-
**kwargs,
389-
)
390-
391-
@classmethod
392-
def from_line(
393-
cls,
394-
fieldset,
395-
pclass,
396-
start,
397-
finish,
398-
size,
399-
depth=None,
400-
time=None,
401-
repeatdt=None,
402-
lonlatdepth_dtype=None,
403-
**kwargs,
404-
):
405-
"""Create a particleset in the shape of a line (according to a cartesian grid).
406-
407-
Initialise the ParticleSet from start/finish coordinates with equidistant spacing
408-
Note that this method uses simple numpy.linspace calls and does not take into account
409-
great circles, so may not be a exact on a globe
410-
411-
Parameters
412-
----------
413-
fieldset :
414-
mod:`parcels.fieldset.FieldSet` object from which to sample velocity
415-
pclass :
416-
Particle class. May be a parcels.particle.Particle as defined in parcels, or a subclass defining a custom particle.
417-
start :
418-
Start point (longitude, latitude) for initialisation of particles on a straight line.
419-
finish :
420-
End point (longitude, latitude) for initialisation of particles on a straight line.
421-
size :
422-
Initial size of particle set
423-
depth :
424-
Optional list of initial depth values for particles. Default is 0m
425-
time :
426-
Optional start time value for particles. Default is fieldset.U.time[0]
427-
repeatdt :
428-
Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
429-
lonlatdepth_dtype :
430-
Floating precision for lon, lat, depth particle coordinates.
431-
It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
432-
and np.float64 if the interpolation method is 'cgrid_velocity'
433-
"""
434-
lon = np.linspace(start[0], finish[0], size)
435-
lat = np.linspace(start[1], finish[1], size)
436-
if type(depth) in [int, float]:
437-
depth = [depth] * size
438-
return cls(
439-
fieldset=fieldset,
440-
pclass=pclass,
441-
lon=lon,
442-
lat=lat,
443-
depth=depth,
444-
time=time,
445-
repeatdt=repeatdt,
446-
lonlatdepth_dtype=lonlatdepth_dtype,
447-
**kwargs,
448-
)
449-
450-
@classmethod
451-
def _monte_carlo_sample(cls, start_field, size, mode="monte_carlo"):
452-
"""Converts a starting field into a monte-carlo sample of lons and lats.
453-
454-
Parameters
455-
----------
456-
start_field : parcels.field.Field
457-
mod:`parcels.fieldset.Field` object for initialising particles stochastically (horizontally) according to the presented density field.
458-
size :
459-
460-
mode :
461-
(Default value = 'monte_carlo')
462-
463-
Returns
464-
-------
465-
list of float
466-
A list of longitude values.
467-
list of float
468-
A list of latitude values.
469-
"""
470-
if mode == "monte_carlo":
471-
data = start_field.data if isinstance(start_field.data, np.ndarray) else np.array(start_field.data)
472-
if start_field.interp_method == "cgrid_tracer":
473-
p_interior = np.squeeze(data[0, 1:, 1:])
474-
else: # if A-grid
475-
d = data
476-
p_interior = (d[0, :-1, :-1] + d[0, 1:, :-1] + d[0, :-1, 1:] + d[0, 1:, 1:]) / 4.0
477-
p_interior = np.where(d[0, :-1, :-1] == 0, 0, p_interior)
478-
p_interior = np.where(d[0, 1:, :-1] == 0, 0, p_interior)
479-
p_interior = np.where(d[0, 1:, 1:] == 0, 0, p_interior)
480-
p_interior = np.where(d[0, :-1, 1:] == 0, 0, p_interior)
481-
p = np.reshape(p_interior, (1, p_interior.size))
482-
inds = np.random.choice(p_interior.size, size, replace=True, p=p[0] / np.sum(p))
483-
xsi = np.random.uniform(size=len(inds))
484-
eta = np.random.uniform(size=len(inds))
485-
j, i = np.unravel_index(inds, p_interior.shape)
486-
grid = start_field.grid
487-
lon, lat = ([], [])
488-
if grid._gtype in [GridType.RectilinearZGrid, GridType.RectilinearSGrid]:
489-
lon = grid.lon[i] + xsi * (grid.lon[i + 1] - grid.lon[i])
490-
lat = grid.lat[j] + eta * (grid.lat[j + 1] - grid.lat[j])
491-
else:
492-
lons = np.array([grid.lon[j, i], grid.lon[j, i + 1], grid.lon[j + 1, i + 1], grid.lon[j + 1, i]])
493-
if grid.mesh == "spherical":
494-
lons[1:] = np.where(lons[1:] - lons[0] > 180, lons[1:] - 360, lons[1:])
495-
lons[1:] = np.where(-lons[1:] + lons[0] > 180, lons[1:] + 360, lons[1:])
496-
lon = (
497-
(1 - xsi) * (1 - eta) * lons[0]
498-
+ xsi * (1 - eta) * lons[1]
499-
+ xsi * eta * lons[2]
500-
+ (1 - xsi) * eta * lons[3]
501-
)
502-
lat = (
503-
(1 - xsi) * (1 - eta) * grid.lat[j, i]
504-
+ xsi * (1 - eta) * grid.lat[j, i + 1]
505-
+ xsi * eta * grid.lat[j + 1, i + 1]
506-
+ (1 - xsi) * eta * grid.lat[j + 1, i]
507-
)
508-
return list(lat), list(lon)
509-
else:
510-
raise NotImplementedError(f'Mode {mode} not implemented. Please use "monte carlo" algorithm instead.')
511-
512-
@classmethod
513-
def from_field(
514-
cls,
515-
fieldset,
516-
pclass,
517-
start_field,
518-
size,
519-
mode="monte_carlo",
520-
depth=None,
521-
time=None,
522-
repeatdt=None,
523-
lonlatdepth_dtype=None,
524-
):
525-
"""Initialise the ParticleSet randomly drawn according to distribution from a field.
526-
527-
Parameters
528-
----------
529-
fieldset : parcels.fieldset.FieldSet
530-
mod:`parcels.fieldset.FieldSet` object from which to sample velocity
531-
pclass :
532-
Particle class. May be a parcels.particle.Particle class as defined in parcels, or a subclass defining a custom particle.
533-
start_field : parcels.field.Field
534-
Field for initialising particles stochastically (horizontally) according to the presented density field.
535-
size :
536-
Initial size of particle set
537-
mode :
538-
Type of random sampling. Currently only 'monte_carlo' is implemented (Default value = 'monte_carlo')
539-
depth :
540-
Optional list of initial depth values for particles. Default is 0m
541-
time :
542-
Optional start time value for particles. Default is fieldset.U.time[0]
543-
repeatdt :
544-
Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
545-
lonlatdepth_dtype :
546-
Floating precision for lon, lat, depth particle coordinates.
547-
It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
548-
and np.float64 if the interpolation method is 'cgrid_velocity'
549-
"""
550-
lat, lon = cls._monte_carlo_sample(start_field, size, mode)
551-
552-
return cls(
553-
fieldset=fieldset,
554-
pclass=pclass,
555-
lon=lon,
556-
lat=lat,
557-
depth=depth,
558-
time=time,
559-
lonlatdepth_dtype=lonlatdepth_dtype,
560-
repeatdt=repeatdt,
561-
)
562-
563-
@classmethod
564-
def from_particlefile(cls, fieldset, pclass, filename, restart=True, restarttime=None, repeatdt=None, **kwargs):
350+
def from_particlefile(cls, fieldset, pclass, filename, restart=True, restarttime=None, **kwargs):
565351
"""Initialise the ParticleSet from a zarr ParticleFile.
566352
This creates a new ParticleSet based on locations of all particles written
567353
in a zarr ParticleFile at a certain time. Particle IDs are preserved if restart=True

tests/test_fieldset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ def sampleTemp(particle, fieldset, time): # pragma: no cover
343343
]
344344
)
345345

346-
pset = ParticleSet.from_list(fieldset, pclass=MyParticle, lon=[0.5], lat=[0.5], depth=[0.5])
346+
pset = ParticleSet(fieldset, pclass=MyParticle, lon=[0.5], lat=[0.5], depth=[0.5])
347347
pset.execute(
348348
AdvectionRK4_3D + pset.Kernel(sampleTemp), runtime=timedelta(hours=51), dt=timedelta(hours=dt_sign * 1)
349349
)

tests/test_particlesets.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def test_pset_create_list_with_customvariable(fieldset):
3232
MyParticle = Particle.add_variable("v")
3333

3434
v_vals = np.arange(npart)
35-
pset = ParticleSet.from_list(fieldset, lon=lon, lat=lat, v=v_vals, pclass=MyParticle)
35+
pset = ParticleSet(fieldset, lon=lon, lat=lat, v=v_vals, pclass=MyParticle)
3636
assert np.allclose([p.lon for p in pset], lon, rtol=1e-12)
3737
assert np.allclose([p.lat for p in pset], lat, rtol=1e-12)
3838
assert np.allclose([p.v for p in pset], v_vals, rtol=1e-12)
@@ -127,7 +127,7 @@ def test_pset_create_with_time(fieldset):
127127
time = 5.0
128128
pset = ParticleSet(fieldset, lon=lon, lat=lat, pclass=Particle, time=time)
129129
assert np.allclose([p.time for p in pset], time, rtol=1e-12)
130-
pset = ParticleSet.from_list(fieldset, lon=lon, lat=lat, pclass=Particle, time=[time] * npart)
130+
pset = ParticleSet(fieldset, lon=lon, lat=lat, pclass=Particle, time=[time] * npart)
131131
assert np.allclose([p.time for p in pset], time, rtol=1e-12)
132132
pset = ParticleSet.from_line(fieldset, size=npart, start=(0, 1), finish=(1, 0), pclass=Particle, time=time)
133133
assert np.allclose([p.time for p in pset], time, rtol=1e-12)

tests/v4/test_particleset.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,6 @@ def test_pset_create_lon_lat(fieldset):
3737
assert np.allclose([p.lat for p in pset], lat, rtol=1e-12)
3838

3939

40-
@pytest.mark.parametrize("lonlatdepth_dtype", [np.float64, np.float32])
41-
def test_pset_create_line(fieldset, lonlatdepth_dtype):
42-
npart = 100
43-
lon = np.linspace(0, 1, npart, dtype=lonlatdepth_dtype)
44-
lat = np.linspace(1, 0, npart, dtype=lonlatdepth_dtype)
45-
pset = ParticleSet.from_line(
46-
fieldset, size=npart, start=(0, 1), finish=(1, 0), pclass=Particle, lonlatdepth_dtype=lonlatdepth_dtype
47-
)
48-
assert np.allclose([p.lon for p in pset], lon, rtol=1e-12)
49-
assert np.allclose([p.lat for p in pset], lat, rtol=1e-12)
50-
assert isinstance(pset[0].lat, lonlatdepth_dtype)
51-
52-
5340
def test_create_empty_pset(fieldset):
5441
pset = ParticleSet(fieldset, pclass=Particle)
5542
assert pset.size == 0

tests/v4/test_structured_gcm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ def test_fieldset_frompop():
1212
# dimensions = {"lon": "lon", "lat": "lat", "time": "time"}
1313

1414
# fieldset = FieldSet.from_pop(filenames, variables, dimensions, mesh="flat")
15-
# pset = ParticleSet.from_list(fieldset, Particle, lon=[3, 5, 1], lat=[3, 5, 1])
15+
# pset = ParticleSet(fieldset, Particle, lon=[3, 5, 1], lat=[3, 5, 1])
1616
# pset.execute(AdvectionRK4, runtime=3, dt=1)
1717
pass

v3to4-breaking-changes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ FieldSet
1212
ParticleSet
1313

1414
- ParticleSet.execute() expects `numpy.datetime64`/`numpy.timedelta.64` for `runtime`, `endtime` and `dt`
15+
- `ParticleSet.from_field()`, `ParticleSet.from_line()`, `ParticleSet.from_list()` has been removed

0 commit comments

Comments
 (0)