Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a1f9401
readd cell measure after extract region
valeriupredoi Aug 7, 2023
5df45b3
add conditionals
valeriupredoi Aug 7, 2023
41583f6
readd ancillary variable
valeriupredoi Aug 7, 2023
a7e9d65
fix flake
valeriupredoi Aug 7, 2023
eaf39d5
yapf the crap outta it
valeriupredoi Aug 7, 2023
2e8c8b4
can flake pls shut up
valeriupredoi Aug 7, 2023
2352688
add test case dir
valeriupredoi Aug 7, 2023
eeca3d9
appease flake
valeriupredoi Aug 7, 2023
85ec670
add test netcdf file
valeriupredoi Aug 7, 2023
93b0858
polish inline comments
valeriupredoi Aug 7, 2023
15d4973
Manu suggestion
valeriupredoi Aug 8, 2023
6d8652a
Manu suggestion to deal with irregular grids too
valeriupredoi Aug 8, 2023
429a0c7
fix flake
valeriupredoi Aug 8, 2023
85e8b33
fix booboo from Manu
valeriupredoi Aug 8, 2023
3f0dede
plug in Manu's infinite recursion to fix it in terminal
valeriupredoi Aug 8, 2023
2efbc9e
unfubar the workflow
valeriupredoi Aug 8, 2023
74b979b
Update esmvalcore/preprocessor/_area.py
valeriupredoi Aug 8, 2023
bf35614
Update esmvalcore/preprocessor/_area.py
valeriupredoi Aug 8, 2023
8011040
Revert "Update esmvalcore/preprocessor/_area.py"
valeriupredoi Aug 8, 2023
ae5be95
Revert "Update esmvalcore/preprocessor/_area.py"
valeriupredoi Aug 8, 2023
a458ba8
Revert "unfubar the workflow"
valeriupredoi Aug 8, 2023
107c9e0
Revert "plug in Manu's infinite recursion to fix it in terminal"
valeriupredoi Aug 8, 2023
619ebb1
Revert "fix booboo from Manu"
valeriupredoi Aug 8, 2023
7757f36
Revert "fix flake"
valeriupredoi Aug 8, 2023
34707ad
Revert "Manu suggestion to deal with irregular grids too"
valeriupredoi Aug 8, 2023
73b2b0c
Revert "Manu suggestion"
valeriupredoi Aug 8, 2023
78cb1d3
apply Manu suggestion to generalize for irreg grids too
valeriupredoi Aug 8, 2023
c1825ec
re-black code
valeriupredoi Aug 8, 2023
6964fec
missed a couple blacks
valeriupredoi Aug 8, 2023
e085a5e
optimized test without need of data file
valeriupredoi Aug 8, 2023
24114bd
rm data file
valeriupredoi Aug 8, 2023
bdb88ad
Merge branch 'main' into readd_cell_measure_after_extract_region
valeriupredoi Aug 8, 2023
2420fba
Made extract_region work with cell measures and ancillaries with ever…
schlunma Aug 8, 2023
0bb1101
add time dim to test cube
valeriupredoi Aug 9, 2023
345d7bf
fix indentation
valeriupredoi Aug 9, 2023
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
54 changes: 54 additions & 0 deletions esmvalcore/preprocessor/_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ def extract_region(cube, start_longitude, end_longitude, start_latitude,
iris.cube.Cube
smaller cube.
"""
# first examine if any cell_measures are present
cell_measures = cube.cell_measures()
ancil_vars = cube.ancillary_variables()

if abs(start_latitude) > 90.:
raise ValueError(f"Invalid start_latitude: {start_latitude}")
if abs(end_latitude) > 90.:
Expand All @@ -87,6 +91,56 @@ def extract_region(cube, start_longitude, end_longitude, start_latitude,
start_latitude,
end_latitude,
)

# put back cell measures and ancillary_variables;
# iris.Cube.cube.intersection removes them both.
# This is a workaround resulting from opening upstream
# https://github.com/SciTools/iris/issues/5413
# When removing this block after iris have a fix, make sure to remove the
# test too tests/integration/preprocessor/_extract_region/

def _extract_region_from_dim_metadata(dim_metadata, dim_metadata_dims):
"""Extract region from dimensional metadata."""
idx = tuple((
slice(None) if d in dim_metadata_dims else 0
for d in range(cube.ndim)
))
subcube = cube[idx].copy(dim_metadata.core_data())
for sub_cm in subcube.cell_measures():
subcube.remove_cell_measure(sub_cm)
for sub_av in subcube.ancillary_variables():
subcube.remove_ancillary_variable(sub_av)
subcube = extract_region(
subcube,
start_longitude,
end_longitude,
start_latitude,
end_latitude,
)
return dim_metadata.copy(subcube.core_data())

# Step 1: cell measures
if cell_measures and not region_subset.cell_measures():
for cell_measure in cell_measures:
cell_measure_dims = cube.cell_measure_dims(cell_measure)
cell_measure_subset = _extract_region_from_dim_metadata(
cell_measure, cell_measure_dims
)
region_subset.add_cell_measure(
cell_measure_subset, cell_measure_dims
)

# Step 2: ancillary variables
if ancil_vars and not region_subset.ancillary_variables():
for ancil_var in ancil_vars:
ancil_var_dims = cube.ancillary_variable_dims(ancil_var)
ancil_var_subset = _extract_region_from_dim_metadata(
ancil_var, ancil_var_dims
)
region_subset.add_ancillary_variable(
ancil_var_subset, ancil_var_dims
)

return region_subset


Expand Down
98 changes: 98 additions & 0 deletions tests/integration/preprocessor/_extract_region/test_intersect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""
Temporary test.

Remove this test and test file after iris fixes this
https://github.com/SciTools/iris/issues/5413 .
"""
import iris
import numpy as np
from cf_units import Unit
from iris.fileformats.pp import EARTH_RADIUS

from esmvalcore.preprocessor._area import extract_region
from esmvalcore.preprocessor._shared import guess_bounds


def make_cube():
"""Make a realistic cube with cell measure and ancil var."""
coord_sys = iris.coord_systems.GeogCS(EARTH_RADIUS)
data = np.ones((10, 192, 288), dtype=np.float32)
time = iris.coords.DimCoord(
np.arange(0., 10., 1.),
standard_name='time',
units=Unit('days since 1950-01-01 00:00:00',
calendar='360_day'))
lons = iris.coords.DimCoord(
[i + .5 for i in range(288)],
standard_name='longitude',
bounds=[[i, i + 1.] for i in range(288)],
units='degrees_east',
coord_system=coord_sys)
lats = iris.coords.DimCoord(
[i + .5 for i in range(192)],
standard_name='latitude',
bounds=[[i, i + 1.] for i in range(192)],
units='degrees_north',
coord_system=coord_sys,
)
coords_spec = [(time, 0), (lats, 1), (lons, 2)]
simple_cube = iris.cube.Cube(data, dim_coords_and_dims=coords_spec)

# add a cell measure
simple_cube = guess_bounds(simple_cube, ['longitude', 'latitude'])
grid_areas = iris.analysis.cartography.area_weights(simple_cube)
measure = iris.coords.CellMeasure(
grid_areas,
standard_name='cell_area',
units='m2',
measure='area')
simple_cube.add_cell_measure(measure, range(0, measure.ndim))

# add ancillary variable
ancillary_var = iris.coords.AncillaryVariable(
simple_cube.data,
standard_name='land_ice_area_fraction',
var_name='sftgif',
units='%')
simple_cube.add_ancillary_variable(ancillary_var,
range(0, simple_cube.ndim))

return simple_cube


def test_extract_region_cell_ancil():
"""Test re-adding cell measures ancil variables after extract region."""
cube = make_cube()

# intersection cube loses cellmeas/ancillary variables
# under normal (unpatched) conditions of extract_region
ex1 = extract_region(cube,
start_longitude=-90,
end_longitude=40,
start_latitude=20,
end_latitude=80)

# intersection cube doesn't lose cellmeas/ancillary variables
# under normal (unpatched) conditions of extract_region
# so duplication must be avoided
ex2 = extract_region(cube,
start_longitude=160,
end_longitude=280,
start_latitude=-5,
end_latitude=5)

expected_cm = cube.cell_measures()[0]
result_cm = ex1.cell_measures()
assert result_cm
assert expected_cm.measure == result_cm[0].measure
assert expected_cm.var_name == result_cm[0].var_name
np.testing.assert_array_equal(result_cm[0].shape, (10, 60, 58))
assert expected_cm.standard_name == result_cm[0].standard_name
expected_ancil = cube.ancillary_variables()[0]
result_ancil = ex1.ancillary_variables()
assert result_ancil
assert expected_ancil.var_name == result_ancil[0].var_name
assert expected_ancil.standard_name == result_ancil[0].standard_name
np.testing.assert_array_equal(result_ancil[0].shape, (10, 60, 58))
assert len(ex2.cell_measures()) == 1
assert len(ex2.ancillary_variables()) == 1