roms-tools 1.5.0__py3-none-any.whl → 1.6.1__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 (239) hide show
  1. roms_tools/_version.py +1 -1
  2. roms_tools/setup/boundary_forcing.py +263 -100
  3. roms_tools/setup/datasets.py +169 -39
  4. roms_tools/setup/fill.py +0 -36
  5. roms_tools/setup/grid.py +1 -1
  6. roms_tools/setup/initial_conditions.py +108 -73
  7. roms_tools/setup/regrid.py +43 -98
  8. roms_tools/setup/surface_forcing.py +104 -82
  9. roms_tools/setup/tides.py +76 -48
  10. roms_tools/setup/utils.py +25 -53
  11. roms_tools/tests/test_setup/test_boundary_forcing.py +84 -47
  12. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/0.0.0 +0 -0
  13. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_south/0.0.0 +0 -0
  14. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/0.0.0 +0 -0
  15. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/0.0.0 +0 -0
  16. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_south/0.0.0 +0 -0
  17. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/0.0.0 +0 -0
  18. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/0.0.0 +0 -0
  19. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_south/0.0.0 +0 -0
  20. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/0.0.0 +0 -0
  21. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/0.0.0 +0 -0
  22. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_south/0.0.0 +0 -0
  23. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/0.0.0 +0 -0
  24. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/0.0.0 +0 -0
  25. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_south/0.0.0 +0 -0
  26. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/0.0.0 +0 -0
  27. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/0.0.0 +0 -0
  28. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_south/0.0.0 +0 -0
  29. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/0.0.0 +0 -0
  30. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/0.0.0 +0 -0
  31. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_south/0.0.0 +0 -0
  32. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/0.0.0 +0 -0
  33. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/0.0.0 +0 -0
  34. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_south/0.0.0 +0 -0
  35. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/0.0.0 +0 -0
  36. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/0.0.0 +0 -0
  37. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_south/0.0.0 +0 -0
  38. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/0.0.0 +0 -0
  39. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/0.0.0 +0 -0
  40. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_south/0.0.0 +0 -0
  41. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/0.0.0 +0 -0
  42. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/0.0.0 +0 -0
  43. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_south/0.0.0 +0 -0
  44. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/0.0.0 +0 -0
  45. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/0.0.0 +0 -0
  46. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_south/0.0.0 +0 -0
  47. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/0.0.0 +0 -0
  48. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/0.0.0 +0 -0
  49. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_south/0.0.0 +0 -0
  50. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/0.0.0 +0 -0
  51. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/0.0.0 +0 -0
  52. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_south/0.0.0 +0 -0
  53. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/0.0.0 +0 -0
  54. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/0.0.0 +0 -0
  55. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_south/0.0.0 +0 -0
  56. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/0.0.0 +0 -0
  57. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/0.0.0 +0 -0
  58. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_south/0.0.0 +0 -0
  59. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/0.0.0 +0 -0
  60. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/0.0.0 +0 -0
  61. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_south/0.0.0 +0 -0
  62. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/0.0.0 +0 -0
  63. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/0.0.0 +0 -0
  64. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_south/0.0.0 +0 -0
  65. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/0.0.0 +0 -0
  66. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/0.0.0 +0 -0
  67. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_south/0.0.0 +0 -0
  68. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/0.0.0 +0 -0
  69. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/0.0.0 +0 -0
  70. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_south/0.0.0 +0 -0
  71. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/0.0.0 +0 -0
  72. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/0.0.0 +0 -0
  73. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_south/0.0.0 +0 -0
  74. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/0.0.0 +0 -0
  75. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/0.0.0 +0 -0
  76. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_south/0.0.0 +0 -0
  77. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/0.0.0 +0 -0
  78. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/0.0.0 +0 -0
  79. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_south/0.0.0 +0 -0
  80. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/0.0.0 +0 -0
  81. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/0.0.0 +0 -0
  82. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_south/0.0.0 +0 -0
  83. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/0.0.0 +0 -0
  84. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/0.0.0 +0 -0
  85. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_south/0.0.0 +0 -0
  86. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/0.0.0 +0 -0
  87. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/0.0.0 +0 -0
  88. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_south/0.0.0 +0 -0
  89. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/0.0.0 +0 -0
  90. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/0.0.0 +0 -0
  91. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_south/0.0.0 +0 -0
  92. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/0.0.0 +0 -0
  93. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/0.0.0 +0 -0
  94. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_south/0.0.0 +0 -0
  95. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/0.0.0 +0 -0
  96. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/0.0.0 +0 -0
  97. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_south/0.0.0 +0 -0
  98. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/0.0.0 +0 -0
  99. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/0.0.0 +0 -0
  100. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_south/0.0.0 +0 -0
  101. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/0.0.0 +0 -0
  102. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/0.0.0 +0 -0
  103. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_south/0.0.0 +0 -0
  104. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/0.0.0 +0 -0
  105. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/0.0.0 +0 -0
  106. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_south/0.0.0 +0 -0
  107. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/0.0.0 +0 -0
  108. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zattrs +1 -1
  109. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zmetadata +1 -1
  110. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust/0.0.0 +0 -0
  111. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron/0.0.0 +0 -0
  112. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy/0.0.0 +0 -0
  113. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox/0.0.0 +0 -0
  114. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air/0.0.0 +0 -0
  115. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air_alt/0.0.0 +0 -0
  116. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zattrs +1 -1
  117. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zmetadata +1 -1
  118. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust/0.0.0 +0 -0
  119. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron/0.0.0 +0 -0
  120. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy/0.0.0 +0 -0
  121. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox/0.0.0 +0 -0
  122. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air/0.0.0 +0 -0
  123. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air_alt/0.0.0 +0 -0
  124. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/.zmetadata +7 -0
  125. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zattrs +3 -0
  126. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/0.0.0 +0 -0
  127. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/0.0.0 +0 -0
  128. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/0.0.0 +0 -0
  129. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/0.0.0 +0 -0
  130. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/0.0.0 +0 -0
  131. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/0.0.0 +0 -0
  132. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/0.0.0 +0 -0
  133. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/0.0.0 +0 -0
  134. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/0.0 +0 -0
  135. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/0.0 +0 -0
  136. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/0.0 +0 -0
  137. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/0.0 +0 -0
  138. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/0.0.0 +0 -0
  139. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/0.0.0 +0 -0
  140. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/0.0.0 +0 -0
  141. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/0.0.0 +0 -0
  142. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/0.0 +0 -0
  143. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/0.0 +0 -0
  144. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/0.0 +0 -0
  145. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/0.0 +0 -0
  146. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zattrs +1 -0
  147. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/0.0 +0 -0
  148. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/.zattrs +1 -0
  149. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zattrs +1 -0
  150. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/0.0 +0 -0
  151. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/.zattrs +1 -0
  152. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/.zattrs +1 -1
  153. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/.zmetadata +1 -1
  154. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/Tair/0.0.0 +0 -0
  155. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/lwrad/0.0.0 +0 -0
  156. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/qair/0.0.0 +0 -0
  157. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/rain/0.0.0 +0 -0
  158. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/swrad/0.0.0 +0 -0
  159. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/uwnd/0.0.0 +0 -0
  160. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/vwnd/0.0.0 +0 -0
  161. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/.zattrs +1 -1
  162. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/.zmetadata +1 -1
  163. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/Tair/0.0.0 +0 -0
  164. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/lwrad/0.0.0 +0 -0
  165. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/qair/0.0.0 +0 -0
  166. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/rain/0.0.0 +0 -0
  167. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/swrad/0.0.0 +0 -0
  168. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/uwnd/0.0.0 +0 -0
  169. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/vwnd/0.0.0 +0 -0
  170. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK/0.0.0.0 +0 -0
  171. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK_ALT_CO2/0.0.0.0 +0 -0
  172. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC/0.0.0.0 +0 -0
  173. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC_ALT_CO2/0.0.0.0 +0 -0
  174. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOC/0.0.0.0 +0 -0
  175. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOCr/0.0.0.0 +0 -0
  176. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DON/0.0.0.0 +0 -0
  177. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DONr/0.0.0.0 +0 -0
  178. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOP/0.0.0.0 +0 -0
  179. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOPr/0.0.0.0 +0 -0
  180. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Fe/0.0.0.0 +0 -0
  181. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Lig/0.0.0.0 +0 -0
  182. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NH4/0.0.0.0 +0 -0
  183. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NO3/0.0.0.0 +0 -0
  184. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/O2/0.0.0.0 +0 -0
  185. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/PO4/0.0.0.0 +0 -0
  186. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/SiO3/0.0.0.0 +0 -0
  187. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatC/0.0.0.0 +0 -0
  188. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatChl/0.0.0.0 +0 -0
  189. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatFe/0.0.0.0 +0 -0
  190. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatP/0.0.0.0 +0 -0
  191. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatSi/0.0.0.0 +0 -0
  192. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazC/0.0.0.0 +0 -0
  193. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazChl/0.0.0.0 +0 -0
  194. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazFe/0.0.0.0 +0 -0
  195. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazP/0.0.0.0 +0 -0
  196. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/salt/0.0.0.0 +0 -0
  197. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spC/0.0.0.0 +0 -0
  198. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spCaCO3/0.0.0.0 +0 -0
  199. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spChl/0.0.0.0 +0 -0
  200. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spFe/0.0.0.0 +0 -0
  201. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spP/0.0.0.0 +0 -0
  202. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/temp/0.0.0.0 +0 -0
  203. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/u/0.0.0.0 +0 -0
  204. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ubar/0.0.0 +0 -0
  205. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/v/0.0.0.0 +0 -0
  206. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/vbar/0.0.0 +0 -0
  207. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zeta/0.0.0 +0 -0
  208. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zooC/0.0.0.0 +0 -0
  209. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/.zattrs +1 -1
  210. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/.zmetadata +1 -1
  211. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/Tair/0.0.0 +0 -0
  212. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/lwrad/0.0.0 +0 -0
  213. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/qair/0.0.0 +0 -0
  214. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/rain/0.0.0 +0 -0
  215. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/swrad/0.0.0 +0 -0
  216. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/uwnd/0.0.0 +0 -0
  217. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/vwnd/0.0.0 +0 -0
  218. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zattrs +1 -1
  219. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zmetadata +4 -2
  220. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/omega/.zattrs +3 -1
  221. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Im/0.0.0 +0 -0
  222. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Re/0.0.0 +0 -0
  223. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Im/0.0.0 +0 -0
  224. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Re/0.0.0 +0 -0
  225. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Im/0.0.0 +0 -0
  226. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Re/0.0.0 +0 -0
  227. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Im/0.0.0 +0 -0
  228. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/0.0.0 +0 -0
  229. roms_tools/tests/test_setup/test_datasets.py +79 -21
  230. roms_tools/tests/test_setup/test_fill.py +18 -105
  231. roms_tools/tests/test_setup/test_initial_conditions.py +29 -25
  232. roms_tools/tests/test_setup/test_regrid.py +2 -8
  233. roms_tools/tests/test_setup/test_surface_forcing.py +49 -29
  234. roms_tools/tests/test_setup/test_tides.py +7 -5
  235. {roms_tools-1.5.0.dist-info → roms_tools-1.6.1.dist-info}/METADATA +13 -3
  236. {roms_tools-1.5.0.dist-info → roms_tools-1.6.1.dist-info}/RECORD +239 -239
  237. {roms_tools-1.5.0.dist-info → roms_tools-1.6.1.dist-info}/WHEEL +1 -1
  238. {roms_tools-1.5.0.dist-info → roms_tools-1.6.1.dist-info}/LICENSE +0 -0
  239. {roms_tools-1.5.0.dist-info → roms_tools-1.6.1.dist-info}/top_level.txt +0 -0
roms_tools/_version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # Do not change! Do not track in version control!
2
- __version__ = "1.5.0"
2
+ __version__ = "1.6.1"
@@ -3,24 +3,24 @@ import numpy as np
3
3
  import pandas as pd
4
4
  import yaml
5
5
  import importlib.metadata
6
+ import warnings
6
7
  from typing import Dict, Union, List
7
8
  from dataclasses import dataclass, field, asdict
8
9
  from roms_tools.setup.grid import Grid
9
- from roms_tools.setup.fill import _lateral_fill
10
- from roms_tools.setup.regrid import _lateral_regrid, _vertical_regrid
10
+ from roms_tools.setup.regrid import LateralRegrid, VerticalRegrid
11
11
  from datetime import datetime
12
12
  from roms_tools.setup.datasets import GLORYSDataset, CESMBGCDataset
13
13
  from roms_tools.setup.utils import (
14
- nan_check,
15
- substitute_nans_by_fillvalue,
16
14
  get_variable_metadata,
17
15
  group_dataset,
18
16
  save_datasets,
19
17
  get_target_coords,
20
18
  rotate_velocities,
21
19
  compute_barotropic_velocity,
22
- _extrapolate_deepest_to_bottom,
23
20
  transpose_dimensions,
21
+ one_dim_fill,
22
+ nan_check,
23
+ substitute_nans_by_fillvalue,
24
24
  )
25
25
  from roms_tools.setup.plot import _section_plot, _line_plot
26
26
  import matplotlib.pyplot as plt
@@ -60,6 +60,10 @@ class BoundaryForcing:
60
60
 
61
61
  model_reference_date : datetime, optional
62
62
  Reference date for the model. Default is January 1, 2000.
63
+ apply_2d_horizontal_fill: bool, optional
64
+ Indicates whether to perform a two-dimensional horizontal fill on the source data prior to regridding to boundaries.
65
+ If `False`, a one-dimensional horizontal fill is performed separately on each of the four regridded boundaries.
66
+ Defaults to `False`.
63
67
  use_dask: bool, optional
64
68
  Indicates whether to use dask for processing. If True, data is processed with dask; if False, data is processed eagerly. Defaults to False.
65
69
 
@@ -89,6 +93,7 @@ class BoundaryForcing:
89
93
  source: Dict[str, Union[str, Path, List[Union[str, Path]]]]
90
94
  type: str = "physics"
91
95
  model_reference_date: datetime = datetime(2000, 1, 1)
96
+ apply_2d_horizontal_fill: bool = False
92
97
  use_dask: bool = False
93
98
 
94
99
  ds: xr.Dataset = field(init=False, repr=False)
@@ -99,31 +104,42 @@ class BoundaryForcing:
99
104
  target_coords = get_target_coords(self.grid)
100
105
 
101
106
  data = self._get_data()
102
- data.choose_subdomain(
103
- latitude_range=[
104
- target_coords["lat"].min().values,
105
- target_coords["lat"].max().values,
106
- ],
107
- longitude_range=[
108
- target_coords["lon"].min().values,
109
- target_coords["lon"].max().values,
110
- ],
111
- margin=2,
112
- straddle=target_coords["straddle"],
113
- )
114
107
 
115
- variable_info = self._set_variable_info(data)
116
-
117
- data_vars = {}
118
- data_vars = _extrapolate_deepest_to_bottom(data_vars, data)
119
- data_vars = _lateral_fill(data_vars, data)
108
+ if self.apply_2d_horizontal_fill:
109
+ data.choose_subdomain(
110
+ target_coords,
111
+ buffer_points=20, # lateral fill needs good buffer from data margin
112
+ )
113
+ data.extrapolate_deepest_to_bottom()
114
+ data.apply_lateral_fill()
120
115
 
116
+ variable_info = self._set_variable_info(data)
121
117
  bdry_coords = get_boundary_info()
122
118
  ds = xr.Dataset()
119
+
123
120
  for direction in ["south", "east", "north", "west"]:
124
121
  if self.boundaries[direction]:
125
122
 
126
- bdry_data_vars = data_vars.copy()
123
+ bdry_target_coords = {
124
+ "lat": target_coords["lat"].isel(
125
+ **bdry_coords["vector"][direction]
126
+ ),
127
+ "lon": target_coords["lon"].isel(
128
+ **bdry_coords["vector"][direction]
129
+ ),
130
+ "straddle": target_coords["straddle"],
131
+ }
132
+
133
+ bdry_data = data.choose_subdomain(
134
+ bdry_target_coords,
135
+ buffer_points=3,
136
+ return_copy=True,
137
+ )
138
+
139
+ if not self.apply_2d_horizontal_fill:
140
+ bdry_data.extrapolate_deepest_to_bottom()
141
+
142
+ processed_fields = {}
127
143
 
128
144
  # lateral regridding of vector fields
129
145
  vector_var_names = [
@@ -132,9 +148,15 @@ class BoundaryForcing:
132
148
  if len(vector_var_names) > 0:
133
149
  lon = target_coords["lon"].isel(**bdry_coords["vector"][direction])
134
150
  lat = target_coords["lat"].isel(**bdry_coords["vector"][direction])
135
- bdry_data_vars = _lateral_regrid(
136
- data, lon, lat, bdry_data_vars, vector_var_names
151
+ lateral_regrid = LateralRegrid(
152
+ {"lat": lat, "lon": lon}, bdry_data.dim_names
137
153
  )
154
+ for var_name in vector_var_names:
155
+ if var_name in bdry_data.var_names.keys():
156
+ processed_fields[var_name] = lateral_regrid.apply(
157
+ bdry_data.ds[bdry_data.var_names[var_name]]
158
+ )
159
+
138
160
  # lateral regridding of tracer fields
139
161
  tracer_var_names = [
140
162
  name
@@ -144,30 +166,38 @@ class BoundaryForcing:
144
166
  if len(tracer_var_names) > 0:
145
167
  lon = target_coords["lon"].isel(**bdry_coords["rho"][direction])
146
168
  lat = target_coords["lat"].isel(**bdry_coords["rho"][direction])
147
- bdry_data_vars = _lateral_regrid(
148
- data, lon, lat, bdry_data_vars, tracer_var_names
169
+ lateral_regrid = LateralRegrid(
170
+ {"lat": lat, "lon": lon}, bdry_data.dim_names
149
171
  )
172
+ for var_name in tracer_var_names:
173
+ if var_name in bdry_data.var_names.keys():
174
+ processed_fields[var_name] = lateral_regrid.apply(
175
+ bdry_data.ds[bdry_data.var_names[var_name]]
176
+ )
150
177
 
151
178
  # rotation of velocities and interpolation to u/v points
152
179
  if "u" in variable_info and "v" in variable_info:
153
180
  angle = target_coords["angle"].isel(
154
181
  **bdry_coords["vector"][direction]
155
182
  )
156
- (bdry_data_vars["u"], bdry_data_vars["v"],) = rotate_velocities(
157
- bdry_data_vars["u"],
158
- bdry_data_vars["v"],
183
+ (processed_fields["u"], processed_fields["v"],) = rotate_velocities(
184
+ processed_fields["u"],
185
+ processed_fields["v"],
159
186
  angle,
160
187
  interpolate=True,
161
188
  )
162
189
 
163
190
  # selection of outermost margin for u/v variables
164
- for var in variable_info.keys():
165
- if var in bdry_data_vars:
166
- location = variable_info[var]["location"]
191
+ for var_name in variable_info.keys():
192
+ if var_name in processed_fields:
193
+ location = variable_info[var_name]["location"]
167
194
  if location in ["u", "v"]:
168
- bdry_data_vars[var] = bdry_data_vars[var].isel(
169
- **bdry_coords[location][direction]
170
- )
195
+ processed_fields[var_name] = processed_fields[
196
+ var_name
197
+ ].isel(**bdry_coords[location][direction])
198
+
199
+ if not self.apply_2d_horizontal_fill:
200
+ processed_fields = apply_1d_horizontal_fill(processed_fields)
171
201
 
172
202
  # vertical regridding
173
203
  for location in ["rho", "u", "v"]:
@@ -177,53 +207,47 @@ class BoundaryForcing:
177
207
  if info["location"] == location and info["is_3d"]
178
208
  ]
179
209
  if len(var_names) > 0:
180
- bdry_data_vars = _vertical_regrid(
181
- data,
210
+ vertical_regrid = VerticalRegrid(
182
211
  self.grid.ds[f"layer_depth_{location}"].isel(
183
- **bdry_coords[location][direction],
212
+ **bdry_coords[location][direction]
184
213
  ),
185
- bdry_data_vars,
186
- var_names,
214
+ bdry_data.ds[bdry_data.dim_names["depth"]],
187
215
  )
216
+ for var_name in var_names:
217
+ if var_name in processed_fields:
218
+ processed_fields[var_name] = vertical_regrid.apply(
219
+ processed_fields[var_name]
220
+ )
188
221
 
189
222
  # compute barotropic velocities
190
223
  if "u" in variable_info and "v" in variable_info:
191
- for var in ["u", "v"]:
192
- bdry_data_vars[f"{var}bar"] = compute_barotropic_velocity(
193
- bdry_data_vars[var],
194
- self.grid.ds[f"interface_depth_{var}"].isel(
195
- **bdry_coords[var][direction]
224
+ for var_name in ["u", "v"]:
225
+ processed_fields[
226
+ f"{var_name}bar"
227
+ ] = compute_barotropic_velocity(
228
+ processed_fields[var_name],
229
+ self.grid.ds[f"interface_depth_{var_name}"].isel(
230
+ **bdry_coords[var_name][direction]
196
231
  ),
197
232
  )
198
233
 
199
234
  # Reorder dimensions
200
- for var in bdry_data_vars.keys():
201
- bdry_data_vars[var] = transpose_dimensions(bdry_data_vars[var])
235
+ for var_name in processed_fields.keys():
236
+ processed_fields[var_name] = transpose_dimensions(
237
+ processed_fields[var_name]
238
+ )
202
239
 
203
240
  # Write the boundary data into dataset
204
- ds = self._write_into_dataset(direction, bdry_data_vars, ds)
241
+ ds = self._write_into_dataset(direction, processed_fields, ds)
205
242
 
206
243
  # Add global information
207
244
  ds = self._add_global_metadata(data, ds)
208
245
 
209
- # NaN values at wet points indicate that the raw data did not cover the domain, and the following will raise a ValueError
210
- # this check works only for 2D fields because for 3D I extrapolate to bottom which eliminates NaNs
211
- for direction in ["south", "east", "north", "west"]:
212
- if self.boundaries[direction]:
213
- if type == "physics":
214
- nan_check(
215
- ds[f"zeta_{direction}"].isel(bry_time=0),
216
- self.grid.ds.mask_rho.isel(**bdry_coords["rho"][direction]),
217
- )
218
- elif type == "bgc":
219
- nan_check(
220
- ds[f"ALK_{direction}"].isel(bry_time=0, s_rho=-1),
221
- self.grid.ds.mask_rho.isel(**bdry_coords["rho"][direction]),
222
- )
246
+ self._validate(ds, variable_info, bdry_coords)
223
247
 
224
248
  # substitute NaNs over land by a fill value to avoid blow-up of ROMS
225
- for var in ds.data_vars:
226
- ds[var] = substitute_nans_by_fillvalue(ds[var])
249
+ for var_name in ds.data_vars:
250
+ ds[var_name] = substitute_nans_by_fillvalue(ds[var_name])
227
251
 
228
252
  object.__setattr__(self, "ds", ds)
229
253
 
@@ -335,25 +359,27 @@ class BoundaryForcing:
335
359
  }
336
360
  elif self.type == "bgc":
337
361
  variable_info = {}
338
- for var in data.var_names.keys():
339
- variable_info[var] = default_info
362
+ for var_name in data.var_names.keys():
363
+ variable_info[var_name] = default_info
340
364
 
341
365
  return variable_info
342
366
 
343
- def _write_into_dataset(self, direction, data_vars, ds=None):
367
+ def _write_into_dataset(self, direction, processed_fields, ds=None):
344
368
  if ds is None:
345
369
  ds = xr.Dataset()
346
370
 
347
371
  d_meta = get_variable_metadata()
348
372
 
349
- for var in data_vars.keys():
350
- ds[f"{var}_{direction}"] = data_vars[var].astype(np.float32)
373
+ for var_name in processed_fields.keys():
374
+ ds[f"{var_name}_{direction}"] = processed_fields[var_name].astype(
375
+ np.float32
376
+ )
351
377
 
352
- ds[f"{var}_{direction}"].attrs[
378
+ ds[f"{var_name}_{direction}"].attrs[
353
379
  "long_name"
354
- ] = f"{direction}ern boundary {d_meta[var]['long_name']}"
380
+ ] = f"{direction}ern boundary {d_meta[var_name]['long_name']}"
355
381
 
356
- ds[f"{var}_{direction}"].attrs["units"] = d_meta[var]["units"]
382
+ ds[f"{var_name}_{direction}"].attrs["units"] = d_meta[var_name]["units"]
357
383
 
358
384
  # Gracefully handle dropping variables that might not be present
359
385
  variables_to_drop = [
@@ -371,7 +397,7 @@ class BoundaryForcing:
371
397
  "lat_v",
372
398
  "lon_v",
373
399
  ]
374
- existing_vars = [var for var in variables_to_drop if var in ds]
400
+ existing_vars = [var_name for var_name in variables_to_drop if var_name in ds]
375
401
  ds = ds.drop_vars(existing_vars)
376
402
 
377
403
  return ds
@@ -480,9 +506,76 @@ class BoundaryForcing:
480
506
 
481
507
  return ds
482
508
 
509
+ def _validate(self, ds, variable_info, bdry_coords):
510
+ """Validate the dataset for NaN values at the first time step based on the fill
511
+ method used.
512
+
513
+ Parameters
514
+ ----------
515
+ ds : xarray.Dataset
516
+ The dataset to validate.
517
+
518
+ variable_info : dict
519
+ A dictionary containing metadata about the variables, including their locations (e.g., 'rho', 'u', 'v').
520
+
521
+ bdry_coords : dict
522
+ A dictionary containing the boundary coordinates for each variable location.
523
+
524
+ Raises
525
+ ------
526
+ ValueError
527
+ If NaN values are found in any of the specified variables at wet points,
528
+ indicating incomplete data coverage.
529
+
530
+ Notes
531
+ -----
532
+ Validation is performed on the initial boundary time step (`bry_time=0`) for each
533
+ variable in the dataset. If the `apply_2d_horizontal_fill` attribute is set to False,
534
+ a warning is issued instead of a strict NaN check, as the data may not be reliably validated.
535
+ Conversely, if `apply_2d_horizontal_fill` is True, a strict NaN check is performed, raising
536
+ a ValueError if any NaN values are detected.
537
+ """
538
+ if self.apply_2d_horizontal_fill:
539
+ # Strict NaN check with ValueError makes sense to be applied
540
+ for var_name in variable_info:
541
+ location = variable_info[var_name]["location"]
542
+
543
+ # Select the appropriate mask based on variable location
544
+ if location == "rho":
545
+ mask = self.grid.ds.mask_rho
546
+ elif location == "u":
547
+ mask = self.grid.ds.mask_u
548
+ elif location == "v":
549
+ mask = self.grid.ds.mask_v
550
+ else:
551
+ continue # Skip if location is not recognized
552
+
553
+ for direction in ["south", "east", "north", "west"]:
554
+ if self.boundaries[direction]:
555
+ bdry_var_name = f"{var_name}_{direction}"
556
+
557
+ # Check for NaN values at the first time step using the nan_check function
558
+ nan_check(
559
+ ds[bdry_var_name].isel(bry_time=0),
560
+ mask.isel(**bdry_coords[location][direction]),
561
+ )
562
+ else:
563
+ # Can't apply strict NaN check because land values haven't been filled before regridding step; instead warn user
564
+ for direction in ["south", "east", "north", "west"]:
565
+ if self.boundaries[direction]:
566
+ for var_name in variable_info:
567
+ bdry_var_name = f"{var_name}_{direction}"
568
+ if ds[bdry_var_name].isel(bry_time=0).isnull().any().values:
569
+ warnings.warn(
570
+ f"NaN values detected in regridded variables along the {direction}ern boundary. This may indicate that the entire boundary is on land in the source data, or that the source data does not cover this boundary.",
571
+ UserWarning,
572
+ )
573
+ # Break after the first warning for this direction to avoid duplicates
574
+ break
575
+
483
576
  def plot(
484
577
  self,
485
- varname,
578
+ var_name,
486
579
  time=0,
487
580
  layer_contours=False,
488
581
  ) -> None:
@@ -490,7 +583,7 @@ class BoundaryForcing:
490
583
 
491
584
  Parameters
492
585
  ----------
493
- varname : str
586
+ var_name : str
494
587
  The name of the boundary forcing field to plot. Options include:
495
588
 
496
589
  - "temp_{direction}": Potential temperature,
@@ -550,37 +643,44 @@ class BoundaryForcing:
550
643
  Raises
551
644
  ------
552
645
  ValueError
553
- If the specified varname is not one of the valid options.
646
+ If the specified var_name is not one of the valid options.
554
647
  """
555
648
 
556
- if varname not in self.ds:
557
- raise ValueError(f"Variable '{varname}' is not found in dataset.")
649
+ if var_name not in self.ds:
650
+ raise ValueError(f"Variable '{var_name}' is not found in dataset.")
651
+
652
+ field = self.ds[var_name].isel(bry_time=time)
653
+
654
+ if self.use_dask:
655
+ from dask.diagnostics import ProgressBar
656
+
657
+ with ProgressBar():
658
+ field = field.load()
558
659
 
559
- field = self.ds[varname].isel(bry_time=time).load()
560
660
  title = field.long_name
561
661
 
562
662
  if "s_rho" in field.dims:
563
- if varname.startswith(("u_", "ubar_")):
663
+ if var_name.startswith(("u_", "ubar_")):
564
664
  point = "u"
565
- elif varname.startswith(("v_", "vbar_")):
665
+ elif var_name.startswith(("v_", "vbar_")):
566
666
  point = "v"
567
667
  else:
568
668
  point = "rho"
569
- direction = varname.split("_")[-1]
669
+ direction = var_name.split("_")[-1]
570
670
 
571
671
  layer_depth, interface_depth = self._get_coordinates(direction, point)
572
672
 
573
673
  field = field.assign_coords({"layer_depth": layer_depth})
574
674
 
575
675
  # chose colorbar
576
- if varname.startswith(("u", "v", "ubar", "vbar", "zeta")):
676
+ if var_name.startswith(("u", "v", "ubar", "vbar", "zeta")):
577
677
  vmax = max(field.max().values, -field.min().values)
578
678
  vmin = -vmax
579
679
  cmap = plt.colormaps.get_cmap("RdBu_r")
580
680
  else:
581
681
  vmax = field.max().values
582
682
  vmin = field.min().values
583
- if varname.startswith(("temp", "salt")):
683
+ if var_name.startswith(("temp", "salt")):
584
684
  cmap = plt.colormaps.get_cmap("YlOrRd")
585
685
  else:
586
686
  cmap = plt.colormaps.get_cmap("YlGn")
@@ -606,24 +706,26 @@ class BoundaryForcing:
606
706
  _line_plot(field, title=title)
607
707
 
608
708
  def save(
609
- self, filepath: Union[str, Path], np_eta: int = None, np_xi: int = None
709
+ self,
710
+ filepath: Union[str, Path],
711
+ np_eta: int = None,
712
+ np_xi: int = None,
713
+ group: bool = False,
610
714
  ) -> None:
611
- """Save the boundary forcing fields to netCDF4 files.
612
-
613
- This method saves the dataset by grouping it into subsets based on the data frequency. The subsets are then written
614
- to one or more netCDF4 files. The filenames of the output files reflect the temporal coverage of the data.
715
+ """Save the boundary forcing fields to one or more netCDF4 files.
615
716
 
616
- There are two modes of saving the dataset:
717
+ This method saves the dataset either as a single file or as multiple files depending on the partitioning and grouping options.
718
+ The dataset can be saved in two modes:
617
719
 
618
- 1. **Single File Mode (default)**:
720
+ 1. **Single File Mode (default)**:
721
+ - If both `np_eta` and `np_xi` are `None`, the entire dataset is saved as a single netCDF4 file.
722
+ - The file is named based on the `filepath`, with `.nc` automatically appended.
619
723
 
620
- If both `np_eta` and `np_xi` are `None`, the entire dataset, divided by temporal subsets, is saved as a single netCDF4 file
621
- with the base filename specified by `filepath.nc`.
724
+ 2. **Partitioned Mode**:
725
+ - If either `np_eta` or `np_xi` is specified, the dataset is partitioned into spatial tiles along the `eta` and `xi` axes.
726
+ - Each tile is saved as a separate netCDF4 file, and filenames are modified with an index (e.g., `"filepath_YYYYMM.0.nc"`, `"filepath_YYYYMM.1.nc"`).
622
727
 
623
- 2. **Partitioned Mode**:
624
-
625
- - If either `np_eta` or `np_xi` is specified, the dataset is divided into spatial tiles along the eta-axis and xi-axis.
626
- - Each spatial tile is saved as a separate netCDF4 file.
728
+ Additionally, if `group` is set to `True`, the dataset is first grouped into temporal subsets, resulting in multiple grouped files before partitioning and saving.
627
729
 
628
730
  Parameters
629
731
  ----------
@@ -635,6 +737,8 @@ class BoundaryForcing:
635
737
  The number of partitions along the `eta` direction. If `None`, no spatial partitioning is performed.
636
738
  np_xi : int, optional
637
739
  The number of partitions along the `xi` direction. If `None`, no spatial partitioning is performed.
740
+ group: bool, optional
741
+ If `True`, groups the dataset into multiple files based on temporal data frequency. Defaults to `False`.
638
742
 
639
743
  Returns
640
744
  -------
@@ -649,7 +753,18 @@ class BoundaryForcing:
649
753
  if filepath.suffix == ".nc":
650
754
  filepath = filepath.with_suffix("")
651
755
 
652
- dataset_list, output_filenames = group_dataset(self.ds.load(), str(filepath))
756
+ if self.use_dask:
757
+ from dask.diagnostics import ProgressBar
758
+
759
+ with ProgressBar():
760
+ self.ds.load()
761
+
762
+ if group:
763
+ dataset_list, output_filenames = group_dataset(self.ds, str(filepath))
764
+ else:
765
+ dataset_list = [self.ds]
766
+ output_filenames = [str(filepath)]
767
+
653
768
  saved_filenames = save_datasets(
654
769
  dataset_list, output_filenames, np_eta=np_eta, np_xi=np_xi
655
770
  )
@@ -703,7 +818,7 @@ class BoundaryForcing:
703
818
  # Write header
704
819
  file.write(header)
705
820
  # Write YAML data
706
- yaml.dump(yaml_data, file, default_flow_style=False)
821
+ yaml.dump(yaml_data, file, default_flow_style=False, sort_keys=False)
707
822
 
708
823
  @classmethod
709
824
  def from_yaml(
@@ -798,3 +913,51 @@ def get_boundary_info():
798
913
  }
799
914
 
800
915
  return bdry_coords
916
+
917
+
918
+ def apply_1d_horizontal_fill(processed_fields: dict) -> dict:
919
+ """Forward and backward fill NaN values in horizontal direction for open boundaries.
920
+
921
+ Parameters
922
+ ----------
923
+ processed_fields : dict
924
+ A dictionary of variables to be updated, where each value is an
925
+ `xarray.DataArray`.
926
+
927
+ Returns
928
+ -------
929
+ dict of str : xarray.DataArray
930
+ The updated dictionary of variables, with NaN values filled.
931
+
932
+ Raises
933
+ ------
934
+ ValueError
935
+ If more than one horizontal dimension is found or none at all.
936
+ """
937
+
938
+ horizontal_dims = ["eta_rho", "eta_v", "xi_rho", "xi_u"]
939
+
940
+ for var_name in processed_fields.keys():
941
+ selected_horizontal_dim = None
942
+ # Determine the horizontal dimension to fill
943
+ for dim in horizontal_dims:
944
+ if dim in processed_fields[var_name].dims:
945
+ if selected_horizontal_dim is not None:
946
+ raise ValueError(
947
+ f"More than one horizontal dimension found in variable '{var_name}'."
948
+ )
949
+ selected_horizontal_dim = dim
950
+
951
+ if selected_horizontal_dim is None:
952
+ raise ValueError(
953
+ f"No valid horizontal dimension found for variable '{var_name}'."
954
+ )
955
+ # Forward and backward fill in the horizontal direction
956
+ filled = one_dim_fill(
957
+ processed_fields[var_name], selected_horizontal_dim, direction="forward"
958
+ )
959
+ processed_fields[var_name] = one_dim_fill(
960
+ filled, selected_horizontal_dim, direction="backward"
961
+ )
962
+
963
+ return processed_fields