Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update adjust time #2490

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 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
58 changes: 29 additions & 29 deletions esmvalcore/preprocessor/_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@

def extract_time(
cube: Cube,
start_year: int,
start_year: int | None,
start_month: int,
start_day: int,
end_year: int,
end_year: int | None,
end_month: int,
end_day: int,
) -> Cube:
Expand All @@ -80,13 +80,23 @@ def extract_time(
cube:
Input cube.
start_year:
Start year.
Start year. If None, the date ranges (start_month-start_day to
end_month-end_day) are selected in each year. For example,
ranges Feb 3 - Apr 6 in each year are selected if
start_year: None, start_month: 2, start_day: 3,
end_year: None, end_month: 4, end_day: 6. If start_year is
None, end_year has to be None too.
malininae marked this conversation as resolved.
Show resolved Hide resolved
start_month:
Start month.
start_day:
Start day.
end_year:
End year.
End year. If None, the date ranges (start_month-start_day to
end_month-end_day) are selected in each year. For example,
ranges Feb 3 - Apr 6 in each year are selected if
start_year: None, start_month: 2, start_day: 3,
end_year: None, end_month: 4, end_day: 6. If end_year is None,
start_year has to be None too.
malininae marked this conversation as resolved.
Show resolved Hide resolved
malininae marked this conversation as resolved.
Show resolved Hide resolved
end_month:
End month.
end_day:
Expand All @@ -101,13 +111,24 @@ def extract_time(
------
ValueError
Time ranges are outside the cube time limits.

"""
if start_year is not None:
start_year = int(start_year)
if end_year is not None:
end_year = int(end_year)
if (not start_year) ^ (not end_year):
malininae marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError(
"If start_year or end_year is None, both "
"start_year and end_year have to be None. "
f"Currently, start_year is {start_year} "
f"and end_year is {end_year}."
)

t_1 = PartialDateTime(
year=int(start_year), month=int(start_month), day=int(start_day)
year=start_year, month=int(start_month), day=int(start_day)
)
t_2 = PartialDateTime(
year=int(end_year), month=int(end_month), day=int(end_day)
year=end_year, month=int(end_month), day=int(end_day)
)

return _extract_datetime(cube, t_1, t_2)
Expand Down Expand Up @@ -219,7 +240,7 @@ def _extract_datetime(
if isinstance(end_datetime.day, int) and end_datetime.day > 30:
end_datetime.day = 30

if not cube.coord_dims(time_coord):
if (not cube.coord_dims(time_coord)) or (start_datetime.year is None):
constraint = iris.Constraint(
time=lambda t: start_datetime <= t.point < end_datetime
)
Expand Down Expand Up @@ -268,7 +289,6 @@ def clip_timerange(cube: Cube, timerange: str) -> Cube:
------
ValueError
Time ranges are outside the cube's time limits.

bouweandela marked this conversation as resolved.
Show resolved Hide resolved
"""
start_date = _parse_start_date(timerange.split("/")[0])
end_date = _parse_end_date(timerange.split("/")[1])
Expand Down Expand Up @@ -326,7 +346,6 @@ def extract_season(cube: Cube, season: str) -> Cube:
------
ValueError
Requested season is not present in the cube.

"""
season = season.upper()

Expand Down Expand Up @@ -380,7 +399,6 @@ def extract_month(cube: Cube, month: int) -> Cube:
------
ValueError
Requested month is not present in the cube.

"""
if month not in range(1, 13):
raise ValueError("Please provide a month number between 1 and 12.")
Expand Down Expand Up @@ -460,7 +478,6 @@ def hourly_statistics(
-------
iris.cube.Cube
Hourly statistics cube.

"""
if not cube.coords("hour_group"):
iris.coord_categorisation.add_categorised_coord(
Expand Down Expand Up @@ -513,7 +530,6 @@ def daily_statistics(
-------
iris.cube.Cube
Daily statistics cube.

"""
if not cube.coords("day_of_year"):
iris.coord_categorisation.add_day_of_year(cube, "time")
Expand Down Expand Up @@ -554,7 +570,6 @@ def monthly_statistics(
-------
iris.cube.Cube
Monthly statistics cube.

"""
if not cube.coords("month_number"):
iris.coord_categorisation.add_month_number(cube, "time")
Expand Down Expand Up @@ -599,7 +614,6 @@ def seasonal_statistics(
-------
iris.cube.Cube
Seasonal statistic cube.

"""
seasons = tuple(sea.upper() for sea in seasons)

Expand Down Expand Up @@ -646,7 +660,6 @@ def spans_full_season(cube: Cube) -> list[bool]:
-------
list[bool]
Truth statements if time bounds are within (month*29, month*31)

"""
time = cube.coord("time")
num_days = [(tt.bounds[0, 1] - tt.bounds[0, 0]) for tt in time]
Expand Down Expand Up @@ -690,7 +703,6 @@ def annual_statistics(
-------
iris.cube.Cube
Annual statistics cube.

"""
# TODO: Add weighting in time dimension. See iris issue 3290
# https://github.com/SciTools/iris/issues/3290
Expand Down Expand Up @@ -732,7 +744,6 @@ def decadal_statistics(
-------
iris.cube.Cube
Decadal statistics cube.

"""
# TODO: Add weighting in time dimension. See iris issue 3290
# https://github.com/SciTools/iris/issues/3290
Expand Down Expand Up @@ -1055,7 +1066,6 @@ def regrid_time(
NotImplementedError
An invalid `frequency` is given or `calendar` is set for a
non-supported frequency.

"""
# Do not overwrite input cube
cube = cube.copy()
Expand Down Expand Up @@ -1240,7 +1250,6 @@ def timeseries_filter(
Cube does not have time coordinate.
NotImplementedError:
`filter_type` is not implemented.

"""
try:
cube.coord("time")
Expand Down Expand Up @@ -1316,7 +1325,6 @@ def resample_hours(
`interval` is not a divisor of 24; invalid `interpolate` given; or
input data does not contain any target hour (if `interpolate` is
``None``).

"""
allowed_intervals = (1, 2, 3, 4, 6, 12)
if interval not in allowed_intervals:
Expand Down Expand Up @@ -1415,7 +1423,6 @@ def resample_time(
-------
iris.cube.Cube
Cube with the new frequency.

"""
time = cube.coord("time")
dates = time.units.num2date(time.points)
Expand Down Expand Up @@ -1454,7 +1461,6 @@ def _get_lst_offset(lon_coord: Coord) -> np.ndarray:
----
This function expects longitude in degrees. Can be in [0, 360] or [-180,
180] format.

"""
# Make sure that longitude is in degrees and shift it to [-180, 180] first
# (do NOT overwrite input coordinate)
Expand All @@ -1471,7 +1477,6 @@ def _get_lsts(time_coord: DimCoord, lon_coord: Coord) -> np.ndarray:
----
LSTs outside of the time bins given be the time coordinate bounds are put
into a bin below/above the time coordinate.

"""
# Pad time coordinate with 1 time step at both sides for the bins for LSTs
# outside of the time coordinate
Expand Down Expand Up @@ -1517,7 +1522,6 @@ def _get_time_index_and_mask(
(LSTs) are given. E.g., for hourly data with first time point 01:00:00
UTC, LST in Berlin is already 02:00:00 (assuming no daylight saving time).
Thus, for 01:00:00 LST on this day, there is no value for Berlin.

"""
# Make sure that time coordinate has bounds (these are necessary for the
# binning) and uses 'hours' as reference units
Expand Down Expand Up @@ -1582,7 +1586,6 @@ def _transform_to_lst_eager(
reorder the data along the time axis based on the longitude axis.

`mask` is 2D with shape (time, lon) that will be applied to the final data.

"""
# Apart from the time index, all other dimensions will stay the same; this
# is ensured with np.ogrid
Expand Down Expand Up @@ -1626,7 +1629,6 @@ def _transform_to_lst_lazy(
reorder the data along the time axis based on the longitude axis.

`mask` is 2D with shape (time, lon) that will be applied to the final data.

"""
new_data = da.apply_gufunc(
_transform_to_lst_eager,
Expand Down Expand Up @@ -1657,7 +1659,6 @@ def _transform_arr_to_lst(
----
This function either calls `_transform_to_lst_eager` or
`_transform_to_lst_lazy` depending on the type of input data.

"""
if isinstance(data, np.ndarray):
func = _transform_to_lst_eager # type: ignore
Expand Down Expand Up @@ -1839,7 +1840,6 @@ def local_solar_time(cube: Cube) -> Cube:
Input cube has multidimensional `longitude` coordinate.
ValueError
`time` coordinate of input cube is not monotonically increasing.

"""
# Make sure that cube has valid time and longitude coordinates
_check_cube_coords(cube)
Expand Down
30 changes: 30 additions & 0 deletions tests/unit/preprocessor/_time/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ def test_extract_time_non_gregorian_day(self):
sliced = extract_time(cube, 1950, 2, 30, 1950, 3, 1)
assert_array_equal(np.array([59]), sliced.coord("time").points)

def test_extract_time_none_years(self):
"""Test extract slice if both end and start year are None."""
sliced = extract_time(self.cube, None, 2, 5, None, 4, 17)
assert_array_equal(
np.array([45.0, 75.0, 105.0, 405.0, 435.0, 465.0]),
sliced.coord("time").points,
)

def test_extract_time_no_slice(self):
"""Test fail of extract_time."""
self.cube.coord("time").guess_bounds()
Expand All @@ -180,6 +188,28 @@ def test_extract_time_no_time(self):
sliced = extract_time(cube, 1950, 1, 1, 1950, 12, 31)
assert cube == sliced

def test_extract_time_start_none_year(self):
"""Test extract_time when only start_year is None."""
cube = self.cube.coord("time").guess_bounds()
msg = (
"If start_year or end_year is None, both start_year and "
"end_year have to be None. Currently, start_year is None and "
"end_year is 1950."
)
with pytest.raises(ValueError, match=msg):
extract_time(cube, None, 1, 1, 1950, 2, 1)
malininae marked this conversation as resolved.
Show resolved Hide resolved

def test_extract_time_end_none_year(self):
"""Test extract_time when only end_year is None."""
cube = self.cube.coord("time").guess_bounds()
msg = (
"If start_year or end_year is None, both start_year and "
"end_year have to be None. Currently, start_year is 1950 and "
"end_year is None."
)
with pytest.raises(ValueError, match=msg):
extract_time(cube, 1950, 1, 1, None, 2, 1)


class TestClipTimerange(tests.Test):
"""Tests for clip_timerange."""
Expand Down