roms-tools 3.4.0__py3-none-any.whl → 3.5.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/datasets/lat_lon_datasets.py +12 -0
- roms_tools/datasets/roms_dataset.py +140 -53
- roms_tools/datasets/utils.py +14 -2
- roms_tools/regrid.py +76 -0
- roms_tools/setup/boundary_forcing.py +2 -2
- roms_tools/setup/grid.py +17 -3
- roms_tools/setup/initial_conditions.py +314 -55
- roms_tools/setup/mask.py +2 -5
- roms_tools/setup/nesting.py +6 -3
- roms_tools/setup/surface_forcing.py +1 -2
- roms_tools/setup/tides.py +6 -5
- roms_tools/setup/utils.py +220 -142
- roms_tools/tests/test_datasets/test_roms_dataset.py +225 -21
- roms_tools/tests/test_regrid.py +120 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ALK/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ALK/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ALK_ALT_CO2/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ALK_ALT_CO2/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Cs_r/c/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Cs_r/zarr.json +47 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Cs_w/c/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Cs_w/zarr.json +47 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DIC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DIC/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DIC_ALT_CO2/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DIC_ALT_CO2/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOC/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOCr/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOCr/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DON/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DON/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DONr/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DONr/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOP/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOP/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOPr/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOPr/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Fe/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Fe/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Lig/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Lig/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/NH4/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/NH4/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/NO3/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/NO3/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/O2/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/O2/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/PO4/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/PO4/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/SiO3/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/SiO3/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/abs_time/zarr.json +47 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatC/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatChl/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatChl/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatFe/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatFe/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatP/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatP/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatSi/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatSi/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazC/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazChl/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazChl/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazFe/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazFe/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazP/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazP/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ocean_time/c/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ocean_time/zarr.json +47 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/salt/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/salt/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spC/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spCaCO3/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spCaCO3/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spChl/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spChl/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spFe/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spFe/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spP/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spP/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/temp/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/temp/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/u/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/u/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ubar/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ubar/zarr.json +54 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/v/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/v/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/vbar/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/vbar/zarr.json +54 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/w/zarr.json +57 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zarr.json +2481 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zeta/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zeta/zarr.json +54 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zooC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zooC/zarr.json +57 -0
- roms_tools/tests/test_setup/test_grid.py +24 -0
- roms_tools/tests/test_setup/test_initial_conditions.py +128 -11
- roms_tools/tests/test_setup/test_validation.py +15 -0
- roms_tools/tests/test_utils.py +287 -0
- roms_tools/utils.py +177 -72
- {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/METADATA +2 -3
- {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/RECORD +111 -24
- {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/WHEEL +1 -1
- {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/licenses/LICENSE +0 -0
- {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shape": [
|
|
3
|
+
1,
|
|
4
|
+
7,
|
|
5
|
+
7
|
|
6
|
+
],
|
|
7
|
+
"data_type": "float32",
|
|
8
|
+
"chunk_grid": {
|
|
9
|
+
"name": "regular",
|
|
10
|
+
"configuration": {
|
|
11
|
+
"chunk_shape": [
|
|
12
|
+
1,
|
|
13
|
+
7,
|
|
14
|
+
7
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"chunk_key_encoding": {
|
|
19
|
+
"name": "default",
|
|
20
|
+
"configuration": {
|
|
21
|
+
"separator": "/"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"fill_value": 0.0,
|
|
25
|
+
"codecs": [
|
|
26
|
+
{
|
|
27
|
+
"name": "bytes",
|
|
28
|
+
"configuration": {
|
|
29
|
+
"endian": "little"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "zstd",
|
|
34
|
+
"configuration": {
|
|
35
|
+
"level": 0,
|
|
36
|
+
"checksum": false
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"attributes": {
|
|
41
|
+
"long_name": "sea surface height",
|
|
42
|
+
"units": "m",
|
|
43
|
+
"coordinates": "abs_time",
|
|
44
|
+
"_FillValue": "AAAAAAAA+H8="
|
|
45
|
+
},
|
|
46
|
+
"dimension_names": [
|
|
47
|
+
"ocean_time",
|
|
48
|
+
"eta_rho",
|
|
49
|
+
"xi_rho"
|
|
50
|
+
],
|
|
51
|
+
"zarr_format": 3,
|
|
52
|
+
"node_type": "array",
|
|
53
|
+
"storage_transformers": []
|
|
54
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shape": [
|
|
3
|
+
1,
|
|
4
|
+
3,
|
|
5
|
+
7,
|
|
6
|
+
7
|
|
7
|
+
],
|
|
8
|
+
"data_type": "float32",
|
|
9
|
+
"chunk_grid": {
|
|
10
|
+
"name": "regular",
|
|
11
|
+
"configuration": {
|
|
12
|
+
"chunk_shape": [
|
|
13
|
+
1,
|
|
14
|
+
3,
|
|
15
|
+
7,
|
|
16
|
+
7
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"chunk_key_encoding": {
|
|
21
|
+
"name": "default",
|
|
22
|
+
"configuration": {
|
|
23
|
+
"separator": "/"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"fill_value": 0.0,
|
|
27
|
+
"codecs": [
|
|
28
|
+
{
|
|
29
|
+
"name": "bytes",
|
|
30
|
+
"configuration": {
|
|
31
|
+
"endian": "little"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "zstd",
|
|
36
|
+
"configuration": {
|
|
37
|
+
"level": 0,
|
|
38
|
+
"checksum": false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"attributes": {
|
|
43
|
+
"long_name": "zooplankton carbon",
|
|
44
|
+
"units": "mmol/m^3",
|
|
45
|
+
"coordinates": "abs_time",
|
|
46
|
+
"_FillValue": "AAAAAAAA+H8="
|
|
47
|
+
},
|
|
48
|
+
"dimension_names": [
|
|
49
|
+
"ocean_time",
|
|
50
|
+
"s_rho",
|
|
51
|
+
"eta_rho",
|
|
52
|
+
"xi_rho"
|
|
53
|
+
],
|
|
54
|
+
"zarr_format": 3,
|
|
55
|
+
"node_type": "array",
|
|
56
|
+
"storage_transformers": []
|
|
57
|
+
}
|
|
@@ -867,6 +867,30 @@ def test_mask_topography_boundary():
|
|
|
867
867
|
)
|
|
868
868
|
|
|
869
869
|
|
|
870
|
+
def test_grid_copy_with_ds_does_not_mutate_original(grid):
|
|
871
|
+
"""
|
|
872
|
+
copy_with_ds should return a new Grid instance with the same metadata
|
|
873
|
+
but a different backing Dataset, leaving the original Grid unchanged.
|
|
874
|
+
"""
|
|
875
|
+
orig_ds = grid.ds
|
|
876
|
+
new_ds = orig_ds.isel(xi_rho=slice(0, 2), eta_rho=slice(0, 2))
|
|
877
|
+
|
|
878
|
+
new_grid = grid.copy_with_ds(new_ds)
|
|
879
|
+
|
|
880
|
+
# New object
|
|
881
|
+
assert new_grid is not grid
|
|
882
|
+
|
|
883
|
+
# Dataset replaced on copy
|
|
884
|
+
assert new_grid.ds is new_ds
|
|
885
|
+
|
|
886
|
+
# Original grid untouched
|
|
887
|
+
assert grid.ds is orig_ds
|
|
888
|
+
|
|
889
|
+
# Metadata preserved (adjust as needed for your Grid attributes)
|
|
890
|
+
for attr in ["nx", "ny", "size_x", "size_y", "center_lon", "center_lat", "rot"]:
|
|
891
|
+
assert getattr(new_grid, attr) == getattr(grid, attr)
|
|
892
|
+
|
|
893
|
+
|
|
870
894
|
# More Grid.from_file() tests
|
|
871
895
|
|
|
872
896
|
|
|
@@ -14,12 +14,21 @@ from roms_tools.datasets.lat_lon_datasets import (
|
|
|
14
14
|
CESMBGCDataset,
|
|
15
15
|
UnifiedBGCDataset,
|
|
16
16
|
)
|
|
17
|
+
from roms_tools.setup.initial_conditions import _set_required_vars
|
|
17
18
|
from roms_tools.tests.test_setup.utils import download_regional_and_bigger
|
|
18
19
|
|
|
19
20
|
try:
|
|
20
21
|
import copernicusmarine # type: ignore
|
|
21
22
|
except ImportError:
|
|
22
23
|
copernicusmarine = None
|
|
24
|
+
try:
|
|
25
|
+
import xesmf # type: ignore
|
|
26
|
+
except ImportError:
|
|
27
|
+
xesmf = None
|
|
28
|
+
|
|
29
|
+
skip_xesmf = pytest.mark.skipif(
|
|
30
|
+
xesmf is None, reason="xesmf required for ROMS regridding"
|
|
31
|
+
)
|
|
23
32
|
|
|
24
33
|
|
|
25
34
|
@pytest.fixture
|
|
@@ -48,6 +57,7 @@ def example_grid():
|
|
|
48
57
|
"initial_conditions_with_bgc",
|
|
49
58
|
"initial_conditions_with_bgc_from_climatology",
|
|
50
59
|
"initial_conditions_with_unified_bgc_from_climatology",
|
|
60
|
+
pytest.param("initial_conditions_from_roms_without_bgc", marks=skip_xesmf),
|
|
51
61
|
],
|
|
52
62
|
)
|
|
53
63
|
def test_initial_conditions_creation_with_nondefault_glorys_dataset(
|
|
@@ -55,15 +65,7 @@ def test_initial_conditions_creation_with_nondefault_glorys_dataset(
|
|
|
55
65
|
):
|
|
56
66
|
"""Test the creation of the InitialConditions object."""
|
|
57
67
|
ic = request.getfixturevalue(ic_fixture)
|
|
58
|
-
|
|
59
|
-
assert ic.ini_time == datetime(2021, 6, 29)
|
|
60
|
-
assert ic.source == {
|
|
61
|
-
"name": "GLORYS",
|
|
62
|
-
"path": Path(download_test_data("GLORYS_coarse_test_data.nc")),
|
|
63
|
-
"climatology": False,
|
|
64
|
-
}
|
|
65
68
|
assert hasattr(ic.ds, "adjust_depth_for_sea_surface_height")
|
|
66
|
-
assert ic.ds.attrs["adjust_depth_for_sea_surface_height"] == "False"
|
|
67
69
|
assert isinstance(ic.ds, xr.Dataset)
|
|
68
70
|
assert ic.ds.coords["ocean_time"].attrs["units"] == "seconds"
|
|
69
71
|
expected_vars = {"temp", "salt", "u", "v", "zeta", "ubar", "vbar"}
|
|
@@ -171,12 +173,12 @@ def test_initial_conditions_creation_with_duplicates(use_dask: bool) -> None:
|
|
|
171
173
|
"initial_conditions_with_bgc",
|
|
172
174
|
"initial_conditions_with_bgc_from_climatology",
|
|
173
175
|
"initial_conditions_with_unified_bgc_from_climatology",
|
|
176
|
+
pytest.param("initial_conditions_from_roms", marks=skip_xesmf),
|
|
174
177
|
],
|
|
175
178
|
)
|
|
176
179
|
def test_initial_condition_creation_with_bgc(ic_fixture, request):
|
|
177
180
|
"""Test the creation of the BoundaryForcing object."""
|
|
178
181
|
ic = request.getfixturevalue(ic_fixture)
|
|
179
|
-
|
|
180
182
|
expected_bgc_variables = [
|
|
181
183
|
"PO4",
|
|
182
184
|
"NO3",
|
|
@@ -216,6 +218,88 @@ def test_initial_condition_creation_with_bgc(ic_fixture, request):
|
|
|
216
218
|
assert var in ic.ds
|
|
217
219
|
|
|
218
220
|
|
|
221
|
+
@pytest.mark.skipif(xesmf is None, reason="xesmf required")
|
|
222
|
+
def test_initial_conditions_raises_on_regridded_nans(use_dask):
|
|
223
|
+
"""Raise ValueError if regridded ROMS fields contain NaNs due to grid mismatch."""
|
|
224
|
+
parent_grid = Grid(
|
|
225
|
+
center_lon=-120, center_lat=30, nx=8, ny=13, size_x=3000, size_y=4000, rot=32
|
|
226
|
+
)
|
|
227
|
+
restart_file = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
|
|
228
|
+
# create grid that is not entirely contained in the parent grid
|
|
229
|
+
grid_params = {
|
|
230
|
+
"nx": 5,
|
|
231
|
+
"ny": 5,
|
|
232
|
+
"center_lon": -128,
|
|
233
|
+
"center_lat": 9,
|
|
234
|
+
"size_x": 100,
|
|
235
|
+
"size_y": 100,
|
|
236
|
+
}
|
|
237
|
+
grid = Grid(**grid_params)
|
|
238
|
+
|
|
239
|
+
with pytest.raises(ValueError, match="NaN values found in regridded field."):
|
|
240
|
+
InitialConditions(
|
|
241
|
+
grid=grid,
|
|
242
|
+
ini_time=datetime(1998, 1, 6),
|
|
243
|
+
source={"name": "ROMS", "grid": parent_grid, "path": restart_file},
|
|
244
|
+
use_dask=use_dask,
|
|
245
|
+
bgc_source={
|
|
246
|
+
"name": "ROMS",
|
|
247
|
+
"grid": parent_grid,
|
|
248
|
+
"path": restart_file,
|
|
249
|
+
},
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@pytest.mark.skipif(xesmf is None, reason="xesmf required")
|
|
254
|
+
def test_initial_conditions_unchanged_when_parent_and_child_grids_match(use_dask):
|
|
255
|
+
grid_params = {
|
|
256
|
+
"nx": 8,
|
|
257
|
+
"ny": 13,
|
|
258
|
+
"center_lon": -120,
|
|
259
|
+
"center_lat": 30,
|
|
260
|
+
"size_x": 3000,
|
|
261
|
+
"size_y": 4000,
|
|
262
|
+
"rot": 32,
|
|
263
|
+
}
|
|
264
|
+
parent_grid = Grid(**grid_params)
|
|
265
|
+
grid = Grid(**grid_params)
|
|
266
|
+
|
|
267
|
+
restart_file = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
|
|
268
|
+
ds = xr.open_dataset(restart_file)
|
|
269
|
+
|
|
270
|
+
ic = InitialConditions(
|
|
271
|
+
grid=grid,
|
|
272
|
+
ini_time=datetime(1998, 1, 6),
|
|
273
|
+
source={"name": "ROMS", "grid": parent_grid, "path": restart_file},
|
|
274
|
+
use_dask=use_dask,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
mask = grid.ds.mask_rho
|
|
278
|
+
|
|
279
|
+
# For scalar fields (temp, salt, zeta), values should be preserved exactly
|
|
280
|
+
# when parent and child grids are identical.
|
|
281
|
+
#
|
|
282
|
+
# NOTE:
|
|
283
|
+
# Velocity variables (u, v) are excluded here because their initialization
|
|
284
|
+
# involves multiple non-exact operations:
|
|
285
|
+
# - interpolation from staggered (u/v) points to rho-points,
|
|
286
|
+
# - rotation between grid-relative and earth-relative coordinates,
|
|
287
|
+
# - interpolation back to staggered grids.
|
|
288
|
+
#
|
|
289
|
+
# These steps are not mathematically invertible and introduce small
|
|
290
|
+
# numerical differences throughout the domain (not only at boundaries),
|
|
291
|
+
# so bitwise or near-bitwise agreement cannot be expected.
|
|
292
|
+
for var_name in ["temp", "salt", "zeta"]:
|
|
293
|
+
restart_values = ds[var_name].isel(time=1).where(mask).values
|
|
294
|
+
ic_values = ic.ds[var_name].squeeze().where(mask).values
|
|
295
|
+
|
|
296
|
+
assert np.allclose(
|
|
297
|
+
ic_values,
|
|
298
|
+
restart_values,
|
|
299
|
+
equal_nan=True,
|
|
300
|
+
), f"{var_name} values changed during initialization"
|
|
301
|
+
|
|
302
|
+
|
|
219
303
|
# Test initialization with missing 'name' in source
|
|
220
304
|
def test_initial_conditions_missing_physics_name(example_grid, use_dask):
|
|
221
305
|
with pytest.raises(ValueError, match="`source` must include a 'name'"):
|
|
@@ -259,8 +343,8 @@ def test_initial_conditions_missing_bgc_path(example_grid, use_dask):
|
|
|
259
343
|
def test_initial_conditions_missing_ini_time(example_grid, use_dask):
|
|
260
344
|
fname = Path(download_test_data("GLORYS_coarse_test_data.nc"))
|
|
261
345
|
with pytest.raises(
|
|
262
|
-
|
|
263
|
-
match="`ini_time` must be a
|
|
346
|
+
TypeError,
|
|
347
|
+
match="`ini_time` must be a datetime object",
|
|
264
348
|
):
|
|
265
349
|
InitialConditions(
|
|
266
350
|
grid=example_grid,
|
|
@@ -413,6 +497,7 @@ def test_computed_missing_optional_fields(
|
|
|
413
497
|
[
|
|
414
498
|
"initial_conditions_with_bgc_from_climatology",
|
|
415
499
|
"initial_conditions_with_unified_bgc_from_climatology",
|
|
500
|
+
pytest.param("initial_conditions_from_roms", marks=skip_xesmf),
|
|
416
501
|
],
|
|
417
502
|
)
|
|
418
503
|
def test_initial_conditions_plot(initial_conditions_fixture, request):
|
|
@@ -460,6 +545,7 @@ def test_initial_conditions_plot(initial_conditions_fixture, request):
|
|
|
460
545
|
"initial_conditions",
|
|
461
546
|
"initial_conditions_with_bgc_from_climatology",
|
|
462
547
|
"initial_conditions_with_unified_bgc_from_climatology",
|
|
548
|
+
pytest.param("initial_conditions_from_roms", marks=skip_xesmf),
|
|
463
549
|
],
|
|
464
550
|
)
|
|
465
551
|
def test_initial_conditions_save(initial_conditions_fixture, request, tmp_path):
|
|
@@ -487,6 +573,7 @@ def test_initial_conditions_save(initial_conditions_fixture, request, tmp_path):
|
|
|
487
573
|
"initial_conditions",
|
|
488
574
|
"initial_conditions_with_bgc_from_climatology",
|
|
489
575
|
"initial_conditions_with_unified_bgc_from_climatology",
|
|
576
|
+
pytest.param("initial_conditions_from_roms", marks=skip_xesmf),
|
|
490
577
|
],
|
|
491
578
|
)
|
|
492
579
|
def test_roundtrip_yaml(initial_conditions_fixture, request, tmp_path, use_dask):
|
|
@@ -519,6 +606,8 @@ def test_roundtrip_yaml(initial_conditions_fixture, request, tmp_path, use_dask)
|
|
|
519
606
|
"initial_conditions",
|
|
520
607
|
"initial_conditions_with_bgc_from_climatology",
|
|
521
608
|
"initial_conditions_with_unified_bgc_from_climatology",
|
|
609
|
+
pytest.param("initial_conditions_from_roms_without_bgc", marks=skip_xesmf),
|
|
610
|
+
pytest.param("initial_conditions_from_roms", marks=skip_xesmf),
|
|
522
611
|
],
|
|
523
612
|
)
|
|
524
613
|
def test_files_have_same_hash(initial_conditions_fixture, request, tmp_path, use_dask):
|
|
@@ -585,3 +674,31 @@ def test_from_yaml_missing_initial_conditions(tmp_path, use_dask):
|
|
|
585
674
|
|
|
586
675
|
yaml_filepath = Path(yaml_filepath)
|
|
587
676
|
yaml_filepath.unlink()
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
# Test _set_required_vars
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
def test_default_var_type():
|
|
683
|
+
vars_map = _set_required_vars()
|
|
684
|
+
# Default is "physics"
|
|
685
|
+
expected_keys = {"zeta", "temp", "salt", "u", "v"}
|
|
686
|
+
assert set(vars_map.keys()) == expected_keys
|
|
687
|
+
# Values should match keys
|
|
688
|
+
for key, val in vars_map.items():
|
|
689
|
+
assert key == val
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
def test_bgc_var_type():
|
|
693
|
+
vars_map = _set_required_vars("bgc")
|
|
694
|
+
# Check a few expected keys exist
|
|
695
|
+
expected_keys = {"PO4", "NO3", "SiO3", "NH4", "Fe", "DIC", "spChl", "zooC"}
|
|
696
|
+
assert expected_keys.issubset(vars_map.keys())
|
|
697
|
+
# Values should match keys
|
|
698
|
+
for key, val in vars_map.items():
|
|
699
|
+
assert key == val
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
def test_invalid_var_type():
|
|
703
|
+
with pytest.raises(ValueError, match="Unsupported var_type"):
|
|
704
|
+
_set_required_vars("invalid_type")
|
|
@@ -5,6 +5,15 @@ from pathlib import Path
|
|
|
5
5
|
import pytest
|
|
6
6
|
import xarray as xr
|
|
7
7
|
|
|
8
|
+
try:
|
|
9
|
+
import xesmf # type: ignore
|
|
10
|
+
except ImportError:
|
|
11
|
+
xesmf = None
|
|
12
|
+
|
|
13
|
+
skip_xesmf = pytest.mark.skipif(
|
|
14
|
+
xesmf is None, reason="xesmf required for ROMS regridding"
|
|
15
|
+
)
|
|
16
|
+
|
|
8
17
|
|
|
9
18
|
@pytest.mark.parametrize(
|
|
10
19
|
"forcing_fixture",
|
|
@@ -14,6 +23,7 @@ import xarray as xr
|
|
|
14
23
|
"tidal_forcing",
|
|
15
24
|
"initial_conditions_with_bgc_from_climatology",
|
|
16
25
|
"initial_conditions_with_unified_bgc_from_climatology",
|
|
26
|
+
pytest.param("initial_conditions_from_roms", marks=skip_xesmf),
|
|
17
27
|
"surface_forcing",
|
|
18
28
|
"coarse_surface_forcing",
|
|
19
29
|
"corrected_surface_forcing",
|
|
@@ -59,6 +69,7 @@ def test_save_results(
|
|
|
59
69
|
"tidal_forcing",
|
|
60
70
|
"initial_conditions_with_bgc_from_climatology",
|
|
61
71
|
"initial_conditions_with_unified_bgc_from_climatology",
|
|
72
|
+
pytest.param("initial_conditions_from_roms", marks=skip_xesmf),
|
|
62
73
|
"surface_forcing",
|
|
63
74
|
"coarse_surface_forcing",
|
|
64
75
|
"corrected_surface_forcing",
|
|
@@ -93,13 +104,17 @@ def test_check_results(
|
|
|
93
104
|
[
|
|
94
105
|
"tidal_forcing",
|
|
95
106
|
"initial_conditions_with_bgc_from_climatology",
|
|
107
|
+
"initial_conditions_with_unified_bgc_from_climatology",
|
|
108
|
+
pytest.param("initial_conditions_from_roms", marks=skip_xesmf),
|
|
96
109
|
"surface_forcing",
|
|
97
110
|
"coarse_surface_forcing",
|
|
98
111
|
"corrected_surface_forcing",
|
|
99
112
|
"bgc_surface_forcing",
|
|
100
113
|
"bgc_surface_forcing_from_climatology",
|
|
114
|
+
"bgc_surface_forcing_from_unified_climatology",
|
|
101
115
|
"boundary_forcing",
|
|
102
116
|
"bgc_boundary_forcing_from_climatology",
|
|
117
|
+
"bgc_boundary_forcing_from_unified_climatology",
|
|
103
118
|
],
|
|
104
119
|
)
|
|
105
120
|
def test_dask_vs_no_dask(
|