grib2io.utils.gauss_grid

Tools for working with Gaussian grids.

 1"""
 2Tools for working with Gaussian grids.
 3"""
 4
 5# Adopted from: https://gist.github.com/ajdawson/b64d24dfac618b91974f
 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
38    **`nlat`**: The number of latitudes in the Gaussian grid.
39
40    Returns
41    -------
42
43    Numpy array 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
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
39    **`nlat`**: The number of latitudes in the Gaussian grid.
40
41    Returns
42    -------
43
44    Numpy array 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.
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

Construct latitudes for a Gaussian grid.

Parameters

nlat: The number of latitudes in the Gaussian grid.

Returns

Numpy array of latitudes (in degrees) with a length of nlat.