Skip to content

Commit 2b0ec4a

Browse files
Adding unit tests for particle.time and execute dt, runtime and endtime
1 parent 6a9304a commit 2b0ec4a

2 files changed

Lines changed: 91 additions & 16 deletions

File tree

parcels/particleset.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import sys
22
import warnings
33
from collections.abc import Iterable
4-
from datetime import date, datetime, timedelta
54

65
import numpy as np
76
import xarray as xr
@@ -109,19 +108,16 @@ def __init__(
109108
depth = convert_to_flat_array(depth)
110109
assert lon.size == lat.size and lon.size == depth.size, "lon, lat, depth don't all have the same lenghts"
111110

112-
if time.size > 0:
113-
time = np.repeat(time, lon.size) if time.size == 1 else time
111+
if time is None or len(time) == 0:
112+
time = fieldset.U.time.values[0] # TODO set this to NaT if no time is given
113+
time = np.repeat(time, lon.size) if time.size == 1 else time
114114

115-
if type(time[0]) in [np.datetime64, np.timedelta64]:
116-
pass # already in the right format
117-
elif type(time[0]) in [datetime, date]:
118-
time = np.array([np.datetime64(t) for t in time])
119-
elif type(time[0]) in [timedelta]:
120-
time = np.array([np.timedelta64(t) for t in time])
121-
else:
122-
raise NotImplementedError("particle time must be a datetime, timedelta, or date object")
115+
if type(time[0]) in [np.datetime64, np.timedelta64]:
116+
pass # already in the right format
117+
else:
118+
raise TypeError("particle time must be a datetime, timedelta, or date object")
123119

124-
assert lon.size == time.size, "time and positions (lon, lat, depth) do not have the same lengths."
120+
assert lon.size == time.size, "time and positions (lon, lat, depth) do not have the same lengths."
125121

126122
if fieldset.time_interval:
127123
_warn_particle_times_outside_fieldset_time_bounds(time, fieldset.time_interval)
@@ -800,13 +796,13 @@ def execute(
800796
if self.fieldset.time_interval is None:
801797
start_time = np.timedelta64(0, "s") # For the execution loop, we need a start time as a timedelta object
802798
if runtime is None:
803-
raise ValueError("The runtime must be provided when the time_interval is not defined for a fieldset.")
799+
raise TypeError("The runtime must be provided when the time_interval is not defined for a fieldset.")
804800

805801
else:
806802
if isinstance(runtime, np.timedelta64):
807803
end_time = runtime
808804
else:
809-
raise ValueError("The runtime must be a np.timedelta64 object")
805+
raise TypeError("The runtime must be a np.timedelta64 object")
810806

811807
else:
812808
start_time = self.fieldset.time_interval.left
@@ -822,7 +818,7 @@ def execute(
822818
raise ValueError("The endtime must be after the start time of the fieldset.time_interval")
823819
end_time = min(endtime, self.fieldset.time_interval.right)
824820
else:
825-
raise ValueError("The endtime must be of the same type as the fieldset.time_interval start time.")
821+
raise TypeError("The endtime must be of the same type as the fieldset.time_interval start time.")
826822
else:
827823
end_time = start_time + runtime
828824

tests/v4/test_particleset.py

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from datetime import timedelta
1+
from contextlib import nullcontext as does_not_raise
2+
from datetime import datetime, timedelta
23

34
import numpy as np
45
import pytest
@@ -11,9 +12,87 @@
1112
ParticleSet,
1213
UXPiecewiseConstantFace,
1314
VectorField,
15+
xgcm,
1416
)
17+
from parcels._datasets.structured.generic import datasets as datasets_structured
1518
from parcels._datasets.unstructured.generic import datasets as datasets_unstructured
1619
from parcels.uxgrid import UxGrid
20+
from parcels.xgrid import XGrid
21+
22+
23+
@pytest.fixture
24+
def fieldset() -> FieldSet:
25+
ds = datasets_structured["ds_2d_left"]
26+
grid = XGrid(xgcm.Grid(ds))
27+
U = Field("U", ds["U (A grid)"], grid, mesh_type="flat")
28+
V = Field("V", ds["V (A grid)"], grid, mesh_type="flat")
29+
return FieldSet([U, V])
30+
31+
32+
def DoNothing(particle, fieldset, time):
33+
pass
34+
35+
36+
@pytest.mark.parametrize(
37+
"time, expectation",
38+
[
39+
(np.timedelta64(0, "s"), does_not_raise()),
40+
(np.datetime64("2000-01-02T00:00:00"), does_not_raise()),
41+
(0.0, pytest.raises(TypeError)),
42+
(timedelta(seconds=0), pytest.raises(TypeError)),
43+
(datetime(2023, 1, 1, 0, 0, 0), pytest.raises(TypeError)),
44+
],
45+
)
46+
def test_particleset_init_time_type(fieldset, time, expectation):
47+
with expectation:
48+
ParticleSet(fieldset, lon=[0.2], lat=[5.0], time=[time], pclass=Particle)
49+
50+
51+
@pytest.mark.parametrize(
52+
"dt, expectation",
53+
[
54+
(np.timedelta64(5, "s"), does_not_raise()),
55+
(5.0, pytest.raises(TypeError)),
56+
(np.datetime64("2000-01-02T00:00:00"), pytest.raises(TypeError)),
57+
(timedelta(seconds=2), pytest.raises(TypeError)),
58+
],
59+
)
60+
def test_particleset_dt_type(fieldset, dt, expectation):
61+
pset = ParticleSet(fieldset, lon=[0.2], lat=[5.0], depth=[50.0], pclass=Particle)
62+
with expectation:
63+
pset.execute(runtime=np.timedelta64(10, "s"), dt=dt, pyfunc=DoNothing)
64+
65+
66+
@pytest.mark.parametrize(
67+
"runtime, expectation",
68+
[
69+
(np.timedelta64(5, "s"), does_not_raise()),
70+
(5.0, pytest.raises(TypeError)),
71+
(timedelta(seconds=2), pytest.raises(TypeError)),
72+
(np.datetime64("2001-01-02T00:00:00"), pytest.raises(TypeError)),
73+
(datetime(2000, 1, 2, 0, 0, 0), pytest.raises(TypeError)),
74+
],
75+
)
76+
def test_particleset_runtime_type(fieldset, runtime, expectation):
77+
pset = ParticleSet(fieldset, lon=[0.2], lat=[5.0], depth=[50.0], pclass=Particle)
78+
with expectation:
79+
pset.execute(runtime=runtime, dt=np.timedelta64(10, "s"), pyfunc=DoNothing)
80+
81+
82+
@pytest.mark.parametrize(
83+
"endtime, expectation",
84+
[
85+
(np.datetime64("2000-01-02T00:00:00"), does_not_raise()),
86+
(5.0, pytest.raises(TypeError)),
87+
(np.timedelta64(5, "s"), pytest.raises(TypeError)),
88+
(timedelta(seconds=2), pytest.raises(TypeError)),
89+
(datetime(2000, 1, 2, 0, 0, 0), pytest.raises(TypeError)),
90+
],
91+
)
92+
def test_particleset_endtime_type(fieldset, endtime, expectation):
93+
pset = ParticleSet(fieldset, lon=[0.2], lat=[5.0], depth=[50.0], pclass=Particle)
94+
with expectation:
95+
pset.execute(endtime=endtime, dt=np.timedelta64(10, "m"), pyfunc=DoNothing)
1796

1897

1998
@pytest.mark.parametrize("verbose_progress", [True, False])

0 commit comments

Comments
 (0)