roms-tools 1.6.1__py3-none-any.whl → 1.6.2__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 (156) hide show
  1. roms_tools/__init__.py +4 -1
  2. roms_tools/_version.py +1 -1
  3. roms_tools/setup/boundary_forcing.py +117 -36
  4. roms_tools/setup/datasets.py +5 -5
  5. roms_tools/setup/grid.py +8 -10
  6. roms_tools/setup/initial_conditions.py +63 -20
  7. roms_tools/setup/plot.py +68 -10
  8. roms_tools/setup/surface_forcing.py +23 -26
  9. roms_tools/setup/tides.py +18 -9
  10. roms_tools/setup/utils.py +15 -6
  11. roms_tools/tests/test_setup/test_boundary_forcing.py +98 -3
  12. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/0.0.0 +0 -0
  13. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_south/0.0.0 +0 -0
  14. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/0.0.0 +0 -0
  15. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/0.0.0 +0 -0
  16. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_south/0.0.0 +0 -0
  17. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/0.0.0 +0 -0
  18. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/0.0.0 +0 -0
  19. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_south/0.0.0 +0 -0
  20. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/0.0.0 +0 -0
  21. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/0.0.0 +0 -0
  22. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_south/0.0.0 +0 -0
  23. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/0.0.0 +0 -0
  24. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/0.0.0 +0 -0
  25. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_south/0.0.0 +0 -0
  26. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/0.0.0 +0 -0
  27. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/0.0.0 +0 -0
  28. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_south/0.0.0 +0 -0
  29. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/0.0.0 +0 -0
  30. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/0.0.0 +0 -0
  31. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_south/0.0.0 +0 -0
  32. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/0.0.0 +0 -0
  33. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/0.0.0 +0 -0
  34. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_south/0.0.0 +0 -0
  35. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/0.0.0 +0 -0
  36. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/0.0.0 +0 -0
  37. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_south/0.0.0 +0 -0
  38. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/0.0.0 +0 -0
  39. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/0.0.0 +0 -0
  40. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_south/0.0.0 +0 -0
  41. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/0.0.0 +0 -0
  42. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/0.0.0 +0 -0
  43. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_south/0.0.0 +0 -0
  44. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/0.0.0 +0 -0
  45. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/0.0.0 +0 -0
  46. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_south/0.0.0 +0 -0
  47. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/0.0.0 +0 -0
  48. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/0.0.0 +0 -0
  49. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_north/0.0.0 +0 -0
  50. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_south/0.0.0 +0 -0
  51. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/0.0.0 +0 -0
  52. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/0.0.0 +0 -0
  53. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_south/0.0.0 +0 -0
  54. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/0.0.0 +0 -0
  55. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/0.0.0 +0 -0
  56. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_south/0.0.0 +0 -0
  57. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/0.0.0 +0 -0
  58. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/0.0.0 +0 -0
  59. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_south/0.0.0 +0 -0
  60. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/0.0.0 +0 -0
  61. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/0.0.0 +0 -0
  62. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_south/0.0.0 +0 -0
  63. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/0.0.0 +0 -0
  64. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/0.0.0 +0 -0
  65. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_north/0.0.0 +0 -0
  66. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_south/0.0.0 +0 -0
  67. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/0.0.0 +0 -0
  68. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/0.0.0 +0 -0
  69. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_north/0.0.0 +0 -0
  70. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_south/0.0.0 +0 -0
  71. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/0.0.0 +0 -0
  72. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/0.0.0 +0 -0
  73. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_north/0.0.0 +0 -0
  74. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_south/0.0.0 +0 -0
  75. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/0.0.0 +0 -0
  76. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/0.0.0 +0 -0
  77. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_north/0.0.0 +0 -0
  78. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_south/0.0.0 +0 -0
  79. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/0.0.0 +0 -0
  80. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/0.0.0 +0 -0
  81. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_north/0.0.0 +0 -0
  82. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_south/0.0.0 +0 -0
  83. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/0.0.0 +0 -0
  84. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/0.0.0 +0 -0
  85. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_north/0.0.0 +0 -0
  86. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_south/0.0.0 +0 -0
  87. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/0.0.0 +0 -0
  88. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/0.0.0 +0 -0
  89. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_north/0.0.0 +0 -0
  90. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_south/0.0.0 +0 -0
  91. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/0.0.0 +0 -0
  92. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/0.0.0 +0 -0
  93. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_north/0.0.0 +0 -0
  94. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_south/0.0.0 +0 -0
  95. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/0.0.0 +0 -0
  96. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/0.0.0 +0 -0
  97. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_north/0.0.0 +0 -0
  98. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_south/0.0.0 +0 -0
  99. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/0.0.0 +0 -0
  100. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/0.0.0 +0 -0
  101. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_north/0.0.0 +0 -0
  102. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_south/0.0.0 +0 -0
  103. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/0.0.0 +0 -0
  104. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/0.0.0 +0 -0
  105. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_north/0.0.0 +0 -0
  106. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_south/0.0.0 +0 -0
  107. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/0.0.0 +0 -0
  108. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/0.0.0 +0 -0
  109. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_north/0.0.0 +0 -0
  110. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_south/0.0.0 +0 -0
  111. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/0.0.0 +0 -0
  112. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/0.0.0 +0 -0
  113. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_north/0.0.0 +0 -0
  114. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_south/0.0.0 +0 -0
  115. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/0.0.0 +0 -0
  116. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/0.0.0 +0 -0
  117. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_north/0.0.0 +0 -0
  118. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_south/0.0.0 +0 -0
  119. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/0.0.0 +0 -0
  120. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/0.0.0 +0 -0
  121. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_north/0.0.0 +0 -0
  122. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_south/0.0.0 +0 -0
  123. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/0.0.0 +0 -0
  124. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/.zmetadata +0 -7
  125. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zattrs +0 -3
  126. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/0.0.0 +0 -0
  127. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/0.0.0 +0 -0
  128. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/0.0.0 +0 -0
  129. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/0.0.0 +0 -0
  130. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/0.0.0 +0 -0
  131. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/0.0.0 +0 -0
  132. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/0.0.0 +0 -0
  133. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/0.0 +0 -0
  134. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/0.0 +0 -0
  135. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/0.0 +0 -0
  136. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/0.0.0 +0 -0
  137. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/0.0.0 +0 -0
  138. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/0.0.0 +0 -0
  139. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/0.0.0 +0 -0
  140. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/0.0 +0 -0
  141. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/0.0 +0 -0
  142. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/0.0 +0 -0
  143. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/0.0 +0 -0
  144. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zattrs +0 -1
  145. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/0.0 +0 -0
  146. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/.zattrs +0 -1
  147. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zattrs +0 -1
  148. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/0.0 +0 -0
  149. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/.zattrs +0 -1
  150. roms_tools/tests/test_setup/test_datasets.py +8 -3
  151. roms_tools/tests/test_setup/test_grid.py +6 -5
  152. {roms_tools-1.6.1.dist-info → roms_tools-1.6.2.dist-info}/METADATA +1 -1
  153. {roms_tools-1.6.1.dist-info → roms_tools-1.6.2.dist-info}/RECORD +156 -156
  154. {roms_tools-1.6.1.dist-info → roms_tools-1.6.2.dist-info}/LICENSE +0 -0
  155. {roms_tools-1.6.1.dist-info → roms_tools-1.6.2.dist-info}/WHEEL +0 -0
  156. {roms_tools-1.6.1.dist-info → roms_tools-1.6.2.dist-info}/top_level.txt +0 -0
roms_tools/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from importlib.metadata import version as _version
2
-
2
+ import logging # noqa: F811
3
3
 
4
4
  try:
5
5
  __version__ = _version("roms_tools")
@@ -13,3 +13,6 @@ from roms_tools.setup.tides import TidalForcing # noqa: F401
13
13
  from roms_tools.setup.surface_forcing import SurfaceForcing # noqa: F401
14
14
  from roms_tools.setup.initial_conditions import InitialConditions # noqa: F401
15
15
  from roms_tools.setup.boundary_forcing import BoundaryForcing # noqa: F401
16
+
17
+ # Configure logging when the package is imported
18
+ logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s")
roms_tools/_version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # Do not change! Do not track in version control!
2
- __version__ = "1.6.1"
2
+ __version__ = "1.6.2"
@@ -1,9 +1,10 @@
1
1
  import xarray as xr
2
2
  import numpy as np
3
3
  import pandas as pd
4
+ from scipy.ndimage import label
5
+ import logging
4
6
  import yaml
5
7
  import importlib.metadata
6
- import warnings
7
8
  from typing import Dict, Union, List
8
9
  from dataclasses import dataclass, field, asdict
9
10
  from roms_tools.setup.grid import Grid
@@ -197,6 +198,13 @@ class BoundaryForcing:
197
198
  ].isel(**bdry_coords[location][direction])
198
199
 
199
200
  if not self.apply_2d_horizontal_fill:
201
+ self._validate_1d_fill(
202
+ processed_fields,
203
+ variable_info,
204
+ bdry_coords,
205
+ direction,
206
+ bdry_data.dim_names["depth"],
207
+ )
200
208
  processed_fields = apply_1d_horizontal_fill(processed_fields)
201
209
 
202
210
  # vertical regridding
@@ -329,38 +337,46 @@ class BoundaryForcing:
329
337
  "is_vector": False,
330
338
  "vector_pair": None,
331
339
  "is_3d": False,
340
+ "validate": True,
332
341
  },
333
- "temp": default_info,
334
- "salt": default_info,
342
+ "temp": {**default_info, "validate": True},
343
+ "salt": {**default_info, "validate": False},
335
344
  "u": {
336
345
  "location": "u",
337
346
  "is_vector": True,
338
347
  "vector_pair": "v",
339
348
  "is_3d": True,
349
+ "validate": True,
340
350
  },
341
351
  "v": {
342
352
  "location": "v",
343
353
  "is_vector": True,
344
354
  "vector_pair": "u",
345
355
  "is_3d": True,
356
+ "validate": True,
346
357
  },
347
358
  "ubar": {
348
359
  "location": "u",
349
360
  "is_vector": True,
350
361
  "vector_pair": "vbar",
351
362
  "is_3d": False,
363
+ "validate": False,
352
364
  },
353
365
  "vbar": {
354
366
  "location": "v",
355
367
  "is_vector": True,
356
368
  "vector_pair": "ubar",
357
369
  "is_3d": False,
370
+ "validate": False,
358
371
  },
359
372
  }
360
373
  elif self.type == "bgc":
361
374
  variable_info = {}
362
375
  for var_name in data.var_names.keys():
363
- variable_info[var_name] = default_info
376
+ if var_name == "ALK":
377
+ variable_info[var_name] = {**default_info, "validate": True}
378
+ else:
379
+ variable_info[var_name] = {**default_info, "validate": False}
364
380
 
365
381
  return variable_info
366
382
 
@@ -506,9 +522,78 @@ class BoundaryForcing:
506
522
 
507
523
  return ds
508
524
 
525
+ def _validate_1d_fill(
526
+ self, processed_fields, variable_info, bdry_coords, direction, depth_dim
527
+ ):
528
+ """Check if any boundary is divided by land and issue a warning if so,
529
+ suggesting the use of 2D horizontal fill for safer regridding.
530
+
531
+ Parameters
532
+ ----------
533
+ processed_fields : dict
534
+ A dictionary where keys are variable names and values are `xarray.DataArray`
535
+ objects representing the processed data for each variable.
536
+
537
+ variable_info : dict
538
+ A dictionary containing metadata about each variable (e.g., location,
539
+ whether it's a 3D variable, etc.). Used to retrieve information for
540
+ validating each variable.
541
+
542
+ bdry_coords : dict
543
+ A dictionary containing boundary coordinates for different directions (north, south,
544
+ east, west), used to slice the boundary-specific data for each variable.
545
+
546
+ direction : str
547
+ The boundary direction being processed (e.g., "north", "south", "east", or "west").
548
+
549
+ depth_dim : str
550
+ The dimension representing depth (e.g., 'z', 'depth', etc.), used when slicing 3D
551
+ data for a specific depth level.
552
+
553
+ Returns
554
+ -------
555
+ None
556
+ If a boundary is divided by land, a warning is issued. No return value is provided.
557
+ """
558
+
559
+ for var_name in processed_fields.keys():
560
+ # Only validate variables based on "validate" flag if use_dask is False
561
+ if not self.use_dask or variable_info[var_name]["validate"]:
562
+ location = variable_info[var_name]["location"]
563
+
564
+ # Select the appropriate mask based on variable location
565
+ if location == "rho":
566
+ mask = self.grid.ds.mask_rho
567
+ elif location == "u":
568
+ mask = self.grid.ds.mask_u
569
+ elif location == "v":
570
+ mask = self.grid.ds.mask_v
571
+
572
+ mask = mask.isel(**bdry_coords[location][direction])
573
+
574
+ if variable_info[var_name]["is_3d"]:
575
+ da = processed_fields[var_name].isel({depth_dim: 0, "time": 0})
576
+ else:
577
+ da = processed_fields[var_name].isel({"time": 0})
578
+
579
+ wet_nans = xr.where(da.where(mask).isnull(), 1, 0)
580
+ # Apply label to find connected components of wet NaNs
581
+ labeled_array, num_features = label(wet_nans)
582
+ left_margin = labeled_array[0]
583
+ right_margin = labeled_array[-1]
584
+ if left_margin != 0:
585
+ num_features = num_features - 1
586
+ if right_margin != 0:
587
+ num_features = num_features - 1
588
+ if num_features > 0:
589
+ logging.warning(
590
+ f"For {var_name}, the {direction}ern boundary is divided by land. It would be safer (but slower) to use `apply_2d_horizontal_fill = True`."
591
+ )
592
+
509
593
  def _validate(self, ds, variable_info, bdry_coords):
510
- """Validate the dataset for NaN values at the first time step based on the fill
511
- method used.
594
+ """Validate the dataset for NaN values at the first time step (bry_time=0) for
595
+ specified variables. If NaN values are found at wet points, this function raises
596
+ an error.
512
597
 
513
598
  Parameters
514
599
  ----------
@@ -530,14 +615,11 @@ class BoundaryForcing:
530
615
  Notes
531
616
  -----
532
617
  Validation is performed on the initial boundary time step (`bry_time=0`) for each
533
- variable in the dataset. If the `apply_2d_horizontal_fill` attribute is set to False,
534
- a warning is issued instead of a strict NaN check, as the data may not be reliably validated.
535
- Conversely, if `apply_2d_horizontal_fill` is True, a strict NaN check is performed, raising
536
- a ValueError if any NaN values are detected.
618
+ variable in the dataset.
537
619
  """
538
- if self.apply_2d_horizontal_fill:
539
- # Strict NaN check with ValueError makes sense to be applied
540
- for var_name in variable_info:
620
+ for var_name in variable_info:
621
+ # only validate variables based on "validate" flag if use_dask is false
622
+ if not self.use_dask or variable_info[var_name]["validate"]:
541
623
  location = variable_info[var_name]["location"]
542
624
 
543
625
  # Select the appropriate mask based on variable location
@@ -547,38 +629,29 @@ class BoundaryForcing:
547
629
  mask = self.grid.ds.mask_u
548
630
  elif location == "v":
549
631
  mask = self.grid.ds.mask_v
550
- else:
551
- continue # Skip if location is not recognized
552
632
 
553
633
  for direction in ["south", "east", "north", "west"]:
554
634
  if self.boundaries[direction]:
555
635
  bdry_var_name = f"{var_name}_{direction}"
556
636
 
557
637
  # Check for NaN values at the first time step using the nan_check function
638
+ if self.apply_2d_horizontal_fill:
639
+ error_message = None
640
+ else:
641
+ error_message = (
642
+ f"{bdry_var_name} consists entirely of NaNs after regridding. "
643
+ f"This may be due to the {direction}ern boundary being on land in the "
644
+ f"{self.source['name']} data, which could have a coarser resolution than the ROMS domain. "
645
+ f"Try setting `apply_2d_horizontal_fill = True` to resolve this issue."
646
+ )
647
+
558
648
  nan_check(
559
649
  ds[bdry_var_name].isel(bry_time=0),
560
650
  mask.isel(**bdry_coords[location][direction]),
651
+ error_message=error_message,
561
652
  )
562
- else:
563
- # Can't apply strict NaN check because land values haven't been filled before regridding step; instead warn user
564
- for direction in ["south", "east", "north", "west"]:
565
- if self.boundaries[direction]:
566
- for var_name in variable_info:
567
- bdry_var_name = f"{var_name}_{direction}"
568
- if ds[bdry_var_name].isel(bry_time=0).isnull().any().values:
569
- warnings.warn(
570
- f"NaN values detected in regridded variables along the {direction}ern boundary. This may indicate that the entire boundary is on land in the source data, or that the source data does not cover this boundary.",
571
- UserWarning,
572
- )
573
- # Break after the first warning for this direction to avoid duplicates
574
- break
575
653
 
576
- def plot(
577
- self,
578
- var_name,
579
- time=0,
580
- layer_contours=False,
581
- ) -> None:
654
+ def plot(self, var_name, time=0, layer_contours=False, ax=None) -> None:
582
655
  """Plot the boundary forcing field for a given time-slice.
583
656
 
584
657
  Parameters
@@ -634,6 +707,8 @@ class BoundaryForcing:
634
707
  If True, contour lines representing the boundaries between vertical layers will
635
708
  be added to the plot. For clarity, the number of layer
636
709
  contours displayed is limited to a maximum of 10. Default is False.
710
+ ax : matplotlib.axes.Axes, optional
711
+ The axes to plot on. If None, a new figure is created.
637
712
 
638
713
  Returns
639
714
  -------
@@ -700,10 +775,14 @@ class BoundaryForcing:
700
775
  interface_depth = None
701
776
 
702
777
  _section_plot(
703
- field, interface_depth=interface_depth, title=title, kwargs=kwargs
778
+ field,
779
+ interface_depth=interface_depth,
780
+ title=title,
781
+ kwargs=kwargs,
782
+ ax=ax,
704
783
  )
705
784
  else:
706
- _line_plot(field, title=title)
785
+ _line_plot(field, title=title, ax=ax)
707
786
 
708
787
  def save(
709
788
  self,
@@ -805,6 +884,7 @@ class BoundaryForcing:
805
884
  "boundaries": self.boundaries,
806
885
  "source": self.source,
807
886
  "type": self.type,
887
+ "apply_2d_horizontal_fill": self.apply_2d_horizontal_fill,
808
888
  "model_reference_date": self.model_reference_date.isoformat(),
809
889
  }
810
890
  }
@@ -952,6 +1032,7 @@ def apply_1d_horizontal_fill(processed_fields: dict) -> dict:
952
1032
  raise ValueError(
953
1033
  f"No valid horizontal dimension found for variable '{var_name}'."
954
1034
  )
1035
+
955
1036
  # Forward and backward fill in the horizontal direction
956
1037
  filled = one_dim_fill(
957
1038
  processed_fields[var_name], selected_horizontal_dim, direction="forward"
@@ -6,7 +6,7 @@ from datetime import datetime, timedelta
6
6
  import numpy as np
7
7
  from typing import Dict, Optional, Union, List
8
8
  from pathlib import Path
9
- import warnings
9
+ import logging
10
10
  from roms_tools.setup.utils import (
11
11
  assign_dates_to_climatology,
12
12
  interpolate_from_climatology,
@@ -410,7 +410,7 @@ class Dataset:
410
410
  ds[time_dim].where(before_start, drop=True).max()
411
411
  )
412
412
  else:
413
- warnings.warn("No records found at or before the start_time.")
413
+ logging.warning("No records found at or before the start_time.")
414
414
  closest_before_start = ds[time_dim].min()
415
415
 
416
416
  # Identify records after or at end_time
@@ -420,7 +420,7 @@ class Dataset:
420
420
  ds[time_dim].where(after_end, drop=True).min()
421
421
  )
422
422
  else:
423
- warnings.warn("No records found at or after the end_time.")
423
+ logging.warning("No records found at or after the end_time.")
424
424
  closest_after_end = ds[time_dim].max()
425
425
 
426
426
  # Select records within the time range and add the closest before/after
@@ -451,11 +451,11 @@ class Dataset:
451
451
  if ds.sizes[time_dim] > 1:
452
452
  # Pick the time closest to self.start_time
453
453
  ds = ds.isel({time_dim: 0})
454
- print(
454
+ logging.info(
455
455
  f"Selected time entry closest to the specified start_time ({self.start_time}) within the range [{self.start_time}, {self.start_time + timedelta(hours=24)}]: {ds[time_dim].values}"
456
456
  )
457
457
  else:
458
- warnings.warn(
458
+ logging.warning(
459
459
  "Dataset does not contain any time information. Please check if the time dimension "
460
460
  "is correctly named or if the dataset includes time data."
461
461
  )
roms_tools/setup/grid.py CHANGED
@@ -13,7 +13,7 @@ from roms_tools.setup.plot import _plot, _section_plot, _profile_plot, _line_plo
13
13
  from roms_tools.setup.utils import interpolate_from_rho_to_u, interpolate_from_rho_to_v
14
14
  from roms_tools.setup.vertical_coordinate import sigma_stretch, compute_depth
15
15
  from roms_tools.setup.utils import extract_single_value, save_datasets
16
- import warnings
16
+ import logging
17
17
  from pathlib import Path
18
18
 
19
19
  RADIUS_OF_EARTH = 6371315.0 # in m
@@ -350,11 +350,7 @@ class Grid:
350
350
  _plot(self.ds, straddle=self.straddle)
351
351
 
352
352
  def plot_vertical_coordinate(
353
- self,
354
- varname="layer_depth_rho",
355
- s=None,
356
- eta=None,
357
- xi=None,
353
+ self, varname="layer_depth_rho", s=None, eta=None, xi=None, ax=None
358
354
  ) -> None:
359
355
  """Plot the vertical coordinate system for a given eta-, xi-, or s-slice.
360
356
 
@@ -376,6 +372,8 @@ class Grid:
376
372
  The eta-index to plot. Default is None.
377
373
  xi : int, optional
378
374
  The xi-index to plot. Default is None.
375
+ ax : matplotlib.axes.Axes, optional
376
+ The axes to plot on. If None, a new figure is created. Note that this argument does not work for horizontal plots that display the eta- and xi-dimensions at the same time.
379
377
 
380
378
  Returns
381
379
  -------
@@ -477,12 +475,13 @@ class Grid:
477
475
  interface_depth=interface_depth,
478
476
  title=title,
479
477
  kwargs=kwargs,
478
+ ax=ax,
480
479
  )
481
480
  else:
482
481
  if "s_rho" in field.dims or "s_w" in field.dims:
483
- _profile_plot(field, title=title)
482
+ _profile_plot(field, title=title, ax=ax)
484
483
  else:
485
- _line_plot(field, title=title)
484
+ _line_plot(field, title=title, ax=ax)
486
485
 
487
486
  def save(
488
487
  self, filepath: Union[str, Path], np_eta: int = None, np_xi: int = None
@@ -728,9 +727,8 @@ class Grid:
728
727
  roms_tools_version_current = "unknown"
729
728
 
730
729
  if roms_tools_version_header != roms_tools_version_current:
731
- warnings.warn(
730
+ logging.warning(
732
731
  f"Current roms-tools version ({roms_tools_version_current}) does not match the version in the YAML header ({roms_tools_version_header}).",
733
- UserWarning,
734
732
  )
735
733
 
736
734
  if grid_data is None:
@@ -91,14 +91,13 @@ class InitialConditions:
91
91
  self._input_checks()
92
92
 
93
93
  processed_fields = {}
94
- processed_fields = self._process_data(processed_fields, type="physics")
94
+ processed_fields, variable_info = self._process_data(
95
+ processed_fields, type="physics"
96
+ )
95
97
 
96
98
  if self.bgc_source is not None:
97
- processed_fields = self._process_data(processed_fields, type="bgc")
98
-
99
- for var_name in processed_fields.keys():
100
- processed_fields[var_name] = transpose_dimensions(
101
- processed_fields[var_name]
99
+ processed_fields, bgc_variable_info = self._process_data(
100
+ processed_fields, type="bgc"
102
101
  )
103
102
 
104
103
  d_meta = get_variable_metadata()
@@ -106,7 +105,9 @@ class InitialConditions:
106
105
 
107
106
  ds = self._add_global_metadata(ds)
108
107
 
109
- self._validate(ds)
108
+ if self.bgc_source is not None:
109
+ variable_info = {**variable_info, **bgc_variable_info}
110
+ self._validate(ds, variable_info)
110
111
 
111
112
  # substitute NaNs over land by a fill value to avoid blow-up of ROMS
112
113
  for var_name in ds.data_vars:
@@ -184,7 +185,12 @@ class InitialConditions:
184
185
  {"time": processed_fields["temp"]["time"]}
185
186
  )
186
187
 
187
- return processed_fields
188
+ for var_name in processed_fields.keys():
189
+ processed_fields[var_name] = transpose_dimensions(
190
+ processed_fields[var_name]
191
+ )
192
+
193
+ return processed_fields, variable_info
188
194
 
189
195
  def _input_checks(self):
190
196
 
@@ -259,11 +265,21 @@ class InitialConditions:
259
265
  - `vector_pair`: For vector variables, this indicates the associated variable that forms the vector (e.g., 'u' and 'v').
260
266
  - `is_3d`: Indicates whether the variable is 3D (True for variables like 'temp' and 'salt') or 2D (False for 'zeta').
261
267
 
268
+ Parameters
269
+ ----------
270
+ data : object
271
+ The data object which contains variable names for the "bgc" type variables.
272
+
273
+ type : str, optional, default="physics"
274
+ The type of variable metadata to return. Can be one of:
275
+ - "physics": for physical variables such as temperature, salinity, and velocity components.
276
+ - "bgc": for biogeochemical variables (like ALK).
277
+
262
278
  Returns
263
279
  -------
264
280
  dict
265
281
  A dictionary where the keys are variable names and the values are dictionaries of metadata
266
- about each variable, including 'location', 'is_vector', 'vector_pair', and 'is_3d'.
282
+ about each variable, including 'location', 'is_vector', 'vector_pair', 'is_3d', and 'validate'.
267
283
  """
268
284
  default_info = {
269
285
  "location": "rho",
@@ -272,7 +288,6 @@ class InitialConditions:
272
288
  "is_3d": True,
273
289
  }
274
290
 
275
- # Define a dictionary for variable names and their associated information
276
291
  if type == "physics":
277
292
  variable_info = {
278
293
  "zeta": {
@@ -280,38 +295,54 @@ class InitialConditions:
280
295
  "is_vector": False,
281
296
  "vector_pair": None,
282
297
  "is_3d": False,
298
+ "validate": True,
283
299
  },
284
- "temp": default_info,
285
- "salt": default_info,
300
+ "temp": {**default_info, "validate": False},
301
+ "salt": {**default_info, "validate": False},
286
302
  "u": {
287
303
  "location": "u",
288
304
  "is_vector": True,
289
305
  "vector_pair": "v",
290
306
  "is_3d": True,
307
+ "validate": False,
291
308
  },
292
309
  "v": {
293
310
  "location": "v",
294
311
  "is_vector": True,
295
312
  "vector_pair": "u",
296
313
  "is_3d": True,
314
+ "validate": False,
297
315
  },
298
316
  "ubar": {
299
317
  "location": "u",
300
318
  "is_vector": True,
301
319
  "vector_pair": "vbar",
302
320
  "is_3d": False,
321
+ "validate": False,
303
322
  },
304
323
  "vbar": {
305
324
  "location": "v",
306
325
  "is_vector": True,
307
326
  "vector_pair": "ubar",
308
327
  "is_3d": False,
328
+ "validate": False,
329
+ },
330
+ "w": {
331
+ "location": "rho",
332
+ "is_vector": False,
333
+ "vector_pair": None,
334
+ "is_3d": True,
335
+ "validate": False,
309
336
  },
310
337
  }
311
- elif type == "bgc":
338
+
339
+ if type == "bgc":
312
340
  variable_info = {}
313
341
  for var_name in data.var_names.keys():
314
- variable_info[var_name] = default_info
342
+ if var_name == "ALK":
343
+ variable_info[var_name] = {**default_info, "validate": True}
344
+ else:
345
+ variable_info[var_name] = {**default_info, "validate": False}
315
346
 
316
347
  return variable_info
317
348
 
@@ -373,7 +404,7 @@ class InitialConditions:
373
404
 
374
405
  return ds
375
406
 
376
- def _validate(self, ds):
407
+ def _validate(self, ds, variable_info):
377
408
  """Validates the dataset by checking for NaN values in SSH at wet points, which
378
409
  would indicate missing raw data coverage over the target domain.
379
410
 
@@ -381,6 +412,8 @@ class InitialConditions:
381
412
  ----------
382
413
  ds : xarray.Dataset
383
414
  The dataset to validate.
415
+ variable_info : dict
416
+ A dictionary containing metadata about the variables, including whether to validate them.
384
417
 
385
418
  Raises
386
419
  ------
@@ -393,8 +426,11 @@ class InitialConditions:
393
426
  This check is only applied to the 2D variable SSH to improve performance.
394
427
  """
395
428
 
396
- ds["zeta"].load()
397
- nan_check(ds["zeta"].squeeze(), self.grid.ds.mask_rho)
429
+ for var_name in variable_info:
430
+ # Only validate variables based on "validate" flag if use_dask is False
431
+ if not self.use_dask or variable_info[var_name]["validate"]:
432
+ ds[var_name].load()
433
+ nan_check(ds[var_name].squeeze(), self.grid.ds.mask_rho)
398
434
 
399
435
  def _add_global_metadata(self, ds):
400
436
 
@@ -425,6 +461,7 @@ class InitialConditions:
425
461
  xi=None,
426
462
  depth_contours=False,
427
463
  layer_contours=False,
464
+ ax=None,
428
465
  ) -> None:
429
466
  """Plot the initial conditions field for a given eta-, xi-, or s_rho- slice.
430
467
 
@@ -492,6 +529,8 @@ class InitialConditions:
492
529
  be added to the plot. This is particularly useful in vertical sections to
493
530
  visualize the layering of the water column. For clarity, the number of layer
494
531
  contours displayed is limited to a maximum of 10. Default is False.
532
+ ax : matplotlib.axes.Axes, optional
533
+ The axes to plot on. If None, a new figure is created. Note that this argument does not work for horizontal plots that display the eta- and xi-dimensions at the same time.
495
534
 
496
535
  Returns
497
536
  -------
@@ -639,13 +678,17 @@ class InitialConditions:
639
678
 
640
679
  if len(field.dims) == 2:
641
680
  _section_plot(
642
- field, interface_depth=interface_depth, title=title, kwargs=kwargs
681
+ field,
682
+ interface_depth=interface_depth,
683
+ title=title,
684
+ kwargs=kwargs,
685
+ ax=ax,
643
686
  )
644
687
  else:
645
688
  if "s_rho" in field.dims:
646
- _profile_plot(field, title=title)
689
+ _profile_plot(field, title=title, ax=ax)
647
690
  else:
648
- _line_plot(field, title=title)
691
+ _line_plot(field, title=title, ax=ax)
649
692
 
650
693
  def save(
651
694
  self, filepath: Union[str, Path], np_eta: int = None, np_xi: int = None