roms-tools 1.6.2__py3-none-any.whl → 2.0.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 (283) hide show
  1. ci/environment.yml +1 -1
  2. roms_tools/__init__.py +1 -0
  3. roms_tools/_version.py +1 -1
  4. roms_tools/setup/boundary_forcing.py +266 -256
  5. roms_tools/setup/datasets.py +986 -231
  6. roms_tools/setup/download.py +41 -15
  7. roms_tools/setup/grid.py +561 -512
  8. roms_tools/setup/initial_conditions.py +162 -106
  9. roms_tools/setup/mask.py +69 -0
  10. roms_tools/setup/plot.py +81 -23
  11. roms_tools/setup/regrid.py +4 -2
  12. roms_tools/setup/river_forcing.py +589 -0
  13. roms_tools/setup/surface_forcing.py +21 -130
  14. roms_tools/setup/tides.py +15 -79
  15. roms_tools/setup/topography.py +92 -128
  16. roms_tools/setup/utils.py +307 -25
  17. roms_tools/setup/vertical_coordinate.py +5 -16
  18. roms_tools/tests/test_setup/test_boundary_forcing.py +10 -7
  19. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zattrs +1 -1
  20. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zmetadata +157 -130
  21. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/.zattrs +1 -1
  22. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_north/.zattrs +1 -1
  23. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_south/.zattrs +1 -1
  24. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/.zattrs +1 -1
  25. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/.zattrs +1 -1
  26. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_north/.zattrs +1 -1
  27. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_south/.zattrs +1 -1
  28. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/.zattrs +1 -1
  29. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/.zattrs +1 -1
  30. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_north/.zattrs +1 -1
  31. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_south/.zattrs +1 -1
  32. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/.zattrs +1 -1
  33. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/.zattrs +1 -1
  34. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_north/.zattrs +1 -1
  35. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_south/.zattrs +1 -1
  36. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/.zattrs +1 -1
  37. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/.zattrs +1 -1
  38. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_north/.zattrs +1 -1
  39. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_south/.zattrs +1 -1
  40. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/.zattrs +1 -1
  41. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/.zattrs +1 -1
  42. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_north/.zattrs +1 -1
  43. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_south/.zattrs +1 -1
  44. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/.zattrs +1 -1
  45. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/.zattrs +1 -1
  46. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_north/.zattrs +1 -1
  47. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_south/.zattrs +1 -1
  48. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/.zattrs +1 -1
  49. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/.zattrs +1 -1
  50. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_north/.zattrs +1 -1
  51. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_south/.zattrs +1 -1
  52. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/.zattrs +1 -1
  53. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/.zattrs +1 -1
  54. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_north/.zattrs +1 -1
  55. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_south/.zattrs +1 -1
  56. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/.zattrs +1 -1
  57. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/.zattrs +1 -1
  58. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_north/.zattrs +1 -1
  59. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_south/.zattrs +1 -1
  60. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/.zattrs +1 -1
  61. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/.zattrs +1 -1
  62. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_north/.zattrs +1 -1
  63. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_south/.zattrs +1 -1
  64. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/.zattrs +1 -1
  65. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/.zattrs +1 -1
  66. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_north/.zattrs +1 -1
  67. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_south/.zattrs +1 -1
  68. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/.zattrs +1 -1
  69. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/.zattrs +1 -1
  70. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_north/.zattrs +1 -1
  71. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_south/.zattrs +1 -1
  72. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/.zattrs +1 -1
  73. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/.zattrs +1 -1
  74. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_north/.zattrs +1 -1
  75. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_south/.zattrs +1 -1
  76. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/.zattrs +1 -1
  77. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/.zattrs +1 -1
  78. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_north/.zattrs +1 -1
  79. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_south/.zattrs +1 -1
  80. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/.zattrs +1 -1
  81. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/.zattrs +1 -1
  82. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_north/.zattrs +1 -1
  83. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_south/.zattrs +1 -1
  84. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/.zattrs +1 -1
  85. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/.zattrs +1 -1
  86. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_north/.zattrs +1 -1
  87. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_south/.zattrs +1 -1
  88. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/.zattrs +1 -1
  89. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/abs_time/.zattrs +1 -0
  90. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/bry_time/.zattrs +1 -1
  91. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/.zattrs +1 -1
  92. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_north/.zattrs +1 -1
  93. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_south/.zattrs +1 -1
  94. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/.zattrs +1 -1
  95. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/.zattrs +1 -1
  96. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_north/.zattrs +1 -1
  97. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_south/.zattrs +1 -1
  98. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/.zattrs +1 -1
  99. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/.zattrs +1 -1
  100. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_north/.zattrs +1 -1
  101. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_south/.zattrs +1 -1
  102. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/.zattrs +1 -1
  103. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/.zattrs +1 -1
  104. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_north/.zattrs +1 -1
  105. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_south/.zattrs +1 -1
  106. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/.zattrs +1 -1
  107. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/.zattrs +1 -1
  108. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_north/.zattrs +1 -1
  109. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_south/.zattrs +1 -1
  110. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/.zattrs +1 -1
  111. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/.zattrs +1 -1
  112. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_north/.zattrs +1 -1
  113. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_south/.zattrs +1 -1
  114. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/.zattrs +1 -1
  115. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/.zattrs +1 -1
  116. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_north/.zattrs +1 -1
  117. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_south/.zattrs +1 -1
  118. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/.zattrs +1 -1
  119. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/.zattrs +1 -1
  120. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_north/.zattrs +1 -1
  121. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_south/.zattrs +1 -1
  122. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/.zattrs +1 -1
  123. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/.zattrs +1 -1
  124. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_north/.zattrs +1 -1
  125. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_south/.zattrs +1 -1
  126. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/.zattrs +1 -1
  127. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/month/.zarray +20 -0
  128. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/month/.zattrs +6 -0
  129. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/month/0 +0 -0
  130. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/.zattrs +1 -1
  131. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_north/.zattrs +1 -1
  132. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_south/.zattrs +1 -1
  133. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/.zattrs +1 -1
  134. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/.zattrs +1 -1
  135. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_north/.zattrs +1 -1
  136. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_south/.zattrs +1 -1
  137. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/.zattrs +1 -1
  138. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/.zattrs +1 -1
  139. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_north/.zattrs +1 -1
  140. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_south/.zattrs +1 -1
  141. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/.zattrs +1 -1
  142. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/.zattrs +1 -1
  143. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_north/.zattrs +1 -1
  144. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_south/.zattrs +1 -1
  145. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/.zattrs +1 -1
  146. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/.zattrs +1 -1
  147. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_north/.zattrs +1 -1
  148. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_south/.zattrs +1 -1
  149. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/.zattrs +1 -1
  150. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/.zattrs +1 -1
  151. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_north/.zattrs +1 -1
  152. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_south/.zattrs +1 -1
  153. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/.zattrs +1 -1
  154. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zattrs +1 -1
  155. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zmetadata +39 -12
  156. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/abs_time/.zattrs +1 -0
  157. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust/.zattrs +1 -1
  158. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust_time/.zattrs +1 -1
  159. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron/.zattrs +1 -1
  160. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron_time/.zattrs +1 -1
  161. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/month/.zarray +20 -0
  162. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/month/.zattrs +6 -0
  163. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/month/0 +0 -0
  164. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy/.zattrs +1 -1
  165. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy_time/.zattrs +1 -1
  166. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox/.zattrs +1 -1
  167. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox_time/.zattrs +1 -1
  168. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air/.zattrs +1 -1
  169. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air_alt/.zattrs +1 -1
  170. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_time/.zattrs +1 -1
  171. roms_tools/tests/test_setup/test_data/grid.zarr/.zattrs +0 -1
  172. roms_tools/tests/test_setup/test_data/grid.zarr/.zmetadata +56 -201
  173. roms_tools/tests/test_setup/test_data/grid.zarr/Cs_r/.zattrs +1 -1
  174. roms_tools/tests/test_setup/test_data/grid.zarr/Cs_w/.zattrs +1 -1
  175. roms_tools/tests/test_setup/test_data/grid.zarr/{interface_depth_rho → sigma_r}/.zarray +2 -6
  176. roms_tools/tests/test_setup/test_data/grid.zarr/sigma_r/.zattrs +7 -0
  177. roms_tools/tests/test_setup/test_data/grid.zarr/sigma_r/0 +0 -0
  178. roms_tools/tests/test_setup/test_data/grid.zarr/{interface_depth_u → sigma_w}/.zarray +2 -6
  179. roms_tools/tests/test_setup/test_data/grid.zarr/sigma_w/.zattrs +7 -0
  180. roms_tools/tests/test_setup/test_data/grid.zarr/sigma_w/0 +0 -0
  181. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zattrs +1 -2
  182. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zmetadata +58 -203
  183. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/Cs_r/.zattrs +1 -1
  184. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/Cs_w/.zattrs +1 -1
  185. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/.zattrs +1 -1
  186. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/0.0 +0 -0
  187. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_coarse/0.0 +0 -0
  188. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_rho/0.0 +0 -0
  189. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_u/0.0 +0 -0
  190. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_v/0.0 +0 -0
  191. roms_tools/tests/test_setup/test_data/{grid.zarr/interface_depth_v → grid_that_straddles_dateline.zarr/sigma_r}/.zarray +2 -6
  192. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_r/.zattrs +7 -0
  193. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_r/0 +0 -0
  194. roms_tools/tests/test_setup/test_data/{grid.zarr/layer_depth_rho → grid_that_straddles_dateline.zarr/sigma_w}/.zarray +2 -6
  195. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_w/.zattrs +7 -0
  196. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_w/0 +0 -0
  197. roms_tools/tests/test_setup/test_data/river_forcing.zarr/.zattrs +3 -0
  198. roms_tools/tests/test_setup/test_data/river_forcing.zarr/.zgroup +3 -0
  199. roms_tools/tests/test_setup/test_data/river_forcing.zarr/.zmetadata +214 -0
  200. roms_tools/tests/test_setup/test_data/river_forcing.zarr/abs_time/.zarray +20 -0
  201. roms_tools/tests/test_setup/test_data/river_forcing.zarr/abs_time/.zattrs +8 -0
  202. roms_tools/tests/test_setup/test_data/river_forcing.zarr/abs_time/0 +0 -0
  203. roms_tools/tests/test_setup/test_data/river_forcing.zarr/month/.zarray +20 -0
  204. roms_tools/tests/test_setup/test_data/river_forcing.zarr/month/.zattrs +6 -0
  205. roms_tools/tests/test_setup/test_data/river_forcing.zarr/month/0 +0 -0
  206. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_name/.zarray +24 -0
  207. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_name/.zattrs +6 -0
  208. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_name/0 +0 -0
  209. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_time/.zarray +20 -0
  210. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_time/.zattrs +8 -0
  211. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_time/0 +0 -0
  212. roms_tools/tests/test_setup/test_data/{grid.zarr/layer_depth_v → river_forcing.zarr/river_tracer}/.zarray +4 -4
  213. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_tracer/.zattrs +10 -0
  214. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_tracer/0.0.0 +0 -0
  215. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_volume/.zarray +22 -0
  216. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_volume/.zattrs +9 -0
  217. roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_volume/0.0 +0 -0
  218. roms_tools/tests/test_setup/test_data/{grid.zarr/layer_depth_u → river_forcing.zarr/tracer_name}/.zarray +2 -6
  219. roms_tools/tests/test_setup/test_data/river_forcing.zarr/tracer_name/.zattrs +6 -0
  220. roms_tools/tests/test_setup/test_data/river_forcing.zarr/tracer_name/0 +0 -0
  221. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zattrs +1 -0
  222. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zgroup +3 -0
  223. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +185 -0
  224. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/abs_time/.zarray +20 -0
  225. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/abs_time/.zattrs +8 -0
  226. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/abs_time/0 +0 -0
  227. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_name/.zarray +24 -0
  228. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_name/.zattrs +6 -0
  229. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_name/0 +0 -0
  230. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_time/.zarray +20 -0
  231. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_time/.zattrs +7 -0
  232. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_time/0 +0 -0
  233. roms_tools/tests/test_setup/test_data/{grid_that_straddles_dateline.zarr/interface_depth_v → river_forcing_no_climatology.zarr/river_tracer}/.zarray +4 -4
  234. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_tracer/.zattrs +10 -0
  235. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_tracer/0.0.0 +0 -0
  236. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_volume/.zarray +22 -0
  237. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_volume/.zattrs +9 -0
  238. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_volume/0.0 +0 -0
  239. roms_tools/tests/test_setup/test_data/{grid_that_straddles_dateline.zarr/interface_depth_u → river_forcing_no_climatology.zarr/tracer_name}/.zarray +2 -6
  240. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_name/.zattrs +6 -0
  241. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_name/0 +0 -0
  242. roms_tools/tests/test_setup/test_grid.py +110 -12
  243. roms_tools/tests/test_setup/test_initial_conditions.py +2 -3
  244. roms_tools/tests/test_setup/test_river_forcing.py +367 -0
  245. roms_tools/tests/test_setup/test_surface_forcing.py +2 -24
  246. roms_tools/tests/test_setup/test_tides.py +2 -3
  247. roms_tools/tests/test_setup/test_topography.py +106 -1
  248. roms_tools/tests/test_setup/test_validation.py +4 -0
  249. roms_tools/utils.py +12 -10
  250. {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/LICENSE +1 -1
  251. {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/METADATA +6 -5
  252. {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/RECORD +254 -225
  253. {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/WHEEL +1 -1
  254. roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_rho/.zattrs +0 -9
  255. roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_rho/0.0.0 +0 -0
  256. roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_u/.zattrs +0 -9
  257. roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_u/0.0.0 +0 -0
  258. roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_v/.zattrs +0 -9
  259. roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_v/0.0.0 +0 -0
  260. roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_rho/.zattrs +0 -9
  261. roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_rho/0.0.0 +0 -0
  262. roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_u/.zattrs +0 -9
  263. roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_u/0.0.0 +0 -0
  264. roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_v/.zattrs +0 -9
  265. roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_v/0.0.0 +0 -0
  266. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_rho/.zarray +0 -24
  267. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_rho/.zattrs +0 -9
  268. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_rho/0.0.0 +0 -0
  269. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_u/.zattrs +0 -9
  270. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_u/0.0.0 +0 -0
  271. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_v/.zattrs +0 -9
  272. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_v/0.0.0 +0 -0
  273. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_rho/.zarray +0 -24
  274. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_rho/.zattrs +0 -9
  275. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_rho/0.0.0 +0 -0
  276. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_u/.zarray +0 -24
  277. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_u/.zattrs +0 -9
  278. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_u/0.0.0 +0 -0
  279. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_v/.zarray +0 -24
  280. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_v/.zattrs +0 -9
  281. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_v/0.0.0 +0 -0
  282. roms_tools/tests/test_setup/test_vertical_coordinate.py +0 -91
  283. {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,15 @@
1
1
  import xarray as xr
2
2
  import numpy as np
3
- import pandas as pd
4
3
  from scipy.ndimage import label
5
4
  import logging
6
- import yaml
7
5
  import importlib.metadata
8
6
  from typing import Dict, Union, List
9
- from dataclasses import dataclass, field, asdict
7
+ from dataclasses import dataclass, field
10
8
  from roms_tools.setup.grid import Grid
11
9
  from roms_tools.setup.regrid import LateralRegrid, VerticalRegrid
12
10
  from datetime import datetime
13
11
  from roms_tools.setup.datasets import GLORYSDataset, CESMBGCDataset
12
+ from roms_tools.setup.vertical_coordinate import compute_depth
14
13
  from roms_tools.setup.utils import (
15
14
  get_variable_metadata,
16
15
  group_dataset,
@@ -22,6 +21,11 @@ from roms_tools.setup.utils import (
22
21
  one_dim_fill,
23
22
  nan_check,
24
23
  substitute_nans_by_fillvalue,
24
+ interpolate_from_rho_to_u,
25
+ interpolate_from_rho_to_v,
26
+ convert_to_roms_time,
27
+ _to_yaml,
28
+ _from_yaml,
25
29
  )
26
30
  from roms_tools.setup.plot import _section_plot, _line_plot
27
31
  import matplotlib.pyplot as plt
@@ -59,12 +63,12 @@ class BoundaryForcing:
59
63
  - "physics": for physical atmospheric forcing.
60
64
  - "bgc": for biogeochemical forcing.
61
65
 
62
- model_reference_date : datetime, optional
63
- Reference date for the model. Default is January 1, 2000.
64
66
  apply_2d_horizontal_fill: bool, optional
65
67
  Indicates whether to perform a two-dimensional horizontal fill on the source data prior to regridding to boundaries.
66
68
  If `False`, a one-dimensional horizontal fill is performed separately on each of the four regridded boundaries.
67
69
  Defaults to `False`.
70
+ model_reference_date : datetime, optional
71
+ Reference date for the model. Default is January 1, 2000.
68
72
  use_dask: bool, optional
69
73
  Indicates whether to use dask for processing. If True, data is processed with dask; if False, data is processed eagerly. Defaults to False.
70
74
 
@@ -93,8 +97,8 @@ class BoundaryForcing:
93
97
  )
94
98
  source: Dict[str, Union[str, Path, List[Union[str, Path]]]]
95
99
  type: str = "physics"
96
- model_reference_date: datetime = datetime(2000, 1, 1)
97
100
  apply_2d_horizontal_fill: bool = False
101
+ model_reference_date: datetime = datetime(2000, 1, 1)
98
102
  use_dask: bool = False
99
103
 
100
104
  ds: xr.Dataset = field(init=False, repr=False)
@@ -114,8 +118,8 @@ class BoundaryForcing:
114
118
  data.extrapolate_deepest_to_bottom()
115
119
  data.apply_lateral_fill()
116
120
 
117
- variable_info = self._set_variable_info(data)
118
- bdry_coords = get_boundary_info()
121
+ self._set_variable_info(data)
122
+ self._set_boundary_info()
119
123
  ds = xr.Dataset()
120
124
 
121
125
  for direction in ["south", "east", "north", "west"]:
@@ -123,10 +127,10 @@ class BoundaryForcing:
123
127
 
124
128
  bdry_target_coords = {
125
129
  "lat": target_coords["lat"].isel(
126
- **bdry_coords["vector"][direction]
130
+ **self.bdry_coords["vector"][direction]
127
131
  ),
128
132
  "lon": target_coords["lon"].isel(
129
- **bdry_coords["vector"][direction]
133
+ **self.bdry_coords["vector"][direction]
130
134
  ),
131
135
  "straddle": target_coords["straddle"],
132
136
  }
@@ -144,11 +148,17 @@ class BoundaryForcing:
144
148
 
145
149
  # lateral regridding of vector fields
146
150
  vector_var_names = [
147
- name for name, info in variable_info.items() if info["is_vector"]
151
+ name
152
+ for name, info in self.variable_info.items()
153
+ if info["is_vector"]
148
154
  ]
149
155
  if len(vector_var_names) > 0:
150
- lon = target_coords["lon"].isel(**bdry_coords["vector"][direction])
151
- lat = target_coords["lat"].isel(**bdry_coords["vector"][direction])
156
+ lon = target_coords["lon"].isel(
157
+ **self.bdry_coords["vector"][direction]
158
+ )
159
+ lat = target_coords["lat"].isel(
160
+ **self.bdry_coords["vector"][direction]
161
+ )
152
162
  lateral_regrid = LateralRegrid(
153
163
  {"lat": lat, "lon": lon}, bdry_data.dim_names
154
164
  )
@@ -161,12 +171,16 @@ class BoundaryForcing:
161
171
  # lateral regridding of tracer fields
162
172
  tracer_var_names = [
163
173
  name
164
- for name, info in variable_info.items()
174
+ for name, info in self.variable_info.items()
165
175
  if not info["is_vector"]
166
176
  ]
167
177
  if len(tracer_var_names) > 0:
168
- lon = target_coords["lon"].isel(**bdry_coords["rho"][direction])
169
- lat = target_coords["lat"].isel(**bdry_coords["rho"][direction])
178
+ lon = target_coords["lon"].isel(
179
+ **self.bdry_coords["rho"][direction]
180
+ )
181
+ lat = target_coords["lat"].isel(
182
+ **self.bdry_coords["rho"][direction]
183
+ )
170
184
  lateral_regrid = LateralRegrid(
171
185
  {"lat": lat, "lon": lon}, bdry_data.dim_names
172
186
  )
@@ -177,9 +191,9 @@ class BoundaryForcing:
177
191
  )
178
192
 
179
193
  # rotation of velocities and interpolation to u/v points
180
- if "u" in variable_info and "v" in variable_info:
194
+ if "u" in self.variable_info and "v" in self.variable_info:
181
195
  angle = target_coords["angle"].isel(
182
- **bdry_coords["vector"][direction]
196
+ **self.bdry_coords["vector"][direction]
183
197
  )
184
198
  (processed_fields["u"], processed_fields["v"],) = rotate_velocities(
185
199
  processed_fields["u"],
@@ -189,54 +203,68 @@ class BoundaryForcing:
189
203
  )
190
204
 
191
205
  # selection of outermost margin for u/v variables
192
- for var_name in variable_info.keys():
206
+ for var_name in self.variable_info.keys():
193
207
  if var_name in processed_fields:
194
- location = variable_info[var_name]["location"]
208
+ location = self.variable_info[var_name]["location"]
195
209
  if location in ["u", "v"]:
196
210
  processed_fields[var_name] = processed_fields[
197
211
  var_name
198
- ].isel(**bdry_coords[location][direction])
212
+ ].isel(**self.bdry_coords[location][direction])
199
213
 
200
214
  if not self.apply_2d_horizontal_fill:
201
215
  self._validate_1d_fill(
202
216
  processed_fields,
203
- variable_info,
204
- bdry_coords,
205
217
  direction,
206
218
  bdry_data.dim_names["depth"],
207
219
  )
208
220
  processed_fields = apply_1d_horizontal_fill(processed_fields)
209
221
 
210
- # vertical regridding
222
+ var_names_dict = {}
211
223
  for location in ["rho", "u", "v"]:
212
- var_names = [
224
+ var_names_dict[location] = [
213
225
  name
214
- for name, info in variable_info.items()
226
+ for name, info in self.variable_info.items()
215
227
  if info["location"] == location and info["is_3d"]
216
228
  ]
217
- if len(var_names) > 0:
229
+ # compute layer depth coordinates
230
+ if len(var_names_dict["u"]) > 0 or len(var_names_dict["v"]) > 0:
231
+ self._get_vertical_coordinates(
232
+ type="layer",
233
+ direction=direction,
234
+ additional_locations=["u", "v"],
235
+ )
236
+ else:
237
+ if len(var_names_dict["rho"]) > 0:
238
+ self._get_vertical_coordinates(
239
+ type="layer", direction=direction, additional_locations=[]
240
+ )
241
+
242
+ # vertical regridding
243
+ for location in ["rho", "u", "v"]:
244
+ if len(var_names_dict[location]) > 0:
218
245
  vertical_regrid = VerticalRegrid(
219
- self.grid.ds[f"layer_depth_{location}"].isel(
220
- **bdry_coords[location][direction]
221
- ),
246
+ self.grid.ds[f"layer_depth_{location}_{direction}"],
222
247
  bdry_data.ds[bdry_data.dim_names["depth"]],
223
248
  )
224
- for var_name in var_names:
249
+ for var_name in var_names_dict[location]:
225
250
  if var_name in processed_fields:
226
251
  processed_fields[var_name] = vertical_regrid.apply(
227
252
  processed_fields[var_name]
228
253
  )
229
254
 
230
255
  # compute barotropic velocities
231
- if "u" in variable_info and "v" in variable_info:
232
- for var_name in ["u", "v"]:
256
+ if "u" in self.variable_info and "v" in self.variable_info:
257
+ self._get_vertical_coordinates(
258
+ type="interface",
259
+ direction=direction,
260
+ additional_locations=["u", "v"],
261
+ )
262
+ for location in ["u", "v"]:
233
263
  processed_fields[
234
- f"{var_name}bar"
264
+ f"{location}bar"
235
265
  ] = compute_barotropic_velocity(
236
- processed_fields[var_name],
237
- self.grid.ds[f"interface_depth_{var_name}"].isel(
238
- **bdry_coords[var_name][direction]
239
- ),
266
+ processed_fields[location],
267
+ self.grid.ds[f"interface_depth_{location}_{direction}"],
240
268
  )
241
269
 
242
270
  # Reorder dimensions
@@ -251,7 +279,7 @@ class BoundaryForcing:
251
279
  # Add global information
252
280
  ds = self._add_global_metadata(data, ds)
253
281
 
254
- self._validate(ds, variable_info, bdry_coords)
282
+ self._validate(ds)
255
283
 
256
284
  # substitute NaNs over land by a fill value to avoid blow-up of ROMS
257
285
  for var_name in ds.data_vars:
@@ -316,11 +344,15 @@ class BoundaryForcing:
316
344
  - `vector_pair`: For vector variables, this indicates the associated variable that forms the vector (e.g., 'u' and 'v').
317
345
  - `is_3d`: Indicates whether the variable is 3D (True for variables like 'temp' and 'salt') or 2D (False for 'zeta').
318
346
 
347
+ Parameters
348
+ ----------
349
+ data : object
350
+ An object that contains variable names for the data being processed. This is used to set variable information for biogeochemical data.
351
+
319
352
  Returns
320
353
  -------
321
- dict
322
- A dictionary where the keys are variable names and the values are dictionaries of metadata
323
- about each variable, including 'location', 'is_vector', 'vector_pair', and 'is_3d'.
354
+ None
355
+ This method updates the instance attribute `variable_info` with the metadata dictionary for the variables.
324
356
  """
325
357
  default_info = {
326
358
  "location": "rho",
@@ -378,7 +410,7 @@ class BoundaryForcing:
378
410
  else:
379
411
  variable_info[var_name] = {**default_info, "validate": False}
380
412
 
381
- return variable_info
413
+ object.__setattr__(self, "variable_info", variable_info)
382
414
 
383
415
  def _write_into_dataset(self, direction, processed_fields, ds=None):
384
416
  if ds is None:
@@ -413,45 +445,178 @@ class BoundaryForcing:
413
445
  "lat_v",
414
446
  "lon_v",
415
447
  ]
416
- existing_vars = [var_name for var_name in variables_to_drop if var_name in ds]
448
+ suffixes = ["", "_south", "_east", "_north", "_west"]
449
+ # Existing variables with suffixes
450
+ existing_vars = []
451
+ for var_name in variables_to_drop:
452
+ for suffix in suffixes:
453
+ full_var_name = f"{var_name}{suffix}"
454
+ if full_var_name in ds:
455
+ existing_vars.append(full_var_name)
456
+
417
457
  ds = ds.drop_vars(existing_vars)
418
458
 
419
459
  return ds
420
460
 
421
- def _get_coordinates(self, direction, point):
461
+ def _set_boundary_info(self):
462
+ """Updates boundary coordinates for rho, u, and v variables on the grid.
463
+
464
+ This method determines the boundary points for the grid variables by specifying the
465
+ indices for the south, east, north, and west boundaries. The resulting boundary
466
+ information is stored in the instance attribute `bdry_coords`.
467
+
468
+ Returns
469
+ -------
470
+ None
471
+ The method does not return a value. Instead, it updates the instance attribute
472
+ `bdry_coords`, which is a dictionary structured as follows:
473
+ - Keys: Variable types ("rho", "u", "v", "vector").
474
+ - Values: Nested dictionaries mapping each direction ("south", "east", "north", "west")
475
+ to their corresponding boundary coordinates. The coordinates are specified in terms of
476
+ grid indices for the respective variable types.
477
+ """
478
+
479
+ bdry_coords = {
480
+ "rho": {
481
+ "south": {"eta_rho": 0},
482
+ "east": {"xi_rho": -1},
483
+ "north": {"eta_rho": -1},
484
+ "west": {"xi_rho": 0},
485
+ },
486
+ "u": {
487
+ "south": {"eta_rho": 0},
488
+ "east": {"xi_u": -1},
489
+ "north": {"eta_rho": -1},
490
+ "west": {"xi_u": 0},
491
+ },
492
+ "v": {
493
+ "south": {"eta_v": 0},
494
+ "east": {"xi_rho": -1},
495
+ "north": {"eta_v": -1},
496
+ "west": {"xi_rho": 0},
497
+ },
498
+ "vector": {
499
+ "south": {"eta_rho": [0, 1]},
500
+ "east": {"xi_rho": [-2, -1]},
501
+ "north": {"eta_rho": [-2, -1]},
502
+ "west": {"xi_rho": [0, 1]},
503
+ },
504
+ }
505
+
506
+ object.__setattr__(self, "bdry_coords", bdry_coords)
507
+
508
+ def _get_vertical_coordinates(
509
+ self, type, direction, additional_locations=["u", "v"]
510
+ ):
422
511
  """Retrieve layer and interface depth coordinates for a specified grid boundary.
423
512
 
424
- This method extracts the layer depth and interface depth coordinates along
425
- a specified boundary (north, south, east, or west) and for a specified point
426
- type (rho, u, or v) from the grid dataset.
513
+ This method computes and updates the layer and interface depth coordinates along a specified
514
+ boundary (north, south, east, or west). It handles depth calculations for rho points and
515
+ additional specified locations (u and v).
427
516
 
428
517
  Parameters
429
518
  ----------
430
- direction : str
431
- The direction of the boundary to retrieve coordinates for. Valid options
432
- are "north", "south", "east", and "west".
433
- point : str
434
- The type of grid point to retrieve coordinates for. Valid options are
435
- "rho" for the grid's central points, "u" for the u-flux points, and "v"
436
- for the v-flux points.
519
+ type : str
520
+ The type of depth coordinate to retrieve. Valid options are:
521
+ - "layer": Retrieves layer depth coordinates.
522
+ - "interface": Retrieves interface depth coordinates.
437
523
 
438
- Returns
524
+ direction : str
525
+ The direction of the boundary to retrieve coordinates for. Valid options are:
526
+ - "north"
527
+ - "south"
528
+ - "east"
529
+ - "west"
530
+
531
+ additional_locations : list of str, optional
532
+ Specifies additional locations to compute depth coordinates for. Default is ["u", "v"].
533
+ Valid options include:
534
+ - "u": Computes depth coordinates for u points.
535
+ - "v": Computes depth coordinates for v points.
536
+
537
+ Updates
439
538
  -------
440
- xarray.DataArray, xarray.DataArray
441
- The layer depth and interface depth coordinates for the specified grid
442
- boundary and point type.
539
+ self.grid.ds : xarray.Dataset
540
+ The dataset is updated with the following vertical depth coordinates:
541
+ - f"{type}_depth_rho_{direction}": Depth coordinates at rho points.
542
+ - f"{type}_depth_u_{direction}": Depth coordinates at u points (if applicable).
543
+ - f"{type}_depth_v_{direction}": Depth coordinates at v points (if applicable).
443
544
  """
444
545
 
445
- bdry_coords = get_boundary_info()
546
+ layer_vars = []
547
+ for location in ["rho"] + additional_locations:
548
+ layer_vars.append(f"{type}_depth_{location}_{direction}")
446
549
 
447
- layer_depth = self.grid.ds[f"layer_depth_{point}"].isel(
448
- **bdry_coords[point][direction]
449
- )
450
- interface_depth = self.grid.ds[f"interface_depth_{point}"].isel(
451
- **bdry_coords[point][direction]
452
- )
550
+ if all(layer_var in self.grid.ds for layer_var in layer_vars):
551
+ # Vertical coordinate data already exists
552
+ pass
553
+
554
+ elif f"{type}_depth_rho" in self.grid.ds:
555
+ depth = self.grid.ds[f"{type}_depth_rho"]
556
+ depth.attrs["long_name"] = f"{type} depth at rho-points"
557
+ depth.attrs["units"] = "m"
558
+ self.grid.ds[f"{type}_depth_rho_{direction}"] = depth.isel(
559
+ **self.bdry_coords["rho"][direction]
560
+ )
561
+
562
+ if "u" in additional_locations or "v" in additional_locations:
563
+ # selection of margin consisting of 2 grid cells
564
+ depth = depth.isel(**self.bdry_coords["vector"][direction])
565
+ # interpolation
566
+ if "u" in additional_locations:
567
+ depth_u = interpolate_from_rho_to_u(depth)
568
+ depth_u.attrs["long_name"] = f"{type} depth at u-points"
569
+ depth_u.attrs["units"] = "m"
570
+ self.grid.ds[f"{type}_depth_u_{direction}"] = depth_u.isel(
571
+ **self.bdry_coords["u"][direction]
572
+ )
573
+ if "v" in additional_locations:
574
+ depth_v = interpolate_from_rho_to_v(depth)
575
+ depth_v.attrs["long_name"] = f"{type} depth at v-points"
576
+ depth_v.attrs["units"] = "m"
577
+ self.grid.ds[f"{type}_depth_v_{direction}"] = depth_v.isel(
578
+ **self.bdry_coords["v"][direction]
579
+ )
580
+ else:
581
+ if "u" in additional_locations or "v" in additional_locations:
582
+ h = self.grid.ds["h"].isel(**self.bdry_coords["vector"][direction])
583
+ else:
584
+ h = self.grid.ds["h"].isel(**self.bdry_coords["rho"][direction])
585
+ if type == "layer":
586
+ depth = compute_depth(
587
+ 0, h, self.grid.hc, self.grid.ds.Cs_r, self.grid.ds.sigma_r
588
+ )
589
+ else:
590
+ depth = compute_depth(
591
+ 0, h, self.grid.hc, self.grid.ds.Cs_w, self.grid.ds.sigma_w
592
+ )
453
593
 
454
- return layer_depth, interface_depth
594
+ if "u" in additional_locations or "v" in additional_locations:
595
+ depth.attrs["long_name"] = f"{type} depth at rho-points"
596
+ depth.attrs["units"] = "m"
597
+ self.grid.ds[f"{type}_depth_rho_{direction}"] = depth.isel(
598
+ **self.bdry_coords["rho"][direction]
599
+ )
600
+ # selection of margin consisting of 2 grid cells
601
+ depth = depth.isel(**self.bdry_coords["vector"][direction])
602
+ # interpolation
603
+ depth_u = interpolate_from_rho_to_u(depth)
604
+ depth_v = interpolate_from_rho_to_v(depth)
605
+ # selection of outermost margin
606
+ depth_u.attrs["long_name"] = f"{type} depth at u-points"
607
+ depth_u.attrs["units"] = "m"
608
+ self.grid.ds[f"{type}_depth_u_{direction}"] = depth_u.isel(
609
+ **self.bdry_coords["u"][direction]
610
+ )
611
+ depth_v.attrs["long_name"] = f"{type} depth at v-points"
612
+ depth_v.attrs["units"] = "m"
613
+ self.grid.ds[f"{type}_depth_v_{direction}"] = depth_v.isel(
614
+ **self.bdry_coords["v"][direction]
615
+ )
616
+ else:
617
+ depth.attrs["long_name"] = f"{type} depth at rho-points"
618
+ depth.attrs["units"] = "m"
619
+ self.grid.ds[f"{type}_depth_rho_{direction}"] = depth
455
620
 
456
621
  def _add_global_metadata(self, data, ds=None):
457
622
 
@@ -474,57 +639,17 @@ class BoundaryForcing:
474
639
  ds.attrs["hc"] = self.grid.ds.attrs["hc"]
475
640
 
476
641
  # Convert the time coordinate to the format expected by ROMS
477
- if data.climatology:
478
- ds.attrs["climatology"] = str(True)
479
- # Preserve absolute time coordinate for readability
480
- ds = ds.assign_coords(
481
- {"abs_time": np.datetime64(self.model_reference_date) + ds["time"]}
482
- )
483
- # Convert to pandas TimedeltaIndex
484
- timedelta_index = pd.to_timedelta(ds["time"].values)
485
-
486
- # Determine the start of the year for the base_datetime
487
- start_of_year = datetime(self.model_reference_date.year, 1, 1)
488
-
489
- # Calculate the offset from midnight of the new year
490
- offset = self.model_reference_date - start_of_year
491
-
492
- # Convert the timedelta to nanoseconds first, then to days
493
- bry_time = xr.DataArray(
494
- (timedelta_index - offset).view("int64") / 3600 / 24 * 1e-9,
495
- dims="time",
496
- )
497
-
498
- else:
499
- # Preserve absolute time coordinate for readability
500
- ds = ds.assign_coords({"abs_time": ds["time"]})
501
- bry_time = (
502
- (ds["time"] - np.datetime64(self.model_reference_date)).astype(
503
- "float64"
504
- )
505
- / 3600
506
- / 24
507
- * 1e-9
508
- )
642
+ ds, bry_time = convert_to_roms_time(
643
+ ds, self.model_reference_date, data.climatology
644
+ )
509
645
 
510
646
  ds = ds.assign_coords({"bry_time": bry_time})
511
- ds["bry_time"].attrs[
512
- "long_name"
513
- ] = f"days since {str(self.model_reference_date)}"
514
- ds["bry_time"].encoding["units"] = "days"
515
- ds["bry_time"].attrs["units"] = "days"
516
647
  ds = ds.swap_dims({"time": "bry_time"})
517
648
  ds = ds.drop_vars("time")
518
- ds.encoding["unlimited_dims"] = "bry_time"
519
-
520
- if data.climatology:
521
- ds["bry_time"].attrs["cycle_length"] = 365.25
522
649
 
523
650
  return ds
524
651
 
525
- def _validate_1d_fill(
526
- self, processed_fields, variable_info, bdry_coords, direction, depth_dim
527
- ):
652
+ def _validate_1d_fill(self, processed_fields, direction, depth_dim):
528
653
  """Check if any boundary is divided by land and issue a warning if so,
529
654
  suggesting the use of 2D horizontal fill for safer regridding.
530
655
 
@@ -534,15 +659,6 @@ class BoundaryForcing:
534
659
  A dictionary where keys are variable names and values are `xarray.DataArray`
535
660
  objects representing the processed data for each variable.
536
661
 
537
- variable_info : dict
538
- A dictionary containing metadata about each variable (e.g., location,
539
- whether it's a 3D variable, etc.). Used to retrieve information for
540
- validating each variable.
541
-
542
- bdry_coords : dict
543
- A dictionary containing boundary coordinates for different directions (north, south,
544
- east, west), used to slice the boundary-specific data for each variable.
545
-
546
662
  direction : str
547
663
  The boundary direction being processed (e.g., "north", "south", "east", or "west").
548
664
 
@@ -558,8 +674,8 @@ class BoundaryForcing:
558
674
 
559
675
  for var_name in processed_fields.keys():
560
676
  # Only validate variables based on "validate" flag if use_dask is False
561
- if not self.use_dask or variable_info[var_name]["validate"]:
562
- location = variable_info[var_name]["location"]
677
+ if not self.use_dask or self.variable_info[var_name]["validate"]:
678
+ location = self.variable_info[var_name]["location"]
563
679
 
564
680
  # Select the appropriate mask based on variable location
565
681
  if location == "rho":
@@ -569,9 +685,9 @@ class BoundaryForcing:
569
685
  elif location == "v":
570
686
  mask = self.grid.ds.mask_v
571
687
 
572
- mask = mask.isel(**bdry_coords[location][direction])
688
+ mask = mask.isel(**self.bdry_coords[location][direction])
573
689
 
574
- if variable_info[var_name]["is_3d"]:
690
+ if self.variable_info[var_name]["is_3d"]:
575
691
  da = processed_fields[var_name].isel({depth_dim: 0, "time": 0})
576
692
  else:
577
693
  da = processed_fields[var_name].isel({"time": 0})
@@ -590,7 +706,7 @@ class BoundaryForcing:
590
706
  f"For {var_name}, the {direction}ern boundary is divided by land. It would be safer (but slower) to use `apply_2d_horizontal_fill = True`."
591
707
  )
592
708
 
593
- def _validate(self, ds, variable_info, bdry_coords):
709
+ def _validate(self, ds):
594
710
  """Validate the dataset for NaN values at the first time step (bry_time=0) for
595
711
  specified variables. If NaN values are found at wet points, this function raises
596
712
  an error.
@@ -600,12 +716,6 @@ class BoundaryForcing:
600
716
  ds : xarray.Dataset
601
717
  The dataset to validate.
602
718
 
603
- variable_info : dict
604
- A dictionary containing metadata about the variables, including their locations (e.g., 'rho', 'u', 'v').
605
-
606
- bdry_coords : dict
607
- A dictionary containing the boundary coordinates for each variable location.
608
-
609
719
  Raises
610
720
  ------
611
721
  ValueError
@@ -617,10 +727,10 @@ class BoundaryForcing:
617
727
  Validation is performed on the initial boundary time step (`bry_time=0`) for each
618
728
  variable in the dataset.
619
729
  """
620
- for var_name in variable_info:
730
+ for var_name in self.variable_info:
621
731
  # only validate variables based on "validate" flag if use_dask is false
622
- if not self.use_dask or variable_info[var_name]["validate"]:
623
- location = variable_info[var_name]["location"]
732
+ if not self.use_dask or self.variable_info[var_name]["validate"]:
733
+ location = self.variable_info[var_name]["location"]
624
734
 
625
735
  # Select the appropriate mask based on variable location
626
736
  if location == "rho":
@@ -647,7 +757,7 @@ class BoundaryForcing:
647
757
 
648
758
  nan_check(
649
759
  ds[bdry_var_name].isel(bry_time=0),
650
- mask.isel(**bdry_coords[location][direction]),
760
+ mask.isel(**self.bdry_coords[location][direction]),
651
761
  error_message=error_message,
652
762
  )
653
763
 
@@ -733,20 +843,13 @@ class BoundaryForcing:
733
843
  field = field.load()
734
844
 
735
845
  title = field.long_name
846
+ var_name_wo_direction, direction = var_name.split("_")
847
+ location = self.variable_info[var_name_wo_direction]["location"]
736
848
 
737
849
  if "s_rho" in field.dims:
738
- if var_name.startswith(("u_", "ubar_")):
739
- point = "u"
740
- elif var_name.startswith(("v_", "vbar_")):
741
- point = "v"
742
- else:
743
- point = "rho"
744
- direction = var_name.split("_")[-1]
745
-
746
- layer_depth, interface_depth = self._get_coordinates(direction, point)
747
-
748
- field = field.assign_coords({"layer_depth": layer_depth})
749
-
850
+ field = field.assign_coords(
851
+ {"layer_depth": self.grid.ds[f"layer_depth_{location}_{direction}"]}
852
+ )
750
853
  # chose colorbar
751
854
  if var_name.startswith(("u", "v", "ubar", "vbar", "zeta")):
752
855
  vmax = max(field.max().values, -field.min().values)
@@ -764,6 +867,19 @@ class BoundaryForcing:
764
867
 
765
868
  if len(field.dims) == 2:
766
869
  if layer_contours:
870
+ if location in ["u", "v"]:
871
+ additional_locations = ["u", "v"]
872
+ else:
873
+ additional_locations = []
874
+ self._get_vertical_coordinates(
875
+ type="interface",
876
+ direction=direction,
877
+ additional_locations=additional_locations,
878
+ )
879
+
880
+ interface_depth = self.grid.ds[
881
+ f"interface_depth_{location}_{direction}"
882
+ ]
767
883
  # restrict number of layer_contours to 10 for the sake of plot clearity
768
884
  nr_layers = len(interface_depth["s_w"])
769
885
  selected_layers = np.linspace(
@@ -859,46 +975,8 @@ class BoundaryForcing:
859
975
  filepath : Union[str, Path]
860
976
  The path to the YAML file where the parameters will be saved.
861
977
  """
862
- filepath = Path(filepath)
863
978
 
864
- # Serialize Grid data
865
- grid_data = asdict(self.grid)
866
- grid_data.pop("ds", None) # Exclude non-serializable fields
867
- grid_data.pop("straddle", None)
868
-
869
- # Include the version of roms-tools
870
- try:
871
- roms_tools_version = importlib.metadata.version("roms-tools")
872
- except importlib.metadata.PackageNotFoundError:
873
- roms_tools_version = "unknown"
874
-
875
- # Create header
876
- header = f"---\nroms_tools_version: {roms_tools_version}\n---\n"
877
-
878
- grid_yaml_data = {"Grid": grid_data}
879
-
880
- boundary_forcing_data = {
881
- "BoundaryForcing": {
882
- "start_time": self.start_time.isoformat(),
883
- "end_time": self.end_time.isoformat(),
884
- "boundaries": self.boundaries,
885
- "source": self.source,
886
- "type": self.type,
887
- "apply_2d_horizontal_fill": self.apply_2d_horizontal_fill,
888
- "model_reference_date": self.model_reference_date.isoformat(),
889
- }
890
- }
891
-
892
- yaml_data = {
893
- **grid_yaml_data,
894
- **boundary_forcing_data,
895
- }
896
-
897
- with filepath.open("w") as file:
898
- # Write header
899
- file.write(header)
900
- # Write YAML data
901
- yaml.dump(yaml_data, file, default_flow_style=False, sort_keys=False)
979
+ _to_yaml(self, filepath)
902
980
 
903
981
  @classmethod
904
982
  def from_yaml(
@@ -919,80 +997,12 @@ class BoundaryForcing:
919
997
  An instance of the BoundaryForcing class.
920
998
  """
921
999
  filepath = Path(filepath)
922
- # Read the entire file content
923
- with filepath.open("r") as file:
924
- file_content = file.read()
925
-
926
- # Split the content into YAML documents
927
- documents = list(yaml.safe_load_all(file_content))
928
-
929
- boundary_forcing_data = None
930
-
931
- # Process the YAML documents
932
- for doc in documents:
933
- if doc is None:
934
- continue
935
- if "BoundaryForcing" in doc:
936
- boundary_forcing_data = doc["BoundaryForcing"]
937
- break
938
-
939
- if boundary_forcing_data is None:
940
- raise ValueError("No BoundaryForcing configuration found in the YAML file.")
941
-
942
- # Convert from string to datetime
943
- for date_string in ["model_reference_date", "start_time", "end_time"]:
944
- boundary_forcing_data[date_string] = datetime.fromisoformat(
945
- boundary_forcing_data[date_string]
946
- )
947
1000
 
948
1001
  grid = Grid.from_yaml(filepath)
1002
+ params = _from_yaml(cls, filepath)
949
1003
 
950
1004
  # Create and return an instance of InitialConditions
951
- return cls(grid=grid, **boundary_forcing_data, use_dask=use_dask)
952
-
953
-
954
- def get_boundary_info():
955
- """This function provides information about the boundary points for the rho, u, and
956
- v variables on the grid, specifying the indices for the south, east, north, and west
957
- boundaries.
958
-
959
- Returns
960
- -------
961
- dict
962
- A dictionary where keys are variable types ("rho", "u", "v"), and values
963
- are nested dictionaries mapping directions ("south", "east", "north", "west")
964
- to the corresponding boundary coordinates.
965
- """
966
-
967
- # Boundary coordinates
968
- bdry_coords = {
969
- "rho": {
970
- "south": {"eta_rho": 0},
971
- "east": {"xi_rho": -1},
972
- "north": {"eta_rho": -1},
973
- "west": {"xi_rho": 0},
974
- },
975
- "u": {
976
- "south": {"eta_rho": 0},
977
- "east": {"xi_u": -1},
978
- "north": {"eta_rho": -1},
979
- "west": {"xi_u": 0},
980
- },
981
- "v": {
982
- "south": {"eta_v": 0},
983
- "east": {"xi_rho": -1},
984
- "north": {"eta_v": -1},
985
- "west": {"xi_rho": 0},
986
- },
987
- "vector": {
988
- "south": {"eta_rho": [0, 1]},
989
- "east": {"xi_rho": [-2, -1]},
990
- "north": {"eta_rho": [-2, -1]},
991
- "west": {"xi_rho": [0, 1]},
992
- },
993
- }
994
-
995
- return bdry_coords
1005
+ return cls(grid=grid, **params, use_dask=use_dask)
996
1006
 
997
1007
 
998
1008
  def apply_1d_horizontal_fill(processed_fields: dict) -> dict: