Source code for improver.blending.blend_across_adjacent_points

# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# (C) British Crown Copyright 2017-2019 Met Office.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
"""Module containing Blending classes that blend over adjacent points, as
opposed to collapsing the whole dimension."""

import iris
from cf_units import Unit

from improver import BasePlugin
from improver.blending.weighted_blend import WeightedBlendAcrossWholeDimension
from improver.blending.weights import ChooseDefaultWeightsTriangular
from improver.utilities.cube_checker import check_cube_coordinates


[docs]class TriangularWeightedBlendAcrossAdjacentPoints(BasePlugin): """ Apply a Weighted blend to a coordinate, using triangular weights at each point in the coordinate. Returns a cube with the same coordinates as the input cube, with each point in the coordinate of interest having been blended with the adjacent points according to a triangular weighting function of a specified width. """
[docs] def __init__(self, coord, central_point, parameter_units, width): """Set up for a Weighted Blending plugin Args: coord (str): The name of a coordinate dimension in the cube that we will blend over. central_point (float or int): Central point at which the output from the triangular weighted blending will be calculated. parameter_units (str): The units of the width of the triangular weighting function and the units of the central_point. This does not need to be the same as the units of the coordinate we are blending over, but it should be possible to convert between them. width (float): The width of the triangular weighting function we will use to blend. """ self.coord = coord self.central_point = central_point self.parameter_units = parameter_units self.width = width # Set up a plugin to calculate the triangular weights. self.WeightsPlugin = ChooseDefaultWeightsTriangular( width, units=parameter_units) # Set up the blending function, based on whether weighted blending or # maximum probabilities are needed. self.BlendingPlugin = ( WeightedBlendAcrossWholeDimension(coord, timeblending=True))
def __repr__(self): """Represent the configured plugin instance as a string.""" msg = ('<TriangularWeightedBlendAcrossAdjacentPoints:' ' coord = {0:s}, central_point = {1:.2f}, ' 'parameter_units = {2:s}, width = {3:.2f}') return msg.format( self.coord, self.central_point, self.parameter_units, self.width)
[docs] def _find_central_point(self, cube): """ Find the cube that contains the central point, otherwise, raise an exception. Args: cube (iris.cube.Cube): Cube containing input for blending. Returns: iris.cube.Cube: Cube containing central point. Raises: ValueError: Central point is not available within the input cube. """ # Convert central point into the units of the cube, so that a # central point can be extracted. central_point = ( Unit(self.parameter_units).convert( self.central_point, cube.coord(self.coord).units)) constr = iris.Constraint( coord_values={self.coord: central_point}) central_point_cube = cube.extract(constr) if central_point_cube is None: msg = ("The central point {} in units of {} not available " "within input cube coordinate points: {}.".format( self.central_point, self.parameter_units, cube.coord(self.coord).points)) raise ValueError(msg) return central_point_cube
[docs] def process(self, cube): """ Apply the weighted blend for each point in the given coordinate. Args: cube (iris.cube.Cube): Cube containing input for blending. Returns: iris.cube.Cube: The processed cube, with the same coordinates as the input central_cube. The points in one coordinate will be blended with the adjacent points based on a triangular weighting function of the specified width. """ # Extract the central point from the input cube. central_point_cube = self._find_central_point(cube) # Calculate weights and produce blended output. weights = self.WeightsPlugin.process( cube, self.coord, self.central_point) blended_cube = self.BlendingPlugin.process(cube, weights) # With one threshold dimension (such as for low cloud), the threshold # axis is demoted to a scalar co-ordinate by BlendingPlugin. This line # promotes threshold to match the dimensions of central_point_cube. blended_cube = check_cube_coordinates(central_point_cube, blended_cube) blended_cube = central_point_cube.copy(blended_cube.data) return blended_cube