Skip to content

Commit 8b961e4

Browse files
antscloudIllviljandcherianheadtr1ckkmuehlbauer
authored
Implement cftime vectorization as discussed in PR #8322 (#8324)
* feat: implement as discussed in PR #8322 * fix: Stick closer to the original function and add PR suggestions * Update xarray/coding/times.py Co-authored-by: Michael Niklas <[email protected]> * Update xarray/coding/times.py * Update xarray/coding/times.py * Add what's new entry --------- Co-authored-by: Illviljan <[email protected]> Co-authored-by: Deepak Cherian <[email protected]> Co-authored-by: Michael Niklas <[email protected]> Co-authored-by: Kai Mühlbauer <[email protected]> Co-authored-by: Kai Mühlbauer <[email protected]> Co-authored-by: Spencer Clark <[email protected]>
1 parent 83ccfff commit 8b961e4

File tree

2 files changed

+28
-30
lines changed

2 files changed

+28
-30
lines changed

doc/whats-new.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ Performance
6565
in :py:class:`~xarray.indexing.VectorizedIndexer` and :py:class:`~xarray.indexing.OuterIndexer`
6666
(:issue:`10316`).
6767
By `Jesse Rusak <https://github.com/jder>`_.
68-
68+
- Speed up encoding of :py:class:`cftime.datetime` objects by roughly a factor
69+
of three (:pull:`8324`). By `Antoine Gibek <https://github.com/antscloud>`_.
6970

7071
Documentation
7172
~~~~~~~~~~~~~

xarray/coding/times.py

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -946,41 +946,38 @@ def _encode_datetime_with_cftime(dates, units: str, calendar: str) -> np.ndarray
946946
else:
947947
cftime = attempt_import("cftime")
948948

949+
dates = np.asarray(dates)
950+
original_shape = dates.shape
951+
949952
if np.issubdtype(dates.dtype, np.datetime64):
950953
# numpy's broken datetime conversion only works for us precision
951954
dates = dates.astype("M8[us]").astype(datetime)
952955

953-
def wrap_dt(dt):
954-
# convert to cftime proleptic gregorian in case of datetime.datetime
955-
# needed because of https://github.com/Unidata/cftime/issues/354
956-
if isinstance(dt, datetime) and not isinstance(dt, cftime.datetime):
957-
dt = cftime.datetime(
958-
dt.year,
959-
dt.month,
960-
dt.day,
961-
dt.hour,
962-
dt.minute,
963-
dt.second,
964-
dt.microsecond,
965-
calendar="proleptic_gregorian",
966-
)
967-
return dt
956+
dates = np.atleast_1d(dates)
968957

969-
def encode_datetime(d):
970-
# Since netCDF files do not support storing float128 values, we ensure
971-
# that float64 values are used by setting longdouble=False in num2date.
972-
# This try except logic can be removed when xarray's minimum version of
973-
# cftime is at least 1.6.2.
974-
try:
975-
return (
976-
np.nan
977-
if d is None
978-
else cftime.date2num(wrap_dt(d), units, calendar, longdouble=False)
979-
)
980-
except TypeError:
981-
return np.nan if d is None else cftime.date2num(wrap_dt(d), units, calendar)
958+
# Find all the None position
959+
none_position = dates == None # noqa: E711
960+
filtered_dates = dates[~none_position]
961+
962+
# Since netCDF files do not support storing float128 values, we ensure
963+
# that float64 values are used by setting longdouble=False in num2date.
964+
# This try except logic can be removed when xarray's minimum version of
965+
# cftime is at least 1.6.2.
966+
try:
967+
encoded_nums = cftime.date2num(
968+
filtered_dates, units, calendar, longdouble=False
969+
)
970+
except TypeError:
971+
encoded_nums = cftime.date2num(filtered_dates, units, calendar)
972+
973+
if filtered_dates.size == none_position.size:
974+
return encoded_nums.reshape(original_shape)
982975

983-
return reshape(np.array([encode_datetime(d) for d in ravel(dates)]), dates.shape)
976+
# Create a full matrix of NaN
977+
# And fill the num dates in the not NaN or None position
978+
result = np.full(dates.shape, np.nan)
979+
result[np.nonzero(~none_position)] = encoded_nums
980+
return result.reshape(original_shape)
984981

985982

986983
def cast_to_int_if_safe(num) -> np.ndarray:

0 commit comments

Comments
 (0)