def _cube_area_sum(cube):
    """Calculate total area-sum - Iris can't do this in one operation."""
    area_sums = cube * i_cartog.area_weights(cube, normalize=False)
    area_sum = area_sums.collapsed(
        area_sums.coords(dim_coords=True), iris.analysis.SUM
    )
    return area_sum.data.flatten()[0]
Beispiel #2
0
def calculate_area(features, mask):
    from tobac.utils import mask_features_surface, mask_features
    from iris import Constraint
    from iris.analysis.cartography import area_weights

    features['area'] = np.nan

    mask_coords = [coord.name() for coord in mask.coords()]
    if ('projection_x_coordinate' in features.columns) and (
            'projection_y_coordinate' in features.columns) and (
                'projection_x_coordinate'
                in mask_coords) and ('projection_y_coordinate' in mask_coords):
        method_area = 'xy'
    elif ('latitude'
          in features.columns) and ('longitude' in features.columns) and (
              'latitude' in mask_coords) and ('longitude' in mask_coords):
        if mask.coord('latitude').ndim == 1:
            method_area = 'latlon'
        else:
            raise ValueError('2D latitude/longitude coordinates not supported')
    else:
        raise ValueError(
            'either latitude/longitude or projection_x_coordinate/projection_y_coordinate have to be present to calculate distances'
        )

    for time_i, features_i in features.groupby('time'):
        loggin.debug(str(time_i))
        constraint_time = Constraint(time=time_i)
        mask_i = mask.extract(constraint_time)

        if method_area == 'xy':
            if not (mask.coord('projection_x_coordinate').has_bounds()
                    and mask.coord('projection_y_coordinate').has_bounds()):
                mask.coord('projection_x_coordinate').guess_bounds()
                mask.coord('projection_y_coordinate').guess_bounds()
            area = np.outer(
                np.diff(mask.coord('projection_x_coordinate').bounds, axis=1),
                np.diff(mask.coord('projection_y_coordinate').bounds, axis=1))
        elif method_area == 'latlon':
            if not (mask.coord('latitude').has_bounds()
                    and mask.coord('longitude').has_bounds()):
                mask.coord('latitude').guess_bounds()
                mask.coord('longitude').guess_bounds()
            area = area_weights(mask, normalize=False)
        else:
            raise ValueError('method undefined')
        for i in features_i.index:
            if len(mask_i.shape) == 3:
                mask_i_surface = mask_features_surface(
                    mask_i,
                    features_i.loc[i, 'feature'],
                    z_coord='model_level_number')
            elif len(mask_i.shape) == 2:
                mask_i_surface = mask_features(mask_i,
                                               features_i.loc[i, 'feature'])
            area_feature = np.sum(area * (mask_i_surface.data > 0))
            features.at[i, 'area'] = area_feature
    return features
Beispiel #3
0
def area_average(x,latitude='latitude',longitude='longitude'):

    if x.coord(latitude).bounds is None:
        x.coord(latitude).guess_bounds()
    if x.coord(longitude).bounds is None:
        x.coord(longitude).guess_bounds()
    grid_areas = icart.area_weights(x)
    x_avg = x.collapsed([longitude, latitude], iris.analysis.MEAN, 
                            weights=grid_areas)
    return x_avg
Beispiel #4
0
def weights_array(cube, scheme):
    """Weights for a data set on a grid.

    Returned weights are a `numpy.ndarray` broadcastable to the shape of
    the input cube.

    **Arguments:**

    *cube*
        An `~iris.cube.Cube` instance to generate weights for.

    *scheme*
        Weighting scheme to use. The following values are accepted:

        * *'coslat'* : Square-root of cosine of latitude.
        * *'area'* : Square-root of grid cell area normalized by total
                     grid area.

    **Returns:**

    *weights*
        An array contanining the weights (not a `~iris.cube.Cube`).

    **Examples:**

    Area weights for a `~iris.cube.Cube` on 2D grid:

        weights = weights_array(cube, scheme='area')

    Square-root of cosine of latitude weights for a `~iris.cube.Cube`
    with a latitude dimension:

        weights = weights_array(cube, scheme='coslat')

    """
    # Always use lower-case for the scheme, allowing the user to use
    # upper-case in their calling code without an error.
    scheme = scheme.lower()
    if scheme in ('area',):
        # Handle area weighting.
        try:
            with warnings.catch_warnings():
                warnings.simplefilter('ignore', UserWarning)
                weights = np.sqrt(area_weights(cube, normalize=True))
        except (ValueError, CoordinateMultiDimError):
            raise ValueError('cannot generate area weights')
    elif scheme in ('coslat',):
        # Handle square-root of cosine of latitude weighting.
        try:
            weights = np.sqrt(cosine_latitude_weights(cube))
        except (ValueError, CoordinateMultiDimError):
            raise ValueError('cannot generate latitude weights')
    else:
        raise ValueError("invalid weighting scheme: '{!s}'".format(scheme))
    return weights
Beispiel #5
0
def weights_array(cube, scheme):
    """Weights for a data set on a grid.

    Returned weights are a `numpy.ndarray` broadcastable to the shape of
    the input cube.

    **Arguments:**

    *cube*
        An `~iris.cube.Cube` instance to generate weights for.

    *scheme*
        Weighting scheme to use. The following values are accepted:

        * *'coslat'* : Square-root of cosine of latitude.
        * *'area'* : Square-root of grid cell area normalized by total
                     grid area.

    **Returns:**

    *weights*
        An array contanining the weights (not a `~iris.cube.Cube`).

    **Examples:**

    Area weights for a `~iris.cube.Cube` on 2D grid:

        weights = weights_array(cube, scheme='area')

    Square-root of cosine of latitude weights for a `~iris.cube.Cube`
    with a latitude dimension:

        weights = weights_array(cube, scheme='coslat')

    """
    # Always use lower-case for the scheme, allowing the user to use
    # upper-case in their calling code without an error.
    scheme = scheme.lower()
    if scheme in ('area', ):
        # Handle area weighting.
        try:
            with warnings.catch_warnings():
                warnings.simplefilter('ignore', UserWarning)
                weights = np.sqrt(area_weights(cube, normalize=True))
        except (ValueError, CoordinateMultiDimError):
            raise ValueError('cannot generate area weights')
    elif scheme in ('coslat', ):
        # Handle square-root of cosine of latitude weighting.
        try:
            weights = np.sqrt(cosine_latitude_weights(cube))
        except (ValueError, CoordinateMultiDimError):
            raise ValueError('cannot generate latitude weights')
    else:
        raise ValueError("invalid weighting scheme: '{!s}'".format(scheme))
    return weights
Beispiel #6
0
def get_gridbox_vol(incube):
    """ Calculate grid-box volumes for input cube """

    import iris.analysis.cartography as icarto

    if incube.ndim < 3:
        raise TC_error('GET_VOL: Cube must have at least 3 dimensions')

    # Array for grid box areas. Same for all levels so can
    # work on 2-D cube
    if incube.ndim == 4:
        tcube = incube[0, 0, :, :]
    else:
        tcube = incube[0, :, :]

    if not tcube.coord('latitude').has_bounds():
        tcube.coord('latitude').guess_bounds()
    if not tcube.coord('longitude').has_bounds():
        tcube.coord('longitude').guess_bounds()

    grid_areas = icarto.area_weights(tcube)
    tcube = 'a'

    nlat = incube.coord('latitude').shape[0]
    nlong = incube.coord('longitude').shape[0]
    nlevs = incube.coord('level_height').shape[0]

    # Obtain grid top-boundary heights, so that subtracting from lower
    # will give height of each grid-box (horizontally uniform)
    grid_top = np.zeros(nlevs + 1, dtype=np.float32)
    grid_top[1:] = incube.coord('level_height').bounds[:, 1]  # top bound

    # Volume -area x height, always 3-D array (lat,long,hgt)
    vol_box = np.zeros([nlevs, nlat, nlong], dtype=np.float)

    for l in np.arange(nlevs):
        vol_box[l, :, :] = grid_areas[:, :] * (grid_top[l + 1] - grid_top[l])

    # Setup coords and generate a cube from computed values
    dm_long = incube.coord('longitude')
    dm_lat = incube.coord('latitude')
    dm_lev = incube.coord('model_level_number')
    aux_hgt = incube.coord('level_height')

    oucube = iris.cube.Cube(
        vol_box,
        var_name='grid_cell_volume',
        units='m^3',
        dim_coords_and_dims=[(dm_lev, 0), (dm_lat, 1), (dm_long, 2)],
        attributes={'Source': 'Derived from grid_area and level_height'})

    oucube.add_aux_coord(incube.coord('level_height'), 0)

    vol_box = np.zeros(1, dtype=np.int)
    return oucube
Beispiel #7
0
def area_average(x, latitude='latitude', longitude='longitude'):

    if x.coord(latitude).bounds is None:
        x.coord(latitude).guess_bounds()
    if x.coord(longitude).bounds is None:
        x.coord(longitude).guess_bounds()
    grid_areas = icart.area_weights(x)
    x_avg = x.collapsed([longitude, latitude],
                        iris.analysis.MEAN,
                        weights=grid_areas)
    return x_avg
Beispiel #8
0
def area_avg(cube, vert=None):
    ''' Routine to calculate global area-weighted mean fields '''
    if cube:
        cube.coord('longitude').guess_bounds()
        cube.coord('latitude').guess_bounds()
        weights = iac.area_weights(cube)
        mean = cube.collapsed(['time', 'longitude', 'latitude'],
                              iris.analysis.MEAN,
                              weights=weights)
        # Do vertical average if requested, using named vertical coordinate
        if vert:
            mean = mean.collapsed(vert, iris.analysis.MEAN)
    else:
        mean = None
    return mean
def _cube_area_sum(cube):
    """Calculate total area-sum - Iris can't do this in one operation."""
    area_sums = cube * i_cartog.area_weights(cube, normalize=False)
    area_sum = area_sums.collapsed(area_sums.coords(dim_coords=True),
                                   iris.analysis.SUM)
    return area_sum.data.flatten()[0]
Beispiel #10
0
def weight_lat_ave(cube):
    """Routine to calculate weighted latitudinal average."""
    grid_areas = iac.area_weights(cube)
    return cube.collapsed('latitude', iris.analysis.MEAN, weights=grid_areas)
Beispiel #11
0
print("Picking months...")
month_cubes = []
for month in range(1,13):
    print("Picking {}...".format(month_name[month]))
    #We pick the desired cubes:
    month_cubes.append(pick_times(test_cube,[],[month],[],[]))
print("...done picking months.")

#This loop calculates the mean temperature over all space,
#it "collapses" the cube.
print("Calculating spatial means...")
collapsed_cubes = []
for i in range(len(month_cubes)):
    print("Calculating spatial mean for {}...".format(month_name[i+1]))
    #We get the area weights of the cells composing the region:
    grid_areas = area_weights(month_cubes[i])

    #We "collapse" our 2D+Time cube into a 0D+Time by averaging using MEAN aggregator:
    collapsed_cubes.append(month_cubes[i].collapsed(['longitude', 'latitude'], MEAN, weights=grid_areas))
print("...done calculating spatial means.")


#Finally, we cast our analysis into a plot
import matplotlib.pyplot as plt
import iris.quickplot as iplt

print("Plotting...".format(month_name[i+1]))
for i in range(len(collapsed_cubes)):
    #Plot...
    iplt.plot(collapsed_cubes[i],linewidth='10',label=month_name[i+1])
    plt.legend(loc=4)
Beispiel #12
0
def calculate_area(features, mask, method_area=None):
    from tobac.utils import mask_features_surface, mask_features
    from iris import Constraint
    from iris.analysis.cartography import area_weights

    features["area"] = np.nan

    mask_coords = [coord.name() for coord in mask.coords()]
    if method_area is None:
        if ("projection_x_coordinate" in mask_coords) and (
            "projection_y_coordinate" in mask_coords
        ):
            method_area = "xy"
        elif ("latitude" in mask_coords) and ("longitude" in mask_coords):
            method_area = "latlon"
        else:
            raise ValueError(
                "either latitude/longitude or projection_x_coordinate/projection_y_coordinate have to be present to calculate distances"
            )
    logging.debug("calculating area using method " + method_area)
    if method_area == "xy":
        if not (
            mask.coord("projection_x_coordinate").has_bounds()
            and mask.coord("projection_y_coordinate").has_bounds()
        ):
            mask.coord("projection_x_coordinate").guess_bounds()
            mask.coord("projection_y_coordinate").guess_bounds()
        area = np.outer(
            np.diff(mask.coord("projection_x_coordinate").bounds, axis=1),
            np.diff(mask.coord("projection_y_coordinate").bounds, axis=1),
        )
    elif method_area == "latlon":
        if (mask.coord("latitude").ndim == 1) and (mask.coord("latitude").ndim == 1):
            if not (
                mask.coord("latitude").has_bounds()
                and mask.coord("longitude").has_bounds()
            ):
                mask.coord("latitude").guess_bounds()
                mask.coord("longitude").guess_bounds()
            area = area_weights(mask, normalize=False)
        elif mask.coord("latitude").ndim == 2 and mask.coord("longitude").ndim == 2:
            raise ValueError("2D latitude/longitude coordinates not supported yet")
            # area=calculate_areas_2Dlatlon(mask.coord('latitude'),mask.coord('longitude'))
        else:
            raise ValueError("latitude/longitude coordinate shape not supported")
    else:
        raise ValueError("method undefined")

    for time_i, features_i in features.groupby("time"):
        logging.debug("timestep:" + str(time_i))
        constraint_time = Constraint(time=time_i)
        mask_i = mask.extract(constraint_time)
        for i in features_i.index:
            if len(mask_i.shape) == 3:
                mask_i_surface = mask_features_surface(
                    mask_i, features_i.loc[i, "feature"], z_coord="model_level_number"
                )
            elif len(mask_i.shape) == 2:
                mask_i_surface = mask_features(mask_i, features_i.loc[i, "feature"])
            area_feature = np.sum(area * (mask_i_surface.data > 0))
            features.at[i, "area"] = area_feature
    return features