Skip to content

Commit

Permalink
Add aggregate operator with corresponding yaml file and changes in re…
Browse files Browse the repository at this point in the history
…cipes.
  • Loading branch information
Sylviabohnenstengel committed Jul 25, 2023
1 parent 9d9e36b commit a259dc4
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/CSET/operators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"""This subpackage contains all of CSET's operators."""

# Import operators here so they are exported for use by recipes.
from CSET.operators import constraints, read, write, filters, plot, misc
from CSET.operators import constraints, read, write, filters, aggregate, plot, misc


from pathlib import Path
Expand Down
109 changes: 109 additions & 0 deletions src/CSET/operators/aggregate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Copyright 2022 Met Office and contributors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Operators to perform various kind of aggregation on either 1 or 2 dimensions.
"""

import iris
import iris.cube
import iris.analysis


def aggregate_1dim(
cube: iris.cube.Cube, coordinate: str, method: str, **kwargs
) -> iris.cube.Cube:
"""
Aggregates similar (stash) fields in a cube into a cube aggregating around the specified coordinate and method.
This could be a (weighted) mean or an accumulation.
Arguments
---------
cube: iris.cube.Cube
Cube to aggregate and iterate over one dimension
coordinate: str
Coordinate to aggregate over i.e.
'time', 'longitude', 'latitude','model_level_number'
method: str
Type of aggregation i.e. method: 'MEAN', 'MAX', 'MIN', 'MEDIAN', 'PERCENTILE'
getattr creates iris.analysis.MEAN, etc
For PERCENTILE YAML file requires i.e.
method: 'PERCENTILE'
additional_percent: 90
Returns
-------
cube: iris.cube.Cube
Single variable but several methods of aggregation
Raises
------
ValueError
If the constraint doesn't produce a single cube containing a field.
"""

if method != "PERCENTILE":
aggregated_cube = cube.collapsed(coordinate, getattr(iris.analysis, method))
if method == "PERCENTILE":
for num in kwargs.values():
aggregated_cube = cube.collapsed(
coordinate, getattr(iris.analysis, method), percent=num
)

return aggregated_cube


def aggregate_cube_2dim(
cube: iris.cube.Cube, coordinate1: str, coordinate2: str, method: str, **kargs
) -> iris.cube.Cube:
"""
Aggregates similar (stash) fields in a cube into a 2D field in a cube based on 2 coordinates and method to aggregated. This could include time and vertical coordinate for instance.
This could be a (weighted) mean or an accumulation.
Arguments
---------
cube: iris.cube.Cube
Cube to aggregate and iterate over one dimension
coordinate: str
Coordinate to aggregate over
method: Type of aggregation i.e. method: 'MEAN', 'MAX', 'MIN', 'MEDIAN', 'PERCENTILE'
getattr creates iris.analysis.MEAN, etc
For PERCENTILE YAML file requires i.e.
method: 'PERCENTILE'
additional_percent: 90
Returns
-------
cube: iris.cube.Cube
Single variable but several methods of aggregation such as mean, median, max, min, percentile
Raises
------
ValueError
If the constraint doesn't produce a single cube containing a field.
"""

# aggregate cube over single dimension
# dimensions: 2 of i.e. 'time', 'longitude', 'latitude'
# method: iris.analysis.MEAN, iris.analysis.MAX, iris.analysis.MIN
# ensure that time is passed in as 'time'
# aggregated_cube = cube.collapsed("time", iris.analysis.MEAN)
aggregated_cube = cube.collapsed(
[coordinate2, coordinate2], getattr(iris.analysis, method)
)

return aggregated_cube
32 changes: 32 additions & 0 deletions tests/operators/test_aggregate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2022 Met Office and contributors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import iris
import iris.cube
import iris.analysis
from CSET.operators import read, filters, constraints


def test_aggregate_1dim():
"""Reduces dimension of cube."""
cubes = read.read_cubes("tests/test_data/air_temp.nc")
constraint = constraints.combine_constraints(
constraints.generate_stash_constraint("m01s03i236"),
a=constraints.generate_cell_methods_constraint([]),
)
cube = filters.filter_cubes(cubes, constraint)
aggregated_cube = cube.collapsed("time", iris.analysis.MEAN)
assert aggregated_cube.cell_methods == ()
expected_cube = "<iris 'Cube' of air_temperature / (K) (time: 1; grid_latitude: 17; grid_longitude: 13)>"
assert repr(aggregated_cube) == expected_cube
36 changes: 36 additions & 0 deletions tests/test_data/plot_instant_air_temp_aggregate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Extract Instant Air Temperature
description: |
Extracts out the instantaneous 1.5m air temperature from a file and writes it
to a new one.
steps:
- operator: read.read_cubes
constraint:
operator: constraints.generate_stash_constraint
stash: m01s03i236

- operator: filters.filter_cubes
constraint:
operator: constraints.combine_constraints
stash_constraint:
operator: constraints.generate_stash_constraint
stash: m01s03i236
cell_methods_constraint:
operator: constraints.generate_cell_methods_constraint
cell_methods: []
# time_constraint:
# operator: constraints.generate_time_constraint
# time_start: 2022-09-21T03:00:00
# time_end: 2022-09-21T03:30:00

- operator: aggregate.aggregate_1dim
coordinate: 'time'
method: 'MEAN'
additional_percent: 90

- operator: write.write_cube_to_nc
# This is a magic value that becomes the runtime output file path.
file_path: CSET_OUTPUT_PATH
plot_data_as_well:
operator: plot.spatial_contour_plot
file_path: CSET_OUTPUT_PATH

0 comments on commit a259dc4

Please sign in to comment.