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