From 33cc205ec186ade0f205e8316fbedbb50806b56b Mon Sep 17 00:00:00 2001
From: tomrink <rink@ssec.wisc.edu>
Date: Thu, 24 Oct 2024 13:48:22 -0500
Subject: [PATCH] snapshot...

---
 modules/util/resample.py | 111 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)
 create mode 100644 modules/util/resample.py

diff --git a/modules/util/resample.py b/modules/util/resample.py
new file mode 100644
index 00000000..93d601b9
--- /dev/null
+++ b/modules/util/resample.py
@@ -0,0 +1,111 @@
+import numpy as np
+from scipy.interpolate import RegularGridInterpolator, griddata
+from cartopy.crs import LambertAzimuthalEqualArea
+import cartopy.crs as ccrs
+from netCDF4 import Dataset
+import xarray as xr
+
+# resample methods:
+linear = 'linear'
+cubic = 'cubic'
+nearest = 'nearest'
+
+
+def fill_missing(fld_a, fld_b, mask):
+    min_val = min(np.nanmin(fld_a), np.nanmin(fld_b))
+    max_val = max(np.nanmax(fld_a), np.nanmax(fld_b))
+    random_values_a = np.random.uniform(min_val, max_val, size=fld_a.shape)
+    random_values_b = np.random.uniform(min_val, max_val, size=fld_a.shape)
+
+    fld_a[mask] = random_values_a[mask]
+    fld_b[mask] = random_values_b[mask]
+
+
+def get_projection(cartopy_map_name, cen_lat, cen_lon):
+    if cartopy_map_name == "LambertAzimuthalEqualArea":
+        projection = ccrs.LambertAzimuthalEqualArea(
+            central_longitude=cen_lon, central_latitude=cen_lat
+        )
+    elif cartopy_map_name == "AlbersEqualArea":
+        projection = ccrs.AlbersEqualArea(
+            central_longitude=cen_lon, central_latitude=cen_lat
+        )
+    elif cartopy_map_name == "Sinusoidal":
+        projection = ccrs.Sinusoidal(central_longitude=cen_lon)
+    else:
+        raise ValueError("Projection: " + cartopy_map_name + " is not supported")
+
+    return projection
+
+
+def resample_reg_grid(scalar_field, y, x, y_s, x_s, method='linear'):
+
+    intrp = RegularGridInterpolator((y, x), scalar_field, method=method, bounds_error=False)
+
+    xg, yg = np.meshgrid(x_s, y_s, indexing='xy')
+    yg, xg = yg.flatten(), xg.flatten()
+    pts = np.array([yg, xg])
+    t_pts = np.transpose(pts)
+
+    return np.reshape(intrp(t_pts), (y_s.shape[0], x_s.shape[0]))
+
+
+def resample(scalar_field, y_d, x_d, y_t, x_t, method='linear'):
+    # 2D target locations shape
+    t_shape = y_t.shape
+    # reproject scalar fields
+    fld_repro = griddata((y_d.flatten(), x_d.flatten()), scalar_field.flatten(),(y_t.flatten(), x_t.flatten()), method=method)
+    fld_repro = fld_repro.reshape(t_shape)
+    return fld_repro
+
+
+def reproject(fld_2d, lat_2d, lon_2d, proj, target_grid=None, grid_spacing=15000, method=linear):
+    """
+    :param fld_2d: the 2D scalar field to reproject
+    :param lat_2d: 2D latitude of the scalar field domain
+    :param lon_2d: 2D longitude of the scalar field domain
+    :param proj: the map projection (Cartopy). Default: LambertAzimuthalEqualArea
+    :param region_grid: the larger region grid that we pull the target grid from
+    :param target_grid: the resampling target (y_map, x_map) where y_map and x_map are 2D. If None, the grid is created
+           automatically. The target grid is always returned.
+    :param grid_spacing: distance between the target grid points (in meters)
+    :param method: resampling method: 'linear', 'nearest', 'cubic'
+    :return: reprojected 2D scalar field, the target grid (will be 2D if rotate=True)
+    """
+
+    data_xy = proj.transform_points(ccrs.PlateCarree(), lon_2d, lat_2d)[..., :2]
+
+    # Generate a regular 2d grid extending the min and max of the xy dimensions with grid_spacing
+    if target_grid is None:
+        x_min, y_min = np.amin(data_xy, axis=(0, 1))
+        x_max, y_max = np.amax(data_xy, axis=(0, 1))
+        x_map = np.arange(x_min, x_max, grid_spacing)
+        y_map = np.arange(y_min, y_max, grid_spacing)
+        x_map_2d, y_map_2d = np.meshgrid(x_map, y_map)
+    else:
+        y_map_2d, x_map_2d = target_grid
+
+    fld_reproj = resample(fld_2d, data_xy[..., 1], data_xy[..., 0], y_map_2d, x_map_2d, method=method)
+
+    return fld_reproj, (y_map_2d, x_map_2d)
+
+
+def bisect_great_circle(lon_a, lat_a, lon_b, lat_b):
+    lon_a = np.radians(lon_a)
+    lat_a = np.radians(lat_a)
+    lon_b = np.radians(lon_b)
+    lat_b = np.radians(lat_b)
+
+    dlon = lon_b - lon_a
+
+    Bx = np.cos(lat_b) * np.cos(dlon)
+    By = np.cos(lat_b) * np.sin(dlon)
+
+    lat_c = np.arctan2(np.sin(lat_a) + np.sin(lat_b), np.sqrt((np.cos(lat_a) + Bx) ** 2 + By ** 2))
+    lon_c = lon_a + np.arctan2(By, np.cos(lat_a) + Bx)
+
+    lon_c = np.degrees(lon_c)
+    lat_c = np.degrees(lat_c)
+
+    return lon_c, lat_c
+
-- 
GitLab