grib2io.utils.arakawa_rotated_grid

Functions for handling an Arakawa Rotated Lat/Lon Grids.

This grid is not often used, but is currently used for the NCEP/RAP using GRIB2 Grid Definition Template 32769

These functions are adapted from the NCAR Command Language (ncl), from NcGRIB2.c

  1"""
  2Functions for handling an Arakawa Rotated Lat/Lon Grids.
  3
  4This grid is not often used, but is currently used for the NCEP/RAP using
  5[GRIB2 Grid Definition Template 32769](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp3-32769.shtml)
  6
  7These functions are adapted from the NCAR Command Language (ncl),
  8from [NcGRIB2.c](https://github.com/NCAR/ncl/blob/develop/ni/src/ncl/NclGRIB2.c)
  9"""
 10
 11import math
 12
 13from . import rotated_grid
 14
 15DEG2RAD = rotated_grid.DEG2RAD
 16RAD2DEG = rotated_grid.RAD2DEG
 17
 18
 19def ll2rot(latin: float, lonin: float, latpole: float, lonpole: float) -> tuple[float, float]:
 20    """
 21    Rotate a latitude/longitude pair.
 22
 23    Parameters
 24    ----------
 25    latin
 26        Unrotated latitude in units of degrees.
 27    lonin
 28        Unrotated longitude in units of degrees.
 29    latpole
 30        Latitude of Pole.
 31    lonpole
 32        Longitude of Pole.
 33
 34    Returns
 35    -------
 36    tlat
 37        Rotated latitude in units of degrees.
 38    tlons
 39        Rotated longitude in units of degrees.
 40    """
 41    tlon = lonin - lonpole
 42
 43    # Convert to xyz coordinates
 44    x = math.cos(latin * DEG2RAD) * math.cos(tlon * DEG2RAD)
 45    y = math.cos(latin * DEG2RAD) * math.sin(tlon * DEG2RAD)
 46    z = math.sin(latin * DEG2RAD)
 47
 48    # Rotate around y axis
 49    rotang = (latpole + 90) * DEG2RAD
 50    sinrot = math.sin(rotang)
 51    cosrot = math.cos(rotang)
 52    ry = y
 53    rx = x * cosrot + z * sinrot
 54    rz = -x * sinrot + z * cosrot
 55
 56    # Convert back to lat/lon
 57    tlat = math.asin(rz) / DEG2RAD
 58    if math.fabs(rx) > 0.0001:
 59        tlon = math.atan2(ry, rx) / DEG2RAD
 60    elif ry > 0:
 61        tlon = 90.0
 62    else:
 63        tlon = -90.0
 64
 65    if tlon < -180:
 66        tlon += 360.0
 67    if tlon >= 180:
 68        tlon -= 360.0
 69
 70    return tlat, tlon
 71
 72
 73def rot2ll(latin: float, lonin: float, latpole: float, lonpole: float) -> tuple[float, float]:
 74    """
 75    Unrotate a latitude/longitude pair.
 76
 77    Parameters
 78    ----------
 79    latin
 80        Rotated latitude in units of degrees.
 81    lonin
 82        Rotated longitude in units of degrees.
 83    latpole
 84        Latitude of Pole.
 85    lonpole
 86        Longitude of Pole.
 87
 88    Returns
 89    -------
 90    tlat
 91        Unrotated latitude in units of degrees.
 92    tlons
 93        Unrotated longitude in units of degrees.
 94    """
 95    tlon = lonin
 96
 97    # Convert to xyz coordinates
 98    x = math.cos(latin * DEG2RAD) * math.cos(lonin * DEG2RAD)
 99    y = math.cos(latin * DEG2RAD) * math.sin(lonin * DEG2RAD)
100    z = math.sin(latin * DEG2RAD)
101
102    # Rotate around y axis
103    rotang = -(latpole + 90) * DEG2RAD
104    sinrot = math.sin(rotang)
105    cosrot = math.cos(rotang)
106    ry = y
107    rx = x * cosrot + z * sinrot
108    rz = -x * sinrot + z * cosrot
109
110    # Convert back to lat/lon
111    tlat = math.asin(rz) / DEG2RAD
112    if math.fabs(rx) > 0.0001:
113        tlon = math.atan2(ry, rx) / DEG2RAD
114    elif ry > 0:
115        tlon = 90.0
116    else:
117        tlon = -90.0
118
119    # Remove the longitude rotation
120    tlon += lonpole
121    if tlon < 0:
122        tlon += 360.0
123    if tlon > 360:
124        tlon -= 360.0
125
126    return tlat, tlon
127
128
129def vector_rotation_angles(
130    tlat: float,
131    tlon: float,
132    clat: float,
133    losp: float,
134    xlat: float,
135) -> float:
136    """
137    Generate a rotation angle value.
138
139    The rotation angle value can be applied to a vector quantity to make it
140    Earth-oriented.
141
142    Parameters
143    ----------
144    tlat
145        True latitude in units of degrees.
146    tlon
147        True longitude in units of degrees..
148    clat
149        Latitude of center grid point in units of degrees.
150    losp
151        Longitude of the southern pole in units of degrees.
152    xlat
153        Latitude of the rotated grid in units of degrees.
154
155    Returns
156    -------
157    rot
158        Rotation angle in units of radians.
159    """
160    slon = math.sin((tlon - losp) * DEG2RAD)
161    cgridlat = math.cos(xlat * DEG2RAD)
162    if cgridlat <= 0.0:
163        rot = 0.0
164    else:
165        crot = (
166            math.cos(clat * DEG2RAD) * math.cos(tlat * DEG2RAD) + math.sin(clat * DEG2RAD) * math.sin(tlat * DEG2RAD) * math.cos(tlon * DEG2RAD)
167        ) / cgridlat
168        srot = (-1.0 * math.sin(clat * DEG2RAD) * slon) / cgridlat
169        rot = math.atan2(srot, crot)
170    return rot
DEG2RAD = 0.017453292519943295
RAD2DEG = 57.29577951308232
def ll2rot( latin: float, lonin: float, latpole: float, lonpole: float) -> tuple[float, float]:
20def ll2rot(latin: float, lonin: float, latpole: float, lonpole: float) -> tuple[float, float]:
21    """
22    Rotate a latitude/longitude pair.
23
24    Parameters
25    ----------
26    latin
27        Unrotated latitude in units of degrees.
28    lonin
29        Unrotated longitude in units of degrees.
30    latpole
31        Latitude of Pole.
32    lonpole
33        Longitude of Pole.
34
35    Returns
36    -------
37    tlat
38        Rotated latitude in units of degrees.
39    tlons
40        Rotated longitude in units of degrees.
41    """
42    tlon = lonin - lonpole
43
44    # Convert to xyz coordinates
45    x = math.cos(latin * DEG2RAD) * math.cos(tlon * DEG2RAD)
46    y = math.cos(latin * DEG2RAD) * math.sin(tlon * DEG2RAD)
47    z = math.sin(latin * DEG2RAD)
48
49    # Rotate around y axis
50    rotang = (latpole + 90) * DEG2RAD
51    sinrot = math.sin(rotang)
52    cosrot = math.cos(rotang)
53    ry = y
54    rx = x * cosrot + z * sinrot
55    rz = -x * sinrot + z * cosrot
56
57    # Convert back to lat/lon
58    tlat = math.asin(rz) / DEG2RAD
59    if math.fabs(rx) > 0.0001:
60        tlon = math.atan2(ry, rx) / DEG2RAD
61    elif ry > 0:
62        tlon = 90.0
63    else:
64        tlon = -90.0
65
66    if tlon < -180:
67        tlon += 360.0
68    if tlon >= 180:
69        tlon -= 360.0
70
71    return tlat, tlon

Rotate a latitude/longitude pair.

Parameters
  • latin: Unrotated latitude in units of degrees.
  • lonin: Unrotated longitude in units of degrees.
  • latpole: Latitude of Pole.
  • lonpole: Longitude of Pole.
Returns
  • tlat: Rotated latitude in units of degrees.
  • tlons: Rotated longitude in units of degrees.
def rot2ll( latin: float, lonin: float, latpole: float, lonpole: float) -> tuple[float, float]:
 74def rot2ll(latin: float, lonin: float, latpole: float, lonpole: float) -> tuple[float, float]:
 75    """
 76    Unrotate a latitude/longitude pair.
 77
 78    Parameters
 79    ----------
 80    latin
 81        Rotated latitude in units of degrees.
 82    lonin
 83        Rotated longitude in units of degrees.
 84    latpole
 85        Latitude of Pole.
 86    lonpole
 87        Longitude of Pole.
 88
 89    Returns
 90    -------
 91    tlat
 92        Unrotated latitude in units of degrees.
 93    tlons
 94        Unrotated longitude in units of degrees.
 95    """
 96    tlon = lonin
 97
 98    # Convert to xyz coordinates
 99    x = math.cos(latin * DEG2RAD) * math.cos(lonin * DEG2RAD)
100    y = math.cos(latin * DEG2RAD) * math.sin(lonin * DEG2RAD)
101    z = math.sin(latin * DEG2RAD)
102
103    # Rotate around y axis
104    rotang = -(latpole + 90) * DEG2RAD
105    sinrot = math.sin(rotang)
106    cosrot = math.cos(rotang)
107    ry = y
108    rx = x * cosrot + z * sinrot
109    rz = -x * sinrot + z * cosrot
110
111    # Convert back to lat/lon
112    tlat = math.asin(rz) / DEG2RAD
113    if math.fabs(rx) > 0.0001:
114        tlon = math.atan2(ry, rx) / DEG2RAD
115    elif ry > 0:
116        tlon = 90.0
117    else:
118        tlon = -90.0
119
120    # Remove the longitude rotation
121    tlon += lonpole
122    if tlon < 0:
123        tlon += 360.0
124    if tlon > 360:
125        tlon -= 360.0
126
127    return tlat, tlon

Unrotate a latitude/longitude pair.

Parameters
  • latin: Rotated latitude in units of degrees.
  • lonin: Rotated longitude in units of degrees.
  • latpole: Latitude of Pole.
  • lonpole: Longitude of Pole.
Returns
  • tlat: Unrotated latitude in units of degrees.
  • tlons: Unrotated longitude in units of degrees.
def vector_rotation_angles(tlat: float, tlon: float, clat: float, losp: float, xlat: float) -> float:
130def vector_rotation_angles(
131    tlat: float,
132    tlon: float,
133    clat: float,
134    losp: float,
135    xlat: float,
136) -> float:
137    """
138    Generate a rotation angle value.
139
140    The rotation angle value can be applied to a vector quantity to make it
141    Earth-oriented.
142
143    Parameters
144    ----------
145    tlat
146        True latitude in units of degrees.
147    tlon
148        True longitude in units of degrees..
149    clat
150        Latitude of center grid point in units of degrees.
151    losp
152        Longitude of the southern pole in units of degrees.
153    xlat
154        Latitude of the rotated grid in units of degrees.
155
156    Returns
157    -------
158    rot
159        Rotation angle in units of radians.
160    """
161    slon = math.sin((tlon - losp) * DEG2RAD)
162    cgridlat = math.cos(xlat * DEG2RAD)
163    if cgridlat <= 0.0:
164        rot = 0.0
165    else:
166        crot = (
167            math.cos(clat * DEG2RAD) * math.cos(tlat * DEG2RAD) + math.sin(clat * DEG2RAD) * math.sin(tlat * DEG2RAD) * math.cos(tlon * DEG2RAD)
168        ) / cgridlat
169        srot = (-1.0 * math.sin(clat * DEG2RAD) * slon) / cgridlat
170        rot = math.atan2(srot, crot)
171    return rot

Generate a rotation angle value.

The rotation angle value can be applied to a vector quantity to make it Earth-oriented.

Parameters
  • tlat: True latitude in units of degrees.
  • tlon: True longitude in units of degrees..
  • clat: Latitude of center grid point in units of degrees.
  • losp: Longitude of the southern pole in units of degrees.
  • xlat: Latitude of the rotated grid in units of degrees.
Returns
  • rot: Rotation angle in units of radians.