Skip to content

Commit f979749

Browse files
Revert "[#2034] Remove repeatdt references"
This reverts commit 1c1cbe3.
1 parent 87277c7 commit f979749

1 file changed

Lines changed: 68 additions & 4 deletions

File tree

parcels/particleset.py

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from parcels.grid import GridType
1515
from parcels.interaction.interactionkernel import InteractionKernel
1616
from parcels.kernel import Kernel
17-
from parcels.particle import Particle
17+
from parcels.particle import Particle, Variable
1818
from parcels.particledata import ParticleData, ParticleDataIterator
1919
from parcels.particlefile import ParticleFile
2020
from parcels.tools.converters import _get_cftime_calendars, convert_to_flat_array
@@ -54,6 +54,8 @@ class ParticleSet:
5454
Optional list of initial depth values for particles. Default is 0m
5555
time :
5656
Optional list of initial time values for particles. Default is fieldset.U.grid.time[0]
57+
repeatdt : datetime.timedelta or float, optional
58+
Optional interval on which to repeat the release of the ParticleSet. Either timedelta object, or float in seconds.
5759
lonlatdepth_dtype :
5860
Floating precision for lon, lat, depth particle coordinates.
5961
It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
@@ -82,12 +84,49 @@ def __init__(
8284
**kwargs,
8385
):
8486
self.particledata = None
87+
self._repeat_starttime = None
88+
self._repeatlon = None
89+
self._repeatlat = None
90+
self._repeatdepth = None
91+
self._repeatpclass = None
92+
self._repeatkwargs = None
8593
self._kernel = None
8694
self._interaction_kernel = None
8795

8896
self.fieldset = fieldset
8997
self._pclass = pclass
9098

99+
# ==== first: create a new subclass of the pclass that includes the required variables ==== #
100+
# ==== see dynamic-instantiation trick here: https://www.python-course.eu/python3_classes_and_type.php ==== #
101+
class_name = pclass.__name__
102+
array_class = None
103+
if class_name not in dir():
104+
105+
def ArrayClass_init(self, *args, **kwargs):
106+
fieldset = kwargs.get("fieldset", None)
107+
ngrids = kwargs.get("ngrids", None)
108+
if type(self).ngrids.initial < 0:
109+
numgrids = ngrids
110+
if numgrids is None and fieldset is not None:
111+
numgrids = fieldset.gridset_size
112+
assert numgrids is not None, "Neither fieldsets nor number of grids are specified - exiting."
113+
type(self).ngrids.initial = numgrids
114+
self.ngrids = type(self).ngrids.initial
115+
if self.ngrids >= 0:
116+
self.ei = np.zeros(self.ngrids, dtype=np.int32)
117+
super(type(self), self).__init__(*args, **kwargs)
118+
119+
array_class_vdict = {
120+
"ngrids": Variable("ngrids", dtype=np.int32, to_write=False, initial=-1),
121+
"ei": Variable("ei", dtype=np.int32, to_write=False),
122+
"__init__": ArrayClass_init,
123+
}
124+
array_class = type(class_name, (pclass,), array_class_vdict)
125+
else:
126+
array_class = locals()[class_name]
127+
# ==== dynamic re-classing completed ==== #
128+
_pclass = array_class
129+
91130
lon = np.empty(shape=0) if lon is None else convert_to_flat_array(lon)
92131
lat = np.empty(shape=0) if lat is None else convert_to_flat_array(lat)
93132

@@ -132,7 +171,7 @@ def __init__(
132171
), f"{kwvar} and positions (lon, lat, depth) don't have the same lengths."
133172

134173
self.particledata = ParticleData(
135-
self._pclass,
174+
_pclass,
136175
lon=lon,
137176
lat=lat,
138177
depth=depth,
@@ -317,7 +356,9 @@ def populate_indices(self):
317356
self.particledata.data["ei"][:, i] = idx # assumes that we are in the surface layer (zi=0)
318357

319358
@classmethod
320-
def from_list(cls, fieldset, pclass, lon, lat, depth=None, time=None, lonlatdepth_dtype=None, **kwargs):
359+
def from_list(
360+
cls, fieldset, pclass, lon, lat, depth=None, time=None, repeatdt=None, lonlatdepth_dtype=None, **kwargs
361+
):
321362
"""Initialise the ParticleSet from lists of lon and lat.
322363
323364
Parameters
@@ -334,6 +375,8 @@ def from_list(cls, fieldset, pclass, lon, lat, depth=None, time=None, lonlatdept
334375
Optional list of initial depth values for particles. Default is 0m
335376
time :
336377
Optional list of start time values for particles. Default is fieldset.U.time[0]
378+
repeatdt :
379+
Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
337380
lonlatdepth_dtype :
338381
Floating precision for lon, lat, depth particle coordinates.
339382
It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
@@ -349,6 +392,7 @@ def from_list(cls, fieldset, pclass, lon, lat, depth=None, time=None, lonlatdept
349392
lat=lat,
350393
depth=depth,
351394
time=time,
395+
repeatdt=repeatdt,
352396
lonlatdepth_dtype=lonlatdepth_dtype,
353397
**kwargs,
354398
)
@@ -363,6 +407,7 @@ def from_line(
363407
size,
364408
depth=None,
365409
time=None,
410+
repeatdt=None,
366411
lonlatdepth_dtype=None,
367412
**kwargs,
368413
):
@@ -388,6 +433,8 @@ def from_line(
388433
Optional list of initial depth values for particles. Default is 0m
389434
time :
390435
Optional start time value for particles. Default is fieldset.U.time[0]
436+
repeatdt :
437+
Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
391438
lonlatdepth_dtype :
392439
Floating precision for lon, lat, depth particle coordinates.
393440
It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
@@ -404,6 +451,7 @@ def from_line(
404451
lat=lat,
405452
depth=depth,
406453
time=time,
454+
repeatdt=repeatdt,
407455
lonlatdepth_dtype=lonlatdepth_dtype,
408456
**kwargs,
409457
)
@@ -480,6 +528,7 @@ def from_field(
480528
mode="monte_carlo",
481529
depth=None,
482530
time=None,
531+
repeatdt=None,
483532
lonlatdepth_dtype=None,
484533
):
485534
"""Initialise the ParticleSet randomly drawn according to distribution from a field.
@@ -500,6 +549,8 @@ def from_field(
500549
Optional list of initial depth values for particles. Default is 0m
501550
time :
502551
Optional start time value for particles. Default is fieldset.U.time[0]
552+
repeatdt :
553+
Optional interval (in seconds) on which to repeat the release of the ParticleSet (Default value = None)
503554
lonlatdepth_dtype :
504555
Floating precision for lon, lat, depth particle coordinates.
505556
It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
@@ -515,11 +566,12 @@ def from_field(
515566
depth=depth,
516567
time=time,
517568
lonlatdepth_dtype=lonlatdepth_dtype,
569+
repeatdt=repeatdt,
518570
)
519571

520572
@classmethod
521573
def from_particlefile(
522-
cls, fieldset, pclass, filename, restart=True, restarttime=None, lonlatdepth_dtype=None, **kwargs
574+
cls, fieldset, pclass, filename, restart=True, restarttime=None, repeatdt=None, lonlatdepth_dtype=None, **kwargs
523575
):
524576
"""Initialise the ParticleSet from a zarr ParticleFile.
525577
This creates a new ParticleSet based on locations of all particles written
@@ -540,13 +592,24 @@ def from_particlefile(
540592
time at which the Particles will be restarted. Default is the last time written.
541593
Alternatively, restarttime could be a time value (including np.datetime64) or
542594
a callable function such as np.nanmin. The last is useful when running with dt < 0.
595+
repeatdt : datetime.timedelta or float, optional
596+
Optional interval on which to repeat the release of the ParticleSet. Either timedelta object, or float in seconds.
543597
lonlatdepth_dtype :
544598
Floating precision for lon, lat, depth particle coordinates.
545599
It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
546600
and np.float64 if the interpolation method is 'cgrid_velocity'
547601
**kwargs :
548602
Keyword arguments passed to the particleset constructor.
549603
"""
604+
if repeatdt is not None:
605+
warnings.warn(
606+
f"Note that the `repeatdt` argument is not retained from {filename}, and that "
607+
"setting a new repeatdt will start particles from the _new_ particle "
608+
"locations.",
609+
ParticleSetWarning,
610+
stacklevel=2,
611+
)
612+
550613
pfile = xr.open_zarr(str(filename))
551614
pfile_vars = [v for v in pfile.data_vars]
552615

@@ -612,6 +675,7 @@ def from_particlefile(
612675
time=vars["time"],
613676
pid_orig=vars["id"],
614677
lonlatdepth_dtype=lonlatdepth_dtype,
678+
repeatdt=repeatdt,
615679
**kwargs,
616680
)
617681

0 commit comments

Comments
 (0)