|
7 | 7 | from typing import Optional # , Tuple |
8 | 8 |
|
9 | 9 | import numpy as np |
| 10 | +import xarray as xr |
10 | 11 | from xarray import DataArray, Dataset |
11 | 12 |
|
12 | 13 | from pydomcfg.utils import _smooth_MB06 # , _calc_rmax |
@@ -121,15 +122,14 @@ def __call__( |
121 | 122 |
|
122 | 123 | bathy = self._bathy["Bathymetry"] |
123 | 124 |
|
124 | | - # Land-Sea mask of the domain: |
| 125 | + # compute land-sea mask of the domain: |
125 | 126 | # 0 = land |
126 | 127 | # 1 = ocean |
127 | | - self._ocean = bathy.where(bathy == 0, 1) |
| 128 | + self._lsm = xr.where(bathy > 0, 1, 0) |
128 | 129 |
|
129 | 130 | # set maximum and minumum depths of model bathymetry |
130 | | - bathy = bathy.where(bathy < self._max_dep, self._max_dep) |
131 | | - bathy = bathy.where(bathy > self._min_dep, self._min_dep) |
132 | | - bathy *= self._ocean |
| 131 | + bathy = np.minimum(bathy, self._max_dep) |
| 132 | + bathy = np.maximum(bathy, self._min_dep) * self._lsm |
133 | 133 |
|
134 | 134 | # compute envelope bathymetry DataArray |
135 | 135 | self._envlp = self._compute_env(bathy) |
@@ -193,46 +193,79 @@ def _compute_env(self, depth: DataArray) -> DataArray: |
193 | 193 | ---------- |
194 | 194 | depth: DataArray |
195 | 195 | xarray DataArray of the 2D bottom topography |
| 196 | + it MUST have only two dimensions named "x" and "y" |
196 | 197 | Returns |
197 | 198 | ------- |
198 | 199 | DataArray |
199 | 200 | xarray DataArray of the 2D envelope bathymetry |
200 | 201 | """ |
201 | 202 |
|
202 | | - da_zenv = depth.copy() |
203 | | - |
204 | 203 | if self._rmax: |
205 | 204 |
|
206 | | - # getting the actual numpy array |
207 | | - # TO BE OPTIMISED |
208 | | - zenv = da_zenv.data |
209 | | - nj = zenv.shape[0] |
210 | | - ni = zenv.shape[1] |
| 205 | + lsm = self._lsm |
211 | 206 |
|
212 | 207 | # set first land point adjacent to a wet cell to |
213 | 208 | # min_dep as this needs to be included in smoothing |
214 | | - for j in range(nj - 1): |
215 | | - for i in range(ni - 1): |
216 | | - if not self._ocean[j, i]: |
217 | | - ip1 = np.minimum(i + 1, ni) |
218 | | - jp1 = np.minimum(j + 1, nj) |
219 | | - im1 = np.maximum(i - 1, 0) |
220 | | - jm1 = np.maximum(j - 1, 0) |
221 | | - if ( |
222 | | - depth[jp1, im1] |
223 | | - + depth[jp1, i] |
224 | | - + depth[jp1, ip1] |
225 | | - + depth[j, im1] |
226 | | - + depth[j, ip1] |
227 | | - + depth[jm1, im1] |
228 | | - + depth[jm1, i] |
229 | | - + depth[jm1, ip1] |
230 | | - ) > 0.0: |
231 | | - zenv[j, i] = self._min_dep |
232 | | - |
233 | | - da_zenv.data = zenv |
234 | | - # print(np.nanmax(_calc_rmax(da_zenv)*self._ocean)) |
235 | | - da_zenv = _smooth_MB06(da_zenv, self._rmax) |
236 | | - da_zenv = da_zenv.where(da_zenv > self._min_dep, self._min_dep) |
237 | | - |
238 | | - return da_zenv |
| 209 | + |
| 210 | + # ------------------------------------------------------------ |
| 211 | + # This is the original NEMO Fortran90 code: translated |
| 212 | + # in python it is very inefficient |
| 213 | + # ------------------------------------------------------------ |
| 214 | + # zenv = depth.copy() |
| 215 | + # env = zenv.data |
| 216 | + # |
| 217 | + # nj = env.shape[0] |
| 218 | + # ni = env.shape[1] |
| 219 | + # |
| 220 | + # for j in range(nj - 1): |
| 221 | + # for i in range(ni - 1): |
| 222 | + # if not lsm[j, i]: |
| 223 | + # ip1 = np.minimum(i + 1, ni) |
| 224 | + # jp1 = np.minimum(j + 1, nj) |
| 225 | + # im1 = np.maximum(i - 1, 0) |
| 226 | + # jm1 = np.maximum(j - 1, 0) |
| 227 | + # if ( |
| 228 | + # depth[jp1, im1] |
| 229 | + # + depth[jp1, i] |
| 230 | + # + depth[jp1, ip1] |
| 231 | + # + depth[j, im1] |
| 232 | + # + depth[j, ip1] |
| 233 | + # + depth[jm1, im1] |
| 234 | + # + depth[jm1, i] |
| 235 | + # + depth[jm1, ip1] |
| 236 | + # ) > 0.0: |
| 237 | + # env[j, i] = min_dep |
| 238 | + # |
| 239 | + # zenv.data = env |
| 240 | + # ------------------------------------------------------------ |
| 241 | + |
| 242 | + # ------------------------------------------------------------ |
| 243 | + # This is my translation into xarray. I think it does what |
| 244 | + # it should, a part on the boundaries: I tested with AMM7, |
| 245 | + # and zenv computed with NEMO-like code (above) and this |
| 246 | + # one are perfectly identical apart for two single different |
| 247 | + # points just on the border ... I don't think it will make |
| 248 | + # a huge difference but if there is a better way to manage |
| 249 | + # the borders with xarray and obtain exactly the same results |
| 250 | + # of the original NEMO-like code, happy to use it. |
| 251 | + # ------------------------------------------------------------ |
| 252 | + cst_lsm = lsm * 0.0 |
| 253 | + ngb_pnt = [-1, 0, 1] |
| 254 | + for j in ngb_pnt: |
| 255 | + for i in ngb_pnt: |
| 256 | + if j != 0 or i != 0: |
| 257 | + lsm_sft = lsm.shift({lsm.dims[1]: i, lsm.dims[0]: j}) |
| 258 | + cst_lsm += lsm_sft |
| 259 | + |
| 260 | + cst_lsm = cst_lsm.where(lsm == 0, 0) |
| 261 | + cst_lsm = cst_lsm.where(cst_lsm == 0, 1) |
| 262 | + zenv = depth.where(cst_lsm == 0, self._min_dep) |
| 263 | + for dim in lsm.dims: |
| 264 | + for indx in [0, -1]: |
| 265 | + zenv[{dim: indx}] = depth[{dim: indx}] |
| 266 | + # ------------------------------------------------------------ |
| 267 | + |
| 268 | + zenv = _smooth_MB06(zenv, self._rmax) |
| 269 | + zenv = zenv.where(zenv > self._min_dep, self._min_dep) |
| 270 | + |
| 271 | + return zenv |
0 commit comments