grib2io.utils.gauss_grid

Tools for working with Gaussian grids.

Adopted from: https://gist.github.com/ajdawson/b64d24dfac618b91974f

 1"""
 2Tools for working with Gaussian grids.
 3
 4Adopted from: https://gist.github.com/ajdawson/b64d24dfac618b91974f
 5"""
 6
 7from __future__ import absolute_import, division, print_function
 8
 9import functools
10
11import numpy as np
12import numpy.linalg as la
13from numpy.polynomial.legendre import legcompanion, legder, legval
14
15
16def __single_arg_fast_cache(func):
17    """Caching decorator for functions of one argument."""
18
19    class CachingDict(dict):
20        def __missing__(self, key):
21            result = self[key] = func(key)
22            return result
23
24        @functools.wraps(func)
25        def __getitem__(self, *args, **kwargs):
26            return super(CachingDict, self).__getitem__(*args, **kwargs)
27
28    return CachingDict().__getitem__
29
30
31@__single_arg_fast_cache
32def gaussian_latitudes(nlat: int):
33    """
34    Construct latitudes for a Gaussian grid.
35
36    Parameters
37    ----------
38    nlat
39        The number of latitudes in the Gaussian grid.
40
41    Returns
42    -------
43    latitudes
44        `numpy.ndarray` of latitudes (in degrees) with a length of `nlat`.
45    """
46    if abs(int(nlat)) != nlat:
47        raise ValueError("nlat must be a non-negative integer")
48    # Create the coefficients of the Legendre polynomial and construct the
49    # companion matrix:
50    cs = np.array([0] * nlat + [1], dtype=int)
51    cm = legcompanion(cs)
52    # Compute the eigenvalues of the companion matrix (the roots of the
53    # Legendre polynomial) taking advantage of the fact that the matrix is
54    # symmetric:
55    roots = la.eigvalsh(cm)
56    roots.sort()
57    # Improve the roots by one application of Newton's method, using the
58    # solved root as the initial guess:
59    fx = legval(roots, cs)
60    fpx = legval(roots, legder(cs))
61    roots -= fx / fpx
62    # The roots should exhibit symmetry, but with a sign change, so make sure
63    # this is the case:
64    roots = (roots - roots[::-1]) / 2.0
65    # Convert the roots from the interval [-1, 1] to latitude values on the
66    # interval [-90, 90] degrees:
67    latitudes = np.rad2deg(np.arcsin(roots))
68    # Flip latitudes such that it is oriented from North to South [90, -90]
69    latitudes = np.flip(latitudes)
70    return latitudes
def gaussian_latitudes(nlat: int):
32@__single_arg_fast_cache
33def gaussian_latitudes(nlat: int):
34    """
35    Construct latitudes for a Gaussian grid.
36
37    Parameters
38    ----------
39    nlat
40        The number of latitudes in the Gaussian grid.
41
42    Returns
43    -------
44    latitudes
45        `numpy.ndarray` of latitudes (in degrees) with a length of `nlat`.
46    """
47    if abs(int(nlat)) != nlat:
48        raise ValueError("nlat must be a non-negative integer")
49    # Create the coefficients of the Legendre polynomial and construct the
50    # companion matrix:
51    cs = np.array([0] * nlat + [1], dtype=int)
52    cm = legcompanion(cs)
53    # Compute the eigenvalues of the companion matrix (the roots of the
54    # Legendre polynomial) taking advantage of the fact that the matrix is
55    # symmetric:
56    roots = la.eigvalsh(cm)
57    roots.sort()
58    # Improve the roots by one application of Newton's method, using the
59    # solved root as the initial guess:
60    fx = legval(roots, cs)
61    fpx = legval(roots, legder(cs))
62    roots -= fx / fpx
63    # The roots should exhibit symmetry, but with a sign change, so make sure
64    # this is the case:
65    roots = (roots - roots[::-1]) / 2.0
66    # Convert the roots from the interval [-1, 1] to latitude values on the
67    # interval [-90, 90] degrees:
68    latitudes = np.rad2deg(np.arcsin(roots))
69    # Flip latitudes such that it is oriented from North to South [90, -90]
70    latitudes = np.flip(latitudes)
71    return latitudes

Construct latitudes for a Gaussian grid.

Parameters
  • nlat: The number of latitudes in the Gaussian grid.
Returns
  • latitudes: numpy.ndarray of latitudes (in degrees) with a length of nlat.