Skip to content

Commit 4c2bbfe

Browse files
authored
Merge pull request #145 from GeoOcean/WMS
[EJP] Greensurge recovery for Cadiz
2 parents 8c6d7bc + 9f85723 commit 4c2bbfe

2 files changed

Lines changed: 134 additions & 30 deletions

File tree

bluemath_tk/additive/greensurge.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,3 +2031,107 @@ def actualize_grid_info(
20312031
)
20322032

20332033
return ds_GFD_calc_info
2034+
2035+
def GS_windsetup_reconstruction_nc(
2036+
greensurge_dataset,
2037+
ds_gfd_metadata: xr.Dataset,
2038+
wind_direction_input: xr.Dataset,
2039+
velocity_thresholds: np.ndarray = np.array([0, 100, 100]),
2040+
drag_coefficients: np.ndarray = np.array([0.00063, 0.00723, 0.00723]),
2041+
) -> xr.Dataset:
2042+
"""
2043+
Reconstructs the GreenSurge wind setup using the provided wind direction input and metadata.
2044+
2045+
Parameters
2046+
----------
2047+
greensurge_dataset : xr.Dataset
2048+
xarray Dataset containing the GreenSurge mesh and forcing data.
2049+
ds_gfd_metadata: xr.Dataset
2050+
xarray Dataset containing metadata for the GFD mesh.
2051+
wind_direction_input: xr.Dataset
2052+
xarray Dataset containing wind direction and speed data.
2053+
velocity_thresholds : np.ndarray
2054+
Array of velocity thresholds for drag coefficient calculation.
2055+
drag_coefficients : np.ndarray
2056+
Array of drag coefficients corresponding to the velocity thresholds.
2057+
2058+
Returns
2059+
-------
2060+
xr.Dataset
2061+
xarray Dataset containing the reconstructed wind setup.
2062+
"""
2063+
2064+
velocity_thresholds = np.asarray(velocity_thresholds)
2065+
drag_coefficients = np.asarray(drag_coefficients)
2066+
2067+
direction_bins = ds_gfd_metadata.wind_directions.values
2068+
forcing_cell_indices = ds_gfd_metadata.element_forcing_index.values
2069+
wind_speed_reference = ds_gfd_metadata.wind_speed.values.item()
2070+
base_drag_coeff = GS_LinearWindDragCoef(
2071+
wind_speed_reference, drag_coefficients, velocity_thresholds
2072+
)
2073+
time_step_hours = ds_gfd_metadata.time_step_hours.values
2074+
2075+
time_start = wind_direction_input.time.values.min()
2076+
time_end = wind_direction_input.time.values.max()
2077+
duration_in_steps = (
2078+
int((ds_gfd_metadata.simulation_duration_hours.values) / time_step_hours) + 1
2079+
)
2080+
output_time_vector = np.arange(
2081+
time_start, time_end, np.timedelta64(int(60 * time_step_hours.item()), "m")
2082+
)
2083+
num_output_times = len(output_time_vector)
2084+
2085+
direction_data = wind_direction_input.Dir.values
2086+
wind_speed_data = wind_direction_input.W.values
2087+
2088+
ds_ex = xr.open_dataset(f"{greensurge_dataset}/GF_T_0_D_0/dflowfmoutput/GreenSurge_GFDcase_map.nc")
2089+
2090+
n_faces = ds_ex["mesh2d_s1"].shape
2091+
2092+
wind_setup_output = np.zeros((num_output_times, n_faces[1]))
2093+
water_level_accumulator = np.zeros(n_faces)
2094+
2095+
for time_index in tqdm(range(num_output_times), desc="Processing time steps"):
2096+
water_level_accumulator[:] = 0
2097+
for cell_index in forcing_cell_indices.astype(int):
2098+
current_dir = direction_data[cell_index, time_index] % 360
2099+
adjusted_bins = np.where(direction_bins == 0, 360, direction_bins)
2100+
closest_direction_index = np.abs(adjusted_bins - current_dir).argmin()
2101+
2102+
water_level_case = xr.open_dataset(
2103+
f"{greensurge_dataset}/GF_T_{cell_index}_D_{closest_direction_index}/dflowfmoutput/GreenSurge_GFDcase_map.nc"
2104+
)["mesh2d_s1"].values
2105+
water_level_case = np.nan_to_num(water_level_case, nan=0)
2106+
2107+
wind_speed_value = wind_speed_data[cell_index, time_index]
2108+
drag_coeff_value = GS_LinearWindDragCoef(
2109+
wind_speed_value, drag_coefficients, velocity_thresholds
2110+
)
2111+
2112+
scaling_factor = (wind_speed_value**2 / wind_speed_reference**2) * (
2113+
drag_coeff_value / base_drag_coeff
2114+
)
2115+
water_level_accumulator += water_level_case * scaling_factor
2116+
2117+
step_window = min(duration_in_steps, num_output_times - time_index)
2118+
if (num_output_times - time_index) > step_window:
2119+
wind_setup_output[time_index : time_index + step_window] += (
2120+
water_level_accumulator
2121+
)
2122+
else:
2123+
shift_counter = step_window - (num_output_times - time_index)
2124+
wind_setup_output[
2125+
time_index : time_index + step_window - shift_counter
2126+
] += water_level_accumulator[: step_window - shift_counter]
2127+
2128+
ds_wind_setup = xr.Dataset(
2129+
{"WL": (["time", "nface"], wind_setup_output)},
2130+
coords={
2131+
"time": output_time_vector,
2132+
"nface": np.arange(wind_setup_output.shape[1]),
2133+
},
2134+
)
2135+
ds_wind_setup.attrs["description"] = "Wind setup from GreenSurge methodology"
2136+
2137+
return ds_wind_setup

bluemath_tk/tcs/vortex.py

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ def vortex2delft_3D_FM_nc(
235235
The extension for the forcing file, default is "GreenSurge_GFDcase_wind.ext".
236236
fill_value : float
237237
The fill value to use for missing data, default is 0.
238+
238239
Returns
239240
-------
240241
xarray.Dataset
@@ -244,46 +245,44 @@ def vortex2delft_3D_FM_nc(
244245
longitude = mesh.mesh2d_node_x.values
245246
latitude = mesh.mesh2d_node_y.values
246247
n_time = ds_vortex.time.size
248+
time_int = np.arange(n_time) * (ds_vortex.time[1] - ds_vortex.time[0]).values / np.timedelta64(1, 'h')
247249

248250
lat_interp = xr.DataArray(latitude, dims="node")
249251
lon_interp = xr.DataArray(longitude, dims="node")
252+
angle = np.deg2rad((270 - ds_vortex.Dir.values) % 360)
253+
W = ds_vortex.W.values
250254

251-
W_node = ds_vortex.W.interp(
252-
lat=lat_interp,
253-
lon=lon_interp,
254-
method="nearest",
255-
)
256-
257-
Dir_node = ds_vortex.Dir.interp(
258-
lat=lat_interp,
259-
lon=lon_interp,
260-
method="nearest",
261-
)
262-
263-
p_node = ds_vortex.p.interp(
264-
lat=lat_interp,
265-
lon=lon_interp,
266-
method="nearest",
267-
)
268-
269-
angle = np.deg2rad((270 - Dir_node.values) % 360)
255+
windx_data = (W * np.cos(angle)).astype(np.float32)
256+
windy_data = (W * np.sin(angle)).astype(np.float32)
257+
pressure_data = ds_vortex.p.values.astype(np.float32)
270258

271-
windx_node = (W_node.values * np.cos(angle)).astype(np.float32)
272-
windy_node = (W_node.values * np.sin(angle)).astype(np.float32)
259+
if windx_data.ndim == 3:
260+
windx_data = np.transpose(windx_data, (2, 0, 1))
261+
windy_data = np.transpose(windy_data, (2, 0, 1))
262+
pressure_data = np.transpose(pressure_data, (2, 0, 1))
273263

274-
forcing_dataset = xr.Dataset(
264+
ds_vortex_interp = xr.Dataset(
275265
{
276-
"windx": (("node", "time"), np.nan_to_num(windx_node, nan=fill_value)),
277-
"windy": (("node", "time"), np.nan_to_num(windy_node, nan=fill_value)),
278-
"airpressure": (("node", "time"), np.nan_to_num(p_node.values.astype(np.float32), nan=fill_value)),
266+
"windx": (
267+
("time", "latitude", "longitude"),
268+
np.nan_to_num(windx_data, nan=fill_value),
269+
),
270+
"windy": (
271+
("time", "latitude", "longitude"),
272+
np.nan_to_num(windy_data, nan=fill_value),
273+
),
274+
"airpressure": (
275+
("time", "latitude", "longitude"),
276+
np.nan_to_num(pressure_data, nan=fill_value),
277+
),
279278
},
280279
coords={
281-
"node": np.arange(lat_interp.size),
282-
"time": np.arange(n_time),
283-
"latitude": ("node", latitude),
284-
"longitude": ("node", longitude),
280+
"time": time_int,
281+
"latitude": ds_vortex.lat.values,
282+
"longitude": ds_vortex.lon.values,
285283
},
286284
)
285+
forcing_dataset = ds_vortex_interp.interp(latitude=lat_interp, longitude=lon_interp)
287286

288287
reference_date_str = (
289288
ds_vortex.time.values[0]
@@ -333,5 +332,6 @@ def vortex2delft_3D_FM_nc(
333332
"long_name": "latitude",
334333
"units": "degrees_north",
335334
}
335+
forcing_dataset = forcing_dataset.fillna(fill_value)
336336

337-
return forcing_dataset
337+
return forcing_dataset

0 commit comments

Comments
 (0)