Skip to content

Commit 1d44cdb

Browse files
merge commit
2 parents af8cff8 + 1c8d5e5 commit 1d44cdb

29 files changed

+1306
-776
lines changed

.github/ci/min_deps_check.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ def parse_requirements(fname) -> Iterator[tuple[str, int, int, int | None]]:
6060

6161
try:
6262
version_tup = tuple(int(x) for x in version.split("."))
63-
except ValueError:
64-
raise ValueError("non-numerical version: " + row)
63+
except ValueError as e:
64+
raise ValueError("non-numerical version: " + row) from e
6565

6666
if len(version_tup) == 2:
6767
yield (pkg, *version_tup, None) # type: ignore[misc]

.github/workflows/pypi-release.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,6 @@ jobs:
9090
path: dist
9191
- name: Publish package to PyPI
9292
uses: pypa/[email protected]
93-
with:
94-
user: __token__
95-
password: ${{ secrets.PARCELS_PYPI_PROD_TOKEN }}
96-
verbose: true
9793

9894
test-pypi-release:
9995
needs: upload-to-pypi

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
[![Anaconda-release](https://anaconda.org/conda-forge/parcels/badges/version.svg)](https://anaconda.org/conda-forge/parcels/)
44
[![Anaconda-date](https://anaconda.org/conda-forge/parcels/badges/latest_release_date.svg)](https://anaconda.org/conda-forge/parcels/)
55
[![Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.823561.svg)](https://doi.org/10.5281/zenodo.823561)
6-
[![Code style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/format.json)](https://github.com/astral-sh/ruff)
6+
[![Xarray](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydata/xarray/refs/heads/main/doc/badge.json)](https://xarray.dev)
7+
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
78
[![unit-tests](https://github.com/OceanParcels/parcels/actions/workflows/ci.yml/badge.svg)](https://github.com/OceanParcels/parcels/actions/workflows/ci.yml)
89
[![codecov](https://codecov.io/gh/OceanParcels/parcels/branch/main/graph/badge.svg)](https://codecov.io/gh/OceanParcels/parcels)
910
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5353/badge)](https://bestpractices.coreinfrastructure.org/projects/5353)

docs/community/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ See the sections in the primary sidebar and below to explore.
1010

1111
contributing
1212
Versioning and Deprecation Policies <policies>
13+
Release Notes <https://github.com/OceanParcels/Parcels/releases>
14+
Parcels v4.0 Migration Guide <v4-migration>
1315

1416

1517

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
## Kernels:
1+
# Parcels v4 migration guide
22

3-
- The Kernel loop has been 'vectorized', so that the input of a Kernel is not one particle anymore, but a list of particles. This means that `if`-statements in Kernels don't work anymore. Replace `if`-statements with `numpy.where` statements.
3+
```{warning}
4+
Version 4 of Parcels is unreleased at the moment. The information in this migration guide is a work in progress, and is subject to change. If you would like to provide feedback on this migration guide (or generally on the development of v4) please [submit an issue](https://github.com/OceanParcels/Parcels/issues/new/choose).
5+
```
6+
7+
## Kernels
8+
9+
- The Kernel loop has been 'vectorized', so that the input of a Kernel is not one particle anymore, but a collection of particles. This means that `if`-statements in Kernels don't work anymore. Replace `if`-statements with `numpy.where` statements.
410
- `particle.delete()` is no longer valid. Instead, use `particle.state = StatusCode.Delete`.
511
- Sharing state between kernels must be done via the particle data (as the kernels are not combined under the hood anymore).
612
- `particl_dlon`, `particle_dlat` etc have been renamed to `particle.dlon` and `particle.dlat`.
713
- `particle.dt` is a np.timedelta64 object; be careful when multiplying `particle.dt` with a velocity, as its value may be cast to nanoseconds.
814
- The `time` argument in the Kernel signature is now standard `None` (and may be removed in the Kernel API before release of v4), so can't be used. Use `particle.time` instead.
15+
- `math` functions should be replaced with array compatible equivalents (e.g., `math.sin` -> `np.sin`). Instead of `ParcelsRandom` you should use numpy's random functions.
916

1017
## FieldSet
1118

@@ -16,3 +23,7 @@
1623
- `repeatdt` and `lonlatdepth_dtype` have been removed from the ParticleSet.
1724
- ParticleSet.execute() expects `numpy.datetime64`/`numpy.timedelta.64` for `runtime`, `endtime` and `dt`.
1825
- `ParticleSet.from_field()`, `ParticleSet.from_line()`, `ParticleSet.from_list()` have been removed.
26+
27+
## ParticleFile
28+
29+
- Particlefiles should be created by `ParticleFile(...)` instead of `pset.ParticleFile(...)`

docs/index.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,5 @@ If you need more help with Parcels, try the `Discussions page on GitHub <https:/
2222
Installation <installation>
2323
Tutorials & Documentation <documentation/index>
2424
API reference <reference>
25-
Release Notes <https://github.com/OceanParcels/Parcels/releases>
26-
Contributing <community/index>
25+
Contributing, Release Notes and more <community/index>
2726
OceanParcels website <https://oceanparcels.org/>

docs/v4/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ api
2222
nojit
2323
TODO
2424
Parcels v4 Project Board <https://github.com/orgs/OceanParcels/projects/5>
25+
Parcels v4 migration guide <../community/v4-migration>
2526
```

parcels/_core/utils/time.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from datetime import datetime
3+
from datetime import datetime, timedelta
44
from typing import TYPE_CHECKING, TypeVar
55

66
import cftime
@@ -118,3 +118,29 @@ def get_datetime_type_calendar(
118118
# datetime isn't a cftime datetime object
119119
pass
120120
return type(example_datetime), calendar
121+
122+
123+
_TD_PRECISION_GETTER_FOR_UNIT = (
124+
(lambda dt: dt.days, "D"),
125+
(lambda dt: dt.seconds, "s"),
126+
(lambda dt: dt.microseconds, "us"),
127+
)
128+
129+
130+
def maybe_convert_python_timedelta_to_numpy(dt: timedelta | np.timedelta64) -> np.timedelta64:
131+
if isinstance(dt, np.timedelta64):
132+
return dt
133+
134+
try:
135+
dts = []
136+
for get_value_for_unit, np_unit in _TD_PRECISION_GETTER_FOR_UNIT:
137+
value = get_value_for_unit(dt)
138+
if value != 0:
139+
dts.append(np.timedelta64(value, np_unit))
140+
141+
if dts:
142+
return sum(dts)
143+
else:
144+
return np.timedelta64(0, "s")
145+
except Exception as e:
146+
raise ValueError(f"Could not convert {dt!r} to np.timedelta64.") from e

parcels/_index_search.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,16 @@ def _search_indices_curvilinear_2d(
8383
cc = a[1] * b[0] - a[0] * b[1] + x * b[1] - y * a[1]
8484

8585
det2 = bb * bb - 4 * aa * cc
86-
det = np.where(det2 > 0, np.sqrt(det2), eta)
87-
eta = np.where(abs(aa) < 1e-12, -cc / bb, np.where(det2 > 0, (-bb + det) / (2 * aa), eta))
88-
89-
xsi = np.where(
90-
abs(a[1] + a[3] * eta) < 1e-12,
91-
((y - py[0]) / (py[1] - py[0]) + (y - py[3]) / (py[2] - py[3])) * 0.5,
92-
(x - a[0] - a[2] * eta) / (a[1] + a[3] * eta),
93-
)
86+
with np.errstate(divide="ignore", invalid="ignore"):
87+
det = np.where(det2 > 0, np.sqrt(det2), eta)
88+
89+
eta = np.where(abs(aa) < 1e-12, -cc / bb, np.where(det2 > 0, (-bb + det) / (2 * aa), eta))
90+
91+
xsi = np.where(
92+
abs(a[1] + a[3] * eta) < 1e-12,
93+
((y - py[0]) / (py[1] - py[0]) + (y - py[3]) / (py[2] - py[3])) * 0.5,
94+
(x - a[0] - a[2] * eta) / (a[1] + a[3] * eta),
95+
)
9496

9597
xi = np.where(xsi < -tol, xi - 1, np.where(xsi > 1 + tol, xi + 1, xi))
9698
yi = np.where(eta < -tol, yi - 1, np.where(eta > 1 + tol, yi + 1, yi))

0 commit comments

Comments
 (0)