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, lonin, latpole, lonpole):
 19    """
 20    Rotate a latitude/longitude pair.
 21
 22    Parameters
 23    ----------
 24    **`latin`**: `float`
 25        Latitudes in units of degrees.
 26
 27    **`lonin`**: `float`
 28        Longitudes in units of degrees.
 29
 30    **`latpole`**: `float`
 31        Latitude of Pole.
 32
 33    **`lonpole`**: `float`
 34        Longitude of Pole.
 35
 36    Returns
 37    -------
 38    **`tlat, tlons`**
 39        Returns two floats of rotated latitude and 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, lonin, latpole, lonpole):
 74    """
 75    Unrotate a latitude/longitude pair.
 76
 77    Parameters
 78    ----------
 79    **`latin`**: `float`
 80        Latitudes in units of degrees.
 81
 82    **`lonin`**: `float`
 83        Longitudes in units of degrees.
 84
 85    **`latpole`**: `float`
 86        Latitude of Pole.
 87
 88    **`lonpole`**: `float`
 89        Longitude of Pole.
 90
 91    Returns
 92    -------
 93    **`tlat, tlons`**
 94        Returns two floats of unrotated latitude and 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
128
129
130def vector_rotation_angles(tlat, tlon, clat, losp, xlat):
131    """
132    Generate a rotation angle value that can be applied to a vector quantity to
133    make it Earth-oriented.
134
135    Parameters
136    ----------
137    **`tlat`**: `float`
138        True latitude in units of degrees.
139
140    **tlon`**: `float`
141        True longitude in units of degrees..
142
143    **`clat`**: `float`
144        Latitude of center grid point in units of degrees.
145
146    **`losp`**: `float`
147        Longitude of the southern pole in units of degrees.
148
149    **`xlat`**: `float`
150        Latitude of the rotated grid in units of degrees.
151
152    Returns
153    -------
154    **`rot : float`**
155        Rotation angle in units of radians. 
156    """
157    slon = math.sin((tlon-losp)*DEG2RAD)
158    cgridlat = math.cos(xlat*DEG2RAD)
159    if cgridlat <= 0.0:
160        rot = 0.0
161    else:
162        crot = (math.cos(clat*DEG2RAD)*math.cos(tlat*DEG2RAD)+
163                math.sin(clat*DEG2RAD)*math.sin(tlat*DEG2RAD)*
164                math.cos(tlon*DEG2RAD))/cgridlat
165        srot = (-1.0*math.sin(clat*DEG2RAD)*slon)/cgridlat
166        rot = math.atan2(srot,crot)
167    return rot
DEG2RAD = 0.017453292519943295
RAD2DEG = 57.29577951308232
def ll2rot(latin, lonin, latpole, lonpole):
19def ll2rot(latin, lonin, latpole, lonpole):
20    """
21    Rotate a latitude/longitude pair.
22
23    Parameters
24    ----------
25    **`latin`**: `float`
26        Latitudes in units of degrees.
27
28    **`lonin`**: `float`
29        Longitudes in units of degrees.
30
31    **`latpole`**: `float`
32        Latitude of Pole.
33
34    **`lonpole`**: `float`
35        Longitude of Pole.
36
37    Returns
38    -------
39    **`tlat, tlons`**
40        Returns two floats of rotated latitude and 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: float Latitudes in units of degrees.

lonin: float Longitudes in units of degrees.

latpole: float Latitude of Pole.

lonpole: float Longitude of Pole.

Returns

tlat, tlons Returns two floats of rotated latitude and longitude in units of degrees.

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

Unrotate a latitude/longitude pair.

Parameters

latin: float Latitudes in units of degrees.

lonin: float Longitudes in units of degrees.

latpole: float Latitude of Pole.

lonpole: float Longitude of Pole.

Returns

tlat, tlons Returns two floats of unrotated latitude and longitude in units of degrees.

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

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

Parameters

tlat: float True latitude in units of degrees.

**tlon**:float` True longitude in units of degrees..

clat: float Latitude of center grid point in units of degrees.

losp: float Longitude of the southern pole in units of degrees.

xlat: float Latitude of the rotated grid in units of degrees.

Returns

rot : float Rotation angle in units of radians.