Source code for esmvalcore.preprocessor._weighting

"""Weighting preprocessor module."""

import logging

import iris

from ._supplementary_vars import register_supplementaries

logger = logging.getLogger(__name__)


def _get_land_fraction(cube):
    """Extract land fraction as :mod:`dask.array`."""
    fx_cube = None
    land_fraction = None
    errors = []
    try:
        fx_cube = cube.ancillary_variable('land_area_fraction')
    except iris.exceptions.AncillaryVariableNotFoundError:
        try:
            fx_cube = cube.ancillary_variable('sea_area_fraction')
        except iris.exceptions.AncillaryVariableNotFoundError:
            errors.append('Ancillary variables land/sea area fraction not '
                          'found in cube. Check ancillary data availability.')
            return (land_fraction, errors)

    if fx_cube.var_name == 'sftlf':
        land_fraction = fx_cube.core_data() / 100.0
    if fx_cube.var_name == 'sftof':
        land_fraction = 1.0 - fx_cube.core_data() / 100.0

    return (land_fraction, errors)


[docs] @register_supplementaries( variables=['sftlf', 'sftof'], required='require_at_least_one', ) def weighting_landsea_fraction(cube, area_type): """Weight fields using land or sea fraction. This preprocessor function weights a field with its corresponding land or sea area fraction (value between 0 and 1). The application of this is important for most carbon cycle variables (and other land-surface outputs), which are e.g. reported in units of `kgC m-2`. This actually refers to 'per square meter of land/sea' and NOT 'per square meter of gridbox'. So in order to integrate these globally or regionally one has to both area-weight the quantity but also weight by the land/sea fraction. Parameters ---------- cube : iris.cube.Cube Data cube to be weighted. It should have an :class:`iris.coords.AncillaryVariable` with standard name ``'land_area_fraction'`` or ``'sea_area_fraction'``. If both are present, only the ``'land_area_fraction'`` will be used. area_type : str Use land (``'land'``) or sea (``'sea'``) fraction for weighting. Returns ------- iris.cube.Cube Land/sea fraction weighted cube. Raises ------ TypeError ``area_type`` is not ``'land'`` or ``'sea'``. ValueError Land/sea fraction variables ``sftlf`` or ``sftof`` not found. """ if area_type not in ('land', 'sea'): raise TypeError( f"Expected 'land' or 'sea' for area_type, got '{area_type}'") (land_fraction, errors) = _get_land_fraction(cube) if land_fraction is None: raise ValueError( f"Weighting of '{cube.var_name}' with '{area_type}' fraction " f"failed because of the following errors: {' '.join(errors)}") core_data = cube.core_data() if area_type == 'land': cube.data = core_data * land_fraction elif area_type == 'sea': cube.data = core_data * (1.0 - land_fraction) return cube