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
139 changes: 74 additions & 65 deletions esmvalcore/preprocessor/_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,7 @@ def extract_time(
f"Currently, start_year is {start_year} "
f"and end_year is {end_year}."
)
raise ValueError(
msg,
)
raise ValueError(msg)

t_1 = PartialDateTime(
year=start_year,
Expand Down Expand Up @@ -282,9 +280,7 @@ def dt2str(time: PartialDateTime) -> str:
f"cube time bounds {time_coord.cell(0).point} to "
f"{time_coord.cell(-1).point}."
)
raise ValueError(
msg,
)
raise ValueError(msg)

return cube_slice

Expand Down Expand Up @@ -374,12 +370,10 @@ def extract_season(cube: Cube, season: str) -> Cube:
allmonths = "JFMAMJJASOND" * 2
if season not in allmonths:
msg = (
f"Unable to extract Season {season} "
f"combination of months not possible."
)
raise ValueError(
msg,
f"Unable to extract Season '{season}': combination of months not "
f"possible"
)
raise ValueError(msg)
sstart = allmonths.index(season)
res_season = allmonths[sstart + len(season) : sstart + 12]
seasons = [season, res_season]
Expand Down Expand Up @@ -493,6 +487,7 @@ def hourly_statistics(
cube: Cube,
hours: int,
operator: str = "mean",
keep_group_coordinates: bool = False,
**operator_kwargs,
) -> Cube:
"""Compute hourly statistics.
Expand All @@ -510,6 +505,9 @@ def hourly_statistics(
The operation. Used to determine the :class:`iris.analysis.Aggregator`
object used to calculate the statistics. Allowed options are given in
:ref:`this table <supported_stat_operator>`.
keep_group_coordinates:
If ``True``, keep temporal group coordinates (i.e., ``hour_group``,
``day_of_year``, ``year``) in the result. If ``False``, remove them.
**operator_kwargs:
Optional keyword arguments for the :class:`iris.analysis.Aggregator`
object defined by `operator`.
Expand Down Expand Up @@ -540,9 +538,10 @@ def hourly_statistics(
**agg_kwargs,
)

result.remove_coord("hour_group")
result.remove_coord("day_of_year")
result.remove_coord("year")
if not keep_group_coordinates:
result.remove_coord("hour_group")
result.remove_coord("day_of_year")
result.remove_coord("year")

return result

Expand All @@ -551,6 +550,7 @@ def hourly_statistics(
def daily_statistics(
cube: Cube,
operator: str = "mean",
keep_group_coordinates: bool = False,
**operator_kwargs,
) -> Cube:
"""Compute daily statistics.
Expand All @@ -565,6 +565,9 @@ def daily_statistics(
The operation. Used to determine the :class:`iris.analysis.Aggregator`
object used to calculate the statistics. Allowed options are given in
:ref:`this table <supported_stat_operator>`.
keep_group_coordinates:
If ``True``, keep temporal group coordinates (i.e., ``day_of_year``,
``year``) in the result. If ``False``, remove them.
**operator_kwargs:
Optional keyword arguments for the :class:`iris.analysis.Aggregator`
object defined by `operator`.
Expand All @@ -583,15 +586,18 @@ def daily_statistics(
with ignore_iris_vague_metadata_warnings():
result = cube.aggregated_by(["day_of_year", "year"], agg, **agg_kwargs)

result.remove_coord("day_of_year")
result.remove_coord("year")
if not keep_group_coordinates:
result.remove_coord("day_of_year")
result.remove_coord("year")

return result


@preserve_float_dtype
def monthly_statistics(
cube: Cube,
operator: str = "mean",
keep_group_coordinates: bool = True,
**operator_kwargs,
) -> Cube:
"""Compute monthly statistics.
Expand All @@ -606,6 +612,9 @@ def monthly_statistics(
The operation. Used to determine the :class:`iris.analysis.Aggregator`
object used to calculate the statistics. Allowed options are given in
:ref:`this table <supported_stat_operator>`.
keep_group_coordinates:
If ``True``, keep temporal group coordinates (i.e., ``month_number``,
``year``) in the result. If ``False``, remove them.
**operator_kwargs:
Optional keyword arguments for the :class:`iris.analysis.Aggregator`
object defined by `operator`.
Expand All @@ -628,6 +637,11 @@ def monthly_statistics(
**agg_kwargs,
)
_aggregate_time_fx(result, cube)

if not keep_group_coordinates:
result.remove_coord("month_number")
result.remove_coord("year")

return result


Expand All @@ -636,6 +650,7 @@ def seasonal_statistics(
cube: Cube,
operator: str = "mean",
seasons: Iterable[str] = ("DJF", "MAM", "JJA", "SON"),
keep_group_coordinates: bool = True,
**operator_kwargs,
) -> Cube:
"""Compute seasonal statistics.
Expand All @@ -655,6 +670,9 @@ def seasonal_statistics(
and all sequentially correct combinations holding every month
of a year: e.g. ('JJAS','ONDJFMAM'), or less in case of prior season
extraction.
keep_group_coordinates:
If ``True``, keep temporal group coordinates (i.e., ``clim_season``,
``season_year``) in the result. If ``False``, remove them.
**operator_kwargs:
Optional keyword arguments for the :class:`iris.analysis.Aggregator`
object defined by `operator`.
Expand All @@ -667,10 +685,8 @@ def seasonal_statistics(
seasons = tuple(sea.upper() for sea in seasons)

if any(len(sea) < 2 for sea in seasons):
msg = f"Minimum of 2 month is required per Seasons: {seasons}."
raise ValueError(
msg,
)
msg = f"Minimum of 2 months is required per season in {seasons}"
raise ValueError(msg)

if not cube.coords("clim_season"):
iris.coord_categorisation.add_season(
Expand All @@ -688,9 +704,7 @@ def seasonal_statistics(
f"Seasons {seasons} do not match prior season extraction "
f"{old_seasons}."
)
raise ValueError(
msg,
)
raise ValueError(msg)

if not cube.coords("season_year"):
iris.coord_categorisation.add_season_year(
Expand Down Expand Up @@ -739,13 +753,19 @@ def spans_full_season(cube: Cube) -> list[bool]:
full_seasons = spans_full_season(result)
result = result[full_seasons]
_aggregate_time_fx(result, cube)

if not keep_group_coordinates:
result.remove_coord("clim_season")
result.remove_coord("season_year")

return result


@preserve_float_dtype
def annual_statistics(
cube: Cube,
operator: str = "mean",
keep_group_coordinates: bool = True,
**operator_kwargs,
) -> Cube:
"""Compute annual statistics.
Expand All @@ -762,6 +782,9 @@ def annual_statistics(
The operation. Used to determine the :class:`iris.analysis.Aggregator`
object used to calculate the statistics. Allowed options are given in
:ref:`this table <supported_stat_operator>`.
keep_group_coordinates:
If ``True``, keep temporal group coordinates (i.e., ``year``) in the
result. If ``False``, remove them.
**operator_kwargs:
Optional keyword arguments for the :class:`iris.analysis.Aggregator`
object defined by `operator`.
Expand All @@ -781,13 +804,18 @@ def annual_statistics(
with ignore_iris_vague_metadata_warnings():
result = cube.aggregated_by("year", agg, **agg_kwargs)
_aggregate_time_fx(result, cube)

if not keep_group_coordinates:
result.remove_coord("year")

return result


@preserve_float_dtype
def decadal_statistics(
cube: Cube,
operator: str = "mean",
keep_group_coordinates: bool = True,
**operator_kwargs,
) -> Cube:
"""Compute decadal statistics.
Expand All @@ -804,6 +832,9 @@ def decadal_statistics(
The operation. Used to determine the :class:`iris.analysis.Aggregator`
object used to calculate the statistics. Allowed options are given in
:ref:`this table <supported_stat_operator>`.
keep_group_coordinates:
If ``True``, keep temporal group coordinates (i.e., ``decade``) in the
result. If ``False``, remove them.
**operator_kwargs:
Optional keyword arguments for the :class:`iris.analysis.Aggregator`
object defined by `operator`.
Expand Down Expand Up @@ -834,6 +865,10 @@ def get_decade(coord, value):
with ignore_iris_vague_metadata_warnings():
result = cube.aggregated_by("decade", agg, **agg_kwargs)
_aggregate_time_fx(result, cube)

if not keep_group_coordinates:
result.remove_coord("decade")

return result


Expand Down Expand Up @@ -1016,13 +1051,11 @@ def anomalies(
reps = cube.shape[tdim] / cube_stddev.shape[tdim]
if reps % 1 != 0:
msg = (
"Cannot safely apply preprocessor to this dataset, "
"since the full time period of this dataset is not "
f"a multiple of the period '{period}'"
)
raise ValueError(
msg,
f"Cannot safely apply preprocessor to this dataset since the "
f"full time period of this dataset is not a multiple of the "
f"period '{period}'"
)
raise ValueError(msg)
cube.data = cube.core_data() / da.concatenate(
[cube_stddev.core_data() for _ in range(int(reps))],
axis=tdim,
Expand Down Expand Up @@ -1171,9 +1204,7 @@ def regrid_time(
f"Setting a fixed calendar is not supported for frequency "
f"'{frequency}'"
)
raise NotImplementedError(
msg,
)
raise NotImplementedError(msg)

# Setup new time coordinate
new_dates = _get_new_dates(frequency, coord)
Expand Down Expand Up @@ -1246,9 +1277,7 @@ def _get_new_dates(frequency: str, coord: Coord) -> list[datetime.datetime]:
f"For `n`-hourly data, `n` must be a divisor of 24, got "
f"'{frequency}'"
)
raise NotImplementedError(
msg,
)
raise NotImplementedError(msg)
half_interval = datetime.timedelta(hours=n_hours / 2.0)
dates = [
datetime.datetime(
Expand Down Expand Up @@ -1376,9 +1405,7 @@ def timeseries_filter(
f"Filter type {filter_type} not implemented, "
f"please choose one of {', '.join(supported_filters)}"
)
raise NotImplementedError(
msg,
)
raise NotImplementedError(msg)

# Apply filter
(agg, agg_kwargs) = get_iris_aggregator(filter_stats, **operator_kwargs)
Expand Down Expand Up @@ -1439,27 +1466,21 @@ def resample_hours(
allowed_intervals = (1, 2, 3, 4, 6, 12)
if interval not in allowed_intervals:
msg = f"The number of hours must be one of {allowed_intervals}"
raise ValueError(
msg,
)
raise ValueError(msg)
if offset >= interval:
msg = (
f"The offset ({offset}) must be lower than "
f"the interval ({interval})"
)
raise ValueError(
msg,
)
raise ValueError(msg)
time = cube.coord("time")
cube_period = time.cell(1).point - time.cell(0).point
if cube_period.total_seconds() / 3600 > interval:
msg = (
f"Data period ({cube_period}) should be lower than "
f"the interval ({interval})"
)
raise ValueError(
msg,
)
raise ValueError(msg)
dates = time.units.num2date(time.points)

# Interpolate input time to requested hours if desired
Expand All @@ -1473,9 +1494,7 @@ def resample_hours(
f"Expected `None`, 'nearest' or 'linear' for `interpolate`, "
f"got '{interpolate}'"
)
raise ValueError(
msg,
)
raise ValueError(msg)
new_dates = sorted(
[
cf_datetime(y, m, d, h, calendar=time.units.calendar)
Expand All @@ -1497,9 +1516,7 @@ def resample_hours(
msg = (
f"Time coordinate {dates} does not contain {hours} for {cube}"
)
raise ValueError(
msg,
)
raise ValueError(msg)

return cube

Expand Down Expand Up @@ -1556,9 +1573,7 @@ def resample_time(
msg = (
f"Time coordinate {dates} does not contain {requested} for {cube}"
)
raise ValueError(
msg,
)
raise ValueError(msg)
return cube


Expand Down Expand Up @@ -1888,9 +1903,7 @@ def _check_cube_coords(cube):
f"Input cube {cube.summary(shorten=True)} needs a dimensional "
f"coordinate `time`"
)
raise CoordinateNotFoundError(
msg,
)
raise CoordinateNotFoundError(msg)
time_coord = cube.coord("time", dim_coords=True)
# The following works since DimCoords are always 1D and monotonic
if time_coord.points[0] > time_coord.points[-1]:
Expand All @@ -1902,18 +1915,14 @@ def _check_cube_coords(cube):
f"Input cube {cube.summary(shorten=True)} needs a coordinate "
f"`longitude`"
)
raise CoordinateNotFoundError(
msg,
)
raise CoordinateNotFoundError(msg)
lon_ndim = len(cube.coord_dims("longitude"))
if lon_ndim != 1:
msg = (
f"Input cube {cube.summary(shorten=True)} needs a 1D coordinate "
f"`longitude`, got {lon_ndim:d}D"
)
raise CoordinateMultiDimError(
msg,
)
raise CoordinateMultiDimError(msg)


@preserve_float_dtype
Expand Down
Loading