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

Construct latitudes for a Gaussian grid.

Parameters

nlat : int The number of latitudes in the Gaussian grid.

Returns

numpy.ndarray of latitudes (in degrees) with a length of nlat.