22Module to generate datasets for testing
33"""
44
5+ import numpy as np
56import xarray as xr
67from xarray import Dataset
78
@@ -44,6 +45,52 @@ def flat(self, depth: float) -> Dataset:
4445 ds ["Bathymetry" ] = xr .full_like (ds ["glamt" ], depth )
4546 return _add_attributes (_add_mask (ds ))
4647
48+ def sea_mount (self , depth : float , stiff = 1.0 ) -> Dataset :
49+ """
50+ Channel with seamount case.
51+
52+ Produces bathymetry of a channel with a Gaussian seamount in order to
53+ simulate an idealised test case. Based on Marsaleix et al., 2009
54+ doi:10.1016/j.ocemod.2009.06.011 Eq. 15.
55+
56+ Parameters
57+ ----------
58+ depth: float
59+ Bottom depth (units: m).
60+ stiff: float
61+ Scale factor for steepness of seamount (units: None)
62+
63+ Returns
64+ -------
65+ Dataset
66+ """
67+ ds = self ._coords
68+
69+ # Find half way point for sea mount location
70+ half_way = {k : v // 2 for k , v in ds .sizes .items ()}
71+ glamt_mid , gphit_mid = (g .isel (half_way ) for g in (ds .glamt , ds .gphit ))
72+
73+ # Define sea mount bathymetry
74+ ds ["Bathymetry" ] = depth * (
75+ 1.0
76+ - 0.9
77+ * np .exp (
78+ - (
79+ stiff
80+ / 40.0e3 ** 2
81+ * ((ds .glamt - glamt_mid ) ** 2 + (ds .gphit - gphit_mid ) ** 2 )
82+ )
83+ )
84+ )
85+
86+ # Add rmax of Bathymetry
87+ # ds["rmax"] = DataArray(
88+ # _calc_rmax(ds["Bathymetry"].to_masked_array()), dims=["y", "x"]
89+ # )
90+ ds ["rmax" ] = _calc_rmax (ds ["Bathymetry" ])
91+
92+ return _add_attributes (_add_mask (ds ))
93+
4794
4895def _add_mask (ds : Dataset ) -> Dataset :
4996 """
@@ -58,7 +105,7 @@ def _add_mask(ds: Dataset) -> Dataset:
58105 -------
59106 Dataset
60107 """
61- ds ["mask" ] = xr .where (ds ["Bathymetry" ] > 0 , 1 , 0 )
108+ ds ["mask" ] = xr .where (ds ["Bathymetry" ] > 0 , 1 , 0 ) # TODO: should this be bool?
62109 return ds
63110
64111
@@ -69,17 +116,60 @@ def _add_attributes(ds: Dataset) -> Dataset:
69116 Parameters
70117 ----------
71118 ds: Dataset
72- Dataset with bathymetry and mask variables
119+ Dataset with bathymetry and mask variables [and rmax]
73120
74121 Returns
75122 -------
76123 Dataset
77124 """
125+
78126 attrs_dict = {
79127 "Bathymetry" : dict (standard_name = "sea_floor_depth_below_geoid" , units = "m" ),
80128 "mask" : dict (standard_name = "sea_binary_mask" , units = "1" ),
81129 }
130+
131+ if "rmax" in ds :
132+ attrs_dict ["rmax" ] = dict (standard_name = "rmax" , units = "1" )
133+
82134 for varname , attrs in attrs_dict .items ():
83135 ds [varname ].attrs = attrs
84136 ds [varname ].attrs ["coordinates" ] = "glamt gphit"
85137 return ds
138+
139+
140+ def _calc_rmax (depth ):
141+ """
142+ Calculate rmax: measure of steepness
143+
144+ This function returns the slope steepness criteria rmax, which is simply
145+ (H[0] - H[1]) / (H[0] + H[1])
146+
147+ Parameters
148+ ----------
149+ depth: float
150+ Bottom depth (units: m).
151+
152+ Returns
153+ -------
154+ rmax: float
155+ Slope steepness value (units: None)
156+ """
157+ depth = depth .reset_index (list (depth .dims ))
158+
159+ both_rmax = []
160+ for dim in depth .dims :
161+
162+ # (H[0] - H[1]) / (H[0] + H[1])
163+ depth_diff = depth .diff (dim )
164+ depth_rolling_sum = depth .rolling ({dim : 2 }).sum ().dropna (dim )
165+ rmax = depth_diff / depth_rolling_sum
166+
167+ # (R[0] + R[1]) / 2
168+ rmax = rmax .rolling ({dim : 2 }).mean ().dropna (dim )
169+
170+ # Fill first row and column
171+ rmax = rmax .pad ({dim : (1 , 1 )}, constant_values = 0 )
172+
173+ both_rmax .append (np .abs (rmax ))
174+
175+ return np .maximum (* both_rmax )
0 commit comments