Skip to content

Commit 58cdd61

Browse files
Merge pull request #2341 from reint-fischer/decode_times_issue_v4
Fix decode_times issue by using signed integers for time writing
2 parents 5bf4a16 + ca46898 commit 58cdd61

File tree

4 files changed

+31
-42
lines changed

4 files changed

+31
-42
lines changed

docs/examples/tutorial_Argofloats.ipynb

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,9 @@
4141
"\n",
4242
" def SinkingPhase(p):\n",
4343
" \"\"\"Phase 0: Sinking with vertical_speed until depth is driftdepth\"\"\"\n",
44-
" p.ddepth += vertical_speed * dt\n",
45-
" p.cycle_phase = np.where(p.depth + p.ddepth >= driftdepth, 1, p.cycle_phase)\n",
46-
" p.ddepth = np.where(\n",
47-
" p.depth + p.ddepth >= driftdepth, driftdepth - p.depth, p.ddepth\n",
48-
" )\n",
44+
" p.dz += vertical_speed * dt\n",
45+
" p.cycle_phase = np.where(p.z + p.dz >= driftdepth, 1, p.cycle_phase)\n",
46+
" p.dz = np.where(p.z + p.dz >= driftdepth, driftdepth - p.z, p.dz)\n",
4947
"\n",
5048
" SinkingPhase(particles[particles.cycle_phase == 0])\n",
5149
"\n",
@@ -67,11 +65,9 @@
6765
"\n",
6866
" def SecondSinkingPhase(p):\n",
6967
" \"\"\"Phase 2: Sinking further to maxdepth\"\"\"\n",
70-
" p.ddepth += vertical_speed * dt\n",
71-
" p.cycle_phase = np.where(p.depth + p.ddepth >= maxdepth, 3, p.cycle_phase)\n",
72-
" p.ddepth = np.where(\n",
73-
" p.depth + p.ddepth >= maxdepth, maxdepth - p.depth, p.ddepth\n",
74-
" )\n",
68+
" p.dz += vertical_speed * dt\n",
69+
" p.cycle_phase = np.where(p.z + p.dz >= maxdepth, 3, p.cycle_phase)\n",
70+
" p.dz = np.where(p.z + p.dz >= maxdepth, maxdepth - p.z, p.dz)\n",
7571
"\n",
7672
" SecondSinkingPhase(particles[particles.cycle_phase == 2])\n",
7773
"\n",
@@ -81,15 +77,13 @@
8177
"\n",
8278
" def RisingPhase(p):\n",
8379
" \"\"\"Phase 3: Rising with vertical_speed until at surface\"\"\"\n",
84-
" p.ddepth -= vertical_speed * dt\n",
85-
" p.temp = fieldset.thetao[p.time, p.depth, p.lat, p.lon]\n",
86-
" p.cycle_phase = np.where(\n",
87-
" p.depth + p.ddepth <= fieldset.mindepth, 4, p.cycle_phase\n",
88-
" )\n",
89-
" p.ddepth = np.where(\n",
90-
" p.depth + p.ddepth <= fieldset.mindepth,\n",
91-
" fieldset.mindepth - p.depth,\n",
92-
" p.ddepth,\n",
80+
" p.dz -= vertical_speed * dt\n",
81+
" p.temp = fieldset.thetao[p.time, p.z, p.lat, p.lon]\n",
82+
" p.cycle_phase = np.where(p.z + p.dz <= fieldset.mindepth, 4, p.cycle_phase)\n",
83+
" p.dz = np.where(\n",
84+
" p.z + p.dz <= fieldset.mindepth,\n",
85+
" fieldset.mindepth - p.z,\n",
86+
" p.dz,\n",
9387
" )\n",
9488
"\n",
9589
" RisingPhase(particles[particles.cycle_phase == 3])\n",
@@ -163,7 +157,7 @@
163157
" pclass=ArgoParticle,\n",
164158
" lon=[32],\n",
165159
" lat=[-31],\n",
166-
" depth=[fieldset.mindepth],\n",
160+
" z=[fieldset.mindepth],\n",
167161
")\n",
168162
"\n",
169163
"# combine Argo vertical movement kernel with built-in Advection kernel\n",
@@ -209,9 +203,7 @@
209203
"metadata": {},
210204
"outputs": [],
211205
"source": [
212-
"ds_out = xr.open_zarr(\n",
213-
" output_file.store, decode_times=False\n",
214-
") # TODO fix without using decode_times=False\n",
206+
"ds_out = xr.open_zarr(output_file.store)\n",
215207
"x = ds_out[\"lon\"][:].squeeze()\n",
216208
"y = ds_out[\"lat\"][:].squeeze()\n",
217209
"z = ds_out[\"z\"][:].squeeze()\n",

docs/examples/tutorial_sampling.ipynb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
"time = np.repeat(\n",
9797
" ds.time.values[0], npart\n",
9898
") # release all particles at the start time of the fieldset\n",
99-
"depth = np.repeat(ds.depth.values[0], npart)\n",
99+
"z = np.repeat(ds.depth.values[0], npart)\n",
100100
"\n",
101101
"# Plot temperature field and initial particle locations\n",
102102
"plt.figure()\n",
@@ -135,7 +135,7 @@
135135
"\n",
136136
"def SampleT(particles, fieldset):\n",
137137
" particles.temperature = fieldset.thetao[\n",
138-
" particles.time, particles.depth, particles.lat, particles.lon\n",
138+
" particles.time, particles.z, particles.lat, particles.lon\n",
139139
" ]"
140140
]
141141
},
@@ -154,7 +154,7 @@
154154
"outputs": [],
155155
"source": [
156156
"pset = parcels.ParticleSet(\n",
157-
" fieldset=fieldset, pclass=SampleParticle, lon=lon, lat=lat, time=time, depth=depth\n",
157+
" fieldset=fieldset, pclass=SampleParticle, lon=lon, lat=lat, time=time, z=z\n",
158158
")\n",
159159
"\n",
160160
"output_file = parcels.ParticleFile(\"SampleTemp.zarr\", outputdt=timedelta(hours=1))\n",
@@ -181,7 +181,7 @@
181181
"metadata": {},
182182
"outputs": [],
183183
"source": [
184-
"Particle_data = xr.open_zarr(\"SampleTemp.zarr\", decode_times=False)\n",
184+
"Particle_data = xr.open_zarr(\"SampleTemp.zarr\")\n",
185185
"\n",
186186
"plt.figure()\n",
187187
"ax = plt.axes()\n",
@@ -228,7 +228,7 @@
228228
"\n",
229229
"\n",
230230
"pset = parcels.ParticleSet(\n",
231-
" fieldset=fieldset, pclass=parcels.Particle, lon=lon, lat=lat, time=time, depth=depth\n",
231+
" fieldset=fieldset, pclass=parcels.Particle, lon=lon, lat=lat, time=time, z=z\n",
232232
")\n",
233233
"\n",
234234
"pset.execute(\n",
@@ -257,7 +257,7 @@
257257
"\n",
258258
"\n",
259259
"pset = parcels.ParticleSet(\n",
260-
" fieldset=fieldset, pclass=parcels.Particle, lon=lon, lat=lat, time=time, depth=depth\n",
260+
" fieldset=fieldset, pclass=parcels.Particle, lon=lon, lat=lat, time=time, z=z\n",
261261
")\n",
262262
"\n",
263263
"pset.execute(SampleVel_correct, runtime=timedelta(hours=30), dt=timedelta(minutes=5))"
@@ -331,7 +331,7 @@
331331
" lon=lon,\n",
332332
" lat=lat,\n",
333333
" time=time,\n",
334-
" depth=depth,\n",
334+
" z=z,\n",
335335
")"
336336
]
337337
},
@@ -406,7 +406,7 @@
406406
"name": "python",
407407
"nbconvert_exporter": "python",
408408
"pygments_lexer": "ipython3",
409-
"version": "3.12.11"
409+
"version": "3.11.0"
410410
},
411411
"pycharm": {
412412
"stem_cell": {

src/parcels/_core/particlefile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
np.dtype(np.int8): np.iinfo(np.int8).max,
3333
np.dtype(np.int16): np.iinfo(np.int16).max,
3434
np.dtype(np.int32): np.iinfo(np.int32).max,
35-
np.dtype(np.int64): np.iinfo(np.int64).max,
35+
np.dtype(np.int64): np.iinfo(np.int64).min,
3636
np.dtype(np.uint8): np.iinfo(np.uint8).max,
3737
np.dtype(np.uint16): np.iinfo(np.uint16).max,
3838
np.dtype(np.uint32): np.iinfo(np.uint32).max,
@@ -335,7 +335,7 @@ def _maybe_convert_time_dtype(dtype: np.dtype | _SAME_AS_FIELDSET_TIME_INTERVAL)
335335
"""Convert the dtype of time to float64 if it is not already."""
336336
if dtype is _SAME_AS_FIELDSET_TIME_INTERVAL.VALUE:
337337
return np.dtype(
338-
np.uint64
338+
np.int64
339339
) #! We need to have here some proper mechanism for converting particle data to the data that is to be output to zarr (namely the time needs to be converted to float seconds by subtracting the time_interval.left)
340340
return dtype
341341

tests/test_particlefile.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ def fieldset() -> FieldSet: # TODO v4: Move into a `conftest.py` file and remov
3030
)
3131

3232

33-
@pytest.mark.skip
3433
def test_metadata(fieldset, tmp_zarrfile):
3534
pset = ParticleSet(fieldset, pclass=Particle, lon=0, lat=0)
3635

37-
pset.execute(DoNothing, runtime=1, output_file=ParticleFile(tmp_zarrfile, outputdt=np.timedelta64(1, "s")))
36+
ofile = ParticleFile(tmp_zarrfile, outputdt=np.timedelta64(1, "s"))
37+
pset.execute(DoNothing, runtime=np.timedelta64(1, "s"), dt=np.timedelta64(1, "s"), output_file=ofile)
3838

39-
ds = xr.open_zarr(tmp_zarrfile, decode_cf=False) # TODO v4: Fix metadata and re-enable decode_cf
40-
assert ds.attrs["parcels_kernels"].lower() == "ParticleDoNothing".lower()
39+
ds = xr.open_zarr(tmp_zarrfile)
40+
assert ds.attrs["parcels_kernels"].lower() == "DoNothing".lower()
4141

4242

4343
def test_pfile_array_write_zarr_memorystore(fieldset):
@@ -76,11 +76,8 @@ def test_pfile_array_remove_particles(fieldset, tmp_zarrfile):
7676
pset._data["time"][:] = new_time
7777
pset._data["time_nextloop"][:] = new_time
7878
pfile.write(pset, new_time)
79-
ds = xr.open_zarr(tmp_zarrfile, decode_cf=False)
79+
ds = xr.open_zarr(tmp_zarrfile)
8080
timearr = ds["time"][:]
81-
pytest.skip(
82-
"TODO v4: Set decode_cf=True, which will mean that missing values get decoded to NaT rather than fill value"
83-
)
8481
assert (np.isnat(timearr[3, 1])) and (np.isfinite(timearr[3, 0]))
8582

8683

@@ -129,7 +126,7 @@ def Update_lon(particles, fieldset): # pragma: no cover
129126
output_file=ofile,
130127
)
131128

132-
ds = xr.open_zarr(tmp_zarrfile, decode_cf=False) # TODO v4: Fix metadata and re-enable decode_cf
129+
ds = xr.open_zarr(tmp_zarrfile)
133130
lons = ds["lon"][:]
134131
assert isinstance(lons.values[0, 0], np.float64)
135132

0 commit comments

Comments
 (0)