roms-tools 2.4.0__py3-none-any.whl → 2.6.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 (214) hide show
  1. ci/environment-with-xesmf.yml +16 -0
  2. roms_tools/__init__.py +1 -1
  3. roms_tools/analysis/roms_output.py +339 -234
  4. roms_tools/analysis/utils.py +137 -0
  5. roms_tools/plot.py +353 -214
  6. roms_tools/regrid.py +154 -9
  7. roms_tools/setup/boundary_forcing.py +51 -37
  8. roms_tools/setup/datasets.py +129 -74
  9. roms_tools/setup/grid.py +32 -33
  10. roms_tools/setup/initial_conditions.py +30 -37
  11. roms_tools/setup/nesting.py +238 -64
  12. roms_tools/setup/river_forcing.py +256 -86
  13. roms_tools/setup/surface_forcing.py +40 -28
  14. roms_tools/setup/tides.py +10 -13
  15. roms_tools/setup/topography.py +27 -4
  16. roms_tools/setup/utils.py +28 -12
  17. roms_tools/tests/test_analysis/test_roms_output.py +299 -80
  18. roms_tools/tests/test_regrid.py +85 -2
  19. roms_tools/tests/test_setup/test_boundary_forcing.py +63 -0
  20. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zattrs +3 -1
  21. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zmetadata +3 -1
  22. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/0.0.0 +0 -0
  23. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_south/0.0.0 +0 -0
  24. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/0.0.0 +0 -0
  25. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/0.0.0 +0 -0
  26. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_south/0.0.0 +0 -0
  27. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/0.0.0 +0 -0
  28. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/0.0.0 +0 -0
  29. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_south/0.0.0 +0 -0
  30. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/0.0.0 +0 -0
  31. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/0.0.0 +0 -0
  32. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_south/0.0.0 +0 -0
  33. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/0.0.0 +0 -0
  34. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/0.0.0 +0 -0
  35. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_south/0.0.0 +0 -0
  36. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/0.0.0 +0 -0
  37. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/0.0.0 +0 -0
  38. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_south/0.0.0 +0 -0
  39. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/0.0.0 +0 -0
  40. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/0.0.0 +0 -0
  41. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_south/0.0.0 +0 -0
  42. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/0.0.0 +0 -0
  43. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/0.0.0 +0 -0
  44. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_south/0.0.0 +0 -0
  45. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/0.0.0 +0 -0
  46. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/0.0.0 +0 -0
  47. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_south/0.0.0 +0 -0
  48. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/0.0.0 +0 -0
  49. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/0.0.0 +0 -0
  50. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_south/0.0.0 +0 -0
  51. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/0.0.0 +0 -0
  52. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/0.0.0 +0 -0
  53. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_south/0.0.0 +0 -0
  54. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/0.0.0 +0 -0
  55. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/0.0.0 +0 -0
  56. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_south/0.0.0 +0 -0
  57. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/0.0.0 +0 -0
  58. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/0.0.0 +0 -0
  59. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_north/0.0.0 +0 -0
  60. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_south/0.0.0 +0 -0
  61. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/0.0.0 +0 -0
  62. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/0.0.0 +0 -0
  63. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_south/0.0.0 +0 -0
  64. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/0.0.0 +0 -0
  65. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/0.0.0 +0 -0
  66. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_south/0.0.0 +0 -0
  67. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/0.0.0 +0 -0
  68. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/0.0.0 +0 -0
  69. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_south/0.0.0 +0 -0
  70. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/0.0.0 +0 -0
  71. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/0.0.0 +0 -0
  72. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_south/0.0.0 +0 -0
  73. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/0.0.0 +0 -0
  74. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/0.0.0 +0 -0
  75. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_north/0.0.0 +0 -0
  76. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_south/0.0.0 +0 -0
  77. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/0.0.0 +0 -0
  78. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/0.0.0 +0 -0
  79. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_north/0.0.0 +0 -0
  80. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_south/0.0.0 +0 -0
  81. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/0.0.0 +0 -0
  82. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/0.0.0 +0 -0
  83. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_north/0.0.0 +0 -0
  84. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_south/0.0.0 +0 -0
  85. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/0.0.0 +0 -0
  86. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/0.0.0 +0 -0
  87. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_north/0.0.0 +0 -0
  88. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_south/0.0.0 +0 -0
  89. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/0.0.0 +0 -0
  90. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/0.0.0 +0 -0
  91. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_north/0.0.0 +0 -0
  92. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_south/0.0.0 +0 -0
  93. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/0.0.0 +0 -0
  94. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/0.0.0 +0 -0
  95. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_north/0.0.0 +0 -0
  96. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_south/0.0.0 +0 -0
  97. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/0.0.0 +0 -0
  98. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/0.0.0 +0 -0
  99. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_north/0.0.0 +0 -0
  100. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_south/0.0.0 +0 -0
  101. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/0.0.0 +0 -0
  102. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/0.0.0 +0 -0
  103. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_north/0.0.0 +0 -0
  104. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_south/0.0.0 +0 -0
  105. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/0.0.0 +0 -0
  106. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/0.0.0 +0 -0
  107. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_north/0.0.0 +0 -0
  108. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_south/0.0.0 +0 -0
  109. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/0.0.0 +0 -0
  110. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/0.0.0 +0 -0
  111. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_north/0.0.0 +0 -0
  112. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_south/0.0.0 +0 -0
  113. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/0.0.0 +0 -0
  114. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/0.0.0 +0 -0
  115. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_north/0.0.0 +0 -0
  116. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_south/0.0.0 +0 -0
  117. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/0.0.0 +0 -0
  118. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/0.0.0 +0 -0
  119. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_north/0.0.0 +0 -0
  120. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_south/0.0.0 +0 -0
  121. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/0.0.0 +0 -0
  122. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/0.0.0 +0 -0
  123. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_north/0.0.0 +0 -0
  124. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_south/0.0.0 +0 -0
  125. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/0.0.0 +0 -0
  126. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/0.0.0 +0 -0
  127. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_north/0.0.0 +0 -0
  128. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_south/0.0.0 +0 -0
  129. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/0.0.0 +0 -0
  130. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/0.0.0 +0 -0
  131. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_north/0.0.0 +0 -0
  132. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_south/0.0.0 +0 -0
  133. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/0.0.0 +0 -0
  134. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zattrs +2 -2
  135. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zmetadata +8 -7
  136. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/abs_time/.zattrs +1 -0
  137. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust/0.0.0 +0 -0
  138. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust_time/.zattrs +1 -1
  139. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron/0.0.0 +0 -0
  140. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron_time/.zattrs +1 -1
  141. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy/0.0.0 +0 -0
  142. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy_time/.zattrs +1 -1
  143. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox/0.0.0 +0 -0
  144. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox_time/.zattrs +1 -1
  145. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air/0.0.0 +0 -0
  146. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air_alt/0.0.0 +0 -0
  147. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_time/.zattrs +1 -1
  148. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zattrs +2 -2
  149. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zmetadata +2 -2
  150. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust/0.0.0 +0 -0
  151. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron/0.0.0 +0 -0
  152. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy/0.0.0 +0 -0
  153. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox/0.0.0 +0 -0
  154. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air/0.0.0 +0 -0
  155. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air_alt/0.0.0 +0 -0
  156. roms_tools/tests/test_setup/test_data/grid.zarr/.zattrs +1 -1
  157. roms_tools/tests/test_setup/test_data/grid.zarr/.zmetadata +2 -2
  158. roms_tools/tests/test_setup/test_data/grid.zarr/angle/0.0 +0 -0
  159. roms_tools/tests/test_setup/test_data/grid.zarr/angle_coarse/0.0 +0 -0
  160. roms_tools/tests/test_setup/test_data/grid.zarr/f/0.0 +0 -0
  161. roms_tools/tests/test_setup/test_data/grid.zarr/h/.zattrs +1 -1
  162. roms_tools/tests/test_setup/test_data/grid.zarr/h/0.0 +0 -0
  163. roms_tools/tests/test_setup/test_data/grid.zarr/lat_coarse/0.0 +0 -0
  164. roms_tools/tests/test_setup/test_data/grid.zarr/lat_rho/0.0 +0 -0
  165. roms_tools/tests/test_setup/test_data/grid.zarr/lat_u/0.0 +0 -0
  166. roms_tools/tests/test_setup/test_data/grid.zarr/lat_v/0.0 +0 -0
  167. roms_tools/tests/test_setup/test_data/grid.zarr/pm/0.0 +0 -0
  168. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zattrs +1 -1
  169. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zmetadata +1 -1
  170. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle/0.0 +0 -0
  171. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle_coarse/0.0 +0 -0
  172. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/f/0.0 +0 -0
  173. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/0.0 +0 -0
  174. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_coarse/0.0 +0 -0
  175. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_rho/0.0 +0 -0
  176. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_u/0.0 +0 -0
  177. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_v/0.0 +0 -0
  178. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_coarse/0.0 +0 -0
  179. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_rho/0.0 +0 -0
  180. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_u/0.0 +0 -0
  181. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_v/0.0 +0 -0
  182. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pm/0.0 +0 -0
  183. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pn/0.0 +0 -0
  184. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zattrs +1 -1
  185. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zmetadata +1 -1
  186. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/salt/0.0.0.0 +0 -0
  187. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/temp/0.0.0.0 +0 -0
  188. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/u/0.0.0.0 +0 -0
  189. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ubar/0.0.0 +0 -0
  190. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/v/0.0.0.0 +0 -0
  191. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/vbar/0.0.0 +0 -0
  192. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zeta/0.0.0 +0 -0
  193. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +27 -1
  194. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/.zarray +20 -0
  195. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/.zattrs +6 -0
  196. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/0 +0 -0
  197. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/.zattrs +1 -1
  198. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/.zmetadata +27 -1
  199. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/.zarray +20 -0
  200. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/.zattrs +6 -0
  201. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/0 +0 -0
  202. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/.zattrs +1 -1
  203. roms_tools/tests/test_setup/test_initial_conditions.py +16 -0
  204. roms_tools/tests/test_setup/test_nesting.py +141 -104
  205. roms_tools/tests/test_setup/test_river_forcing.py +580 -266
  206. roms_tools/tests/test_setup/test_surface_forcing.py +47 -0
  207. roms_tools/tests/test_setup/test_validation.py +34 -2
  208. roms_tools/utils.py +11 -7
  209. roms_tools/vertical_coordinate.py +1 -0
  210. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/METADATA +22 -11
  211. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/RECORD +214 -206
  212. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/WHEEL +1 -1
  213. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info/licenses}/LICENSE +0 -0
  214. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/top_level.txt +0 -0
@@ -7,6 +7,11 @@ from datetime import datetime
7
7
  from roms_tools import Grid, ROMSOutput
8
8
  from roms_tools.download import download_test_data
9
9
 
10
+ try:
11
+ import xesmf # type: ignore
12
+ except ImportError:
13
+ xesmf = None
14
+
10
15
 
11
16
  @pytest.fixture
12
17
  def roms_output_from_restart_file(use_dask):
@@ -18,28 +23,36 @@ def roms_output_from_restart_file(use_dask):
18
23
  return ROMSOutput(
19
24
  grid=grid,
20
25
  path=Path(download_test_data("eastpac25km_rst.19980106000000.nc")),
21
- type="restart",
22
26
  use_dask=use_dask,
23
27
  )
24
28
 
25
29
 
26
- def test_load_model_output_file(roms_output_from_restart_file, use_dask):
27
-
28
- assert isinstance(roms_output_from_restart_file.ds, xr.Dataset)
29
-
30
+ @pytest.fixture
31
+ def roms_output_from_restart_file_adjusted_for_zeta(use_dask):
30
32
 
31
- def test_load_model_output_directory(use_dask):
32
33
  fname_grid = Path(download_test_data("epac25km_grd.nc"))
33
34
  grid = Grid.from_file(fname_grid)
34
35
 
35
- # Download at least two files, so these will be found within the pooch directory
36
- _ = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
37
- _ = Path(download_test_data("eastpac25km_rst.19980126000000.nc"))
36
+ # Single file
37
+ return ROMSOutput(
38
+ grid=grid,
39
+ path=Path(download_test_data("eastpac25km_rst.19980106000000.nc")),
40
+ adjust_depth_for_sea_surface_height=True,
41
+ use_dask=use_dask,
42
+ )
38
43
 
39
- # Directory
40
- directory = os.path.dirname(download_test_data("eastpac25km_rst.19980106000000.nc"))
41
- output = ROMSOutput(grid=grid, path=directory, type="restart", use_dask=use_dask)
42
- assert isinstance(output.ds, xr.Dataset)
44
+
45
+ @pytest.mark.parametrize(
46
+ "roms_output_fixture",
47
+ [
48
+ "roms_output_from_restart_file",
49
+ "roms_output_from_restart_file_adjusted_for_zeta",
50
+ ],
51
+ )
52
+ def test_load_model_output_file(roms_output_fixture, use_dask, request):
53
+ roms_output = request.getfixturevalue(roms_output_fixture)
54
+
55
+ assert isinstance(roms_output.ds, xr.Dataset)
43
56
 
44
57
 
45
58
  def test_load_model_output_file_list(use_dask):
@@ -49,24 +62,23 @@ def test_load_model_output_file_list(use_dask):
49
62
  # List of files
50
63
  file1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
51
64
  file2 = Path(download_test_data("eastpac25km_rst.19980126000000.nc"))
52
- output = ROMSOutput(
53
- grid=grid, path=[file1, file2], type="restart", use_dask=use_dask
54
- )
65
+ output = ROMSOutput(grid=grid, path=[file1, file2], use_dask=use_dask)
55
66
  assert isinstance(output.ds, xr.Dataset)
56
67
 
57
68
 
58
- def test_invalid_type(use_dask):
69
+ def test_load_model_output_with_wildcard(use_dask):
59
70
  fname_grid = Path(download_test_data("epac25km_grd.nc"))
60
71
  grid = Grid.from_file(fname_grid)
61
72
 
62
- # Invalid type
63
- with pytest.raises(ValueError, match="Invalid type 'invalid_type'"):
64
- ROMSOutput(
65
- grid=grid,
66
- path=Path(download_test_data("eastpac25km_rst.19980106000000.nc")),
67
- type="invalid_type",
68
- use_dask=use_dask,
69
- )
73
+ # Download at least two files, so these will be found within the pooch directory
74
+ Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
75
+ Path(download_test_data("eastpac25km_rst.19980126000000.nc"))
76
+ directory = Path(
77
+ os.path.dirname(download_test_data("eastpac25km_rst.19980106000000.nc"))
78
+ )
79
+
80
+ output = ROMSOutput(grid=grid, path=directory / "*rst*.nc", use_dask=use_dask)
81
+ assert isinstance(output.ds, xr.Dataset)
70
82
 
71
83
 
72
84
  def test_invalid_path(use_dask):
@@ -78,16 +90,6 @@ def test_invalid_path(use_dask):
78
90
  ROMSOutput(
79
91
  grid=grid,
80
92
  path=Path("/path/to/nonexistent/file.nc"),
81
- type="restart",
82
- use_dask=use_dask,
83
- )
84
-
85
- # Non-existent directory
86
- with pytest.raises(FileNotFoundError):
87
- ROMSOutput(
88
- grid=grid,
89
- path=Path("/path/to/nonexistent/directory"),
90
- type="restart",
91
93
  use_dask=use_dask,
92
94
  )
93
95
 
@@ -99,7 +101,6 @@ def test_set_correct_model_reference_date(use_dask):
99
101
  output = ROMSOutput(
100
102
  grid=grid,
101
103
  path=Path(download_test_data("eastpac25km_rst.19980106000000.nc")),
102
- type="restart",
103
104
  use_dask=use_dask,
104
105
  )
105
106
  assert output.model_reference_date == datetime(1995, 1, 1)
@@ -117,7 +118,6 @@ def test_model_reference_date_mismatch(use_dask):
117
118
  ROMSOutput(
118
119
  grid=grid,
119
120
  path=Path(download_test_data("eastpac25km_rst.19980106000000.nc")),
120
- type="restart",
121
121
  model_reference_date=model_ref_date,
122
122
  use_dask=use_dask,
123
123
  )
@@ -138,7 +138,7 @@ def test_model_reference_date_no_metadata(use_dask, tmp_path, caplog):
138
138
  expected_exception,
139
139
  match="Model reference date could not be inferred from the metadata",
140
140
  ):
141
- ROMSOutput(grid=grid, path=fname_mod, type="restart", use_dask=use_dask)
141
+ ROMSOutput(grid=grid, path=fname_mod, use_dask=use_dask)
142
142
 
143
143
  # Test case 2: When a model reference date is explicitly set, verify the warning
144
144
  with caplog.at_level(logging.WARNING):
@@ -146,7 +146,6 @@ def test_model_reference_date_no_metadata(use_dask, tmp_path, caplog):
146
146
  grid=grid,
147
147
  path=fname_mod,
148
148
  model_reference_date=datetime(1995, 1, 1),
149
- type="restart",
150
149
  use_dask=use_dask,
151
150
  )
152
151
 
@@ -175,20 +174,53 @@ def test_model_reference_date_no_metadata(use_dask, tmp_path, caplog):
175
174
  def test_compute_depth_coordinates(use_dask):
176
175
  fname_grid = Path(download_test_data("epac25km_grd.nc"))
177
176
  grid = Grid.from_file(fname_grid)
177
+ fname_restart1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
178
+
179
+ for adjust_depth_for_sea_surface_height in [True, False]:
180
+ output = ROMSOutput(
181
+ grid=grid,
182
+ path=fname_restart1,
183
+ use_dask=use_dask,
184
+ adjust_depth_for_sea_surface_height=adjust_depth_for_sea_surface_height,
185
+ )
178
186
 
187
+ # Before calling get_vertical_coordinates, check if the dataset doesn't already have depth coordinates
188
+ assert "layer_depth_rho" not in output.ds_depth_coords.data_vars
189
+
190
+ # Call the method to get vertical coordinates
191
+ output._get_depth_coordinates(depth_type="layer")
192
+
193
+ # Check if the depth coordinates were added
194
+ assert "layer_depth_rho" in output.ds_depth_coords.data_vars
195
+
196
+
197
+ def test_missing_zeta_gets_raised(use_dask):
198
+ """Test that a ValueError is raised when `zeta` is missing from the dataset and
199
+ `adjust_depth_for_sea_surface_height` is enabled."""
200
+ # Load the grid
201
+ fname_grid = Path(download_test_data("epac25km_grd.nc"))
202
+ grid = Grid.from_file(fname_grid)
203
+
204
+ # Load the ROMS output
179
205
  fname_restart1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
180
- output = ROMSOutput(
181
- grid=grid, path=fname_restart1, type="restart", use_dask=use_dask
206
+ roms_output = ROMSOutput(
207
+ grid=grid,
208
+ path=fname_restart1,
209
+ use_dask=use_dask,
210
+ adjust_depth_for_sea_surface_height=True,
182
211
  )
183
212
 
184
- # Before calling get_vertical_coordinates, check if the dataset doesn't already have depth coordinates
185
- assert "layer_depth_rho" not in output.ds.data_vars
186
-
187
- # Call the method to get vertical coordinates
188
- output.compute_depth_coordinates(depth_type="layer")
213
+ # Remove `zeta` from the dataset
214
+ object.__setattr__(
215
+ roms_output, "ds", roms_output.ds.drop_vars("zeta", errors="ignore")
216
+ )
189
217
 
190
- # Check if the depth coordinates were added
191
- assert "layer_depth_rho" in output.ds.data_vars
218
+ # Expect ValueError when calling `_get_depth_coordinates`
219
+ with pytest.raises(
220
+ ValueError,
221
+ match="`zeta` is required in provided ROMS output when `adjust_depth_for_sea_surface_height` is enabled.",
222
+ ):
223
+ roms_output._get_depth_coordinates()
192
224
 
193
225
 
194
226
  def test_check_vertical_coordinate_mismatch(use_dask):
@@ -196,9 +228,7 @@ def test_check_vertical_coordinate_mismatch(use_dask):
196
228
  grid = Grid.from_file(fname_grid)
197
229
 
198
230
  fname_restart1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
199
- output = ROMSOutput(
200
- grid=grid, path=fname_restart1, type="restart", use_dask=use_dask
201
- )
231
+ output = ROMSOutput(grid=grid, path=fname_restart1, use_dask=use_dask)
202
232
 
203
233
  # create a mock dataset with inconsistent vertical coordinate parameters
204
234
  ds_mock = output.ds.copy()
@@ -226,44 +256,233 @@ def test_that_coordinates_are_added(use_dask):
226
256
  grid = Grid.from_file(fname_grid)
227
257
 
228
258
  fname_restart1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
229
- output = ROMSOutput(
230
- grid=grid, path=fname_restart1, type="restart", use_dask=use_dask
231
- )
259
+ output = ROMSOutput(grid=grid, path=fname_restart1, use_dask=use_dask)
232
260
 
233
261
  assert "abs_time" in output.ds.coords
234
262
  assert "lat_rho" in output.ds.coords
235
263
  assert "lon_rho" in output.ds.coords
236
264
 
237
265
 
238
- def test_plot(roms_output_from_restart_file, use_dask):
239
-
240
- kwargs = {}
241
- for var_name in ["temp", "u", "v"]:
242
- roms_output_from_restart_file.plot(var_name, time=0, s=-1, **kwargs)
243
- roms_output_from_restart_file.plot(var_name, time=0, eta=0, **kwargs)
244
- roms_output_from_restart_file.plot(var_name, time=0, xi=0, **kwargs)
245
- roms_output_from_restart_file.plot(var_name, time=0, eta=0, xi=0, **kwargs)
246
- roms_output_from_restart_file.plot(var_name, time=0, s=-1, eta=0, **kwargs)
247
-
248
- kwargs = {"depth_contours": True, "layer_contours": True}
249
- for var_name in ["temp", "u", "v"]:
250
- roms_output_from_restart_file.plot(var_name, time=0, s=-1, **kwargs)
251
- roms_output_from_restart_file.plot(var_name, time=0, eta=0, **kwargs)
252
- roms_output_from_restart_file.plot(var_name, time=0, xi=0, **kwargs)
253
- roms_output_from_restart_file.plot(var_name, time=0, eta=0, xi=0, **kwargs)
254
- roms_output_from_restart_file.plot(var_name, time=0, s=-1, eta=0, **kwargs)
255
-
256
- roms_output_from_restart_file.plot("zeta", time=0, **kwargs)
257
- roms_output_from_restart_file.plot("zeta", time=0, eta=0, **kwargs)
258
- roms_output_from_restart_file.plot("zeta", time=0, xi=0, **kwargs)
266
+ @pytest.mark.parametrize(
267
+ "roms_output_fixture",
268
+ [
269
+ "roms_output_from_restart_file",
270
+ "roms_output_from_restart_file_adjusted_for_zeta",
271
+ ],
272
+ )
273
+ def test_plot_on_native_model_grid(roms_output_fixture, use_dask, request):
274
+ roms_output = request.getfixturevalue(roms_output_fixture)
275
+
276
+ for include_boundary in [False, True]:
277
+ for depth_contours in [False, True]:
278
+
279
+ # 3D fields
280
+ for var_name in ["temp", "u", "v"]:
281
+ kwargs = {
282
+ "include_boundary": include_boundary,
283
+ "depth_contours": depth_contours,
284
+ }
285
+
286
+ roms_output.plot(var_name, time=1, s=-1, **kwargs)
287
+ roms_output.plot(var_name, time=1, depth=1000, **kwargs)
288
+
289
+ roms_output.plot(var_name, time=1, eta=1, **kwargs)
290
+ roms_output.plot(var_name, time=1, xi=1, **kwargs)
291
+
292
+ roms_output.plot(
293
+ var_name,
294
+ time=1,
295
+ eta=1,
296
+ xi=1,
297
+ **kwargs,
298
+ )
299
+
300
+ roms_output.plot(
301
+ var_name,
302
+ time=1,
303
+ s=-1,
304
+ eta=1,
305
+ **kwargs,
306
+ )
307
+ roms_output.plot(
308
+ var_name,
309
+ time=1,
310
+ depth=1000,
311
+ eta=1,
312
+ **kwargs,
313
+ )
314
+
315
+ roms_output.plot(
316
+ var_name,
317
+ time=1,
318
+ s=-1,
319
+ xi=1,
320
+ **kwargs,
321
+ )
322
+ roms_output.plot(
323
+ var_name,
324
+ time=1,
325
+ depth=1000,
326
+ xi=1,
327
+ **kwargs,
328
+ )
329
+
330
+ # 2D fields
331
+ roms_output.plot("zeta", time=1, **kwargs)
332
+ roms_output.plot("zeta", time=1, eta=1, **kwargs)
333
+ roms_output.plot("zeta", time=1, xi=1, **kwargs)
334
+
335
+
336
+ @pytest.mark.parametrize(
337
+ "roms_output_fixture",
338
+ [
339
+ "roms_output_from_restart_file",
340
+ "roms_output_from_restart_file_adjusted_for_zeta",
341
+ ],
342
+ )
343
+ @pytest.mark.skipif(xesmf is None, reason="xesmf required")
344
+ def test_plot_on_lat_lon(roms_output_fixture, use_dask, request):
345
+ roms_output = request.getfixturevalue(roms_output_fixture)
346
+
347
+ for include_boundary in [False, True]:
348
+ for depth_contours in [False, True]:
349
+
350
+ # 3D fields
351
+ for var_name in ["temp", "u", "v"]:
352
+ kwargs = {
353
+ "include_boundary": include_boundary,
354
+ "depth_contours": depth_contours,
355
+ }
356
+ roms_output.plot(
357
+ var_name,
358
+ time=1,
359
+ lat=9,
360
+ lon=-128,
361
+ **kwargs,
362
+ )
363
+ roms_output.plot(
364
+ var_name,
365
+ time=1,
366
+ lat=9,
367
+ **kwargs,
368
+ )
369
+ roms_output.plot(
370
+ var_name,
371
+ time=1,
372
+ lat=9,
373
+ s=-1,
374
+ **kwargs,
375
+ )
376
+ roms_output.plot(
377
+ var_name,
378
+ time=1,
379
+ lat=9,
380
+ depth=1000,
381
+ **kwargs,
382
+ )
383
+ roms_output.plot(
384
+ var_name,
385
+ time=1,
386
+ lon=-128,
387
+ **kwargs,
388
+ )
389
+ roms_output.plot(
390
+ var_name,
391
+ time=1,
392
+ lon=-128,
393
+ s=-1,
394
+ **kwargs,
395
+ )
396
+ roms_output.plot(
397
+ var_name,
398
+ time=1,
399
+ lon=-128,
400
+ depth=1000,
401
+ **kwargs,
402
+ )
403
+
404
+ # 2D fields
405
+ roms_output.plot("zeta", time=1, lat=9, **kwargs)
406
+ roms_output.plot("zeta", time=1, lon=-128, **kwargs)
259
407
 
260
408
 
261
409
  def test_plot_errors(roms_output_from_restart_file, use_dask):
410
+ """Test error conditions for the ROMSOutput.plot() method."""
411
+
412
+ # Invalid time index
262
413
  with pytest.raises(ValueError, match="Invalid time index"):
263
414
  roms_output_from_restart_file.plot("temp", time=10, s=-1)
264
- with pytest.raises(ValueError, match="Invalid input"):
265
- roms_output_from_restart_file.plot("temp", time=0)
415
+
416
+ with pytest.raises(
417
+ ValueError,
418
+ match="Conflicting input: You cannot specify both 's' and 'depth' at the same time.",
419
+ ):
420
+ roms_output_from_restart_file.plot("temp", time=0, s=-1, depth=10)
421
+
422
+ # Ambiguous input: Too many dimensions specified for 3D fields
266
423
  with pytest.raises(ValueError, match="Ambiguous input"):
267
- roms_output_from_restart_file.plot("temp", time=0, s=-1, eta=0, xi=0)
268
- with pytest.raises(ValueError, match="Conflicting input"):
269
- roms_output_from_restart_file.plot("zeta", time=0, eta=0, xi=0)
424
+ roms_output_from_restart_file.plot("temp", time=1, s=-1, eta=0, xi=0)
425
+
426
+ # Vertical dimension specified for 2D fields
427
+ with pytest.raises(
428
+ ValueError, match="Vertical dimension 's' should be None for 2D fields"
429
+ ):
430
+ roms_output_from_restart_file.plot("zeta", time=1, s=-1)
431
+ with pytest.raises(
432
+ ValueError, match="Vertical dimension 'depth' should be None for 2D fields"
433
+ ):
434
+ roms_output_from_restart_file.plot("zeta", time=1, depth=100)
435
+
436
+ # Conflicting input: Both eta and xi specified for 2D fields
437
+ with pytest.raises(
438
+ ValueError,
439
+ match="Conflicting input: For 2D fields, specify only one dimension, either 'eta' or 'xi', not both.",
440
+ ):
441
+ roms_output_from_restart_file.plot("zeta", time=1, eta=0, xi=0)
442
+ # Conflicting input: Both lat and lon specified for 2D fields
443
+ with pytest.raises(
444
+ ValueError,
445
+ match="Conflicting input: For 2D fields, specify only one dimension, either 'lat' or 'lon', not both.",
446
+ ):
447
+ roms_output_from_restart_file.plot("zeta", time=1, lat=0, lon=0)
448
+
449
+ # Conflicting input: lat or lon provided with eta or xi
450
+ with pytest.raises(
451
+ ValueError,
452
+ match="Conflicting input: You cannot specify 'lat' or 'lon' simultaneously with 'eta' or 'xi'.",
453
+ ):
454
+ roms_output_from_restart_file.plot("temp", time=1, lat=10, lon=20, eta=5)
455
+
456
+ # Invalid eta index out of bounds
457
+ with pytest.raises(ValueError, match="Invalid eta index"):
458
+ roms_output_from_restart_file.plot("temp", time=1, eta=999)
459
+
460
+ # Invalid xi index out of bounds
461
+ with pytest.raises(ValueError, match="Invalid eta index"):
462
+ roms_output_from_restart_file.plot("temp", time=1, xi=999)
463
+
464
+ # Boundary exclusion error for eta
465
+ with pytest.raises(ValueError, match="Invalid eta index.*boundary.*excluded"):
466
+ roms_output_from_restart_file.plot(
467
+ "temp", time=1, eta=0, include_boundary=False
468
+ )
469
+
470
+ # Boundary exclusion error for xi
471
+ with pytest.raises(ValueError, match="Invalid xi index.*boundary.*excluded"):
472
+ roms_output_from_restart_file.plot("temp", time=1, xi=0, include_boundary=False)
473
+
474
+ # No dimension specified for 3D field
475
+ with pytest.raises(
476
+ ValueError,
477
+ match="Invalid input: For 3D fields, you must specify at least one of the dimensions",
478
+ ):
479
+ roms_output_from_restart_file.plot("temp", time=1)
480
+
481
+
482
+ def test_figure_gets_saved(roms_output_from_restart_file, tmp_path):
483
+
484
+ filename = tmp_path / "figure.png"
485
+ roms_output_from_restart_file.plot("temp", time=0, depth=1000, save_path=filename)
486
+
487
+ assert filename.exists()
488
+ filename.unlink()
@@ -1,9 +1,92 @@
1
1
  import pytest
2
2
  import numpy as np
3
3
  import xarray as xr
4
- from roms_tools.regrid import VerticalRegrid
4
+ from roms_tools.regrid import VerticalRegridToROMS
5
5
 
6
+ try:
7
+ import xesmf # type: ignore
8
+ except ImportError:
9
+ xesmf = None
6
10
 
11
+ from roms_tools.regrid import LateralRegridFromROMS
12
+
13
+ # Lateral regridding
14
+ @pytest.mark.skipif(xesmf is None, reason="xesmf required")
15
+ def test_lateral_regrid_with_curvilinear_grid():
16
+ """Test that LateralRegridFromROMS regrids data correctly from a curvilinear ROMS
17
+ grid."""
18
+
19
+ # Define ROMS curvilinear grid dimensions
20
+ eta_rho, xi_rho = 10, 20
21
+
22
+ # Create a mock ROMS grid with curvilinear coordinates
23
+ lat_rho = np.linspace(-10, 10, eta_rho).reshape(-1, 1) * np.ones((1, xi_rho))
24
+ lon_rho = np.linspace(120, 140, xi_rho).reshape(1, -1) * np.ones((eta_rho, 1))
25
+
26
+ ds_in = xr.Dataset(
27
+ {
28
+ "temp": (("eta_rho", "xi_rho"), np.random.rand(eta_rho, xi_rho)),
29
+ },
30
+ coords={
31
+ "lat": (("eta_rho", "xi_rho"), lat_rho),
32
+ "lon": (("eta_rho", "xi_rho"), lon_rho),
33
+ },
34
+ )
35
+
36
+ # Define target latitude and longitude coordinates
37
+ target_coords = {
38
+ "lat": np.linspace(-5, 5, 5),
39
+ "lon": np.linspace(125, 135, 10),
40
+ }
41
+
42
+ # Instantiate the regridder
43
+ regridder = LateralRegridFromROMS(ds_in, target_coords, method="bilinear")
44
+
45
+ # Apply the regridding to the input data
46
+ regridded_da = regridder.apply(ds_in["temp"])
47
+
48
+ # Assertions to verify that the output is as expected
49
+ assert isinstance(regridded_da, xr.DataArray)
50
+ assert regridded_da.shape == (5, 10)
51
+ assert np.allclose(regridded_da.coords["lat"], target_coords["lat"])
52
+ assert np.allclose(regridded_da.coords["lon"], target_coords["lon"])
53
+
54
+
55
+ @pytest.mark.skipif(xesmf is not None, reason="xesmf has to be missing")
56
+ def test_lateral_regrid_import_error():
57
+ """Test that LateralRegridFromROMS raises ImportError when xesmf is missing."""
58
+
59
+ # Define mock ROMS curvilinear grid dimensions
60
+ eta_rho, xi_rho = 10, 20
61
+
62
+ # Create a mock ROMS grid with curvilinear coordinates
63
+ lat_rho = np.linspace(-10, 10, eta_rho).reshape(-1, 1) * np.ones((1, xi_rho))
64
+ lon_rho = np.linspace(120, 140, xi_rho).reshape(1, -1) * np.ones((eta_rho, 1))
65
+
66
+ ds_in = xr.Dataset(
67
+ {
68
+ "temp": (("eta_rho", "xi_rho"), np.random.rand(eta_rho, xi_rho)),
69
+ },
70
+ coords={
71
+ "lat": (("eta_rho", "xi_rho"), lat_rho),
72
+ "lon": (("eta_rho", "xi_rho"), lon_rho),
73
+ },
74
+ )
75
+
76
+ # Define target latitude and longitude coordinates
77
+ target_coords = {
78
+ "lat": np.linspace(-5, 5, 5),
79
+ "lon": np.linspace(125, 135, 10),
80
+ }
81
+
82
+ # Check that ImportError is raised when xesmf is missing
83
+ with pytest.raises(
84
+ ImportError, match="xesmf is required for this regridding task.*"
85
+ ):
86
+ LateralRegridFromROMS(ds_in, target_coords, method="bilinear")
87
+
88
+
89
+ # Vertical regridding
7
90
  def vertical_regridder(depth_values, layer_depth_rho_values):
8
91
  class DataContainer:
9
92
  """Mock class for holding data and dimension names."""
@@ -21,7 +104,7 @@ def vertical_regridder(depth_values, layer_depth_rho_values):
21
104
  target_depth = xr.DataArray(data=layer_depth_rho_values, dims=["s_rho"])
22
105
  source_depth = xr.DataArray(data=depth_values, dims=["depth"])
23
106
 
24
- return VerticalRegrid(target_depth, source_depth)
107
+ return VerticalRegridToROMS(target_depth, source_depth)
25
108
 
26
109
 
27
110
  @pytest.mark.parametrize(
@@ -139,6 +139,69 @@ def test_unsuccessful_boundary_forcing_creation_with_1d_fill(use_dask):
139
139
  )
140
140
 
141
141
 
142
+ def test_start_time_end_time_error(use_dask):
143
+ """Test error when start_time and end_time are not both provided or both None."""
144
+ # Case 1: Only start_time provided
145
+ with pytest.raises(
146
+ ValueError, match="Both `start_time` and `end_time` must be provided together"
147
+ ):
148
+ BoundaryForcing(
149
+ grid=None,
150
+ start_time=datetime(2022, 1, 1),
151
+ end_time=None, # end_time is None, should raise an error
152
+ source={"name": "GLORYS", "path": "glorys_data.nc"},
153
+ use_dask=use_dask,
154
+ )
155
+
156
+ # Case 2: Only end_time provided
157
+ with pytest.raises(
158
+ ValueError, match="Both `start_time` and `end_time` must be provided together"
159
+ ):
160
+ BoundaryForcing(
161
+ grid=None,
162
+ start_time=None, # start_time is None, should raise an error
163
+ end_time=datetime(2022, 1, 2),
164
+ source={"name": "GLORYS", "path": "glorys_data.nc"},
165
+ use_dask=use_dask,
166
+ )
167
+
168
+
169
+ def test_start_time_end_time_warning(use_dask, caplog):
170
+ """Test that a warning is triggered when both start_time and end_time are None."""
171
+ # Catching the warning during test
172
+ grid = Grid(
173
+ nx=3,
174
+ ny=3,
175
+ size_x=400,
176
+ size_y=400,
177
+ center_lon=-8,
178
+ center_lat=58,
179
+ rot=0,
180
+ N=3, # number of vertical levels
181
+ theta_s=5.0, # surface control parameter
182
+ theta_b=2.0, # bottom control parameter
183
+ hc=250.0, # critical depth
184
+ )
185
+
186
+ fname1 = Path(download_test_data("GLORYS_NA_20120101.nc"))
187
+ fname2 = Path(download_test_data("GLORYS_NA_20121231.nc"))
188
+
189
+ with caplog.at_level(logging.INFO):
190
+ BoundaryForcing(
191
+ grid=grid,
192
+ start_time=None,
193
+ end_time=None,
194
+ source={"name": "GLORYS", "path": [fname1, fname2]},
195
+ use_dask=use_dask,
196
+ )
197
+
198
+ # Verify the warning message in the log
199
+ assert (
200
+ "Both `start_time` and `end_time` are None. No time filtering will be applied to the source data."
201
+ in caplog.text
202
+ )
203
+
204
+
142
205
  def test_boundary_divided_by_land_warning(caplog, use_dask):
143
206
 
144
207
  # Iceland intersects the western boundary of the following grid
@@ -1,9 +1,11 @@
1
1
  {
2
+ "adjust_depth_for_sea_surface_height": "False",
3
+ "apply_2d_horizontal_fill": "True",
2
4
  "climatology": "True",
3
5
  "end_time": "2021-06-30 00:00:00",
4
6
  "hc": 250.0,
5
7
  "model_reference_date": "2000-01-01 00:00:00",
6
- "roms_tools_version": "0.1.dev169+dirty",
8
+ "roms_tools_version": "2.1.1.dev3+gef240eb.d20250116",
7
9
  "source": "CESM_REGRIDDED",
8
10
  "start_time": "2021-06-29 00:00:00",
9
11
  "theta_b": 2.0,
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "metadata": {
3
3
  ".zattrs": {
4
+ "adjust_depth_for_sea_surface_height": "False",
5
+ "apply_2d_horizontal_fill": "True",
4
6
  "climatology": "True",
5
7
  "end_time": "2021-06-30 00:00:00",
6
8
  "hc": 250.0,
7
9
  "model_reference_date": "2000-01-01 00:00:00",
8
- "roms_tools_version": "0.1.dev169+dirty",
10
+ "roms_tools_version": "2.1.1.dev3+gef240eb.d20250116",
9
11
  "source": "CESM_REGRIDDED",
10
12
  "start_time": "2021-06-29 00:00:00",
11
13
  "theta_b": 2.0,