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

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]:
 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

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:
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 = (math.cos(clat*DEG2RAD)*math.cos(tlat*DEG2RAD)+
166                math.sin(clat*DEG2RAD)*math.sin(tlat*DEG2RAD)*
167                math.cos(tlon*DEG2RAD))/cgridlat
168        srot = (-1.0*math.sin(clat*DEG2RAD)*slon)/cgridlat
169        rot = math.atan2(srot,crot)
170    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.