Source code for pylawr.functions.grid

#!/bin/env python
# -*- coding: utf-8 -*-

# System modules
import logging
import math

# External modules
import numpy as np

# Internal modules
import xarray as xr
from pylawr.grid import LatLonGrid
from pylawr.grid.unstructured import UnstructuredGrid


logger = logging.getLogger(__name__)


[docs]def get_latlon_grid(orig_grid): """ This function can be used to get a rectangular :py:class:`~pylawr.grid.latlon.LatLonGrid`. The edges of the rectangular grid are determined by the boundary values of the original grid. The median step-wide of the original grid is used as resolution. Parameters ---------- orig_grid : child of :py:class:`pylawr.grid.BaseGrid` This original grid is used to determine edges and step wide of the latitude and longitude grid. Returns ------- latlon_grid : :py:class:`pylawr.grid.latlon.LatLonGrid` This grid is created based on given original grid with edges and step wide determined by the original grid. """ lat, lon = orig_grid.lat_lon start_lat = np.min(lat) start_lon = np.min(lon) res_lat = np.median(np.abs(np.diff(lat, axis=-1))) res_lon = np.median(np.abs(np.diff(lon, axis=0))) points_lat = math.ceil((np.max(lat) - start_lat)/res_lat) points_lon = math.ceil((np.max(lon) - start_lon)/res_lon) latlon_grid = LatLonGrid( start=(start_lat, start_lon), resolution=(res_lat, res_lon), nr_points=(points_lat, points_lon), center=orig_grid.center ) return latlon_grid
[docs]def remap_data(data, orig_grid, new_grid, remapper=None): """ This function remaps data based on given grids with given remap instance. If the remap instance was not fitted yet, it will be fitted. Parameters ---------- data : :py:class:`xarray.DataArray` This data is remapped by given remapper. The last coordinate(s) should be the grid coordinates. orig_grid : child of :py:class:`pylawr.grid.BaseGrid` This grid is used as basis grid for the remapping. The last data coordinates should have the same shape as this grid. new_grid : child of :py:class:`pylawr.grid.BaseGrid` The data is remapped to this grid. remapper : child of :py:class:`pylawr.remap.BaseRemap` or None, optional This remapper is used to remap given data to new grid. If the remapper is already fitted, it is assumed that the remapper was fitted to given grids. Default value (None) is an unfitted :py:class:`~pylawr.remap.NearestNeighbor` instance with a single nearest neighbor. Returns ------- remapped_data : :py:class:`xarray.DataArray` This data was remapped to ``new_grid`` with given remapper. remapper : child of :py:class:`pylawr.remap.BaseRemap` This remapper was used to remap given data. This remapper is fitted to given grids. Warnings -------- For a fitted ``remapper``, we assume that the ``remapper`` was fitted to given grids! Notes ----- Most of processing time is spend on fitting given ``remapper``. It is recommended to give a fitted remapper to increase the speed of this function. """ if remapper is None: from pylawr.remap import NearestNeighbor remapper = NearestNeighbor(1) if not remapper.fitted: remapper.fit(orig_grid, new_grid) remapped_data = remapper.remap(data) return remapped_data, remapper
[docs]def get_masked_grid(origin_grid, mask_array): """ Mask value within a given origin grid. Parameters ---------- mask_array : :py:class:`numpy.ndarray` (bool) This mask is applied on given ``origin_grid``. Should have the same shape as ``origin_grid``. All values set to True are used, while values set to False are dismissed. origin_grid : child of :py:class:`pylawr.grid.base.BaseGrid` This grid is used to infer the latitude, longitude and altitude values for the unstructured grid. Returns ------- masked_grid : :py:class:`pylawr.grid.unstructured.UnstructuredGrid` The unstructured grid with all non-masked values. This unstructured grid gets its latitude, longitude and altitude values from given ``origin_grid``. All values set to True within ``mask_array`` are used. """ lat_lon = np.array(origin_grid.lat_lon) masked_latlon = lat_lon[..., mask_array].T masked_altitude = origin_grid.altitude[mask_array][..., None] masked_vals = np.concatenate([masked_latlon, masked_altitude], axis=-1) masked_grid = UnstructuredGrid(masked_vals, origin_grid.center) return masked_grid
[docs]def get_cartesian(grid, use_altitude=False): """ This method calculates cartesian coordinates based on the given grid. The cartesian coordinates are calculated based on simplifications and uses trigonometric functions. The latitude (lat), longitude (lon) and height values (h) are extracted from the given grid, while the earth_radius (R) is set for the remapping. ..math:: x = R * cos(lat) * cos(lon) y = R * cos(lat) * sin(lon) z = h + R * sin(lat) Parameters ---------- grid : child of :py:class:`pylawr.grid.BaseGrid` The cartesian coordinates are calculated based on this grid. The grid needs the methods: :py:meth:`get_altitude` and :py:meth:`get_lat_lon` and should be a child of :py:class:`~pylawr.grid.BaseGrid`. use_altitude : bool Use the altitude for cartesian coordinates. Default is `False`. Note, using the correct altitude for the cartesian coordinates for remapping may not preferred. Returns ------- cartesian : :py:class:`xarray.DataArray` The calculated coordinates based on the given grid. The last dimension is `x`, `y` and `z`, while the other dimension sizes are defined by the shape of the input grid. """ try: lat_lon = grid.get_lat_lon() altitude = grid.get_altitude() earth_radius = grid.earth_radius except AttributeError: raise TypeError( 'The given grid is no valid grid and cannot be used!' ) lat_rad = np.deg2rad(lat_lon['lat']) lon_rad = np.deg2rad(lat_lon['lon']) transposed_dims = [d for d in lat_rad.dims] + ['coord_names', ] x = earth_radius * np.cos(lat_rad) * np.cos(lon_rad) y = earth_radius * np.cos(lat_rad) * np.sin(lon_rad) z = earth_radius * np.sin(lat_rad) if use_altitude: z += altitude cartesian = xr.concat([x, y, z], dim='coord_names') cartesian['coord_names'] = ['x', 'y', 'z'] cartesian = cartesian.transpose(*transposed_dims) return cartesian
[docs]def prepare_grid(grid): """ This method is used to prepare the grid for the remapping, the grid is transformed into cartesian coordinates with :py:meth:``_get_cartesian`` and then stacked and transposed. Parameters ---------- grid : child of :py:class:`pylawr.grid.BaseGrid` The cartesian coordinates are calculated based on this grid. The grid needs the methods: :py:meth:`get_altitude` and :py:meth:`get_lat_lon` and should be a child of :py:class:`~pylawr.grid.BaseGrid`. Returns ------- cartesian : :py:class:`xarray.DataArray` The calculated coordinates based on the given grid. The last dimension is `x`, `y` and `z`, while the first dimension is a stacked dimension based on the original grid dimensions. """ cartesian = get_cartesian(grid) if len(grid.coord_names) > 1: cartesian = cartesian.stack(stacked=grid.coord_names) cartesian = cartesian.transpose() return cartesian