grib2io.utils.rotated_grid
Tools for working with Rotated Lat/Lon Grids.
1"""Tools for working with Rotated Lat/Lon Grids.""" 2 3import numpy as np 4from numpy.typing import NDArray 5 6RAD2DEG = 57.29577951308232087684 7DEG2RAD = 0.01745329251994329576 8 9def rotate( 10 latin: NDArray[np.float32], 11 lonin: NDArray[np.float32], 12 aor: NDArray[np.float32], 13 splat: NDArray[np.float32], 14 splon: NDArray[np.float32], 15) -> tuple[NDArray[np.float32], NDArray[np.float32]]: 16 """ 17 Perform grid rotation. 18 19 This function is adapted from ECMWF's ecCodes library void function, 20 rotate(). 21 22 https://github.com/ecmwf/eccodes/blob/develop/src/grib_geography.cc 23 24 Parameters 25 ---------- 26 latin 27 Latitudes in units of degrees. 28 lonin 29 Longitudes in units of degrees. 30 aor 31 Angle of rotation as defined in GRIB2 GDTN 4.1. 32 splat 33 Latitude of South Pole as defined in GRIB2 GDTN 4.1. 34 splon 35 Longitude of South Pole as defined in GRIB2 GDTN 4.1. 36 37 Returns 38 ------- 39 lats 40 `numpy.ndarrays` with `dtype=numpy.float32` of grid latitudes in units 41 of degrees. 42 lons 43 `numpy.ndarrays` with `dtype=numpy.float32` of grid longitudes in units 44 of degrees. 45 """ 46 zsycen = np.sin(DEG2RAD * (splat + 90.)) 47 zcycen = np.cos(DEG2RAD * (splat + 90.)) 48 zxmxc = DEG2RAD * (lonin - splon) 49 zsxmxc = np.sin(zxmxc) 50 zcxmxc = np.cos(zxmxc) 51 zsyreg = np.sin(DEG2RAD * latin) 52 zcyreg = np.cos(DEG2RAD * latin) 53 zsyrot = zcycen * zsyreg - zsycen * zcyreg * zcxmxc 54 55 zsyrot = np.where(zsyrot>1.0,1.0,zsyrot) 56 zsyrot = np.where(zsyrot<-1.0,-1.0,zsyrot) 57 58 pyrot = np.arcsin(zsyrot) * RAD2DEG 59 60 zcyrot = np.cos(pyrot * DEG2RAD) 61 zcxrot = (zcycen * zcyreg * zcxmxc + zsycen * zsyreg) / zcyrot 62 zcxrot = np.where(zcxrot>1.0,1.0,zcxrot) 63 zcxrot = np.where(zcxrot<-1.0,-1.0,zcxrot) 64 zsxrot = zcyreg * zsxmxc / zcyrot 65 66 pxrot = np.arccos(zcxrot) * RAD2DEG 67 68 pxrot = np.where(zsxrot<0.0,-pxrot,pxrot) 69 70 return pyrot, pxrot 71 72 73def unrotate( 74 latin: NDArray[np.float32], 75 lonin: NDArray[np.float32], 76 aor: NDArray[np.float32], 77 splat: NDArray[np.float32], 78 splon: NDArray[np.float32], 79) -> tuple[NDArray[np.float32], NDArray[np.float32]]: 80 """ 81 Perform grid un-rotation. 82 83 This function is adapted from ECMWF's ecCodes library void function, 84 unrotate(). 85 86 https://github.com/ecmwf/eccodes/blob/develop/src/grib_geography.cc 87 88 Parameters 89 ---------- 90 latin 91 Latitudes in units of degrees. 92 lonin 93 Longitudes in units of degrees. 94 aor 95 Angle of rotation as defined in GRIB2 GDTN 4.1. 96 splat 97 Latitude of South Pole as defined in GRIB2 GDTN 4.1. 98 splon 99 Longitude of South Pole as defined in GRIB2 GDTN 4.1. 100 101 Returns 102 ------- 103 lats 104 `numpy.ndarrays` with `dtype=numpy.float32` of grid latitudes in units 105 of degrees. 106 lons 107 `numpy.ndarrays` with `dtype=numpy.float32` of grid longitudes in units 108 of degrees. 109 """ 110 lon_x = lonin 111 lat_y = latin 112 113 latr = lat_y * DEG2RAD 114 lonr = lon_x * DEG2RAD 115 116 xd = np.cos(lonr) * np.cos(latr) 117 yd = np.sin(lonr) * np.cos(latr) 118 zd = np.sin(latr) 119 120 t = -(90.0 + splat) 121 o = -splon 122 123 sin_t = np.sin(DEG2RAD * t) 124 cos_t = np.cos(DEG2RAD * t) 125 sin_o = np.sin(DEG2RAD * o) 126 cos_o = np.cos(DEG2RAD * o) 127 128 x = cos_t * cos_o * xd + sin_o * yd + sin_t * cos_o * zd 129 y = -cos_t * sin_o * xd + cos_o * yd - sin_t * sin_o * zd 130 z = -sin_t * xd + cos_t * zd 131 132 ret_lat = 0 133 ret_lon = 0 134 135 # Then convert back to 'normal' (lat,lon) 136 # Uses arcsin, to convert back to degrees, put in range -1 to 1 in case of slight rounding error 137 # avoid error on calculating e.g. asin(1.00000001) 138 z = np.where(z>1.0,1.0,z) 139 z = np.where(z<-1.0,-1.0,z) 140 141 ret_lat = np.arcsin(z) * RAD2DEG 142 ret_lon = np.arctan2(y, x) * RAD2DEG 143 144 # Still get a very small rounding error, round to 6 decimal places 145 ret_lat = np.round(ret_lat * 1000000.0) / 1000000.0 146 ret_lon = np.round(ret_lon * 1000000.0) / 1000000.0 147 148 ret_lon -= aor 149 150 return ret_lat, ret_lon
RAD2DEG =
57.29577951308232
DEG2RAD =
0.017453292519943295
def
rotate( latin: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], lonin: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], aor: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], splat: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], splon: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]]) -> tuple[numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]]]:
10def rotate( 11 latin: NDArray[np.float32], 12 lonin: NDArray[np.float32], 13 aor: NDArray[np.float32], 14 splat: NDArray[np.float32], 15 splon: NDArray[np.float32], 16) -> tuple[NDArray[np.float32], NDArray[np.float32]]: 17 """ 18 Perform grid rotation. 19 20 This function is adapted from ECMWF's ecCodes library void function, 21 rotate(). 22 23 https://github.com/ecmwf/eccodes/blob/develop/src/grib_geography.cc 24 25 Parameters 26 ---------- 27 latin 28 Latitudes in units of degrees. 29 lonin 30 Longitudes in units of degrees. 31 aor 32 Angle of rotation as defined in GRIB2 GDTN 4.1. 33 splat 34 Latitude of South Pole as defined in GRIB2 GDTN 4.1. 35 splon 36 Longitude of South Pole as defined in GRIB2 GDTN 4.1. 37 38 Returns 39 ------- 40 lats 41 `numpy.ndarrays` with `dtype=numpy.float32` of grid latitudes in units 42 of degrees. 43 lons 44 `numpy.ndarrays` with `dtype=numpy.float32` of grid longitudes in units 45 of degrees. 46 """ 47 zsycen = np.sin(DEG2RAD * (splat + 90.)) 48 zcycen = np.cos(DEG2RAD * (splat + 90.)) 49 zxmxc = DEG2RAD * (lonin - splon) 50 zsxmxc = np.sin(zxmxc) 51 zcxmxc = np.cos(zxmxc) 52 zsyreg = np.sin(DEG2RAD * latin) 53 zcyreg = np.cos(DEG2RAD * latin) 54 zsyrot = zcycen * zsyreg - zsycen * zcyreg * zcxmxc 55 56 zsyrot = np.where(zsyrot>1.0,1.0,zsyrot) 57 zsyrot = np.where(zsyrot<-1.0,-1.0,zsyrot) 58 59 pyrot = np.arcsin(zsyrot) * RAD2DEG 60 61 zcyrot = np.cos(pyrot * DEG2RAD) 62 zcxrot = (zcycen * zcyreg * zcxmxc + zsycen * zsyreg) / zcyrot 63 zcxrot = np.where(zcxrot>1.0,1.0,zcxrot) 64 zcxrot = np.where(zcxrot<-1.0,-1.0,zcxrot) 65 zsxrot = zcyreg * zsxmxc / zcyrot 66 67 pxrot = np.arccos(zcxrot) * RAD2DEG 68 69 pxrot = np.where(zsxrot<0.0,-pxrot,pxrot) 70 71 return pyrot, pxrot
Perform grid rotation.
This function is adapted from ECMWF's ecCodes library void function, rotate().
https://github.com/ecmwf/eccodes/blob/develop/src/grib_geography.cc
Parameters
- latin: Latitudes in units of degrees.
- lonin: Longitudes in units of degrees.
- aor: Angle of rotation as defined in GRIB2 GDTN 4.1.
- splat: Latitude of South Pole as defined in GRIB2 GDTN 4.1.
- splon: Longitude of South Pole as defined in GRIB2 GDTN 4.1.
Returns
- lats:
numpy.ndarrays
withdtype=numpy.float32
of grid latitudes in units of degrees. - lons:
numpy.ndarrays
withdtype=numpy.float32
of grid longitudes in units of degrees.
def
unrotate( latin: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], lonin: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], aor: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], splat: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], splon: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]]) -> tuple[numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]]]:
74def unrotate( 75 latin: NDArray[np.float32], 76 lonin: NDArray[np.float32], 77 aor: NDArray[np.float32], 78 splat: NDArray[np.float32], 79 splon: NDArray[np.float32], 80) -> tuple[NDArray[np.float32], NDArray[np.float32]]: 81 """ 82 Perform grid un-rotation. 83 84 This function is adapted from ECMWF's ecCodes library void function, 85 unrotate(). 86 87 https://github.com/ecmwf/eccodes/blob/develop/src/grib_geography.cc 88 89 Parameters 90 ---------- 91 latin 92 Latitudes in units of degrees. 93 lonin 94 Longitudes in units of degrees. 95 aor 96 Angle of rotation as defined in GRIB2 GDTN 4.1. 97 splat 98 Latitude of South Pole as defined in GRIB2 GDTN 4.1. 99 splon 100 Longitude of South Pole as defined in GRIB2 GDTN 4.1. 101 102 Returns 103 ------- 104 lats 105 `numpy.ndarrays` with `dtype=numpy.float32` of grid latitudes in units 106 of degrees. 107 lons 108 `numpy.ndarrays` with `dtype=numpy.float32` of grid longitudes in units 109 of degrees. 110 """ 111 lon_x = lonin 112 lat_y = latin 113 114 latr = lat_y * DEG2RAD 115 lonr = lon_x * DEG2RAD 116 117 xd = np.cos(lonr) * np.cos(latr) 118 yd = np.sin(lonr) * np.cos(latr) 119 zd = np.sin(latr) 120 121 t = -(90.0 + splat) 122 o = -splon 123 124 sin_t = np.sin(DEG2RAD * t) 125 cos_t = np.cos(DEG2RAD * t) 126 sin_o = np.sin(DEG2RAD * o) 127 cos_o = np.cos(DEG2RAD * o) 128 129 x = cos_t * cos_o * xd + sin_o * yd + sin_t * cos_o * zd 130 y = -cos_t * sin_o * xd + cos_o * yd - sin_t * sin_o * zd 131 z = -sin_t * xd + cos_t * zd 132 133 ret_lat = 0 134 ret_lon = 0 135 136 # Then convert back to 'normal' (lat,lon) 137 # Uses arcsin, to convert back to degrees, put in range -1 to 1 in case of slight rounding error 138 # avoid error on calculating e.g. asin(1.00000001) 139 z = np.where(z>1.0,1.0,z) 140 z = np.where(z<-1.0,-1.0,z) 141 142 ret_lat = np.arcsin(z) * RAD2DEG 143 ret_lon = np.arctan2(y, x) * RAD2DEG 144 145 # Still get a very small rounding error, round to 6 decimal places 146 ret_lat = np.round(ret_lat * 1000000.0) / 1000000.0 147 ret_lon = np.round(ret_lon * 1000000.0) / 1000000.0 148 149 ret_lon -= aor 150 151 return ret_lat, ret_lon
Perform grid un-rotation.
This function is adapted from ECMWF's ecCodes library void function, unrotate().
https://github.com/ecmwf/eccodes/blob/develop/src/grib_geography.cc
Parameters
- latin: Latitudes in units of degrees.
- lonin: Longitudes in units of degrees.
- aor: Angle of rotation as defined in GRIB2 GDTN 4.1.
- splat: Latitude of South Pole as defined in GRIB2 GDTN 4.1.
- splon: Longitude of South Pole as defined in GRIB2 GDTN 4.1.
Returns
- lats:
numpy.ndarrays
withdtype=numpy.float32
of grid latitudes in units of degrees. - lons:
numpy.ndarrays
withdtype=numpy.float32
of grid longitudes in units of degrees.