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/setup/plot.py CHANGED
@@ -12,6 +12,32 @@ def _plot(
12
12
  title="",
13
13
  kwargs={},
14
14
  ):
15
+ """Plots a grid or field on a map with optional depth contours.
16
+
17
+ This function plots a map using Cartopy projections. It supports plotting a grid, a field, and adding depth contours if desired.
18
+ The projection can be customized, and the grid can be adjusted for domains straddling the 180° meridian.
19
+
20
+ Parameters
21
+ ----------
22
+ grid_ds : xarray.Dataset
23
+ The grid dataset containing coordinates (`lon_rho`, `lat_rho`).
24
+ field : xarray.DataArray, optional
25
+ The field to plot. If None, only the grid is plotted.
26
+ depth_contours : bool, optional
27
+ If True, adds depth contours to the plot.
28
+ straddle : bool, optional
29
+ If True, adjusts longitude values to straddle across the 180° meridian.
30
+ c : str, optional
31
+ Color for the boundary plot (default is 'red').
32
+ title : str, optional
33
+ Title of the plot.
34
+ kwargs : dict, optional
35
+ Additional keyword arguments to pass to `pcolormesh` (e.g., colormap or color limits).
36
+
37
+ Notes
38
+ -----
39
+ The function raises a `NotImplementedError` if the domain contains the North or South Pole.
40
+ """
15
41
 
16
42
  if field is None:
17
43
  lon_deg = grid_ds["lon_rho"]
@@ -84,12 +110,11 @@ def _plot(
84
110
  cs = ax.contour(lon_deg, lat_deg, field.layer_depth, transform=proj, colors="k")
85
111
  ax.clabel(cs, inline=True, fontsize=10)
86
112
 
87
- return fig
88
113
 
114
+ def _section_plot(field, interface_depth=None, title="", kwargs={}, ax=None):
89
115
 
90
- def _section_plot(field, interface_depth=None, title="", kwargs={}):
91
-
92
- fig, ax = plt.subplots(1, 1, figsize=(9, 5))
116
+ if ax is None:
117
+ fig, ax = plt.subplots(1, 1, figsize=(9, 5))
93
118
 
94
119
  dims_to_check = ["eta_rho", "eta_u", "eta_v", "xi_rho", "xi_u", "xi_v"]
95
120
  try:
@@ -132,7 +157,23 @@ def _section_plot(field, interface_depth=None, title="", kwargs={}):
132
157
  ax.set_title(title)
133
158
 
134
159
 
135
- def _profile_plot(field, title=""):
160
+ def _profile_plot(field, title="", ax=None):
161
+ """Plots a profile of the given field against depth.
162
+
163
+ Parameters
164
+ ----------
165
+ field : xarray.DataArray
166
+ Data to plot.
167
+ title : str, optional
168
+ Title of the plot.
169
+ ax : matplotlib.axes.Axes, optional
170
+ Axes to plot on. If None, a new figure is created.
171
+
172
+ Raises
173
+ ------
174
+ ValueError
175
+ If no expected depth coordinate is found in the field.
176
+ """
136
177
 
137
178
  depths_to_check = [
138
179
  "layer_depth_rho",
@@ -153,16 +194,33 @@ def _profile_plot(field, title=""):
153
194
  "None of the expected coordinates (layer_depth_rho, layer_depth_u, layer_depth_v, interface_depth_rho, interface_depth_u, interface_depth_v) found in field.coords"
154
195
  )
155
196
 
156
- fig, ax = plt.subplots(1, 1, figsize=(4, 7))
197
+ if ax is None:
198
+ fig, ax = plt.subplots(1, 1, figsize=(4, 7))
157
199
  kwargs = {"y": depth_label, "yincrease": False}
158
200
  field.plot(**kwargs)
159
201
  ax.set_title(title)
160
202
  ax.grid()
161
203
 
162
204
 
163
- def _line_plot(field, title=""):
164
-
165
- fig, ax = plt.subplots(1, 1, figsize=(7, 4))
166
- field.plot()
205
+ def _line_plot(field, title="", ax=None):
206
+ """Plots a line graph of the given field.
207
+
208
+ Parameters
209
+ ----------
210
+ field : xarray.DataArray
211
+ Data to plot.
212
+ title : str, optional
213
+ Title of the plot.
214
+ ax : matplotlib.axes.Axes, optional
215
+ Axes to plot on. If None, a new figure is created.
216
+
217
+ Returns
218
+ -------
219
+ None
220
+ Modifies the plot in-place.
221
+ """
222
+ if ax is None:
223
+ fig, ax = plt.subplots(1, 1, figsize=(7, 4))
224
+ field.plot(ax=ax)
167
225
  ax.set_title(title)
168
226
  ax.grid()
@@ -133,14 +133,7 @@ class SurfaceForcing:
133
133
 
134
134
  ds = self._write_into_dataset(processed_fields, data, d_meta)
135
135
 
136
- if self.use_coarse_grid:
137
- mask = self.grid.ds["mask_coarse"].rename(
138
- {"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}
139
- )
140
- else:
141
- mask = self.grid.ds["mask_rho"]
142
-
143
- self._validate(ds, mask)
136
+ self._validate(ds, target_coords["mask"], variable_info)
144
137
 
145
138
  # substitute NaNs over land by a fill value to avoid blow-up of ROMS
146
139
  for var_name in ds.data_vars:
@@ -233,28 +226,34 @@ class SurfaceForcing:
233
226
  # Define a dictionary for variable names and their associated information
234
227
  if self.type == "physics":
235
228
  variable_info = {
236
- "swrad": default_info,
237
- "lwrad": default_info,
238
- "Tair": default_info,
239
- "qair": default_info,
240
- "rain": default_info,
229
+ "swrad": {**default_info, "validate": True},
230
+ "lwrad": {**default_info, "validate": False},
231
+ "Tair": {**default_info, "validate": False},
232
+ "qair": {**default_info, "validate": True},
233
+ "rain": {**default_info, "validate": False},
241
234
  "uwnd": {
242
235
  "location": "u",
243
236
  "is_vector": True,
244
237
  "vector_pair": "vwnd",
245
238
  "is_3d": False,
239
+ "validate": True,
246
240
  },
247
241
  "vwnd": {
248
242
  "location": "v",
249
243
  "is_vector": True,
250
244
  "vector_pair": "uwnd",
251
245
  "is_3d": False,
246
+ "validate": True,
252
247
  },
253
248
  }
254
249
  elif self.type == "bgc":
255
250
  variable_info = {}
256
- for var in data.var_names.keys():
257
- variable_info[var] = default_info
251
+ for var_name in data.var_names.keys():
252
+ variable_info[var_name] = default_info
253
+ if var_name == "pco2_air":
254
+ variable_info[var_name] = {**default_info, "validate": True}
255
+ else:
256
+ variable_info[var_name] = {**default_info, "validate": False}
258
257
 
259
258
  return variable_info
260
259
 
@@ -300,9 +299,6 @@ class SurfaceForcing:
300
299
  ds[var_name].attrs["long_name"] = d_meta[var_name]["long_name"]
301
300
  ds[var_name].attrs["units"] = d_meta[var_name]["units"]
302
301
 
303
- if self.use_coarse_grid:
304
- ds = ds.rename({"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"})
305
-
306
302
  ds = self._add_global_metadata(ds)
307
303
 
308
304
  # Convert the time coordinate to the format expected by ROMS
@@ -369,7 +365,7 @@ class SurfaceForcing:
369
365
 
370
366
  return ds
371
367
 
372
- def _validate(self, ds, mask):
368
+ def _validate(self, ds, mask, variable_info):
373
369
  """Validates the dataset by checking for NaN values at wet points, which would
374
370
  indicate missing raw data coverage over the target domain.
375
371
 
@@ -379,6 +375,10 @@ class SurfaceForcing:
379
375
  The dataset to validate.
380
376
  mask : xarray.DataArray
381
377
  Land mask (1=ocean, 0=land) to determine wet points in the domain.
378
+ variable_info : dict
379
+ A dictionary containing metadata about each variable (e.g., location,
380
+ whether it's a 3D variable, etc.). Used to retrieve information for
381
+ validating each variable.
382
382
 
383
383
  Raises
384
384
  ------
@@ -392,7 +392,9 @@ class SurfaceForcing:
392
392
  """
393
393
 
394
394
  for var_name in ds.data_vars:
395
- nan_check(ds[var_name].isel(time=0), mask)
395
+ # Only validate variables based on "validate" flag if use_dask is False
396
+ if not self.use_dask or variable_info[var_name]["validate"]:
397
+ nan_check(ds[var_name].isel(time=0), mask)
396
398
 
397
399
  def _add_global_metadata(self, ds=None):
398
400
 
@@ -471,12 +473,7 @@ class SurfaceForcing:
471
473
 
472
474
  title = field.long_name
473
475
 
474
- # assign lat / lon
475
- if self.use_coarse_grid:
476
- field = field.rename({"eta_rho": "eta_coarse", "xi_rho": "xi_coarse"})
477
- field = field.where(self.grid.ds.mask_coarse)
478
- else:
479
- field = field.where(self.grid.ds.mask_rho)
476
+ field = field.where(self.target_coords["mask"])
480
477
 
481
478
  field = field.assign_coords(
482
479
  {"lon": self.target_coords["lon"], "lat": self.target_coords["lat"]}
roms_tools/setup/tides.py CHANGED
@@ -129,7 +129,7 @@ class TidalForcing:
129
129
 
130
130
  ds = self._add_global_metadata(ds)
131
131
 
132
- self._validate(ds)
132
+ self._validate(ds, variable_info)
133
133
 
134
134
  # substitute NaNs over land by a fill value to avoid blow-up of ROMS
135
135
  for var_name in ds.data_vars:
@@ -176,33 +176,37 @@ class TidalForcing:
176
176
 
177
177
  # Define a dictionary for variable names and their associated information
178
178
  variable_info = {
179
- "ssh_Re": default_info,
180
- "ssh_Im": default_info,
181
- "pot_Re": default_info,
182
- "pot_Im": default_info,
179
+ "ssh_Re": {**default_info, "validate": True},
180
+ "ssh_Im": {**default_info, "validate": False},
181
+ "pot_Re": {**default_info, "validate": False},
182
+ "pot_Im": {**default_info, "validate": False},
183
183
  "u_Re": {
184
184
  "location": "u",
185
185
  "is_vector": True,
186
186
  "vector_pair": "v_Re",
187
187
  "is_3d": False,
188
+ "validate": True,
188
189
  },
189
190
  "v_Re": {
190
191
  "location": "v",
191
192
  "is_vector": True,
192
193
  "vector_pair": "u_Re",
193
194
  "is_3d": False,
195
+ "validate": True,
194
196
  },
195
197
  "u_Im": {
196
198
  "location": "u",
197
199
  "is_vector": True,
198
200
  "vector_pair": "v_Im",
199
201
  "is_3d": False,
202
+ "validate": False,
200
203
  },
201
204
  "v_Im": {
202
205
  "location": "v",
203
206
  "is_vector": True,
204
207
  "vector_pair": "u_Im",
205
208
  "is_3d": False,
209
+ "validate": False,
206
210
  },
207
211
  }
208
212
 
@@ -239,14 +243,17 @@ class TidalForcing:
239
243
 
240
244
  return ds
241
245
 
242
- def _validate(self, ds):
243
- """Validates the dataset by checking for NaN values at wet points, which would
244
- indicate missing raw data coverage over the target domain.
246
+ def _validate(self, ds, variable_info):
247
+ """Validates the dataset by checking for NaN values at wet points for specified
248
+ variables, which would indicate missing raw data coverage over the target
249
+ domain.
245
250
 
246
251
  Parameters
247
252
  ----------
248
253
  ds : xarray.Dataset
249
254
  The dataset to validate, containing tidal variables and a mask for wet points.
255
+ variable_info : dict
256
+ A dictionary containing metadata about the variables, including whether to validate them.
250
257
 
251
258
  Raises
252
259
  ------
@@ -260,7 +267,9 @@ class TidalForcing:
260
267
  The method utilizes `self.grid.ds.mask_rho` to determine the wet points in the domain.
261
268
  """
262
269
  for var_name in ds.data_vars:
263
- nan_check(ds[var_name].isel(ntides=0), self.grid.ds.mask_rho)
270
+ # only validate variables based on "validate" flag if use_dask is false
271
+ if not self.use_dask or variable_info[var_name]["validate"]:
272
+ nan_check(ds[var_name].isel(ntides=0), self.grid.ds.mask_rho)
264
273
 
265
274
  def plot(self, var_name, ntides=0) -> None:
266
275
  """Plot the specified tidal forcing variable for a given tidal constituent.
roms_tools/setup/utils.py CHANGED
@@ -724,23 +724,31 @@ def get_target_coords(grid, use_coarse_grid=False):
724
724
  Returns
725
725
  -------
726
726
  dict
727
- Dictionary containing the longitude, latitude, and angle arrays, along with a boolean indicating
727
+ Dictionary containing the longitude, latitude, angle and mask arrays, along with a boolean indicating
728
728
  if the grid straddles the meridian.
729
729
  """
730
730
  # Select grid variables based on whether the coarse grid is used
731
731
  if use_coarse_grid:
732
- lat, lon, angle = (
733
- grid.ds.lat_coarse,
734
- grid.ds.lon_coarse,
735
- grid.ds.angle_coarse,
732
+ lat, lon, angle, mask = (
733
+ grid.ds.lat_coarse.rename({"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}),
734
+ grid.ds.lon_coarse.rename({"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}),
735
+ grid.ds.angle_coarse.rename(
736
+ {"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}
737
+ ),
738
+ grid.ds.mask_coarse.rename(
739
+ {"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}
740
+ ),
736
741
  )
742
+
737
743
  lat_psi = grid.ds.get("lat_psi_coarse")
738
744
  lon_psi = grid.ds.get("lon_psi_coarse")
745
+
739
746
  else:
740
- lat, lon, angle = (
747
+ lat, lon, angle, mask = (
741
748
  grid.ds.lat_rho,
742
749
  grid.ds.lon_rho,
743
750
  grid.ds.angle,
751
+ grid.ds.mask_rho,
744
752
  )
745
753
  lat_psi = grid.ds.get("lat_psi")
746
754
  lon_psi = grid.ds.get("lon_psi")
@@ -763,6 +771,7 @@ def get_target_coords(grid, use_coarse_grid=False):
763
771
  "lat_psi": lat_psi,
764
772
  "lon_psi": lon_psi,
765
773
  "angle": angle,
774
+ "mask": mask,
766
775
  "straddle": straddle,
767
776
  }
768
777
 
@@ -1,17 +1,19 @@
1
1
  import pytest
2
2
  from datetime import datetime
3
- from roms_tools import BoundaryForcing
3
+ import xarray as xr
4
+ from roms_tools import Grid, BoundaryForcing
4
5
  import textwrap
5
6
  from roms_tools.setup.download import download_test_data
6
7
  from conftest import calculate_file_hash
7
8
  from pathlib import Path
9
+ import logging
8
10
 
9
11
 
10
12
  @pytest.mark.parametrize(
11
13
  "boundary_forcing_fixture",
12
14
  [
13
15
  "boundary_forcing",
14
- "boundary_forcing_with_2d_fill",
16
+ # "boundary_forcing_with_2d_fill",
15
17
  ],
16
18
  )
17
19
  def test_boundary_forcing_creation(boundary_forcing_fixture, request):
@@ -51,7 +53,7 @@ def test_boundary_forcing_creation(boundary_forcing_fixture, request):
51
53
  "boundary_forcing_fixture",
52
54
  [
53
55
  "bgc_boundary_forcing_from_climatology",
54
- "bgc_boundary_forcing_from_climatology_with_2d_fill",
56
+ # "bgc_boundary_forcing_from_climatology_with_2d_fill",
55
57
  ],
56
58
  )
57
59
  def test_boundary_forcing_creation_with_bgc(boundary_forcing_fixture, request):
@@ -85,6 +87,99 @@ def test_boundary_forcing_creation_with_bgc(boundary_forcing_fixture, request):
85
87
  assert hasattr(boundary_forcing.ds, "climatology")
86
88
 
87
89
 
90
+ def test_unsuccessful_boundary_forcing_creation_with_1d_fill(use_dask):
91
+
92
+ grid = Grid(
93
+ nx=2,
94
+ ny=2,
95
+ size_x=500,
96
+ size_y=1000,
97
+ center_lon=0,
98
+ center_lat=55,
99
+ rot=10,
100
+ N=3, # number of vertical levels
101
+ theta_s=5.0, # surface control parameter
102
+ theta_b=2.0, # bottom control parameter
103
+ hc=250.0, # critical depth
104
+ )
105
+
106
+ fname = download_test_data("GLORYS_coarse_test_data.nc")
107
+
108
+ with pytest.raises(ValueError, match="consists entirely of NaNs"):
109
+
110
+ BoundaryForcing(
111
+ grid=grid,
112
+ start_time=datetime(2021, 6, 29),
113
+ end_time=datetime(2021, 6, 30),
114
+ source={"name": "GLORYS", "path": fname},
115
+ apply_2d_horizontal_fill=False,
116
+ use_dask=use_dask,
117
+ )
118
+
119
+ fname_bgc = download_test_data("CESM_regional_coarse_test_data_climatology.nc")
120
+
121
+ with pytest.raises(ValueError, match="consists entirely of NaNs"):
122
+
123
+ BoundaryForcing(
124
+ grid=grid,
125
+ start_time=datetime(2021, 6, 29),
126
+ end_time=datetime(2021, 6, 30),
127
+ source={"path": fname_bgc, "name": "CESM_REGRIDDED", "climatology": True},
128
+ type="bgc",
129
+ apply_2d_horizontal_fill=False,
130
+ use_dask=use_dask,
131
+ )
132
+
133
+
134
+ def test_boundary_divided_by_land_warning(caplog, use_dask):
135
+
136
+ # Iceland intersects the western boundary of the following grid
137
+ grid = Grid(
138
+ nx=5, ny=5, size_x=500, size_y=500, center_lon=-10, center_lat=65, rot=0
139
+ )
140
+
141
+ fname = download_test_data("GLORYS_coarse_test_data.nc")
142
+
143
+ with caplog.at_level(logging.WARNING):
144
+ BoundaryForcing(
145
+ grid=grid,
146
+ start_time=datetime(2021, 6, 29),
147
+ end_time=datetime(2021, 6, 30),
148
+ source={"path": fname, "name": "GLORYS", "climatology": False},
149
+ apply_2d_horizontal_fill=False,
150
+ use_dask=use_dask,
151
+ )
152
+ # Verify the warning message in the log
153
+ assert "the western boundary is divided by land" in caplog.text
154
+
155
+
156
+ def test_1d_and_2d_fill_coincide_if_no_land(use_dask):
157
+
158
+ # this grid lies entirely over open ocean
159
+ grid = Grid(nx=5, ny=5, size_x=300, size_y=300, center_lon=-5, center_lat=65, rot=0)
160
+
161
+ fname = download_test_data("GLORYS_coarse_test_data.nc")
162
+
163
+ kwargs = {
164
+ "grid": grid,
165
+ "start_time": datetime(2021, 6, 29),
166
+ "end_time": datetime(2021, 6, 29),
167
+ "source": {"path": fname, "name": "GLORYS", "climatology": False},
168
+ "use_dask": use_dask,
169
+ }
170
+
171
+ bf_1d_fill = BoundaryForcing(
172
+ **kwargs,
173
+ apply_2d_horizontal_fill=False,
174
+ )
175
+ bf_2d_fill = BoundaryForcing(
176
+ **kwargs,
177
+ apply_2d_horizontal_fill=True,
178
+ )
179
+
180
+ xr.testing.assert_allclose(bf_1d_fill.ds, bf_2d_fill.ds, rtol=1.0e-4)
181
+
182
+
88
183
  def test_boundary_forcing_plot(boundary_forcing):
89
184
  """Test plot."""
90
185