Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/user_guide/convert_mom6.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.14"
},
"mystnb": {
"execution_in_temp": true
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion docs/user_guide/fieldsets_grids.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"Parcels can natively handle two styles of grids; structured and unstructured, where Parcels `Field` objects exist on a (structured) {py:obj}`parcels.XGrid` and conform to [SGRID](https://sgrid.github.io/sgrid/) conventions, or on a (unstructured) {py:obj}`parcels.UxGrid` and conform to [UGRID](https://ugrid-conventions.github.io/ugrid-conventions/) conventions. Here we describe these grids on a conceptual level.\n",
"\n",
"```{note}\n",
"Parcels comes ready with a range of `convert` functions which will convert your `xarray` dataset into a SGRID or UGRID compliant dataset. See [this list](group_convert_models.md) for all the models we have `convert` functions for. If your model is not on that list, you can [create your own `convert` function](./convert_writing_functions.md), or reach out on our discussion board for help.\n",
"Parcels comes ready with a range of `convert` functions which will convert your `xarray` dataset into a SGRID or UGRID compliant dataset. See [this list](group_convert_ocean_models.md) for all the ocean models we have `convert` functions for, and [this list](group_convert_atmospheric_models.md) for all the atmosphere models we have `convert` functions for. If your model is not on that list, you can [create your own `convert` function](./convert_writing_functions.md), or reach out on our discussion board for help.\n",
"```\n",
"\n",
"Under the hood, every `Field` in a `FieldSet` has a `grid` attribute. This `grid` stores the spatial and temporal information of the Field coordinates. The number of Grids in a FieldSet is thus always smaller or equal to the number of Field objects; and this is what the \"grid number\" column in {py:func}`parcels.FieldSet.describe()` refers to.\n",
Expand Down
2 changes: 2 additions & 0 deletions src/parcels/_core/utils/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ def float_to_datelike(dt: float, time_interval) -> np.datetime64 | np.timedelta6
result = np.timedelta64(int(dt), "s") + time_interval.left
if isinstance(result, cftime.datetime):
return result
elif isinstance(result, np.timedelta64):
return result.astype("timedelta64[s]")
return result.astype("datetime64[s]")
else:
return np.timedelta64(int(dt), "s")
43 changes: 43 additions & 0 deletions tests/utils/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from parcels._core.utils.time import (
TimeInterval,
_get_cf_attrs,
float_to_datelike,
maybe_convert_python_timedelta_to_numpy,
timedelta_to_float,
)
Expand Down Expand Up @@ -175,6 +176,48 @@ def test_timedelta_to_float_exceptions():
timedelta_to_float("invalid_type")


@pytest.mark.parametrize(
"left,right,offset,expected",
[
(np.timedelta64(10500, "ms"), np.timedelta64(20, "s"), 2.9, np.timedelta64(12, "s")),
(np.timedelta64(3, "m"), np.timedelta64(5, "m"), -4.7, np.timedelta64(176, "s")),
],
)
def test_float_to_datelike_timedelta_interval(left, right, offset, expected):
result = float_to_datelike(offset, TimeInterval(left, right))

assert isinstance(result, np.timedelta64)
assert result.dtype == np.dtype("timedelta64[s]")
assert result == expected


@pytest.mark.parametrize(
"interval,expected",
[
(None, np.timedelta64(2, "s")),
(
TimeInterval(np.datetime64("2023-01-01"), np.datetime64("2023-01-02")),
np.datetime64("2023-01-01T00:00:02", "s"),
),
(
TimeInterval(
cftime_datetime(2023, 1, 1, calendar="360_day"), cftime_datetime(2023, 1, 2, calendar="360_day")
),
cftime_datetime(2023, 1, 1, 0, 0, 2, calendar="360_day"),
),
],
)
def test_float_to_datelike_other_intervals(interval, expected):
result = float_to_datelike(2.9, interval)

assert isinstance(result, type(expected))
assert result == expected
if isinstance(expected, (np.datetime64, np.timedelta64)):
assert result.dtype == expected.dtype
elif isinstance(expected, cftime_datetime):
assert result.calendar == expected.calendar


@given(pst.time.datetime_various())
def test_datetime_get_cf_attrs(dt):
attrs = _get_cf_attrs(dt)
Expand Down
Loading