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

Use cell area for weights if available #3173

Closed
Show file tree
Hide file tree
Changes from all 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
62 changes: 56 additions & 6 deletions lib/iris/cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -3210,12 +3210,62 @@ def collapsed(self, coords, aggregator, **kwargs):

if (isinstance(aggregator, iris.analysis.WeightedAggregator) and
not aggregator.uses_weighting(**kwargs)):
msg = "Collapsing spatial coordinate {!r} without weighting"
lat_match = [coord for coord in coords
if 'latitude' in coord.name()]
if lat_match:
for coord in lat_match:
warnings.warn(msg.format(coord.name()))
cell_area = [
c for c in self.cell_measures()
if c.measure == 'area'
]
assert len(cell_area) < 2, "more than one cell area measure"
cell_area = cell_area[0] if cell_area else None
if cell_area is not None:
lon, lat = iris.analysis.cartography._get_lon_lat_coords(self)

# would be ideal to resuse the below from
# iris.analysis.cartography.area_weights rather than copying...
if lat.ndim > 1:
raise iris.exceptions.CoordinateMultiDimError(lat)
if lon.ndim > 1:
raise iris.exceptions.CoordinateMultiDimError(lon)

lat_dim = self.coord_dims(lat)
lat_dim = lat_dim[0] if lat_dim else None

lon_dim = self.coord_dims(lon)
lon_dim = lon_dim[0] if lon_dim else None

ll_weights = cell_area.data

# Now we create an array of weights for each cell. This
# process will handle adding the required extra dimensions and
# also take care of the order of dimensions.
broadcast_dims = [
x for x in (lat_dim, lon_dim)
if x is not None
]
wshape = []
for idim, dim in zip((0, 1), (lat_dim, lon_dim)):
if dim is not None:
wshape.append(ll_weights.shape[idim])
ll_weights = ll_weights.reshape(wshape)
broad_weights = iris.util.broadcast_to_shape(
ll_weights,
self.shape,
broadcast_dims
)

kwargs["weights"] = broad_weights
error_msg = (
"still not using the weighting, even after trying with "
"cell_area..."
)
assert aggregator.uses_weighting(**kwargs), error_msg

else:
msg = "Collapsing spatial coordinate {!r} without weighting"
lat_match = [coord for coord in coords
if 'latitude' in coord.name()]
if lat_match:
for coord in lat_match:
warnings.warn(msg.format(coord.name()))

# Determine the dimensions we need to collapse (and those we don't)
if aggregator.cell_method == 'peak':
Expand Down
6 changes: 5 additions & 1 deletion lib/iris/experimental/representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,15 @@ def __init__(self, cube):
'Auxiliary coordinates:': None,
'Derived coordinates:': None,
'Scalar coordinates:': None,
'Scalar cell measures:': None,
'Cell Measures:': None,
'Attributes:': None,
'Cell methods:': None,
}
self.dim_desc_coords = ['Dimension coordinates:',
'Auxiliary coordinates:',
'Derived coordinates:']
'Derived coordinates:',
'Cell Measures:', ]

# Important content that summarises a cube is defined here.
self.shapes = self.cube.shape
Expand Down Expand Up @@ -171,6 +174,7 @@ def _get_bits(self, bits):
else:
start_inds.append(start_ind)
# Mark the end of the file.
start_inds.sort()
start_inds.append(0)

# Retrieve info for each heading from the printout.
Expand Down
19 changes: 19 additions & 0 deletions lib/iris/tests/unit/cube/test_Cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,25 @@ def test_lat_lon_weighted_aggregator_alt(self):
coords = [coord for coord in coords if 'latitude' in coord]
self._assert_warn_collapse_without_weight(coords, warn)

def test_lat_lon_cell_area_no_weights(self):
# Collapse grid_latitude coordinate with weighted aggregator without
# providing weights. Tests coordinate matching logic.
cell_areas = CellMeasure(data=np.arange(4).reshape(2, 2),
long_name='area',
measure='area')

self.cube.add_cell_measure(cell_areas, [0, 1],)
self.cube.remove_coord('grid_latitude')
self.cube.remove_coord('grid_longitude')

coords = ['latitude', 'longitude']

with mock.patch('warnings.warn') as warn:
self.cube.collapsed(coords, iris.analysis.MEAN)

coords = [coord for coord in coords if 'latitude' in coord]
self._assert_nowarn_collapse_without_weight(coords, warn)

def test_no_lat_weighted_aggregator_mixed(self):
# Collapse grid_latitude and an unmatched coordinate (not lat/lon)
# with weighted aggregator without providing weights.
Expand Down