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.