roms-tools 1.7.0__py3-none-any.whl → 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- roms_tools/__init__.py +2 -1
- roms_tools/setup/boundary_forcing.py +246 -146
- roms_tools/setup/datasets.py +229 -69
- roms_tools/setup/download.py +13 -17
- roms_tools/setup/grid.py +777 -614
- roms_tools/setup/initial_conditions.py +168 -32
- roms_tools/setup/mask.py +115 -0
- roms_tools/setup/nesting.py +575 -0
- roms_tools/setup/plot.py +218 -63
- roms_tools/setup/regrid.py +4 -2
- roms_tools/setup/river_forcing.py +125 -29
- roms_tools/setup/surface_forcing.py +31 -25
- roms_tools/setup/tides.py +29 -14
- roms_tools/setup/topography.py +250 -153
- roms_tools/setup/utils.py +174 -44
- roms_tools/setup/vertical_coordinate.py +5 -16
- roms_tools/tests/test_setup/test_boundary_forcing.py +10 -5
- roms_tools/tests/test_setup/test_data/grid.zarr/.zattrs +0 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/.zmetadata +56 -201
- roms_tools/tests/test_setup/test_data/grid.zarr/Cs_r/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/Cs_w/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/{layer_depth_rho → sigma_r}/.zarray +2 -6
- roms_tools/tests/test_setup/test_data/grid.zarr/sigma_r/.zattrs +7 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/sigma_r/0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/sigma_w/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/sigma_w/.zattrs +7 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/sigma_w/0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zattrs +1 -2
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zmetadata +58 -203
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/Cs_r/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/Cs_w/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_rho/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_u/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_v/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_r/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_r/.zattrs +7 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_r/0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_w/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_w/.zattrs +7 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_w/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +2 -3
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_tracer/.zattrs +1 -2
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_name/.zarray +1 -1
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_name/0 +0 -0
- roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/.zmetadata +5 -6
- roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_tracer/.zarray +2 -2
- roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_tracer/.zattrs +1 -2
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_tracer/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/tracer_name/.zarray +2 -2
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_name/0 +0 -0
- roms_tools/tests/test_setup/test_datasets.py +2 -2
- roms_tools/tests/test_setup/test_grid.py +110 -12
- roms_tools/tests/test_setup/test_initial_conditions.py +2 -1
- roms_tools/tests/test_setup/test_nesting.py +489 -0
- roms_tools/tests/test_setup/test_river_forcing.py +53 -15
- roms_tools/tests/test_setup/test_surface_forcing.py +3 -22
- roms_tools/tests/test_setup/test_tides.py +2 -1
- roms_tools/tests/test_setup/test_topography.py +106 -1
- roms_tools/tests/test_setup/test_validation.py +2 -2
- {roms_tools-1.7.0.dist-info → roms_tools-2.1.0.dist-info}/LICENSE +1 -1
- {roms_tools-1.7.0.dist-info → roms_tools-2.1.0.dist-info}/METADATA +9 -4
- {roms_tools-1.7.0.dist-info → roms_tools-2.1.0.dist-info}/RECORD +85 -108
- {roms_tools-1.7.0.dist-info → roms_tools-2.1.0.dist-info}/WHEEL +1 -1
- roms_tools/_version.py +0 -2
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_rho/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_rho/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_rho/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_u/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_u/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_u/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_v/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_v/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_v/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_rho/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_rho/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_u/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_u/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_u/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_v/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_v/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_v/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_rho/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_rho/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_rho/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_u/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_u/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_u/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_v/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_v/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_v/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_rho/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_rho/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_rho/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_u/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_u/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_u/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_v/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_v/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_v/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_tracer/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/tracer_name/0 +0 -0
- roms_tools/tests/test_setup/test_vertical_coordinate.py +0 -91
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/.zattrs +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/.zgroup +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/abs_time/.zarray +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/abs_time/.zattrs +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/abs_time/0 +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/month/.zarray +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/month/.zattrs +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/month/0 +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_name/.zarray +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_name/.zattrs +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_name/0 +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_time/.zarray +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_time/.zattrs +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_time/0 +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_volume/.zarray +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_volume/.zattrs +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/river_volume/0.0 +0 -0
- /roms_tools/tests/test_setup/test_data/{river_forcing.zarr → river_forcing_with_bgc.zarr}/tracer_name/.zattrs +0 -0
- {roms_tools-1.7.0.dist-info → roms_tools-2.1.0.dist-info}/top_level.txt +0 -0
|
@@ -6,6 +6,7 @@ from typing import Dict, Union, List, Optional
|
|
|
6
6
|
from roms_tools.setup.grid import Grid
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
from roms_tools.setup.datasets import GLORYSDataset, CESMBGCDataset
|
|
9
|
+
from roms_tools.setup.vertical_coordinate import compute_depth
|
|
9
10
|
from roms_tools.setup.utils import (
|
|
10
11
|
nan_check,
|
|
11
12
|
substitute_nans_by_fillvalue,
|
|
@@ -15,6 +16,8 @@ from roms_tools.setup.utils import (
|
|
|
15
16
|
rotate_velocities,
|
|
16
17
|
compute_barotropic_velocity,
|
|
17
18
|
transpose_dimensions,
|
|
19
|
+
interpolate_from_rho_to_u,
|
|
20
|
+
interpolate_from_rho_to_v,
|
|
18
21
|
_to_yaml,
|
|
19
22
|
_from_yaml,
|
|
20
23
|
)
|
|
@@ -63,6 +66,10 @@ class InitialConditions:
|
|
|
63
66
|
The reference date for the model. Defaults to January 1, 2000.
|
|
64
67
|
use_dask: bool, optional
|
|
65
68
|
Indicates whether to use dask for processing. If True, data is processed with dask; if False, data is processed eagerly. Defaults to False.
|
|
69
|
+
bypass_validation: bool, optional
|
|
70
|
+
Indicates whether to skip validation checks in the processed data. When set to True,
|
|
71
|
+
the validation process that ensures no NaN values exist at wet points
|
|
72
|
+
in the processed dataset is bypassed. Defaults to False.
|
|
66
73
|
|
|
67
74
|
Examples
|
|
68
75
|
--------
|
|
@@ -84,6 +91,7 @@ class InitialConditions:
|
|
|
84
91
|
bgc_source: Optional[Dict[str, Union[str, Path, List[Union[str, Path]]]]] = None
|
|
85
92
|
model_reference_date: datetime = datetime(2000, 1, 1)
|
|
86
93
|
use_dask: bool = False
|
|
94
|
+
bypass_validation: bool = False
|
|
87
95
|
|
|
88
96
|
ds: xr.Dataset = field(init=False, repr=False)
|
|
89
97
|
|
|
@@ -92,23 +100,18 @@ class InitialConditions:
|
|
|
92
100
|
self._input_checks()
|
|
93
101
|
|
|
94
102
|
processed_fields = {}
|
|
95
|
-
processed_fields
|
|
96
|
-
processed_fields, type="physics"
|
|
97
|
-
)
|
|
103
|
+
processed_fields = self._process_data(processed_fields, type="physics")
|
|
98
104
|
|
|
99
105
|
if self.bgc_source is not None:
|
|
100
|
-
processed_fields
|
|
101
|
-
processed_fields, type="bgc"
|
|
102
|
-
)
|
|
106
|
+
processed_fields = self._process_data(processed_fields, type="bgc")
|
|
103
107
|
|
|
104
108
|
d_meta = get_variable_metadata()
|
|
105
109
|
ds = self._write_into_dataset(processed_fields, d_meta)
|
|
106
110
|
|
|
107
111
|
ds = self._add_global_metadata(ds)
|
|
108
112
|
|
|
109
|
-
if self.
|
|
110
|
-
|
|
111
|
-
self._validate(ds, variable_info)
|
|
113
|
+
if not self.bypass_validation:
|
|
114
|
+
self._validate(ds)
|
|
112
115
|
|
|
113
116
|
# substitute NaNs over land by a fill value to avoid blow-up of ROMS
|
|
114
117
|
for var_name in ds.data_vars:
|
|
@@ -133,7 +136,9 @@ class InitialConditions:
|
|
|
133
136
|
data.extrapolate_deepest_to_bottom()
|
|
134
137
|
data.apply_lateral_fill()
|
|
135
138
|
|
|
136
|
-
|
|
139
|
+
self._set_variable_info(data, type=type)
|
|
140
|
+
attr_name = f"variable_info_{type}"
|
|
141
|
+
variable_info = getattr(self, attr_name)
|
|
137
142
|
var_names = variable_info.keys()
|
|
138
143
|
|
|
139
144
|
# lateral regridding
|
|
@@ -153,19 +158,31 @@ class InitialConditions:
|
|
|
153
158
|
interpolate=True,
|
|
154
159
|
)
|
|
155
160
|
|
|
156
|
-
|
|
161
|
+
var_names_dict = {}
|
|
157
162
|
for location in ["rho", "u", "v"]:
|
|
158
|
-
|
|
163
|
+
var_names_dict[location] = [
|
|
159
164
|
name
|
|
160
165
|
for name, info in variable_info.items()
|
|
161
166
|
if info["location"] == location and info["is_3d"]
|
|
162
167
|
]
|
|
163
|
-
|
|
168
|
+
|
|
169
|
+
# compute layer depth coordinates
|
|
170
|
+
if len(var_names_dict["u"]) > 0 or len(var_names_dict["v"]) > 0:
|
|
171
|
+
self._get_vertical_coordinates(
|
|
172
|
+
type="layer",
|
|
173
|
+
additional_locations=["u", "v"],
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
if len(var_names_dict["rho"]) > 0:
|
|
177
|
+
self._get_vertical_coordinates(type="layer", additional_locations=[])
|
|
178
|
+
# vertical regridding
|
|
179
|
+
for location in ["rho", "u", "v"]:
|
|
180
|
+
if len(var_names_dict[location]) > 0:
|
|
164
181
|
vertical_regrid = VerticalRegrid(
|
|
165
182
|
self.grid.ds[f"layer_depth_{location}"],
|
|
166
183
|
data.ds[data.dim_names["depth"]],
|
|
167
184
|
)
|
|
168
|
-
for var_name in
|
|
185
|
+
for var_name in var_names_dict[location]:
|
|
169
186
|
if var_name in processed_fields:
|
|
170
187
|
processed_fields[var_name] = vertical_regrid.apply(
|
|
171
188
|
processed_fields[var_name]
|
|
@@ -173,10 +190,14 @@ class InitialConditions:
|
|
|
173
190
|
|
|
174
191
|
# compute barotropic velocities
|
|
175
192
|
if "u" in variable_info and "v" in variable_info:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
193
|
+
self._get_vertical_coordinates(
|
|
194
|
+
type="interface",
|
|
195
|
+
additional_locations=["u", "v"],
|
|
196
|
+
)
|
|
197
|
+
for location in ["u", "v"]:
|
|
198
|
+
processed_fields[f"{location}bar"] = compute_barotropic_velocity(
|
|
199
|
+
processed_fields[location],
|
|
200
|
+
self.grid.ds[f"interface_depth_{location}"],
|
|
180
201
|
)
|
|
181
202
|
|
|
182
203
|
if type == "bgc":
|
|
@@ -191,7 +212,7 @@ class InitialConditions:
|
|
|
191
212
|
processed_fields[var_name]
|
|
192
213
|
)
|
|
193
214
|
|
|
194
|
-
return processed_fields
|
|
215
|
+
return processed_fields
|
|
195
216
|
|
|
196
217
|
def _input_checks(self):
|
|
197
218
|
|
|
@@ -345,7 +366,84 @@ class InitialConditions:
|
|
|
345
366
|
else:
|
|
346
367
|
variable_info[var_name] = {**default_info, "validate": False}
|
|
347
368
|
|
|
348
|
-
|
|
369
|
+
object.__setattr__(self, f"variable_info_{type}", variable_info)
|
|
370
|
+
|
|
371
|
+
def _get_vertical_coordinates(self, type, additional_locations=["u", "v"]):
|
|
372
|
+
"""Retrieve layer and interface depth coordinates.
|
|
373
|
+
|
|
374
|
+
This method computes and updates the layer and interface depth coordinates. It handles depth calculations for rho points and
|
|
375
|
+
additional specified locations (u and v).
|
|
376
|
+
|
|
377
|
+
Parameters
|
|
378
|
+
----------
|
|
379
|
+
type : str
|
|
380
|
+
The type of depth coordinate to retrieve. Valid options are:
|
|
381
|
+
- "layer": Retrieves layer depth coordinates.
|
|
382
|
+
- "interface": Retrieves interface depth coordinates.
|
|
383
|
+
|
|
384
|
+
additional_locations : list of str, optional
|
|
385
|
+
Specifies additional locations to compute depth coordinates for. Default is ["u", "v"].
|
|
386
|
+
Valid options include:
|
|
387
|
+
- "u": Computes depth coordinates for u points.
|
|
388
|
+
- "v": Computes depth coordinates for v points.
|
|
389
|
+
|
|
390
|
+
Updates
|
|
391
|
+
-------
|
|
392
|
+
self.grid.ds : xarray.Dataset
|
|
393
|
+
The dataset is updated with the following vertical depth coordinates:
|
|
394
|
+
- f"{type}_depth_rho": Depth coordinates at rho points.
|
|
395
|
+
- f"{type}_depth_u": Depth coordinates at u points (if applicable).
|
|
396
|
+
- f"{type}_depth_v": Depth coordinates at v points (if applicable).
|
|
397
|
+
"""
|
|
398
|
+
|
|
399
|
+
layer_vars = []
|
|
400
|
+
for location in ["rho"] + additional_locations:
|
|
401
|
+
layer_vars.append(f"{type}_depth_{location}")
|
|
402
|
+
|
|
403
|
+
if all(layer_var in self.grid.ds for layer_var in layer_vars):
|
|
404
|
+
# Vertical coordinate data already exists
|
|
405
|
+
pass
|
|
406
|
+
|
|
407
|
+
elif f"{type}_depth_rho" in self.grid.ds:
|
|
408
|
+
depth = self.grid.ds[f"{type}_depth_rho"]
|
|
409
|
+
|
|
410
|
+
if "u" in additional_locations or "v" in additional_locations:
|
|
411
|
+
# interpolation
|
|
412
|
+
if "u" in additional_locations:
|
|
413
|
+
depth_u = interpolate_from_rho_to_u(depth)
|
|
414
|
+
depth_u.attrs["long_name"] = f"{type} depth at u-points"
|
|
415
|
+
depth_u.attrs["units"] = "m"
|
|
416
|
+
self.grid.ds[f"{type}_depth_u"] = depth_u
|
|
417
|
+
if "v" in additional_locations:
|
|
418
|
+
depth_v = interpolate_from_rho_to_v(depth)
|
|
419
|
+
depth_v.attrs["long_name"] = f"{type} depth at v-points"
|
|
420
|
+
depth_v.attrs["units"] = "m"
|
|
421
|
+
self.grid.ds[f"{type}_depth_v"] = depth_v
|
|
422
|
+
else:
|
|
423
|
+
h = self.grid.ds["h"]
|
|
424
|
+
if type == "layer":
|
|
425
|
+
depth = compute_depth(
|
|
426
|
+
0, h, self.grid.hc, self.grid.ds.Cs_r, self.grid.ds.sigma_r
|
|
427
|
+
)
|
|
428
|
+
else:
|
|
429
|
+
depth = compute_depth(
|
|
430
|
+
0, h, self.grid.hc, self.grid.ds.Cs_w, self.grid.ds.sigma_w
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
depth.attrs["long_name"] = f"{type} depth at rho-points"
|
|
434
|
+
depth.attrs["units"] = "m"
|
|
435
|
+
self.grid.ds[f"{type}_depth_rho"] = depth
|
|
436
|
+
|
|
437
|
+
if "u" in additional_locations or "v" in additional_locations:
|
|
438
|
+
# interpolation
|
|
439
|
+
depth_u = interpolate_from_rho_to_u(depth)
|
|
440
|
+
depth_u.attrs["long_name"] = f"{type} depth at u-points"
|
|
441
|
+
depth_u.attrs["units"] = "m"
|
|
442
|
+
depth_v = interpolate_from_rho_to_v(depth)
|
|
443
|
+
depth_v.attrs["long_name"] = f"{type} depth at v-points"
|
|
444
|
+
depth_v.attrs["units"] = "m"
|
|
445
|
+
self.grid.ds[f"{type}_depth_u"] = depth_u
|
|
446
|
+
self.grid.ds[f"{type}_depth_v"] = depth_v
|
|
349
447
|
|
|
350
448
|
def _write_into_dataset(self, processed_fields, d_meta):
|
|
351
449
|
|
|
@@ -410,7 +508,7 @@ class InitialConditions:
|
|
|
410
508
|
|
|
411
509
|
return ds
|
|
412
510
|
|
|
413
|
-
def _validate(self, ds
|
|
511
|
+
def _validate(self, ds):
|
|
414
512
|
"""Validates the dataset by checking for NaN values in SSH at wet points, which
|
|
415
513
|
would indicate missing raw data coverage over the target domain.
|
|
416
514
|
|
|
@@ -418,8 +516,6 @@ class InitialConditions:
|
|
|
418
516
|
----------
|
|
419
517
|
ds : xarray.Dataset
|
|
420
518
|
The dataset to validate.
|
|
421
|
-
variable_info : dict
|
|
422
|
-
A dictionary containing metadata about the variables, including whether to validate them.
|
|
423
519
|
|
|
424
520
|
Raises
|
|
425
521
|
------
|
|
@@ -431,6 +527,10 @@ class InitialConditions:
|
|
|
431
527
|
-----
|
|
432
528
|
This check is only applied to the 2D variable SSH to improve performance.
|
|
433
529
|
"""
|
|
530
|
+
if self.bgc_source is not None:
|
|
531
|
+
variable_info = {**self.variable_info_physics, **self.variable_info_bgc}
|
|
532
|
+
else:
|
|
533
|
+
variable_info = self.variable_info_physics
|
|
434
534
|
|
|
435
535
|
for var_name in variable_info:
|
|
436
536
|
# Only validate variables based on "validate" flag if use_dask is False
|
|
@@ -570,9 +670,17 @@ class InitialConditions:
|
|
|
570
670
|
self.ds[var_name].load()
|
|
571
671
|
|
|
572
672
|
field = self.ds[var_name].squeeze()
|
|
673
|
+
if s is not None:
|
|
674
|
+
layer_contours = False
|
|
573
675
|
|
|
574
676
|
if all(dim in field.dims for dim in ["eta_rho", "xi_rho"]):
|
|
575
|
-
|
|
677
|
+
if layer_contours:
|
|
678
|
+
if "interface_depth_rho" in self.grid.ds:
|
|
679
|
+
interface_depth = self.grid.ds.interface_depth_rho
|
|
680
|
+
else:
|
|
681
|
+
self.get_vertical_coordinates(
|
|
682
|
+
type="interface", additional_locations=[]
|
|
683
|
+
)
|
|
576
684
|
layer_depth = self.grid.ds.layer_depth_rho
|
|
577
685
|
mask = self.grid.ds.mask_rho
|
|
578
686
|
field = field.assign_coords(
|
|
@@ -580,7 +688,13 @@ class InitialConditions:
|
|
|
580
688
|
)
|
|
581
689
|
|
|
582
690
|
elif all(dim in field.dims for dim in ["eta_rho", "xi_u"]):
|
|
583
|
-
|
|
691
|
+
if layer_contours:
|
|
692
|
+
if "interface_depth_u" in self.grid.ds:
|
|
693
|
+
interface_depth = self.grid.ds.interface_depth_u
|
|
694
|
+
else:
|
|
695
|
+
self.get_vertical_coordinates(
|
|
696
|
+
type="interface", additional_locations=["u", "v"]
|
|
697
|
+
)
|
|
584
698
|
layer_depth = self.grid.ds.layer_depth_u
|
|
585
699
|
mask = self.grid.ds.mask_u
|
|
586
700
|
field = field.assign_coords(
|
|
@@ -588,7 +702,13 @@ class InitialConditions:
|
|
|
588
702
|
)
|
|
589
703
|
|
|
590
704
|
elif all(dim in field.dims for dim in ["eta_v", "xi_rho"]):
|
|
591
|
-
|
|
705
|
+
if layer_contours:
|
|
706
|
+
if "interface_depth_v" in self.grid.ds:
|
|
707
|
+
interface_depth = self.grid.ds.interface_depth_v
|
|
708
|
+
else:
|
|
709
|
+
self.get_vertical_coordinates(
|
|
710
|
+
type="interface", additional_locations=["u", "v"]
|
|
711
|
+
)
|
|
592
712
|
layer_depth = self.grid.ds.layer_depth_v
|
|
593
713
|
mask = self.grid.ds.mask_v
|
|
594
714
|
field = field.assign_coords(
|
|
@@ -612,14 +732,16 @@ class InitialConditions:
|
|
|
612
732
|
title = title + f", eta_rho = {field.eta_rho[eta].item()}"
|
|
613
733
|
field = field.isel(eta_rho=eta)
|
|
614
734
|
layer_depth = layer_depth.isel(eta_rho=eta)
|
|
615
|
-
|
|
735
|
+
if layer_contours:
|
|
736
|
+
interface_depth = interface_depth.isel(eta_rho=eta)
|
|
616
737
|
if "s_rho" in field.dims:
|
|
617
738
|
field = field.assign_coords({"layer_depth": layer_depth})
|
|
618
739
|
elif "eta_v" in field.dims:
|
|
619
740
|
title = title + f", eta_v = {field.eta_v[eta].item()}"
|
|
620
741
|
field = field.isel(eta_v=eta)
|
|
621
742
|
layer_depth = layer_depth.isel(eta_v=eta)
|
|
622
|
-
|
|
743
|
+
if layer_contours:
|
|
744
|
+
interface_depth = interface_depth.isel(eta_v=eta)
|
|
623
745
|
if "s_rho" in field.dims:
|
|
624
746
|
field = field.assign_coords({"layer_depth": layer_depth})
|
|
625
747
|
else:
|
|
@@ -631,14 +753,16 @@ class InitialConditions:
|
|
|
631
753
|
title = title + f", xi_rho = {field.xi_rho[xi].item()}"
|
|
632
754
|
field = field.isel(xi_rho=xi)
|
|
633
755
|
layer_depth = layer_depth.isel(xi_rho=xi)
|
|
634
|
-
|
|
756
|
+
if layer_contours:
|
|
757
|
+
interface_depth = interface_depth.isel(xi_rho=xi)
|
|
635
758
|
if "s_rho" in field.dims:
|
|
636
759
|
field = field.assign_coords({"layer_depth": layer_depth})
|
|
637
760
|
elif "xi_u" in field.dims:
|
|
638
761
|
title = title + f", xi_u = {field.xi_u[xi].item()}"
|
|
639
762
|
field = field.isel(xi_u=xi)
|
|
640
763
|
layer_depth = layer_depth.isel(xi_u=xi)
|
|
641
|
-
|
|
764
|
+
if layer_contours:
|
|
765
|
+
interface_depth = interface_depth.isel(xi_u=xi)
|
|
642
766
|
if "s_rho" in field.dims:
|
|
643
767
|
field = field.assign_coords({"layer_depth": layer_depth})
|
|
644
768
|
else:
|
|
@@ -764,7 +888,10 @@ class InitialConditions:
|
|
|
764
888
|
|
|
765
889
|
@classmethod
|
|
766
890
|
def from_yaml(
|
|
767
|
-
cls,
|
|
891
|
+
cls,
|
|
892
|
+
filepath: Union[str, Path],
|
|
893
|
+
use_dask: bool = False,
|
|
894
|
+
bypass_validation: bool = False,
|
|
768
895
|
) -> "InitialConditions":
|
|
769
896
|
"""Create an instance of the InitialConditions class from a YAML file.
|
|
770
897
|
|
|
@@ -774,6 +901,10 @@ class InitialConditions:
|
|
|
774
901
|
The path to the YAML file from which the parameters will be read.
|
|
775
902
|
use_dask: bool, optional
|
|
776
903
|
Indicates whether to use dask for processing. If True, data is processed with dask; if False, data is processed eagerly. Defaults to False.
|
|
904
|
+
bypass_validation: bool, optional
|
|
905
|
+
Indicates whether to skip validation checks in the processed data. When set to True,
|
|
906
|
+
the validation process that ensures no NaN values exist at wet points
|
|
907
|
+
in the processed dataset is bypassed. Defaults to False.
|
|
777
908
|
|
|
778
909
|
Returns
|
|
779
910
|
-------
|
|
@@ -784,4 +915,9 @@ class InitialConditions:
|
|
|
784
915
|
|
|
785
916
|
grid = Grid.from_yaml(filepath)
|
|
786
917
|
initial_conditions_params = _from_yaml(cls, filepath)
|
|
787
|
-
return cls(
|
|
918
|
+
return cls(
|
|
919
|
+
grid=grid,
|
|
920
|
+
**initial_conditions_params,
|
|
921
|
+
use_dask=use_dask,
|
|
922
|
+
bypass_validation=bypass_validation,
|
|
923
|
+
)
|
roms_tools/setup/mask.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import xarray as xr
|
|
2
|
+
import numpy as np
|
|
3
|
+
import regionmask
|
|
4
|
+
import warnings
|
|
5
|
+
from scipy.ndimage import label
|
|
6
|
+
from roms_tools.setup.utils import (
|
|
7
|
+
interpolate_from_rho_to_u,
|
|
8
|
+
interpolate_from_rho_to_v,
|
|
9
|
+
handle_boundaries,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _add_mask(ds):
|
|
14
|
+
"""Adds a land/water mask to the dataset at rho-points.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
ds : xarray.Dataset
|
|
19
|
+
Input dataset containing latitude and longitude coordinates at rho-points.
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
xarray.Dataset
|
|
24
|
+
The original dataset with an added 'mask_rho' variable, representing land/water mask.
|
|
25
|
+
"""
|
|
26
|
+
land = regionmask.defined_regions.natural_earth_v5_0_0.land_10
|
|
27
|
+
|
|
28
|
+
# Suppress specific warning
|
|
29
|
+
with warnings.catch_warnings():
|
|
30
|
+
warnings.filterwarnings(
|
|
31
|
+
"ignore", message="No gridpoint belongs to any region.*"
|
|
32
|
+
)
|
|
33
|
+
land_mask = land.mask(ds["lon_rho"], ds["lat_rho"])
|
|
34
|
+
mask = land_mask.isnull()
|
|
35
|
+
|
|
36
|
+
# fill enclosed basins with land
|
|
37
|
+
mask = _fill_enclosed_basins(mask.values)
|
|
38
|
+
# adjust mask boundaries by copying values from adjacent cells
|
|
39
|
+
mask = handle_boundaries(mask)
|
|
40
|
+
|
|
41
|
+
ds["mask_rho"] = xr.DataArray(mask.astype(np.int32), dims=("eta_rho", "xi_rho"))
|
|
42
|
+
ds["mask_rho"].attrs = {
|
|
43
|
+
"long_name": "Mask at rho-points",
|
|
44
|
+
"units": "land/water (0/1)",
|
|
45
|
+
}
|
|
46
|
+
ds = _add_velocity_masks(ds)
|
|
47
|
+
|
|
48
|
+
return ds
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _fill_enclosed_basins(mask) -> np.ndarray:
|
|
52
|
+
"""Fills enclosed basins in the mask with land (value = 1).
|
|
53
|
+
|
|
54
|
+
This function identifies the largest connected region in the mask, which is assumed to represent
|
|
55
|
+
the land, and sets all other regions to water (value = 0).
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
mask : np.ndarray
|
|
60
|
+
A binary array representing the land/water mask (land = 1, water = 0).
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
np.ndarray
|
|
65
|
+
The modified mask with enclosed basins filled with land (1).
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
# Label connected regions in the mask
|
|
69
|
+
reg, nreg = label(mask)
|
|
70
|
+
# Find the largest region
|
|
71
|
+
lint = 0
|
|
72
|
+
lreg = 0
|
|
73
|
+
for ireg in range(nreg):
|
|
74
|
+
int_ = np.sum(reg == ireg)
|
|
75
|
+
if int_ > lint and mask[reg == ireg].sum() > 0:
|
|
76
|
+
lreg = ireg
|
|
77
|
+
lint = int_
|
|
78
|
+
|
|
79
|
+
# Remove regions other than the largest one
|
|
80
|
+
for ireg in range(nreg):
|
|
81
|
+
if ireg != lreg:
|
|
82
|
+
mask[reg == ireg] = 0
|
|
83
|
+
|
|
84
|
+
return mask
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _add_velocity_masks(ds):
|
|
88
|
+
"""Adds velocity masks for u- and v-points based on the rho-point mask.
|
|
89
|
+
|
|
90
|
+
This function generates masks for u- and v-points by interpolating the rho-point land/water mask.
|
|
91
|
+
The interpolation method used is "multiplicative", which scales the rho-point mask to the respective
|
|
92
|
+
u- and v-points.
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
ds : xarray.Dataset
|
|
97
|
+
The dataset containing the land/water mask at rho-points (`mask_rho`).
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
xarray.Dataset
|
|
102
|
+
The input dataset with added velocity masks (`mask_u` and `mask_v`) for u- and v-points.
|
|
103
|
+
"""
|
|
104
|
+
# add u- and v-masks
|
|
105
|
+
ds["mask_u"] = interpolate_from_rho_to_u(
|
|
106
|
+
ds["mask_rho"], method="multiplicative"
|
|
107
|
+
).astype(np.int32)
|
|
108
|
+
ds["mask_v"] = interpolate_from_rho_to_v(
|
|
109
|
+
ds["mask_rho"], method="multiplicative"
|
|
110
|
+
).astype(np.int32)
|
|
111
|
+
|
|
112
|
+
ds["mask_u"].attrs = {"long_name": "Mask at u-points", "units": "land/water (0/1)"}
|
|
113
|
+
ds["mask_v"].attrs = {"long_name": "Mask at v-points", "units": "land/water (0/1)"}
|
|
114
|
+
|
|
115
|
+
return ds
|