Skip to content

Commit de52d9f

Browse files
committed
[EJPF] Exemple OCSMesh santander actualisated and greensurge actualisations
1 parent a6061f6 commit de52d9f

File tree

3 files changed

+139
-54
lines changed

3 files changed

+139
-54
lines changed

bluemath_tk/additive/greensurge.py

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ def GS_windsetup_reconstruction_with_postprocess(
496496
direction_bins = ds_gfd_metadata.wind_directions.values
497497
forcing_cell_indices = greensurge_dataset.forcing_cell.values
498498
wind_speed_reference = ds_gfd_metadata.wind_speed.values.item()
499-
base_drag_coeff = GS_LinearWindDragCoef_mat(
499+
base_drag_coeff = GS_LinearWindDragCoef(
500500
wind_speed_reference, drag_coefficients, velocity_thresholds
501501
)
502502
time_step_hours = ds_gfd_metadata.time_step_hours.values
@@ -533,7 +533,7 @@ def GS_windsetup_reconstruction_with_postprocess(
533533
water_level_case = np.nan_to_num(water_level_case, nan=0)
534534

535535
wind_speed_value = wind_speed_data[cell_index, time_index]
536-
drag_coeff_value = GS_LinearWindDragCoef_mat(
536+
drag_coeff_value = GS_LinearWindDragCoef(
537537
wind_speed_value, drag_coefficients, velocity_thresholds
538538
)
539539

@@ -616,6 +616,59 @@ def GS_LinearWindDragCoef_mat(
616616

617617
return CD.item() if was_scalar else CD
618618

619+
def GS_LinearWindDragCoef(Wspeed: np.ndarray,CD_Wl_abc: np.ndarray,Wl_abc: np.ndarray)-> np.ndarray:
620+
"""
621+
Calculate the linear drag coefficient based on wind speed and specified thresholds.
622+
Parameters
623+
----------
624+
Wspeed : np.ndarray
625+
Wind speed values (1D array).
626+
CD_Wl_abc : np.ndarray
627+
Coefficients for the drag coefficient calculation, should be a 1D array of length 3.
628+
Wl_abc : np.ndarray
629+
Wind speed thresholds for the drag coefficient calculation, should be a 1D array of length 3.
630+
Returns
631+
-------
632+
np.ndarray
633+
Calculated drag coefficient values based on the input wind speed.
634+
"""
635+
636+
Wla=Wl_abc[0]
637+
Wlb=Wl_abc[1]
638+
Wlc=Wl_abc[2]
639+
CDa=CD_Wl_abc[0]
640+
CDb=CD_Wl_abc[1]
641+
CDc=CD_Wl_abc[2]
642+
643+
644+
#coefs lines y=ax+b
645+
if not Wla==Wlb:
646+
a_CDline_ab=(CDa-CDb)/(Wla-Wlb)
647+
b_CDline_ab=CDb-a_CDline_ab*Wlb
648+
else:
649+
a_CDline_ab=0
650+
b_CDline_ab=CDa
651+
if not Wlb==Wlc:
652+
a_CDline_bc=(CDb-CDc)/(Wlb-Wlc)
653+
b_CDline_bc=CDc-a_CDline_bc*Wlc
654+
else:
655+
a_CDline_bc=0
656+
b_CDline_bc=CDb
657+
a_CDline_cinf=0
658+
b_CDline_cinf=CDc
659+
660+
661+
662+
if Wspeed<=Wlb:
663+
CD=a_CDline_ab*Wspeed+b_CDline_ab
664+
elif (Wspeed>Wlb and Wspeed<=Wlc):
665+
CD=a_CDline_bc*Wspeed+b_CDline_bc
666+
else:
667+
CD=a_CDline_cinf*Wspeed+b_CDline_cinf
668+
669+
670+
return CD
671+
619672

620673
def plot_GS_vs_dynamic_windsetup(
621674
ds_WL_GS_WindSetUp: xr.Dataset,
@@ -718,7 +771,7 @@ def plot_GS_TG_validation_timeseries(
718771
ds_WL_dynamic_WindSetUp: xr.Dataset,
719772
tide_gauge: xr.Dataset,
720773
ds_GFD_info: xr.Dataset,
721-
figsize: tuple = (15, 7),
774+
figsize: tuple = (20, 7),
722775
WLmin: float = None,
723776
WLmax: float = None,
724777
) -> None:
@@ -777,16 +830,27 @@ def plot_GS_TG_validation_timeseries(
777830
Y = ds_WL_dynamic_WindSetUp.mesh2d_node_y.values
778831
triangles = ds_WL_dynamic_WindSetUp.mesh2d_face_nodes.values.astype(int) - 1
779832
Z = np.mean(ds_WL_dynamic_WindSetUp.mesh2d_node_z.values[triangles], axis=1)
833+
vmin = np.nanmin(Z)
834+
vmax = np.nanmax(Z)
780835

781-
ax_map.tripcolor(
836+
cmap, norm = join_colormaps(
837+
cmap1= hex_colors_water,
838+
cmap2= hex_colors_land,
839+
value_range1=(vmin, 0.0), value_range2=(0.0, vmax),
840+
name="raster_cmap")
841+
ax_map.set_facecolor("#518134")
842+
843+
pm = ax_map.tripcolor(
782844
X,
783845
Y,
784846
triangles,
785847
facecolors=Z,
786-
cmap="RdYlBu_r",
848+
cmap=cmap,
849+
norm=norm,
787850
shading="flat",
788851
transform=ccrs.PlateCarree(),
789852
)
853+
790854
ax_map.scatter(
791855
lon_obs,
792856
lat_obs,

bluemath_tk/core/plotting/utils.py

Lines changed: 35 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
import matplotlib.colors as colors
44
import matplotlib.pyplot as plt
55
import numpy as np
6-
from matplotlib.colors import Colormap
7-
6+
from matplotlib.colors import Colormap, ListedColormap, BoundaryNorm
87

98
def get_list_of_colors_for_colormap(
109
cmap: Union[str, Colormap], num_colors: int
@@ -54,69 +53,65 @@ def create_cmap_from_colors(
5453

5554
return colors.LinearSegmentedColormap.from_list(name, rgb_colors, N=256)
5655

57-
5856
def join_colormaps(
5957
cmap1: Union[str, List[str], Colormap],
6058
cmap2: Union[str, List[str], Colormap],
6159
name: str = "joined_cmap",
6260
range1: Tuple[float, float] = (0.0, 1.0),
6361
range2: Tuple[float, float] = (0.0, 1.0),
64-
) -> colors.ListedColormap:
62+
value_range1: Tuple[float, float] = None,
63+
value_range2: Tuple[float, float] = None,
64+
) -> Tuple[ListedColormap, BoundaryNorm]:
6565
"""
66-
Join two colormaps into one. Each input can be either a colormap name, a list of colors,
67-
or an existing colormap. Optionally crop each colormap to a specific range.
66+
Join two colormaps into one, with value ranges specified for each.
6867
6968
Parameters
7069
----------
71-
cmap1 : Union[str, List[str], Colormap]
72-
First colormap (name, color list, or colormap object).
73-
cmap2 : Union[str, List[str], Colormap]
74-
Second colormap (name, color list, or colormap object).
75-
name : str, optional
76-
Name for the resulting colormap. Default is "joined_cmap".
77-
range1 : Tuple[float, float], optional
78-
Range of colors to use from first colormap (start, end) between 0 and 1.
79-
Default is (0.0, 1.0) using the full range.
80-
range2 : Tuple[float, float], optional
81-
Range of colors to use from second colormap (start, end) between 0 and 1.
82-
Default is (0.0, 1.0) using the full range.
70+
cmap1, cmap2 : Union[str, List[str], Colormap]
71+
Input colormaps (name, list of hex codes, or Colormap object).
72+
name : str
73+
Name of the output colormap.
74+
range1, range2 : Tuple[float, float]
75+
Portion of each colormap to use (from 0 to 1).
76+
value_range1, value_range2 : Tuple[float, float]
77+
Value ranges in the data domain corresponding to each colormap.
8378
8479
Returns
8580
-------
86-
colors.ListedColormap
87-
A new colormap that combines both input colormaps.
88-
89-
Examples
90-
--------
91-
>>> # Join two colormaps using only middle 80% of each
92-
>>> cmap = join_colormaps("viridis", "plasma", range1=(0.1, 0.9), range2=(0.1, 0.9))
93-
>>> # Join colormaps with different ranges
94-
>>> cmap = join_colormaps("viridis", "plasma", range1=(0.0, 0.5), range2=(0.5, 1.0))
81+
ListedColormap
82+
Merged colormap object.
83+
BoundaryNorm
84+
Normalization for mapping data to colors.
9585
"""
9686

97-
# Convert inputs to colormaps if they aren't already
87+
# Convert cmap1 to a Colormap if needed
9888
if isinstance(cmap1, str):
99-
if cmap1.startswith("#"):
100-
cmap1 = create_cmap_from_colors([cmap1])
101-
else:
102-
cmap1 = plt.get_cmap(cmap1)
89+
cmap1 = plt.get_cmap(cmap1)
10390
elif isinstance(cmap1, list):
104-
cmap1 = create_cmap_from_colors(cmap1)
91+
cmap1 = colors.LinearSegmentedColormap.from_list("cmap1", cmap1)
10592

10693
if isinstance(cmap2, str):
107-
if cmap2.startswith("#"):
108-
cmap2 = create_cmap_from_colors([cmap2])
109-
else:
110-
cmap2 = plt.get_cmap(cmap2)
94+
cmap2 = plt.get_cmap(cmap2)
11195
elif isinstance(cmap2, list):
112-
cmap2 = create_cmap_from_colors(cmap2)
96+
cmap2 = colors.LinearSegmentedColormap.from_list("cmap2", cmap2)
11397

114-
# Create the joined colormap with specified ranges
98+
# Get colors from each colormap
11599
colors1 = cmap1(np.linspace(range1[0], range1[1], 128))
116100
colors2 = cmap2(np.linspace(range2[0], range2[1], 128))
117101
newcolors = np.vstack((colors1, colors2))
118102

119-
return colors.ListedColormap(newcolors, name=name)
103+
# Create corresponding boundaries in data space
104+
if value_range1 is not None and value_range2 is not None:
105+
106+
bounds1 = np.linspace(value_range1[0], value_range1[1], 129)
107+
bounds2 = np.linspace(value_range2[0], value_range2[1], 129)
108+
all_bounds = np.concatenate([bounds1[:-1], bounds2])
109+
110+
norm = BoundaryNorm(boundaries=all_bounds, ncolors=len(newcolors))
111+
112+
return colors.ListedColormap(newcolors, name=name), norm
113+
else:
114+
return colors.ListedColormap(newcolors, name=name)
120115

121116

122117
if __name__ == "__main__":

bluemath_tk/topo_bathy/mesh_utils.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121

2222
from ..core.geo import buffer_area_for_polygon
2323

24+
from ..core.plotting.colors import hex_colors_land, hex_colors_water
25+
from ..core.plotting.utils import join_colormaps
26+
2427

2528
def plot_mesh_edge(
2629
msh_t: jigsaw_msh_t, ax: Axes = None, to_geo: callable = None, **kwargs
@@ -153,9 +156,19 @@ def plot_bathymetry(rasters_path: List[str], polygon: Polygon, ax: Axes) -> Axes
153156
cols, rows = np.meshgrid(np.arange(width), np.arange(height))
154157
xs, ys = rasterio.transform.xy(transform, rows, cols)
155158

159+
vmin = np.nanmin(data[0])
160+
vmax = np.nanmax(data[0])
161+
162+
cmap, norm = join_colormaps(
163+
cmap1= hex_colors_water,
164+
cmap2= hex_colors_land,
165+
value_range1=(vmin, 0.0), value_range2=(0.0, vmax),
166+
name="raster_cmap")
167+
156168
im = ax.imshow(
157169
data[0],
158-
cmap="gist_earth",
170+
cmap=cmap,
171+
norm=norm,
159172
extent=(np.min(xs), np.max(xs), np.min(ys), np.max(ys)),
160173
)
161174
cbar = plt.colorbar(im, ax=ax)
@@ -343,13 +356,26 @@ def plot_bathymetry_interp(mesh: jigsaw_msh_t, to_geo, ax: Axes) -> None:
343356
crd[:, 0], crd[:, 1] = to_geo(crd[:, 0], crd[:, 1])
344357
bnd = [crd[:, 0].min(), crd[:, 0].max(), crd[:, 1].min(), crd[:, 1].max()]
345358

346-
im = ax.tricontourf(
347-
Triangulation(
348-
crd[:, 0],
349-
crd[:, 1],
350-
triangles=mesh.msh_t.tria3["index"],
351-
),
352-
mesh.msh_t.value.flatten(),
359+
triangle = mesh.msh_t.tria3["index"]
360+
Z = np.mean(mesh.msh_t.value.flatten()[triangle],axis = 1)
361+
vmin = np.nanmin(Z)
362+
vmax = np.nanmax(Z)
363+
364+
cmap, norm = join_colormaps(
365+
cmap1=hex_colors_water,
366+
cmap2=hex_colors_land,
367+
value_range1=(vmin, 0.0),
368+
value_range2=(0.0, vmax),
369+
name="raster_cmap"
370+
)
371+
372+
im = ax.tripcolor(
373+
crd[:, 0],
374+
crd[:, 1],
375+
triangle,
376+
facecolors=Z,
377+
cmap=cmap,
378+
norm=norm,
353379
)
354380
ax.set_title("Interpolated Bathymetry")
355381
gl = ax.gridlines(draw_labels=True)
@@ -974,8 +1000,8 @@ def detect_circumcenter_too_close(
9741000
def define_mesh_target_size(
9751001
rasters: List[rasterio.io.DatasetReader],
9761002
raster_resolution_meters: float,
977-
nprocs: int,
9781003
depth_ranges: float,
1004+
nprocs: int = 1,
9791005
) -> ocsmesh.Hfun:
9801006
"""
9811007
Define the mesh target size based on depth ranges and their corresponding values.

0 commit comments

Comments
 (0)