Coverage for src/CSET/operators/aggregate.py: 100%
12 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-02 08:44 +0000
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-02 08:44 +0000
1# Copyright 2023 Met Office and contributors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
15"""Operators to aggregate across either 1 or 2 dimensions."""
17import iris
18import iris.analysis
19import iris.coord_categorisation
20import iris.cube
21import isodate
24def time_aggregate(
25 cube: iris.cube.Cube,
26 method: str,
27 interval_iso: str,
28 **kwargs,
29) -> iris.cube.Cube:
30 """Aggregate cube by its time coordinate.
32 Aggregates similar (stash) fields in a cube for the specified coordinate and
33 using the method supplied. The aggregated cube will keep the coordinate and
34 add a further coordinate with the aggregated end time points.
36 Examples are: 1. Generating hourly or 6-hourly precipitation accumulations
37 given an interval for the new time coordinate.
39 We use the isodate class to convert ISO 8601 durations into time intervals
40 for creating a new time coordinate for aggregation.
42 We use the lambda function to pass coord and interval into the callable
43 category function in add_categorised to allow users to define their own
44 sub-daily intervals for the new time coordinate.
46 Arguments
47 ---------
48 cube: iris.cube.Cube
49 Cube to aggregate and iterate over one dimension
50 coordinate: str
51 Coordinate to aggregate over i.e. 'time', 'longitude',
52 'latitude','model_level_number'.
53 method: str
54 Type of aggregate i.e. method: 'SUM', getattr creates
55 iris.analysis.SUM, etc.
56 interval_iso: isodate timedelta ISO 8601 object i.e PT6H (6 hours), PT30M (30 mins)
57 Interval to aggregate over.
59 Returns
60 -------
61 cube: iris.cube.Cube
62 Single variable but several methods of aggregation
64 Raises
65 ------
66 ValueError
67 If the constraint doesn't produce a single cube containing a field.
68 """
69 # Duration of ISO timedelta.
70 timedelta = isodate.parse_duration(interval_iso)
72 # Convert interval format to whole hours.
73 interval = int(timedelta.total_seconds() / 3600)
75 # Add time categorisation overwriting hourly increment via lambda coord.
76 # https://scitools-iris.readthedocs.io/en/latest/_modules/iris/coord_categorisation.html
77 iris.coord_categorisation.add_categorised_coord(
78 cube, "interval", "time", lambda coord, cell: cell // interval * interval
79 )
81 # Aggregate cube using supplied method.
82 aggregated_cube = cube.aggregated_by("interval", getattr(iris.analysis, method))
83 aggregated_cube.remove_coord("interval")
84 return aggregated_cube