roms-tools 2.3.0__py3-none-any.whl → 2.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. ci/environment.yml +1 -0
  2. roms_tools/__init__.py +2 -1
  3. roms_tools/analysis/roms_output.py +81 -98
  4. roms_tools/plot.py +4 -2
  5. roms_tools/setup/boundary_forcing.py +207 -208
  6. roms_tools/setup/datasets.py +149 -33
  7. roms_tools/setup/grid.py +35 -102
  8. roms_tools/setup/initial_conditions.py +179 -132
  9. roms_tools/setup/nesting.py +239 -86
  10. roms_tools/setup/river_forcing.py +266 -128
  11. roms_tools/setup/surface_forcing.py +137 -76
  12. roms_tools/setup/tides.py +10 -36
  13. roms_tools/setup/topography.py +25 -2
  14. roms_tools/setup/utils.py +52 -82
  15. roms_tools/tests/test_analysis/test_roms_output.py +233 -70
  16. roms_tools/tests/test_setup/test_boundary_forcing.py +283 -57
  17. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zattrs +3 -1
  18. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zmetadata +3 -1
  19. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/0.0.0 +0 -0
  20. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_south/0.0.0 +0 -0
  21. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/0.0.0 +0 -0
  22. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/0.0.0 +0 -0
  23. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_south/0.0.0 +0 -0
  24. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/0.0.0 +0 -0
  25. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/0.0.0 +0 -0
  26. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_south/0.0.0 +0 -0
  27. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/0.0.0 +0 -0
  28. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/0.0.0 +0 -0
  29. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_south/0.0.0 +0 -0
  30. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/0.0.0 +0 -0
  31. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/0.0.0 +0 -0
  32. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_south/0.0.0 +0 -0
  33. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/0.0.0 +0 -0
  34. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/0.0.0 +0 -0
  35. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_south/0.0.0 +0 -0
  36. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/0.0.0 +0 -0
  37. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/0.0.0 +0 -0
  38. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_south/0.0.0 +0 -0
  39. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/0.0.0 +0 -0
  40. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/0.0.0 +0 -0
  41. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_south/0.0.0 +0 -0
  42. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/0.0.0 +0 -0
  43. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/0.0.0 +0 -0
  44. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_south/0.0.0 +0 -0
  45. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/0.0.0 +0 -0
  46. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/0.0.0 +0 -0
  47. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_south/0.0.0 +0 -0
  48. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/0.0.0 +0 -0
  49. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/0.0.0 +0 -0
  50. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_south/0.0.0 +0 -0
  51. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/0.0.0 +0 -0
  52. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/0.0.0 +0 -0
  53. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_south/0.0.0 +0 -0
  54. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/0.0.0 +0 -0
  55. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/0.0.0 +0 -0
  56. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_north/0.0.0 +0 -0
  57. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_south/0.0.0 +0 -0
  58. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/0.0.0 +0 -0
  59. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/0.0.0 +0 -0
  60. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_south/0.0.0 +0 -0
  61. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/0.0.0 +0 -0
  62. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/0.0.0 +0 -0
  63. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_south/0.0.0 +0 -0
  64. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/0.0.0 +0 -0
  65. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/0.0.0 +0 -0
  66. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_south/0.0.0 +0 -0
  67. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/0.0.0 +0 -0
  68. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/0.0.0 +0 -0
  69. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_south/0.0.0 +0 -0
  70. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/0.0.0 +0 -0
  71. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/0.0.0 +0 -0
  72. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_north/0.0.0 +0 -0
  73. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_south/0.0.0 +0 -0
  74. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/0.0.0 +0 -0
  75. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/0.0.0 +0 -0
  76. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_north/0.0.0 +0 -0
  77. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_south/0.0.0 +0 -0
  78. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/0.0.0 +0 -0
  79. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/0.0.0 +0 -0
  80. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_north/0.0.0 +0 -0
  81. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_south/0.0.0 +0 -0
  82. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/0.0.0 +0 -0
  83. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/0.0.0 +0 -0
  84. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_north/0.0.0 +0 -0
  85. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_south/0.0.0 +0 -0
  86. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/0.0.0 +0 -0
  87. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/0.0.0 +0 -0
  88. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_north/0.0.0 +0 -0
  89. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_south/0.0.0 +0 -0
  90. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/0.0.0 +0 -0
  91. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/0.0.0 +0 -0
  92. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_north/0.0.0 +0 -0
  93. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_south/0.0.0 +0 -0
  94. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/0.0.0 +0 -0
  95. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/0.0.0 +0 -0
  96. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_north/0.0.0 +0 -0
  97. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_south/0.0.0 +0 -0
  98. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/0.0.0 +0 -0
  99. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/0.0.0 +0 -0
  100. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_north/0.0.0 +0 -0
  101. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_south/0.0.0 +0 -0
  102. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/0.0.0 +0 -0
  103. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/0.0.0 +0 -0
  104. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_north/0.0.0 +0 -0
  105. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_south/0.0.0 +0 -0
  106. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/0.0.0 +0 -0
  107. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/0.0.0 +0 -0
  108. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_north/0.0.0 +0 -0
  109. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_south/0.0.0 +0 -0
  110. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/0.0.0 +0 -0
  111. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/0.0.0 +0 -0
  112. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_north/0.0.0 +0 -0
  113. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_south/0.0.0 +0 -0
  114. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/0.0.0 +0 -0
  115. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/0.0.0 +0 -0
  116. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_north/0.0.0 +0 -0
  117. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_south/0.0.0 +0 -0
  118. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/0.0.0 +0 -0
  119. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/0.0.0 +0 -0
  120. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_north/0.0.0 +0 -0
  121. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_south/0.0.0 +0 -0
  122. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/0.0.0 +0 -0
  123. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/0.0.0 +0 -0
  124. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_north/0.0.0 +0 -0
  125. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_south/0.0.0 +0 -0
  126. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/0.0.0 +0 -0
  127. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/0.0.0 +0 -0
  128. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_north/0.0.0 +0 -0
  129. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_south/0.0.0 +0 -0
  130. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/0.0.0 +0 -0
  131. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zattrs +2 -2
  132. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zmetadata +8 -7
  133. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/abs_time/.zattrs +1 -0
  134. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust/0.0.0 +0 -0
  135. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust_time/.zattrs +1 -1
  136. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron/0.0.0 +0 -0
  137. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron_time/.zattrs +1 -1
  138. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy/0.0.0 +0 -0
  139. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy_time/.zattrs +1 -1
  140. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox/0.0.0 +0 -0
  141. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox_time/.zattrs +1 -1
  142. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air/0.0.0 +0 -0
  143. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air_alt/0.0.0 +0 -0
  144. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_time/.zattrs +1 -1
  145. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zattrs +2 -2
  146. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zmetadata +2 -2
  147. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust/0.0.0 +0 -0
  148. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron/0.0.0 +0 -0
  149. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy/0.0.0 +0 -0
  150. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox/0.0.0 +0 -0
  151. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air/0.0.0 +0 -0
  152. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air_alt/0.0.0 +0 -0
  153. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/.zattrs +5 -3
  154. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/.zmetadata +156 -121
  155. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zarray +2 -2
  156. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zattrs +2 -1
  157. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/0 +0 -0
  158. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/bry_time/.zarray +2 -2
  159. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/bry_time/.zattrs +1 -1
  160. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/bry_time/0 +0 -0
  161. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/.zarray +4 -4
  162. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/0.0.0 +0 -0
  163. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_north/.zarray +4 -4
  164. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_north/0.0.0 +0 -0
  165. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/.zarray +4 -4
  166. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/0.0.0 +0 -0
  167. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_west/.zarray +4 -4
  168. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_west/0.0.0 +0 -0
  169. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/.zarray +4 -4
  170. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/0.0.0 +0 -0
  171. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_north/.zarray +4 -4
  172. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_north/0.0.0 +0 -0
  173. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/.zarray +4 -4
  174. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/0.0.0 +0 -0
  175. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_west/.zarray +4 -4
  176. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_west/0.0.0 +0 -0
  177. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/.zarray +4 -4
  178. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/0.0.0 +0 -0
  179. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/.zarray +4 -4
  180. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/0.0.0 +0 -0
  181. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/.zarray +4 -4
  182. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/0.0.0 +0 -0
  183. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/.zarray +4 -4
  184. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/0.0.0 +0 -0
  185. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/.zarray +4 -4
  186. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/0.0 +0 -0
  187. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/.zarray +4 -4
  188. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/0.0 +0 -0
  189. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/.zarray +4 -4
  190. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/0.0 +0 -0
  191. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/.zarray +4 -4
  192. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/0.0 +0 -0
  193. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/.zarray +4 -4
  194. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/0.0.0 +0 -0
  195. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/.zarray +4 -4
  196. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/0.0.0 +0 -0
  197. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/.zarray +4 -4
  198. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/0.0.0 +0 -0
  199. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/.zarray +4 -4
  200. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/0.0.0 +0 -0
  201. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/.zarray +4 -4
  202. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/0.0 +0 -0
  203. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/.zarray +4 -4
  204. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/0.0 +0 -0
  205. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/.zarray +4 -4
  206. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/0.0 +0 -0
  207. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/.zarray +4 -4
  208. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/0.0 +0 -0
  209. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zarray +4 -4
  210. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zattrs +8 -0
  211. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/0.0 +0 -0
  212. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/.zarray +4 -4
  213. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/.zattrs +8 -0
  214. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/0.0 +0 -0
  215. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zarray +4 -4
  216. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zattrs +8 -0
  217. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/0.0 +0 -0
  218. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/.zarray +4 -4
  219. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/.zattrs +8 -0
  220. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/0.0 +0 -0
  221. roms_tools/tests/test_setup/test_data/grid.zarr/.zattrs +1 -1
  222. roms_tools/tests/test_setup/test_data/grid.zarr/.zmetadata +2 -2
  223. roms_tools/tests/test_setup/test_data/grid.zarr/angle/0.0 +0 -0
  224. roms_tools/tests/test_setup/test_data/grid.zarr/angle_coarse/0.0 +0 -0
  225. roms_tools/tests/test_setup/test_data/grid.zarr/f/0.0 +0 -0
  226. roms_tools/tests/test_setup/test_data/grid.zarr/h/.zattrs +1 -1
  227. roms_tools/tests/test_setup/test_data/grid.zarr/h/0.0 +0 -0
  228. roms_tools/tests/test_setup/test_data/grid.zarr/lat_coarse/0.0 +0 -0
  229. roms_tools/tests/test_setup/test_data/grid.zarr/lat_rho/0.0 +0 -0
  230. roms_tools/tests/test_setup/test_data/grid.zarr/lat_u/0.0 +0 -0
  231. roms_tools/tests/test_setup/test_data/grid.zarr/lat_v/0.0 +0 -0
  232. roms_tools/tests/test_setup/test_data/grid.zarr/pm/0.0 +0 -0
  233. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zattrs +4 -4
  234. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zmetadata +4 -4
  235. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle/0.0 +0 -0
  236. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle_coarse/0.0 +0 -0
  237. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/f/0.0 +0 -0
  238. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/0.0 +0 -0
  239. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_coarse/0.0 +0 -0
  240. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_rho/0.0 +0 -0
  241. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_u/0.0 +0 -0
  242. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_v/0.0 +0 -0
  243. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_coarse/0.0 +0 -0
  244. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_rho/0.0 +0 -0
  245. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_u/0.0 +0 -0
  246. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_v/0.0 +0 -0
  247. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_coarse/0.0 +0 -0
  248. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_rho/0.0 +0 -0
  249. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_u/0.0 +0 -0
  250. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_v/0.0 +0 -0
  251. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pm/0.0 +0 -0
  252. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pn/0.0 +0 -0
  253. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zattrs +2 -1
  254. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zmetadata +6 -4
  255. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Cs_r/.zattrs +1 -1
  256. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Cs_w/.zattrs +1 -1
  257. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NH4/0.0.0.0 +0 -0
  258. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NO3/0.0.0.0 +0 -0
  259. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/PO4/0.0.0.0 +0 -0
  260. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/abs_time/.zattrs +1 -0
  261. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatSi/0.0.0.0 +0 -0
  262. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ocean_time/.zattrs +1 -1
  263. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/salt/0.0.0.0 +0 -0
  264. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spC/0.0.0.0 +0 -0
  265. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spCaCO3/0.0.0.0 +0 -0
  266. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spFe/0.0.0.0 +0 -0
  267. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/temp/0.0.0.0 +0 -0
  268. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/u/0.0.0.0 +0 -0
  269. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ubar/0.0.0 +0 -0
  270. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/v/0.0.0.0 +0 -0
  271. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/vbar/0.0.0 +0 -0
  272. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zeta/0.0.0 +0 -0
  273. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +56 -0
  274. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/.zarray +20 -0
  275. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/.zattrs +6 -0
  276. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/0 +0 -0
  277. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/.zarray +22 -0
  278. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/.zattrs +8 -0
  279. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/0.0 +0 -0
  280. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/.zmetadata +56 -0
  281. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/.zarray +20 -0
  282. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/.zattrs +6 -0
  283. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/0 +0 -0
  284. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/.zarray +22 -0
  285. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/.zattrs +8 -0
  286. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/0.0 +0 -0
  287. roms_tools/tests/test_setup/test_grid.py +0 -13
  288. roms_tools/tests/test_setup/test_initial_conditions.py +220 -66
  289. roms_tools/tests/test_setup/test_nesting.py +139 -118
  290. roms_tools/tests/test_setup/test_river_forcing.py +583 -293
  291. roms_tools/tests/test_setup/test_surface_forcing.py +149 -73
  292. roms_tools/tests/test_setup/test_tides.py +4 -16
  293. roms_tools/tests/test_setup/test_utils.py +1 -0
  294. roms_tools/tests/test_setup/test_validation.py +34 -2
  295. roms_tools/tests/{test_utils.py → test_tiling/test_partition.py} +1 -1
  296. roms_tools/tiling/partition.py +338 -0
  297. roms_tools/utils.py +66 -333
  298. roms_tools/vertical_coordinate.py +54 -133
  299. {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/METADATA +1 -1
  300. {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/RECORD +303 -290
  301. {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/WHEEL +1 -1
  302. {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/LICENSE +0 -0
  303. {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/top_level.txt +0 -0
@@ -5,22 +5,26 @@ from datetime import datetime
5
5
  import textwrap
6
6
  from pathlib import Path
7
7
  import pytest
8
+ import logging
8
9
  from conftest import calculate_file_hash
9
- from roms_tools.download import download_river_data
10
10
 
11
11
 
12
12
  @pytest.fixture
13
- def river_forcing_climatology():
14
- """Fixture for creating a RiverForcing object from the global Dai river dataset."""
15
- grid = Grid(
13
+ def iceland_test_grid():
14
+ return Grid(
16
15
  nx=18, ny=18, size_x=800, size_y=800, center_lon=-18, center_lat=65, rot=20, N=3
17
16
  )
18
17
 
18
+
19
+ @pytest.fixture
20
+ def river_forcing_climatology(iceland_test_grid):
21
+ """Fixture for creating a RiverForcing object from the global Dai river dataset."""
22
+
19
23
  start_time = datetime(1998, 1, 1)
20
24
  end_time = datetime(1998, 3, 1)
21
25
 
22
26
  return RiverForcing(
23
- grid=grid,
27
+ grid=iceland_test_grid,
24
28
  start_time=start_time,
25
29
  end_time=end_time,
26
30
  convert_to_climatology="always",
@@ -52,353 +56,639 @@ def river_forcing_for_grid_that_straddles_dateline():
52
56
  )
53
57
 
54
58
 
55
- def compare_dictionaries(dict1, dict2):
56
- assert dict1.keys() == dict2.keys()
59
+ @pytest.fixture
60
+ def single_cell_indices():
61
+ # These are the indices that the `river_forcing` fixture generates automatically.
62
+ return {
63
+ "Hvita(Olfusa)": [(8, 6)],
64
+ "Thjorsa": [(8, 6)],
65
+ "JkulsFjll": [(11, 12)],
66
+ "Lagarfljot": [(9, 13)],
67
+ "Bruara": [(8, 6)],
68
+ "Svarta": [(12, 9)],
69
+ }
57
70
 
58
- for key in dict1.keys():
59
- assert np.array_equal(dict1[key], dict2[key])
71
+
72
+ @pytest.fixture
73
+ def multi_cell_indices():
74
+ # These are the indices that the `river_forcing` fixture generates automatically.
75
+ return {
76
+ "Hvita(Olfusa)": [(8, 6)],
77
+ "Thjorsa": [(8, 6)],
78
+ "JkulsFjll": [(11, 12)],
79
+ "Lagarfljot": [(9, 13), (10, 13)],
80
+ "Bruara": [(8, 6)],
81
+ "Svarta": [(12, 8), (12, 9), (12, 10)],
82
+ }
60
83
 
61
84
 
62
- @pytest.mark.parametrize(
63
- "river_forcing_fixture",
64
- [
65
- "river_forcing",
66
- "river_forcing_for_grid_that_straddles_dateline",
67
- "river_forcing_with_bgc",
68
- ],
69
- )
70
- def test_successful_initialization_with_climatological_dai_data(
71
- river_forcing_fixture, request
85
+ @pytest.fixture
86
+ def river_forcing_with_prescribed_single_cell_indices(
87
+ single_cell_indices, iceland_test_grid
72
88
  ):
89
+ """Fixture for creating a RiverForcing object based on the global Dai river dataset,
90
+ using manually specified single-cell river indices instead of relying on automatic
91
+ detection."""
92
+
93
+ start_time = datetime(1998, 1, 1)
94
+ end_time = datetime(1998, 3, 1)
73
95
 
74
- river_forcing = request.getfixturevalue(river_forcing_fixture)
75
-
76
- assert isinstance(river_forcing.ds, xr.Dataset)
77
- assert len(river_forcing.ds.nriver) > 0
78
- assert len(river_forcing.original_indices["name"]) > 0
79
- assert "river_volume" in river_forcing.ds
80
- assert "river_tracer" in river_forcing.ds
81
- assert river_forcing.climatology
82
- assert "river_time" in river_forcing.ds
83
- assert hasattr(
84
- river_forcing.ds.river_time,
85
- "cycle_length",
96
+ return RiverForcing(
97
+ grid=iceland_test_grid,
98
+ start_time=start_time,
99
+ end_time=end_time,
100
+ indices=single_cell_indices,
86
101
  )
87
- assert hasattr(river_forcing.ds, "climatology")
88
102
 
89
103
 
90
- def test_successful_initialization_with_monthly_dai_data(river_forcing_no_climatology):
104
+ @pytest.fixture
105
+ def river_forcing_with_prescribed_multi_cell_indices(
106
+ multi_cell_indices, iceland_test_grid
107
+ ):
108
+ """Fixture for creating a RiverForcing object based on the global Dai river dataset,
109
+ using manually specified multi-cell river indices instead of relying on automatic
110
+ detection."""
91
111
 
92
- assert isinstance(river_forcing_no_climatology.ds, xr.Dataset)
93
- assert "river_volume" in river_forcing_no_climatology.ds
94
- assert "river_tracer" in river_forcing_no_climatology.ds
95
- assert "river_time" in river_forcing_no_climatology.ds
96
- assert not river_forcing_no_climatology.climatology
97
- assert not hasattr(
98
- river_forcing_no_climatology.ds.river_time,
99
- "cycle_length",
112
+ start_time = datetime(1998, 1, 1)
113
+ end_time = datetime(1998, 3, 1)
114
+
115
+ return RiverForcing(
116
+ grid=iceland_test_grid,
117
+ start_time=start_time,
118
+ end_time=end_time,
119
+ indices=multi_cell_indices,
100
120
  )
101
- assert not hasattr(river_forcing_no_climatology.ds, "climatology")
102
121
 
103
122
 
104
- def test_reproducibility(river_forcing, river_forcing_climatology):
123
+ def compare_dictionaries(dict1, dict2):
124
+ assert dict1.keys() == dict2.keys()
125
+
126
+ for key in dict1.keys():
127
+ assert np.array_equal(dict1[key], dict2[key])
105
128
 
106
- xr.testing.assert_allclose(river_forcing.ds, river_forcing_climatology.ds)
107
129
 
108
- compare_dictionaries(
109
- river_forcing.original_indices, river_forcing_climatology.original_indices
130
+ class TestRiverForcingGeneral:
131
+ @pytest.mark.parametrize(
132
+ "river_forcing_fixture",
133
+ [
134
+ "river_forcing",
135
+ "river_forcing_climatology",
136
+ "river_forcing_with_bgc",
137
+ "river_forcing_for_grid_that_straddles_dateline",
138
+ "river_forcing_with_prescribed_single_cell_indices",
139
+ "river_forcing_with_prescribed_multi_cell_indices",
140
+ ],
110
141
  )
111
- compare_dictionaries(
112
- river_forcing.updated_indices, river_forcing_climatology.updated_indices
142
+ def test_successful_initialization(self, river_forcing_fixture, request):
143
+ river_forcing = request.getfixturevalue(river_forcing_fixture)
144
+ assert isinstance(river_forcing.ds, xr.Dataset)
145
+ assert len(river_forcing.ds.nriver) > 0
146
+ assert len(river_forcing.original_indices) > 0
147
+ assert len(river_forcing.indices) > 0
148
+ assert "river_volume" in river_forcing.ds
149
+ assert "river_tracer" in river_forcing.ds
150
+ assert "river_time" in river_forcing.ds
151
+
152
+ @pytest.mark.parametrize(
153
+ "river_forcing_fixture",
154
+ [
155
+ "river_forcing",
156
+ "river_forcing_climatology",
157
+ "river_forcing_with_bgc",
158
+ "river_forcing_with_prescribed_single_cell_indices",
159
+ "river_forcing_with_prescribed_multi_cell_indices",
160
+ ],
113
161
  )
162
+ def test_climatology_attributes(self, river_forcing_fixture, request):
163
+ river_forcing = request.getfixturevalue(river_forcing_fixture)
164
+ assert river_forcing.climatology
165
+ assert hasattr(
166
+ river_forcing.ds.river_time,
167
+ "cycle_length",
168
+ )
169
+ assert hasattr(river_forcing.ds, "climatology")
114
170
 
115
-
116
- def test_reproducibility_indices(river_forcing, river_forcing_no_climatology):
117
-
118
- compare_dictionaries(
119
- river_forcing.original_indices, river_forcing_no_climatology.original_indices
120
- )
121
- compare_dictionaries(
122
- river_forcing.updated_indices, river_forcing_no_climatology.updated_indices
171
+ def test_no_climatology_attributes(self, river_forcing_no_climatology, request):
172
+ assert not river_forcing_no_climatology.climatology
173
+ assert not hasattr(
174
+ river_forcing_no_climatology.ds.river_time,
175
+ "cycle_length",
176
+ )
177
+ assert not hasattr(river_forcing_no_climatology.ds, "climatology")
178
+
179
+ @pytest.mark.parametrize(
180
+ "river_forcing_fixture",
181
+ [
182
+ "river_forcing_climatology",
183
+ "river_forcing_no_climatology",
184
+ "river_forcing_with_bgc",
185
+ "river_forcing_with_prescribed_single_cell_indices",
186
+ "river_forcing_with_prescribed_multi_cell_indices",
187
+ ],
123
188
  )
189
+ def test_constant_tracers(self, river_forcing_fixture, request):
190
+ river_forcing = request.getfixturevalue(river_forcing_fixture)
191
+ np.testing.assert_allclose(
192
+ river_forcing.ds.river_tracer.isel(ntracers=0).values, 17.0, atol=0
193
+ )
194
+ np.testing.assert_allclose(
195
+ river_forcing.ds.river_tracer.isel(ntracers=1).values, 1.0, atol=0
196
+ )
197
+ np.testing.assert_allclose(
198
+ river_forcing.ds.river_tracer.isel(ntracers=slice(2, None)).values,
199
+ 0.0,
200
+ atol=0,
201
+ )
124
202
 
203
+ def test_reproducibility_same_grid(self, river_forcing):
125
204
 
126
- @pytest.mark.parametrize(
127
- "river_forcing_fixture",
128
- [
129
- "river_forcing_climatology",
130
- "river_forcing_no_climatology",
131
- "river_forcing_with_bgc",
132
- ],
133
- )
134
- def test_constant_tracers(river_forcing_fixture, request):
135
- river_forcing = request.getfixturevalue(river_forcing_fixture)
205
+ the_same_river_forcing = RiverForcing(
206
+ grid=river_forcing.grid,
207
+ start_time=datetime(1998, 1, 1),
208
+ end_time=datetime(1998, 3, 1),
209
+ )
136
210
 
137
- np.testing.assert_allclose(
138
- river_forcing.ds.river_tracer.isel(ntracers=0).values, 17.0, atol=0
211
+ assert river_forcing == the_same_river_forcing
212
+
213
+ @pytest.mark.parametrize(
214
+ "river_forcing_fixture",
215
+ [
216
+ "river_forcing_climatology",
217
+ "river_forcing_no_climatology",
218
+ "river_forcing_with_bgc",
219
+ "river_forcing_with_prescribed_single_cell_indices",
220
+ "river_forcing_with_prescribed_multi_cell_indices",
221
+ ],
139
222
  )
140
- np.testing.assert_allclose(
141
- river_forcing.ds.river_tracer.isel(ntracers=1).values, 1.0, atol=0
223
+ def test_river_locations_are_along_coast(self, river_forcing_fixture, request):
224
+ river_forcing = request.getfixturevalue(river_forcing_fixture)
225
+
226
+ mask = river_forcing.grid.ds.mask_rho
227
+ faces = (
228
+ mask.shift(eta_rho=1)
229
+ + mask.shift(eta_rho=-1)
230
+ + mask.shift(xi_rho=1)
231
+ + mask.shift(xi_rho=-1)
232
+ )
233
+ coast = (1 - mask) * (faces > 0)
234
+
235
+ indices = river_forcing.indices
236
+ for name in indices.keys():
237
+ for (eta_rho, xi_rho) in indices[name]:
238
+ assert coast[eta_rho, xi_rho]
239
+ assert river_forcing.ds["river_location"][eta_rho, xi_rho] > 0
240
+
241
+ def test_missing_source_name(self, iceland_test_grid):
242
+ with pytest.raises(ValueError, match="`source` must include a 'name'."):
243
+ RiverForcing(
244
+ grid=iceland_test_grid,
245
+ start_time=datetime(1998, 1, 1),
246
+ end_time=datetime(1998, 3, 1),
247
+ source={"path": "river_data.nc"},
248
+ )
249
+
250
+ def test_river_forcing_plot(self, river_forcing_with_bgc):
251
+ """Test plot method."""
252
+
253
+ river_forcing_with_bgc.plot_locations()
254
+ river_forcing_with_bgc.plot("river_volume")
255
+ river_forcing_with_bgc.plot("river_temp")
256
+ river_forcing_with_bgc.plot("river_salt")
257
+ river_forcing_with_bgc.plot("river_ALK")
258
+ river_forcing_with_bgc.plot("river_PO4")
259
+
260
+ @pytest.mark.parametrize(
261
+ "river_forcing_fixture",
262
+ [
263
+ "river_forcing_with_bgc",
264
+ "river_forcing_with_prescribed_multi_cell_indices",
265
+ ],
142
266
  )
143
- np.testing.assert_allclose(
144
- river_forcing.ds.river_tracer.isel(ntracers=slice(2, None)).values, 0.0, atol=0
267
+ def test_river_forcing_save(self, river_forcing_fixture, tmp_path, request):
268
+ """Test save method."""
269
+
270
+ river_forcing = request.getfixturevalue(river_forcing_fixture)
271
+ for file_str in ["test_rivers", "test_rivers.nc"]:
272
+ # Create a temporary filepath using the tmp_path fixture
273
+ for filepath in [tmp_path / file_str, str(tmp_path / file_str)]:
274
+
275
+ saved_filenames = river_forcing.save(filepath)
276
+ # Check if the .nc file was created
277
+ filepath = Path(filepath).with_suffix(".nc")
278
+ assert saved_filenames == [filepath]
279
+ assert filepath.exists()
280
+ # Clean up the .nc file
281
+ filepath.unlink()
282
+
283
+ @pytest.mark.parametrize(
284
+ "river_forcing_fixture",
285
+ [
286
+ "river_forcing_climatology",
287
+ "river_forcing_no_climatology",
288
+ "river_forcing_with_bgc",
289
+ "river_forcing_with_prescribed_single_cell_indices",
290
+ "river_forcing_with_prescribed_multi_cell_indices",
291
+ ],
145
292
  )
293
+ def test_roundtrip_yaml(self, river_forcing_fixture, request, tmp_path, caplog):
294
+ """Test that creating an RiverForcing object, saving its parameters to yaml
295
+ file, and re-opening yaml file creates the same object."""
146
296
 
297
+ river_forcing = request.getfixturevalue(river_forcing_fixture)
147
298
 
148
- @pytest.mark.parametrize(
149
- "river_forcing_fixture",
150
- [
151
- "river_forcing_climatology",
152
- "river_forcing_no_climatology",
153
- "river_forcing_with_bgc",
154
- ],
155
- )
156
- def test_river_locations_are_along_coast(river_forcing_fixture, request):
157
- river_forcing = request.getfixturevalue(river_forcing_fixture)
158
-
159
- mask = river_forcing.grid.ds.mask_rho
160
- faces = (
161
- mask.shift(eta_rho=1)
162
- + mask.shift(eta_rho=-1)
163
- + mask.shift(xi_rho=1)
164
- + mask.shift(xi_rho=-1)
165
- )
166
- coast = (1 - mask) * (faces > 0)
299
+ # Create a temporary filepath using the tmp_path fixture
300
+ file_str = "test_yaml"
301
+ for filepath in [
302
+ tmp_path / file_str,
303
+ str(tmp_path / file_str),
304
+ ]: # test for Path object and str
167
305
 
168
- indices = river_forcing.updated_indices
169
- for i in range(len(indices["station"])):
170
- eta_rho = indices["eta_rho"][i]
171
- xi_rho = indices["xi_rho"][i]
172
- assert coast[eta_rho, xi_rho]
173
- assert river_forcing.grid.ds["river_flux"][eta_rho, xi_rho] > 0
306
+ river_forcing.to_yaml(filepath)
174
307
 
308
+ # Clear caplog before running the test
309
+ caplog.clear()
175
310
 
176
- def test_missing_source_name():
311
+ with caplog.at_level(logging.INFO):
312
+ river_forcing_from_file = RiverForcing.from_yaml(filepath)
177
313
 
178
- grid = Grid(
179
- nx=2,
180
- ny=2,
181
- size_x=500,
182
- size_y=1000,
183
- center_lon=0,
184
- center_lat=55,
185
- rot=10,
186
- N=3, # number of vertical levels
314
+ assert "Use provided river indices." in caplog.text
315
+ assert river_forcing == river_forcing_from_file
316
+
317
+ filepath = Path(filepath)
318
+ filepath.unlink()
319
+
320
+ @pytest.mark.parametrize(
321
+ "river_forcing_fixture",
322
+ [
323
+ "river_forcing_climatology",
324
+ "river_forcing_no_climatology",
325
+ "river_forcing_with_bgc",
326
+ "river_forcing_with_prescribed_single_cell_indices",
327
+ "river_forcing_with_prescribed_multi_cell_indices",
328
+ ],
187
329
  )
330
+ def test_files_have_same_hash(self, river_forcing_fixture, request, tmp_path):
188
331
 
189
- with pytest.raises(ValueError, match="`source` must include a 'name'."):
190
- RiverForcing(
191
- grid=grid,
192
- start_time=datetime(1998, 1, 1),
193
- end_time=datetime(1998, 3, 1),
194
- source={"path": "river_data.nc"},
195
- )
332
+ river_forcing = request.getfixturevalue(river_forcing_fixture)
196
333
 
334
+ yaml_filepath = tmp_path / "test_yaml.yaml"
335
+ filepath1 = tmp_path / "test1.nc"
336
+ filepath2 = tmp_path / "test2.nc"
197
337
 
198
- def test_no_rivers_found():
338
+ river_forcing.to_yaml(yaml_filepath)
339
+ river_forcing.save(filepath1)
340
+ rf_from_file = RiverForcing.from_yaml(yaml_filepath)
341
+ rf_from_file.save(filepath2)
199
342
 
200
- # Create a grid over open ocean
201
- grid = Grid(
202
- nx=2, ny=2, size_x=50, size_y=50, center_lon=0, center_lat=55, rot=10, N=3
203
- )
204
- with pytest.raises(
205
- ValueError,
206
- match="No relevant rivers found.",
207
- ):
343
+ hash1 = calculate_file_hash(filepath1)
344
+ hash2 = calculate_file_hash(filepath2)
208
345
 
209
- RiverForcing(
210
- grid=grid,
211
- start_time=datetime(1998, 1, 1),
212
- end_time=datetime(1998, 3, 1),
346
+ assert hash1 == hash2, f"Hashes do not match: {hash1} != {hash2}"
347
+
348
+ yaml_filepath.unlink()
349
+ filepath1.unlink()
350
+ filepath2.unlink()
351
+
352
+ def test_from_yaml_missing_river_forcing(self, tmp_path):
353
+ yaml_content = textwrap.dedent(
354
+ """\
355
+ ---
356
+ roms_tools_version: 0.0.0
357
+ ---
358
+ Grid:
359
+ nx: 100
360
+ ny: 100
361
+ size_x: 1800
362
+ size_y: 2400
363
+ center_lon: -10
364
+ center_lat: 61
365
+ rot: -20
366
+ topography_source:
367
+ name: ETOPO5
368
+ hmin: 5.0
369
+ """
213
370
  )
214
371
 
372
+ # Create a temporary filepath using the tmp_path fixture
373
+ file_str = "test_yaml"
374
+ for yaml_filepath in [
375
+ tmp_path / file_str,
376
+ str(tmp_path / file_str),
377
+ ]: # test for Path object and str
378
+
379
+ # Write YAML content to file
380
+ if isinstance(yaml_filepath, Path):
381
+ yaml_filepath.write_text(yaml_content)
382
+ else:
383
+ with open(yaml_filepath, "w") as f:
384
+ f.write(yaml_content)
385
+
386
+ with pytest.raises(
387
+ ValueError,
388
+ match="No RiverForcing configuration found in the YAML file.",
389
+ ):
390
+ RiverForcing.from_yaml(yaml_filepath)
391
+
392
+ yaml_filepath = Path(yaml_filepath)
393
+ yaml_filepath.unlink()
394
+
395
+
396
+ class TestRiverForcingWithoutPrescribedIndices:
397
+ def test_logging_message(self, iceland_test_grid, caplog):
398
+
399
+ with caplog.at_level(logging.INFO):
400
+ RiverForcing(
401
+ grid=iceland_test_grid,
402
+ start_time=datetime(1998, 1, 1),
403
+ end_time=datetime(1998, 3, 1),
404
+ )
405
+ # Verify the info message in the log
406
+ assert "No river indices provided." in caplog.text
407
+
408
+ def test_reproducibility(self, river_forcing, river_forcing_climatology):
409
+ """Verify that `river_forcing` and `river_forcing_climatology` produce identical
410
+ outputs.
411
+
412
+ `river_forcing` is initialized with `convert_to_climatology="if_any_missing"`, meaning
413
+ it fell back to climatology. This test ensures that the resulting datasets
414
+ and river index mappings are the same between the two cases.
415
+ """
416
+ xr.testing.assert_allclose(river_forcing.ds, river_forcing_climatology.ds)
417
+ compare_dictionaries(
418
+ river_forcing.original_indices, river_forcing_climatology.original_indices
419
+ )
420
+ compare_dictionaries(river_forcing.indices, river_forcing_climatology.indices)
215
421
 
216
- def test_reproducibility_same_grid(river_forcing):
422
+ def test_no_rivers_found(self):
217
423
 
218
- the_same_river_forcing = RiverForcing(
219
- grid=river_forcing.grid,
220
- start_time=datetime(1998, 1, 1),
221
- end_time=datetime(1998, 3, 1),
222
- )
424
+ # Create a grid over open ocean
425
+ grid = Grid(
426
+ nx=2, ny=2, size_x=50, size_y=50, center_lon=0, center_lat=55, rot=10, N=3
427
+ )
223
428
 
224
- assert river_forcing == the_same_river_forcing
429
+ with pytest.raises(ValueError, match="No relevant rivers found."):
430
+ RiverForcing(
431
+ grid=grid,
432
+ start_time=datetime(1998, 1, 1),
433
+ end_time=datetime(1998, 3, 1),
434
+ )
225
435
 
226
436
 
227
- def test_update_river_flux_variable_without_conflicts(river_forcing, tmp_path):
437
+ class TestRiverForcingWithPrescribedIndices:
438
+ def test_logging_message(self, iceland_test_grid, single_cell_indices, caplog):
228
439
 
229
- fname = download_river_data("dai_trenberth_may2019.nc")
230
- ds = xr.open_dataset(fname, decode_times=False)
231
- # only keep the 300 biggest rivers, which will lower the total relevant river number
232
- ds = ds.isel(station=slice(None, 300))
233
- filepath = tmp_path / "test.nc"
234
- ds.to_netcdf(filepath)
440
+ with caplog.at_level(logging.INFO):
441
+ RiverForcing(
442
+ grid=iceland_test_grid,
443
+ start_time=datetime(1998, 1, 1),
444
+ end_time=datetime(1998, 3, 1),
445
+ indices=single_cell_indices,
446
+ )
447
+ # Verify the info message in the log
448
+ assert "Use provided river indices." in caplog.text
235
449
 
236
- another_river_forcing = RiverForcing(
237
- grid=river_forcing.grid,
238
- start_time=datetime(1998, 1, 1),
239
- end_time=datetime(1998, 3, 1),
240
- source={"name": "DAI", "path": filepath},
450
+ @pytest.mark.parametrize(
451
+ "indices_fixture", ["single_cell_indices", "multi_cell_indices"]
241
452
  )
453
+ def test_indices_stay_untouched(self, iceland_test_grid, indices_fixture, request):
454
+ indices = request.getfixturevalue(indices_fixture)
242
455
 
243
- assert isinstance(another_river_forcing.ds, xr.Dataset)
456
+ start_time = datetime(1998, 1, 1)
457
+ end_time = datetime(1998, 3, 1)
244
458
 
459
+ river_forcing = RiverForcing(
460
+ grid=iceland_test_grid,
461
+ start_time=start_time,
462
+ end_time=end_time,
463
+ indices=indices,
464
+ )
465
+ river_forcing.original_indices == indices
466
+ river_forcing.indices == indices
245
467
 
246
- def test_river_forcing_plot(river_forcing_with_bgc):
247
- """Test plot method."""
248
-
249
- river_forcing_with_bgc.plot_locations()
250
- river_forcing_with_bgc.plot("river_volume")
251
- river_forcing_with_bgc.plot("river_temp")
252
- river_forcing_with_bgc.plot("river_salt")
253
- river_forcing_with_bgc.plot("river_ALK")
254
- river_forcing_with_bgc.plot("river_PO4")
468
+ def test_fraction(
469
+ self,
470
+ river_forcing_with_prescribed_single_cell_indices,
471
+ river_forcing_with_prescribed_multi_cell_indices,
472
+ ):
473
+ def list_non_zero_values(data_array):
474
+ non_zero_values = data_array.values
475
+ return non_zero_values[non_zero_values != 0].tolist()
476
+
477
+ # check that all values are integers for single cell rivers
478
+ non_zero_values = river_forcing_with_prescribed_single_cell_indices.ds[
479
+ "river_location"
480
+ ]
481
+ is_integer = non_zero_values == np.floor(non_zero_values)
482
+ assert (is_integer).all()
483
+
484
+ # check that not all values are integers for multi cell rivers
485
+ non_zero_values = river_forcing_with_prescribed_multi_cell_indices.ds[
486
+ "river_location"
487
+ ]
488
+ is_integer = non_zero_values == np.floor(non_zero_values)
489
+ assert not (is_integer).all()
490
+
491
+ def test_reproducibility(
492
+ self, river_forcing, river_forcing_with_prescribed_single_cell_indices
493
+ ):
494
+ """river_forcing_with_prescribed_single_cell_indices was created with the
495
+ indices that were automatically inferred for river_forcing.
496
+
497
+ Test that these two are identical.
498
+ """
499
+ assert (
500
+ river_forcing.indices
501
+ == river_forcing_with_prescribed_single_cell_indices.indices
502
+ )
503
+ assert river_forcing.ds.identical(
504
+ river_forcing_with_prescribed_single_cell_indices.ds
505
+ )
506
+ assert river_forcing == river_forcing_with_prescribed_single_cell_indices
255
507
 
508
+ def test_reproducibility_with_flipped_dictionary_entries(
509
+ self, iceland_test_grid, tmp_path
510
+ ):
511
+ indices = {
512
+ "Hvita(Olfusa)": [(8, 6)],
513
+ "Thjorsa": [(8, 6)],
514
+ "JkulsFjll": [(11, 12)],
515
+ "Lagarfljot": [(9, 13), (10, 13)],
516
+ "Bruara": [(8, 6)],
517
+ "Svarta": [(12, 8), (12, 9), (12, 10)],
518
+ }
519
+
520
+ flipped_indices = {
521
+ "Thjorsa": [(8, 6)],
522
+ "Hvita(Olfusa)": [(8, 6)],
523
+ "JkulsFjll": [(11, 12)],
524
+ "Svarta": [(12, 10), (12, 9), (12, 8)], # also flip order of tuples here
525
+ "Lagarfljot": [(9, 13), (10, 13)],
526
+ "Bruara": [(8, 6)],
527
+ }
528
+
529
+ start_time = datetime(1998, 1, 1)
530
+ end_time = datetime(1998, 3, 1)
531
+
532
+ river_forcing = RiverForcing(
533
+ grid=iceland_test_grid,
534
+ start_time=start_time,
535
+ end_time=end_time,
536
+ indices=indices,
537
+ )
256
538
 
257
- def test_river_forcing_save(river_forcing_with_bgc, tmp_path):
258
- """Test save method."""
539
+ river_forcing_from_flipped_indices = RiverForcing(
540
+ grid=iceland_test_grid,
541
+ start_time=start_time,
542
+ end_time=end_time,
543
+ indices=flipped_indices,
544
+ )
259
545
 
260
- for file_str, grid_file_str in zip(
261
- ["test_rivers", "test_rivers.nc"], ["test_grid", "test_grid.nc"]
262
- ):
263
546
  # Create a temporary filepath using the tmp_path fixture
264
- for filepath, grid_filepath in zip(
265
- [tmp_path / file_str, str(tmp_path / file_str)],
266
- [tmp_path / grid_file_str, str(tmp_path / grid_file_str)],
267
- ): # test for Path object and str
268
-
269
- # Test saving without partitioning
270
- saved_filenames = river_forcing_with_bgc.save(filepath, grid_filepath)
271
- # Check if the .nc file was created
272
- filepath = Path(filepath).with_suffix(".nc")
273
- grid_filepath = Path(grid_filepath).with_suffix(".nc")
274
- assert saved_filenames == [filepath, grid_filepath]
275
- assert filepath.exists()
276
- assert grid_filepath.exists()
277
- # Clean up the .nc file
278
- filepath.unlink()
279
- grid_filepath.unlink()
547
+ file1 = Path(tmp_path / "test1.nc")
548
+ file2 = Path(tmp_path / "test2.nc")
280
549
 
281
- # Test saving with partitioning
282
- saved_filenames = river_forcing_with_bgc.save(
283
- filepath, grid_filepath, np_eta=3, np_xi=3
284
- )
550
+ river_forcing.save(file1)
551
+ river_forcing_from_flipped_indices.save(file2)
285
552
 
286
- filepath_str = str(filepath.with_suffix(""))
287
- grid_filepath_str = str(grid_filepath.with_suffix(""))
288
- expected_filepath_list = [
289
- Path(filepath_str + f".{index}.nc") for index in range(9)
290
- ] + [Path(grid_filepath_str + f".{index}.nc") for index in range(9)]
291
- assert saved_filenames == expected_filepath_list
292
- for expected_filepath in expected_filepath_list:
293
- assert expected_filepath.exists()
294
- expected_filepath.unlink()
295
-
296
-
297
- @pytest.mark.parametrize(
298
- "river_forcing_fixture",
299
- [
300
- "river_forcing_climatology",
301
- "river_forcing_no_climatology",
302
- "river_forcing_with_bgc",
303
- ],
304
- )
305
- def test_roundtrip_yaml(river_forcing_fixture, request, tmp_path):
306
- """Test that creating an RiverForcing object, saving its parameters to yaml file,
307
- and re-opening yaml file creates the same object."""
308
-
309
- river_forcing = request.getfixturevalue(river_forcing_fixture)
310
-
311
- # Create a temporary filepath using the tmp_path fixture
312
- file_str = "test_yaml"
313
- for filepath in [
314
- tmp_path / file_str,
315
- str(tmp_path / file_str),
316
- ]: # test for Path object and str
317
-
318
- river_forcing.to_yaml(filepath)
319
-
320
- river_forcing_from_file = RiverForcing.from_yaml(filepath)
321
-
322
- assert river_forcing == river_forcing_from_file
323
-
324
- filepath = Path(filepath)
325
- filepath.unlink()
326
-
327
-
328
- @pytest.mark.parametrize(
329
- "river_forcing_fixture",
330
- [
331
- "river_forcing_climatology",
332
- "river_forcing_no_climatology",
333
- "river_forcing_with_bgc",
334
- ],
335
- )
336
- def test_files_have_same_hash(river_forcing_fixture, request, tmp_path):
337
-
338
- river_forcing = request.getfixturevalue(river_forcing_fixture)
339
-
340
- yaml_filepath = tmp_path / "test_yaml.yaml"
341
- filepath1 = tmp_path / "test1.nc"
342
- filepath2 = tmp_path / "test2.nc"
343
- grid_filepath1 = tmp_path / "grid_test1.nc"
344
- grid_filepath2 = tmp_path / "grid_test2.nc"
345
-
346
- river_forcing.to_yaml(yaml_filepath)
347
- river_forcing.save(filepath1, grid_filepath1)
348
- rf_from_file = RiverForcing.from_yaml(yaml_filepath)
349
- rf_from_file.save(filepath2, grid_filepath2)
350
-
351
- hash1 = calculate_file_hash(filepath1)
352
- hash2 = calculate_file_hash(filepath2)
353
-
354
- assert hash1 == hash2, f"Hashes do not match: {hash1} != {hash2}"
355
-
356
- yaml_filepath.unlink()
357
- filepath1.unlink()
358
- filepath2.unlink()
359
- grid_filepath1.unlink()
360
- grid_filepath2.unlink()
361
-
362
-
363
- def test_from_yaml_missing_river_forcing(tmp_path):
364
- yaml_content = textwrap.dedent(
365
- """\
366
- ---
367
- roms_tools_version: 0.0.0
368
- ---
369
- Grid:
370
- nx: 100
371
- ny: 100
372
- size_x: 1800
373
- size_y: 2400
374
- center_lon: -10
375
- center_lat: 61
376
- rot: -20
377
- topography_source:
378
- name: ETOPO5
379
- hmin: 5.0
380
- """
381
- )
553
+ hash1 = calculate_file_hash(file1)
554
+ hash2 = calculate_file_hash(file2)
555
+
556
+ assert hash1 == hash2, f"Hashes do not match: {hash1} != {hash2}"
557
+
558
+ file1.unlink()
559
+ file2.unlink()
560
+
561
+ def test_invalid_indices(self, iceland_test_grid):
562
+ invalid_single_cell_indices = {"Hvita(Olfusa)": [(0, 6)]}
563
+ invalid_multi_cell_indices = {"Hvita(Olfusa)": [(8, 6), (0, 6)]}
382
564
 
383
- # Create a temporary filepath using the tmp_path fixture
384
- file_str = "test_yaml"
385
- for yaml_filepath in [
386
- tmp_path / file_str,
387
- str(tmp_path / file_str),
388
- ]: # test for Path object and str
565
+ for indices in [invalid_single_cell_indices, invalid_multi_cell_indices]:
566
+ with pytest.raises(
567
+ ValueError, match="is not located on the coast at grid cell"
568
+ ):
569
+ RiverForcing(
570
+ grid=iceland_test_grid,
571
+ start_time=datetime(1998, 1, 1),
572
+ end_time=datetime(1998, 3, 1),
573
+ indices=indices,
574
+ )
575
+
576
+ def test_raise_missing_rivers(self, iceland_test_grid):
577
+ fake_indices = {"Hvita(Olfusa)": [(8, 6)], "fake": [(11, 12)]}
578
+
579
+ with pytest.raises(
580
+ ValueError, match="The following rivers were not found in the dataset"
581
+ ):
582
+ RiverForcing(
583
+ grid=iceland_test_grid,
584
+ start_time=datetime(1998, 1, 1),
585
+ end_time=datetime(1998, 3, 1),
586
+ indices=fake_indices,
587
+ )
389
588
 
390
- # Write YAML content to file
391
- if isinstance(yaml_filepath, Path):
392
- yaml_filepath.write_text(yaml_content)
393
- else:
394
- with open(yaml_filepath, "w") as f:
395
- f.write(yaml_content)
589
+ def test_indices_is_dict(self, iceland_test_grid):
590
+ with pytest.raises(ValueError, match="`indices` must be a dictionary."):
591
+ RiverForcing(
592
+ grid=iceland_test_grid,
593
+ start_time=datetime(1998, 1, 1),
594
+ end_time=datetime(1998, 3, 1),
595
+ indices="invalid",
596
+ )
396
597
 
598
+ def test_indices_empty(self, iceland_test_grid):
397
599
  with pytest.raises(
398
600
  ValueError,
399
- match="No RiverForcing configuration found in the YAML file.",
601
+ match="The provided 'indices' dictionary must contain at least one river.",
400
602
  ):
401
- RiverForcing.from_yaml(yaml_filepath)
603
+ RiverForcing(
604
+ grid=iceland_test_grid,
605
+ start_time=datetime(1998, 1, 1),
606
+ end_time=datetime(1998, 3, 1),
607
+ indices={},
608
+ )
402
609
 
403
- yaml_filepath = Path(yaml_filepath)
404
- yaml_filepath.unlink()
610
+ def test_invalid_river_name_type(self, iceland_test_grid):
611
+ indices = {123: [(8, 6)]} # Invalid river name (should be a string)
612
+ with pytest.raises(ValueError, match="River name `123` must be a string."):
613
+ RiverForcing(
614
+ grid=iceland_test_grid,
615
+ start_time=datetime(1998, 1, 1),
616
+ end_time=datetime(1998, 3, 1),
617
+ indices=indices,
618
+ )
619
+
620
+ def test_invalid_river_data_type(self, iceland_test_grid):
621
+ indices = {
622
+ "Hvita(Olfusa)": "8, 6" # Invalid river data (should be a list of tuples)
623
+ }
624
+ with pytest.raises(ValueError, match="must be a list of tuples."):
625
+ RiverForcing(
626
+ grid=iceland_test_grid,
627
+ start_time=datetime(1998, 1, 1),
628
+ end_time=datetime(1998, 3, 1),
629
+ indices=indices,
630
+ )
631
+
632
+ def test_invalid_tuple_length(self, iceland_test_grid):
633
+ indices = {
634
+ "Hvita(Olfusa)": [(8, 6, 7)] # Invalid tuple length (should be length 2)
635
+ }
636
+ with pytest.raises(ValueError, match="must be a tuple of length 2"):
637
+ RiverForcing(
638
+ grid=iceland_test_grid,
639
+ start_time=datetime(1998, 1, 1),
640
+ end_time=datetime(1998, 3, 1),
641
+ indices=indices,
642
+ )
643
+
644
+ def test_invalid_eta_rho_type(self, iceland_test_grid):
645
+ indices = {
646
+ "Hvita(Olfusa)": [("a", 6)] # Invalid eta_rho (should be an integer)
647
+ }
648
+ with pytest.raises(ValueError, match="First element of tuple for river"):
649
+ RiverForcing(
650
+ grid=iceland_test_grid,
651
+ start_time=datetime(1998, 1, 1),
652
+ end_time=datetime(1998, 3, 1),
653
+ indices=indices,
654
+ )
655
+
656
+ def test_invalid_xi_rho_type(self, iceland_test_grid):
657
+ indices = {"Hvita(Olfusa)": [(8, "b")]} # Invalid xi_rho (should be an integer)
658
+ with pytest.raises(ValueError, match="Second element of tuple for river"):
659
+ RiverForcing(
660
+ grid=iceland_test_grid,
661
+ start_time=datetime(1998, 1, 1),
662
+ end_time=datetime(1998, 3, 1),
663
+ indices=indices,
664
+ )
665
+
666
+ def test_eta_rho_out_of_range(self, iceland_test_grid):
667
+ indices = {"Hvita(Olfusa)": [(20, 6)]} # eta_rho out of valid range [0, 17]
668
+ with pytest.raises(ValueError, match="Value of eta_rho for river"):
669
+ RiverForcing(
670
+ grid=iceland_test_grid,
671
+ start_time=datetime(1998, 1, 1),
672
+ end_time=datetime(1998, 3, 1),
673
+ indices=indices,
674
+ )
675
+
676
+ def test_xi_rho_out_of_range(self, iceland_test_grid):
677
+ indices = {"Hvita(Olfusa)": [(8, 20)]} # xi_rho out of valid range [0, 17]
678
+ with pytest.raises(ValueError, match="Value of xi_rho for river"):
679
+ RiverForcing(
680
+ grid=iceland_test_grid,
681
+ start_time=datetime(1998, 1, 1),
682
+ end_time=datetime(1998, 3, 1),
683
+ indices=indices,
684
+ )
685
+
686
+ def test_duplicate_location(self, iceland_test_grid):
687
+ indices = {"Hvita(Olfusa)": [(8, 6), (8, 6)]} # Duplicate location
688
+ with pytest.raises(ValueError, match="Duplicate location"):
689
+ RiverForcing(
690
+ grid=iceland_test_grid,
691
+ start_time=datetime(1998, 1, 1),
692
+ end_time=datetime(1998, 3, 1),
693
+ indices=indices,
694
+ )