Source code for pylawr.remap.base
#!/bin/env python
# -*- coding: utf-8 -*-
# System modules
import logging
import abc
import warnings
# External modules
import xarray as xr
# Internal modules
import pylawr.functions.grid as grid_funcs
from pylawr.utilities.decorators import log_decorator
logger = logging.getLogger(__name__)
class NotImprovableError(Exception):
pass
class NotFittedError(Exception):
pass
[docs]class BaseRemap(object):
"""
The BaseRemap is a base class for all remap subclasses.
Parameters
----------
"""
def __init__(self):
self._grid_in = None
self._grid_out = None
[docs] def _prepare_grid(self, grid):
warnings.warn(
'The method `_prepare_grid` will be removed in the next release',
category=DeprecationWarning
)
return grid_funcs.prepare_grid(grid)
@property
@abc.abstractmethod
def fitted(self):
"""
Check if the remapping is fitted.
Returns
-------
fitted : bool
If this remap object is fitted.
"""
pass
[docs] @abc.abstractmethod
def fit(self, grid_in, grid_out):
"""
Fit the remapping for given grids. If the remapping is refitted
and only the output grid changed the old point neighbours are recovered
when possible. If the input grid in a refitting the old tree is reused.
Parameters
----------
grid_in : child of :py:class:`pylawr.grid.BaseGrid`
The data is remapped from this grid to another grid. This grid
needs to have :py:meth:`get_altitude` and :py:meth:`get_lat_lon`.
grid_out : child of :py:class:`pylawr.grid.BaseGrid`
The data is remapped from another grid to this grid. This grid
needs to have :py:meth:`get_altitude` and :py:meth:`get_lat_lon`.
"""
pass
[docs] def optimize(self, data, warm_start=False):
"""
Optimize the parameter of the remapping based on given data.
Parameters
----------
data : :py:class:`xarray.DataArray`
The data is used to optimize the parameters of this remapping.
warm_start : bool, optional
If the last optimized values should used as starting values for this
optimization loop. Default is False.
Returns
-------
self : Interpolation
This optimized interpolation instance.
"""
raise NotImprovableError('This interpolation cannot be optimized!')
[docs] def _stack_grid_coords(self, data):
"""
The data is stacked along matching grid coordinates. It is further
checked whether the array can use this grid.
Parameters
----------
data : :py:class:`xarray.DataArray`
This data is stacked.
Returns
-------
stacked_data : :py:class:`xarray.DataArray`
The stacked data based on the coordinates names of the input grid.
The grid coordinates are stacked to a new grid coordinate.
"""
data = data.lawr.set_grid_coordinates(self._grid_in)
if len(self._grid_in.coord_names) > 1:
stacked_data = data.stack(grid=self._grid_in.coord_names)
dims_wo_grid = [
d for d in data.dims
if d not in self._grid_in.coord_names
]
transpose_dims = dims_wo_grid + ['grid']
stacked_data = stacked_data.transpose(*transpose_dims)
else:
rename_mapping = {self._grid_in.coord_names[0]: 'grid'}
stacked_data = data.rename(rename_mapping)
return stacked_data
[docs] def _array_postprocess(self, remapped_data, original_data):
"""
Replace the grid of the stacked data with the output grid. Unstack the
stacked data and set the output grid as grid of the returned data.
Parameters
----------
remapped_data : :py:class:`numpy.ndarray`
The remapped data which should be converted into a xarray with
``grid_out``'s coordinates.
original_data : :py:class:`xarray.DataArray`
This original data array is used as template for the new data array.
Returns
-------
gridded_data : :py:class:`xarray.DataArray`
The unstacked data with replaced grid. The output grid is accessible
with :py:attr:``gridded_data.lawr.grid``.
"""
data_coords = {dim: original_data[dim] for dim in original_data.dims
if dim != 'grid'}
data_coords['grid'] = self._grid_out.get_multiindex()
data_array = xr.DataArray(
data=remapped_data,
coords=data_coords,
dims=original_data.dims,
attrs=original_data.attrs,
name=original_data.name
)
if len(self._grid_out.grid_shape) > 1:
data_array = data_array.unstack('grid')
gridded_data = data_array.lawr.set_grid_coordinates(self._grid_out)
return gridded_data
[docs] @abc.abstractmethod
def _remap_method(self, data):
pass
[docs] @log_decorator(logger)
def remap(self, data):
"""
Remap the given data with the optimized parameters and the given
grids.
Parameters
----------
data : :py:class:`xarray.DataArray`
This data is remapped from grid_in to grid_out. The data should
have the same shape as the input grid shape.
Returns
-------
remapped_data : :py:class:`xarray.DataArray`
The array with the remapped data based on grid_out. The grid_out
is accessible via ``remapped_data.lawr.Grid``.
Raises
------
NotFittedError
A NotFittedError is raised if the fit method was not called yet.
Warnings
--------
Make sure that there are no NaNs are within the grid because the mapping
from input grid to output grid is static and therefore not "NaN-safe".
To fill up NaN values you can use ``pylawr.filter.interpolation``.
"""
if not self.fitted:
raise NotFittedError('This interpolation was not fitted yet!')
stacked_data = self._stack_grid_coords(data)
stacked_remap_data = self._remap_method(stacked_data)
remapped_data = self._array_postprocess(stacked_remap_data,
stacked_data)
return remapped_data