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.
Files changed (111) hide show
  1. roms_tools/datasets/lat_lon_datasets.py +12 -0
  2. roms_tools/datasets/roms_dataset.py +140 -53
  3. roms_tools/datasets/utils.py +14 -2
  4. roms_tools/regrid.py +76 -0
  5. roms_tools/setup/boundary_forcing.py +2 -2
  6. roms_tools/setup/grid.py +17 -3
  7. roms_tools/setup/initial_conditions.py +314 -55
  8. roms_tools/setup/mask.py +2 -5
  9. roms_tools/setup/nesting.py +6 -3
  10. roms_tools/setup/surface_forcing.py +1 -2
  11. roms_tools/setup/tides.py +6 -5
  12. roms_tools/setup/utils.py +220 -142
  13. roms_tools/tests/test_datasets/test_roms_dataset.py +225 -21
  14. roms_tools/tests/test_regrid.py +120 -1
  15. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ALK/c/0/0/0/0 +0 -0
  16. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ALK/zarr.json +57 -0
  17. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ALK_ALT_CO2/c/0/0/0/0 +0 -0
  18. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ALK_ALT_CO2/zarr.json +57 -0
  19. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Cs_r/c/0 +0 -0
  20. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Cs_r/zarr.json +47 -0
  21. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Cs_w/c/0 +0 -0
  22. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Cs_w/zarr.json +47 -0
  23. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DIC/c/0/0/0/0 +0 -0
  24. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DIC/zarr.json +57 -0
  25. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DIC_ALT_CO2/c/0/0/0/0 +0 -0
  26. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DIC_ALT_CO2/zarr.json +57 -0
  27. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOC/c/0/0/0/0 +0 -0
  28. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOC/zarr.json +57 -0
  29. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOCr/c/0/0/0/0 +0 -0
  30. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOCr/zarr.json +57 -0
  31. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DON/c/0/0/0/0 +0 -0
  32. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DON/zarr.json +57 -0
  33. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DONr/c/0/0/0/0 +0 -0
  34. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DONr/zarr.json +57 -0
  35. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOP/c/0/0/0/0 +0 -0
  36. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOP/zarr.json +57 -0
  37. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOPr/c/0/0/0/0 +0 -0
  38. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/DOPr/zarr.json +57 -0
  39. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Fe/c/0/0/0/0 +0 -0
  40. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Fe/zarr.json +57 -0
  41. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Lig/c/0/0/0/0 +0 -0
  42. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/Lig/zarr.json +57 -0
  43. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/NH4/c/0/0/0/0 +0 -0
  44. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/NH4/zarr.json +57 -0
  45. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/NO3/c/0/0/0/0 +0 -0
  46. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/NO3/zarr.json +57 -0
  47. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/O2/c/0/0/0/0 +0 -0
  48. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/O2/zarr.json +57 -0
  49. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/PO4/c/0/0/0/0 +0 -0
  50. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/PO4/zarr.json +57 -0
  51. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/SiO3/c/0/0/0/0 +0 -0
  52. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/SiO3/zarr.json +57 -0
  53. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/abs_time/zarr.json +47 -0
  54. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatC/c/0/0/0/0 +0 -0
  55. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatC/zarr.json +57 -0
  56. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatChl/c/0/0/0/0 +0 -0
  57. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatChl/zarr.json +57 -0
  58. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatFe/c/0/0/0/0 +0 -0
  59. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatFe/zarr.json +57 -0
  60. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatP/c/0/0/0/0 +0 -0
  61. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatP/zarr.json +57 -0
  62. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatSi/c/0/0/0/0 +0 -0
  63. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diatSi/zarr.json +57 -0
  64. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazC/c/0/0/0/0 +0 -0
  65. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazC/zarr.json +57 -0
  66. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazChl/c/0/0/0/0 +0 -0
  67. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazChl/zarr.json +57 -0
  68. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazFe/c/0/0/0/0 +0 -0
  69. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazFe/zarr.json +57 -0
  70. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazP/c/0/0/0/0 +0 -0
  71. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/diazP/zarr.json +57 -0
  72. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ocean_time/c/0 +0 -0
  73. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ocean_time/zarr.json +47 -0
  74. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/salt/c/0/0/0/0 +0 -0
  75. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/salt/zarr.json +57 -0
  76. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spC/c/0/0/0/0 +0 -0
  77. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spC/zarr.json +57 -0
  78. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spCaCO3/c/0/0/0/0 +0 -0
  79. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spCaCO3/zarr.json +57 -0
  80. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spChl/c/0/0/0/0 +0 -0
  81. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spChl/zarr.json +57 -0
  82. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spFe/c/0/0/0/0 +0 -0
  83. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spFe/zarr.json +57 -0
  84. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spP/c/0/0/0/0 +0 -0
  85. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/spP/zarr.json +57 -0
  86. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/temp/c/0/0/0/0 +0 -0
  87. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/temp/zarr.json +57 -0
  88. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/u/c/0/0/0/0 +0 -0
  89. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/u/zarr.json +57 -0
  90. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ubar/c/0/0/0 +0 -0
  91. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/ubar/zarr.json +54 -0
  92. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/v/c/0/0/0/0 +0 -0
  93. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/v/zarr.json +57 -0
  94. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/vbar/c/0/0/0 +0 -0
  95. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/vbar/zarr.json +54 -0
  96. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/w/zarr.json +57 -0
  97. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zarr.json +2481 -0
  98. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zeta/c/0/0/0 +0 -0
  99. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zeta/zarr.json +54 -0
  100. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zooC/c/0/0/0/0 +0 -0
  101. roms_tools/tests/test_setup/test_data/initial_conditions_from_roms.zarr/zooC/zarr.json +57 -0
  102. roms_tools/tests/test_setup/test_grid.py +24 -0
  103. roms_tools/tests/test_setup/test_initial_conditions.py +128 -11
  104. roms_tools/tests/test_setup/test_validation.py +15 -0
  105. roms_tools/tests/test_utils.py +287 -0
  106. roms_tools/utils.py +177 -72
  107. {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/METADATA +2 -3
  108. {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/RECORD +111 -24
  109. {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/WHEEL +1 -1
  110. {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/licenses/LICENSE +0 -0
  111. {roms_tools-3.4.0.dist-info → roms_tools-3.5.0.dist-info}/top_level.txt +0 -0
@@ -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
+ }
@@ -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
- ValueError,
263
- match="`ini_time` must be a valid datetime object and cannot be None.",
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(