credit.regrid
=============

.. py:module:: credit.regrid

.. autoapi-nested-parse::

   This scripts contains functions that performs nearest, bilinear, and conservative interpolation
   on xarray.Datasets. The original version of this script is available at WeatherBench2.

   Note: only rectalinear grids (one dimensional lat/lon coordinates) are supported.

   Reference
    - WeatherBench2 regridding:
        https://github.com/google-research/weatherbench2/blob/main/weatherbench2/regridding.py

   Example usage
   # ================================================================================== #
   import credit.regrid as regrid

   # --------------------- #
   # prepare grids

   # target grid
   lon_1deg = np.arange(0, 360, 1)
   lat_1deg = np.arange(-90, 91, 1)
   target_grid = regrid.Grid.from_degrees(lon_1deg, lat_1deg)

   # input grid (flip 90 --> -90 to -90 --> 90)
   lon_025deg = ds_static['longitude'].values
   lat_025deg = ds_static['latitude'].values[::-1]
   source_grid = regrid.Grid.from_degrees(lon_025deg, lat_025deg)

   # --------------------- #
   # define regridder
   regridder = regrid.ConservativeRegridder(source=source_grid, target=target_grid)

   # --------------------- #
   # clear old chunking and interpolate data
   ds_static = ds_static.chunk({'longitude': -1, 'latitude': -1})
   ds_static_1deg = regridder.regrid_dataset(ds_static)

   # --------------------- #
   # ... some xarray operations to preserve the order of dims ... #

   # assign coordinates
   lon_1deg = np.arange(0, 360, 1)
   lat_1deg = np.arange(-90, 91, 1)
   ds_static_1deg = ds_static_1deg.assign_coords({
       'latitude': lat_1deg,
       'longitude': lon_1deg
   })

   # flip latitude from -90 --> 90 to 90 --> -90
   ds_static_1deg = ds_static_1deg.isel(latitude=slice(None, None, -1))




Attributes
----------

.. autoapisummary::

   credit.regrid.Array


Classes
-------

.. autoapisummary::

   credit.regrid.Grid
   credit.regrid.Regridder
   credit.regrid.NearestRegridder
   credit.regrid.BilinearRegridder
   credit.regrid.ConservativeRegridder


Functions
---------

.. autoapisummary::

   credit.regrid.nearest_neighbor_indices
   credit.regrid._assert_increasing
   credit.regrid._latitude_cell_bounds
   credit.regrid._latitude_overlap
   credit.regrid._conservative_latitude_weights
   credit.regrid._align_phase_with
   credit.regrid._periodic_upper_bounds
   credit.regrid._periodic_lower_bounds
   credit.regrid._periodic_overlap
   credit.regrid._longitude_overlap
   credit.regrid._conservative_longitude_weights


Module Contents
---------------

.. py:data:: Array

.. py:class:: Grid

   Representation of a rectilinear grid.


   .. py:attribute:: lon
      :type:  numpy.ndarray


   .. py:attribute:: lat
      :type:  numpy.ndarray


   .. py:method:: from_degrees(lon: numpy.ndarray, lat: numpy.ndarray) -> Grid
      :classmethod:



   .. py:property:: shape
      :type: tuple[int, int]



   .. py:method:: _to_tuple() -> tuple[tuple[float, Ellipsis], tuple[float, Ellipsis]]


   .. py:method:: __eq__(other)


   .. py:method:: __hash__()


.. py:class:: Regridder

   Base class for regridding.


   .. py:attribute:: source
      :type:  Grid


   .. py:attribute:: target
      :type:  Grid


   .. py:method:: regrid_array(field: Array) -> numpy.ndarray
      :abstractmethod:


      Regrid an array with dimensions (..., lon, lat) from source to target.



   .. py:method:: regrid_dataset(dataset: xarray.Dataset) -> xarray.Dataset

      Regrid an xarray.Dataset from source to target.



.. py:function:: nearest_neighbor_indices(source_grid: Grid, target_grid: Grid) -> numpy.ndarray

   Returns Haversine nearest neighbor indices from source_grid to target_grid.


.. py:class:: NearestRegridder

   Bases: :py:obj:`Regridder`


   Regrid with nearest neighbor interpolation.


   .. py:method:: indices()

      The interpolation indices associated with source_grid.



   .. py:method:: _nearest_neighbor_2d(array: Array) -> numpy.ndarray

      2D nearest neighbor interpolation using BallTree.



   .. py:method:: regrid_array(field: Array) -> numpy.ndarray

      Regrid an array with dimensions (..., lon, lat) from source to target.



.. py:class:: BilinearRegridder

   Bases: :py:obj:`Regridder`


   Regrid with bilinear interpolation.


   .. py:method:: regrid_array(field: Array) -> numpy.ndarray

      Regrid an array with dimensions (..., lon, lat) from source to target.



.. py:function:: _assert_increasing(x: numpy.ndarray) -> None

.. py:function:: _latitude_cell_bounds(x: Array) -> numpy.ndarray

.. py:function:: _latitude_overlap(source_points: Array, target_points: Array) -> numpy.ndarray

   Calculate the area overlap as a function of latitude.


.. py:function:: _conservative_latitude_weights(source_points: Array, target_points: Array) -> numpy.ndarray

   Create a weight matrix for conservative regridding along latitude.

   :param source_points: 1D latitude coordinates in radians for centers of source cells.
   :param target_points: 1D latitude coordinates in radians for centers of target cells.

   :returns: NumPy array with shape (target_size, source_size). Rows sum to 1.


.. py:function:: _align_phase_with(x, target, period)

   Align the phase of a periodic number to match another.


.. py:function:: _periodic_upper_bounds(x, period)

.. py:function:: _periodic_lower_bounds(x, period)

.. py:function:: _periodic_overlap(x0, x1, y0, y1, period)

   Calculate the overlap between two intervals considering periodicity.


.. py:function:: _longitude_overlap(first_points: Array, second_points: Array, period: float = 2 * np.pi) -> numpy.ndarray

   Calculate the area overlap as a function of longitude.


.. py:function:: _conservative_longitude_weights(source_points: numpy.ndarray, target_points: numpy.ndarray) -> numpy.ndarray

   Create a weight matrix for conservative regridding along longitude.

   :param source_points: 1D longitude coordinates in radians for centers of source cells.
   :param target_points: 1D longitude coordinates in radians for centers of target cells.

   :returns: NumPy array with shape (target_size, source_size). Rows sum to 1.


.. py:class:: ConservativeRegridder

   Bases: :py:obj:`Regridder`


   Regrid with linear conservative regridding.


   .. py:method:: _mean(field: Array) -> numpy.ndarray

      Computes cell-averages of field on the target grid.



   .. py:method:: _nanmean(field: Array) -> numpy.ndarray

      Compute cell-averages skipping NaNs like np.nanmean.



   .. py:method:: regrid_array(field: Array) -> numpy.ndarray

      Regrid an array with dimensions (..., lon, lat) from source to target.



