Coverage for src/CSET/operators/aggregate.py: 100%

12 statements  

« prev     ^ index     » next       coverage.py v7.5.4, created at 2024-07-01 16:16 +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. 

14 

15"""Operators to aggregate across either 1 or 2 dimensions.""" 

16 

17import iris 

18import iris.analysis 

19import iris.coord_categorisation 

20import iris.cube 

21import isodate 

22 

23 

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. 

31 

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. 

35 

36 Examples are: 1. Generating hourly or 6-hourly precipitation accumulations 

37 given an interval for the new time coordinate. 

38 

39 We use the isodate class to convert ISO 8601 durations into time intervals 

40 for creating a new time coordinate for aggregation. 

41 

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. 

45 

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. 

58 

59 Returns 

60 ------- 

61 cube: iris.cube.Cube 

62 Single variable but several methods of aggregation 

63 

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) 

71 

72 # Convert interval format to whole hours. 

73 interval = int(timedelta.total_seconds() / 3600) 

74 

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 ) 

80 

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