roms-tools 1.5.0__py3-none-any.whl → 1.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. roms_tools/_version.py +1 -1
  2. roms_tools/setup/boundary_forcing.py +226 -85
  3. roms_tools/setup/datasets.py +169 -39
  4. roms_tools/setup/fill.py +0 -36
  5. roms_tools/setup/initial_conditions.py +90 -69
  6. roms_tools/setup/regrid.py +43 -98
  7. roms_tools/setup/surface_forcing.py +68 -67
  8. roms_tools/setup/tides.py +60 -45
  9. roms_tools/setup/utils.py +25 -53
  10. roms_tools/tests/test_setup/test_boundary_forcing.py +42 -32
  11. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/0.0.0 +0 -0
  12. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_south/0.0.0 +0 -0
  13. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/0.0.0 +0 -0
  14. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/0.0.0 +0 -0
  15. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_south/0.0.0 +0 -0
  16. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/0.0.0 +0 -0
  17. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/0.0.0 +0 -0
  18. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_south/0.0.0 +0 -0
  19. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/0.0.0 +0 -0
  20. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/0.0.0 +0 -0
  21. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_south/0.0.0 +0 -0
  22. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/0.0.0 +0 -0
  23. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/0.0.0 +0 -0
  24. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_south/0.0.0 +0 -0
  25. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/0.0.0 +0 -0
  26. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/0.0.0 +0 -0
  27. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_south/0.0.0 +0 -0
  28. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/0.0.0 +0 -0
  29. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/0.0.0 +0 -0
  30. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_south/0.0.0 +0 -0
  31. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/0.0.0 +0 -0
  32. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/0.0.0 +0 -0
  33. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_south/0.0.0 +0 -0
  34. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/0.0.0 +0 -0
  35. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/0.0.0 +0 -0
  36. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_south/0.0.0 +0 -0
  37. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/0.0.0 +0 -0
  38. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/0.0.0 +0 -0
  39. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_south/0.0.0 +0 -0
  40. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/0.0.0 +0 -0
  41. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/0.0.0 +0 -0
  42. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_south/0.0.0 +0 -0
  43. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/0.0.0 +0 -0
  44. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/0.0.0 +0 -0
  45. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_south/0.0.0 +0 -0
  46. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/0.0.0 +0 -0
  47. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/0.0.0 +0 -0
  48. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_south/0.0.0 +0 -0
  49. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/0.0.0 +0 -0
  50. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/0.0.0 +0 -0
  51. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_south/0.0.0 +0 -0
  52. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/0.0.0 +0 -0
  53. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/0.0.0 +0 -0
  54. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_south/0.0.0 +0 -0
  55. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/0.0.0 +0 -0
  56. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/0.0.0 +0 -0
  57. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_south/0.0.0 +0 -0
  58. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/0.0.0 +0 -0
  59. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/0.0.0 +0 -0
  60. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_south/0.0.0 +0 -0
  61. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/0.0.0 +0 -0
  62. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/0.0.0 +0 -0
  63. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_south/0.0.0 +0 -0
  64. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/0.0.0 +0 -0
  65. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/0.0.0 +0 -0
  66. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_south/0.0.0 +0 -0
  67. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/0.0.0 +0 -0
  68. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/0.0.0 +0 -0
  69. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_south/0.0.0 +0 -0
  70. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/0.0.0 +0 -0
  71. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/0.0.0 +0 -0
  72. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_south/0.0.0 +0 -0
  73. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/0.0.0 +0 -0
  74. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/0.0.0 +0 -0
  75. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_south/0.0.0 +0 -0
  76. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/0.0.0 +0 -0
  77. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/0.0.0 +0 -0
  78. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_south/0.0.0 +0 -0
  79. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/0.0.0 +0 -0
  80. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/0.0.0 +0 -0
  81. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_south/0.0.0 +0 -0
  82. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/0.0.0 +0 -0
  83. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/0.0.0 +0 -0
  84. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_south/0.0.0 +0 -0
  85. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/0.0.0 +0 -0
  86. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/0.0.0 +0 -0
  87. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_south/0.0.0 +0 -0
  88. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/0.0.0 +0 -0
  89. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/0.0.0 +0 -0
  90. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_south/0.0.0 +0 -0
  91. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/0.0.0 +0 -0
  92. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/0.0.0 +0 -0
  93. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_south/0.0.0 +0 -0
  94. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/0.0.0 +0 -0
  95. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/0.0.0 +0 -0
  96. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_south/0.0.0 +0 -0
  97. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/0.0.0 +0 -0
  98. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/0.0.0 +0 -0
  99. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_south/0.0.0 +0 -0
  100. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/0.0.0 +0 -0
  101. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/0.0.0 +0 -0
  102. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_south/0.0.0 +0 -0
  103. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/0.0.0 +0 -0
  104. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/0.0.0 +0 -0
  105. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_south/0.0.0 +0 -0
  106. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/0.0.0 +0 -0
  107. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zattrs +1 -1
  108. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zmetadata +1 -1
  109. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust/0.0.0 +0 -0
  110. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron/0.0.0 +0 -0
  111. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy/0.0.0 +0 -0
  112. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox/0.0.0 +0 -0
  113. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air/0.0.0 +0 -0
  114. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air_alt/0.0.0 +0 -0
  115. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zattrs +1 -1
  116. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zmetadata +1 -1
  117. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust/0.0.0 +0 -0
  118. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron/0.0.0 +0 -0
  119. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy/0.0.0 +0 -0
  120. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox/0.0.0 +0 -0
  121. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air/0.0.0 +0 -0
  122. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air_alt/0.0.0 +0 -0
  123. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/.zmetadata +7 -0
  124. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zattrs +3 -0
  125. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/0.0.0 +0 -0
  126. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/0.0.0 +0 -0
  127. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/0.0.0 +0 -0
  128. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/0.0.0 +0 -0
  129. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/0.0.0 +0 -0
  130. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/0.0.0 +0 -0
  131. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/0.0.0 +0 -0
  132. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/0.0.0 +0 -0
  133. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/0.0 +0 -0
  134. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/0.0 +0 -0
  135. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/0.0 +0 -0
  136. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/0.0 +0 -0
  137. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/0.0.0 +0 -0
  138. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/0.0.0 +0 -0
  139. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/0.0.0 +0 -0
  140. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/0.0.0 +0 -0
  141. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/0.0 +0 -0
  142. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/0.0 +0 -0
  143. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/0.0 +0 -0
  144. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/0.0 +0 -0
  145. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zattrs +1 -0
  146. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/0.0 +0 -0
  147. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/.zattrs +1 -0
  148. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zattrs +1 -0
  149. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/0.0 +0 -0
  150. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/.zattrs +1 -0
  151. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/.zattrs +1 -1
  152. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/.zmetadata +1 -1
  153. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/Tair/0.0.0 +0 -0
  154. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/lwrad/0.0.0 +0 -0
  155. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/qair/0.0.0 +0 -0
  156. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/rain/0.0.0 +0 -0
  157. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/swrad/0.0.0 +0 -0
  158. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/uwnd/0.0.0 +0 -0
  159. roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/vwnd/0.0.0 +0 -0
  160. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/.zattrs +1 -1
  161. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/.zmetadata +1 -1
  162. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/Tair/0.0.0 +0 -0
  163. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/lwrad/0.0.0 +0 -0
  164. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/qair/0.0.0 +0 -0
  165. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/rain/0.0.0 +0 -0
  166. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/swrad/0.0.0 +0 -0
  167. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/uwnd/0.0.0 +0 -0
  168. roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/vwnd/0.0.0 +0 -0
  169. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK/0.0.0.0 +0 -0
  170. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK_ALT_CO2/0.0.0.0 +0 -0
  171. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC/0.0.0.0 +0 -0
  172. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC_ALT_CO2/0.0.0.0 +0 -0
  173. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOC/0.0.0.0 +0 -0
  174. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOCr/0.0.0.0 +0 -0
  175. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DON/0.0.0.0 +0 -0
  176. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DONr/0.0.0.0 +0 -0
  177. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOP/0.0.0.0 +0 -0
  178. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOPr/0.0.0.0 +0 -0
  179. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Fe/0.0.0.0 +0 -0
  180. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Lig/0.0.0.0 +0 -0
  181. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NH4/0.0.0.0 +0 -0
  182. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NO3/0.0.0.0 +0 -0
  183. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/O2/0.0.0.0 +0 -0
  184. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/PO4/0.0.0.0 +0 -0
  185. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/SiO3/0.0.0.0 +0 -0
  186. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatC/0.0.0.0 +0 -0
  187. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatChl/0.0.0.0 +0 -0
  188. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatFe/0.0.0.0 +0 -0
  189. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatP/0.0.0.0 +0 -0
  190. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatSi/0.0.0.0 +0 -0
  191. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazC/0.0.0.0 +0 -0
  192. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazChl/0.0.0.0 +0 -0
  193. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazFe/0.0.0.0 +0 -0
  194. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazP/0.0.0.0 +0 -0
  195. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/salt/0.0.0.0 +0 -0
  196. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spC/0.0.0.0 +0 -0
  197. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spCaCO3/0.0.0.0 +0 -0
  198. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spChl/0.0.0.0 +0 -0
  199. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spFe/0.0.0.0 +0 -0
  200. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spP/0.0.0.0 +0 -0
  201. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/temp/0.0.0.0 +0 -0
  202. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/u/0.0.0.0 +0 -0
  203. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ubar/0.0.0 +0 -0
  204. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/v/0.0.0.0 +0 -0
  205. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/vbar/0.0.0 +0 -0
  206. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zeta/0.0.0 +0 -0
  207. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zooC/0.0.0.0 +0 -0
  208. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/.zattrs +1 -1
  209. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/.zmetadata +1 -1
  210. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/Tair/0.0.0 +0 -0
  211. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/lwrad/0.0.0 +0 -0
  212. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/qair/0.0.0 +0 -0
  213. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/rain/0.0.0 +0 -0
  214. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/swrad/0.0.0 +0 -0
  215. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/uwnd/0.0.0 +0 -0
  216. roms_tools/tests/test_setup/test_data/surface_forcing.zarr/vwnd/0.0.0 +0 -0
  217. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zattrs +1 -1
  218. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zmetadata +4 -2
  219. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/omega/.zattrs +3 -1
  220. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Im/0.0.0 +0 -0
  221. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Re/0.0.0 +0 -0
  222. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Im/0.0.0 +0 -0
  223. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Re/0.0.0 +0 -0
  224. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Im/0.0.0 +0 -0
  225. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Re/0.0.0 +0 -0
  226. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Im/0.0.0 +0 -0
  227. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/0.0.0 +0 -0
  228. roms_tools/tests/test_setup/test_datasets.py +79 -21
  229. roms_tools/tests/test_setup/test_fill.py +18 -105
  230. roms_tools/tests/test_setup/test_initial_conditions.py +21 -21
  231. roms_tools/tests/test_setup/test_regrid.py +2 -8
  232. roms_tools/tests/test_setup/test_surface_forcing.py +3 -3
  233. roms_tools/tests/test_setup/test_tides.py +1 -1
  234. {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/METADATA +12 -3
  235. {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/RECORD +238 -238
  236. {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/WHEEL +1 -1
  237. {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/LICENSE +0 -0
  238. {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/top_level.txt +0 -0
@@ -12,8 +12,10 @@ from roms_tools.setup.utils import (
12
12
  interpolate_from_climatology,
13
13
  get_time_type,
14
14
  convert_cftime_to_datetime,
15
+ one_dim_fill,
15
16
  )
16
17
  from roms_tools.setup.download import download_correction_data
18
+ from roms_tools.setup.fill import LateralFill
17
19
 
18
20
 
19
21
  @dataclass(frozen=True, kw_only=True)
@@ -117,6 +119,8 @@ class Dataset:
117
119
  # Make sure that depth is ascending
118
120
  ds = self.ensure_dimension_is_ascending(ds, dim="depth")
119
121
 
122
+ self.infer_horizontal_resolution(ds)
123
+
120
124
  # Check whether the data covers the entire globe
121
125
  object.__setattr__(self, "is_global", self.check_if_global(ds))
122
126
 
@@ -487,6 +491,34 @@ class Dataset:
487
491
 
488
492
  return ds
489
493
 
494
+ def infer_horizontal_resolution(self, ds: xr.Dataset):
495
+ """Estimate and set the average horizontal resolution of a dataset based on
496
+ latitude and longitude spacing.
497
+
498
+ Parameters
499
+ ----------
500
+ ds : xr.Dataset
501
+ Dataset containing latitude and longitude dimensions.
502
+
503
+ Sets
504
+ ----
505
+ resolution : float
506
+ The average horizontal resolution, derived from the mean spacing
507
+ between points in latitude and longitude.
508
+ """
509
+ lat_dim = self.dim_names["latitude"]
510
+ lon_dim = self.dim_names["longitude"]
511
+
512
+ # Calculate mean difference along latitude and longitude
513
+ lat_resolution = ds[lat_dim].diff(dim=lat_dim).mean(dim=lat_dim)
514
+ lon_resolution = ds[lon_dim].diff(dim=lon_dim).mean(dim=lon_dim)
515
+
516
+ # Compute the average horizontal resolution
517
+ resolution = np.mean([lat_resolution, lon_resolution])
518
+
519
+ # Set the computed resolution as an attribute
520
+ object.__setattr__(self, "resolution", resolution)
521
+
490
522
  def check_if_global(self, ds) -> bool:
491
523
  """Checks if the dataset covers the entire globe in the longitude dimension.
492
524
 
@@ -569,40 +601,31 @@ class Dataset:
569
601
  """
570
602
  pass
571
603
 
572
- def choose_subdomain(
573
- self, latitude_range, longitude_range, margin, straddle, return_subdomain=False
574
- ):
575
- """Selects a subdomain from the xarray Dataset based on specified latitude and
576
- longitude ranges, extending the selection by a specified margin. Handles
577
- longitude conversions to accommodate different longitude ranges.
604
+ def choose_subdomain(self, target_coords, buffer_points=20, return_copy=False):
605
+ """Selects a subdomain from the xarray Dataset based on specified target
606
+ coordinates, extending the selection by a defined buffer. Adjusts longitude
607
+ ranges as necessary to accommodate the dataset's expected range and handles
608
+ potential discontinuities.
578
609
 
579
610
  Parameters
580
611
  ----------
581
- latitude_range : tuple of float
582
- A tuple (lat_min, lat_max) specifying the minimum and maximum latitude values of the subdomain.
583
- longitude_range : tuple of float
584
- A tuple (lon_min, lon_max) specifying the minimum and maximum longitude values of the subdomain.
585
- margin : float
586
- Margin in degrees to extend beyond the specified latitude and longitude ranges when selecting the subdomain.
587
- straddle : bool
588
- If True, target longitudes are expected in the range [-180, 180].
589
- If False, target longitudes are expected in the range [0, 360].
612
+ target_coords : dict
613
+ A dictionary containing the target latitude and longitude coordinates, typically
614
+ with keys "lat", "lon", and "straddle".
615
+ buffer_points : int
616
+ The number of grid points to extend beyond the specified latitude and longitude
617
+ ranges when selecting the subdomain. Defaults to 20.
590
618
  return_subdomain : bool, optional
591
- If True, returns the subset of the original dataset as an xarray Dataset. If False, assigns the subset to `self.ds`.
592
- Defaults to False.
619
+ If True, returns the subset of the original dataset representing the chosen
620
+ subdomain. If False, assigns the subset to `self.ds`. Defaults to False.
593
621
 
594
622
  Returns
595
623
  -------
596
624
  xr.Dataset or None
597
- If `return_subdomain` is True, returns the subset of the original dataset representing the chosen subdomain,
598
- including an extended area to cover one extra grid point beyond the specified ranges. If `return_subdomain` is False,
599
- returns None as the subset is assigned to `self.ds`.
600
-
601
- Notes
602
- -----
603
- This method adjusts the longitude range if necessary to ensure it matches the expected range for the dataset.
604
- It also handles longitude discontinuities that can occur when converting to different longitude ranges.
605
- This is important for avoiding artifacts in the interpolation process.
625
+ Returns the subset of the original dataset as an xarray Dataset if
626
+ `return_subdomain` is True, including an extended area covering additional
627
+ grid points beyond the specified ranges. Returns None if `return_subdomain`
628
+ is False, as the subset is assigned to `self.ds`.
606
629
 
607
630
  Raises
608
631
  ------
@@ -610,13 +633,17 @@ class Dataset:
610
633
  If the selected latitude or longitude range does not intersect with the dataset.
611
634
  """
612
635
 
613
- lat_min, lat_max = latitude_range
614
- lon_min, lon_max = longitude_range
636
+ lat_min = target_coords["lat"].min().values
637
+ lat_max = target_coords["lat"].max().values
638
+ lon_min = target_coords["lon"].min().values
639
+ lon_max = target_coords["lon"].max().values
640
+
641
+ margin = self.resolution * buffer_points
615
642
 
616
643
  if not self.is_global:
617
644
  # Adjust longitude range if needed to match the expected range
618
645
  lon = self.ds[self.dim_names["longitude"]]
619
- if not straddle:
646
+ if not target_coords["straddle"]:
620
647
  if lon.min() < -180:
621
648
  if lon_max + margin > 0:
622
649
  lon_min -= 360
@@ -626,7 +653,7 @@ class Dataset:
626
653
  lon_min -= 360
627
654
  lon_max -= 360
628
655
 
629
- if straddle:
656
+ if target_coords["straddle"]:
630
657
  if lon.max() > 360:
631
658
  if lon_min - margin < 180:
632
659
  lon_min += 360
@@ -637,6 +664,7 @@ class Dataset:
637
664
  lon_max += 360
638
665
 
639
666
  # Select the subdomain
667
+
640
668
  subdomain = self.ds.sel(
641
669
  **{
642
670
  self.dim_names["latitude"]: slice(lat_min - margin, lat_max + margin),
@@ -655,16 +683,109 @@ class Dataset:
655
683
 
656
684
  # Adjust longitudes to expected range if needed
657
685
  lon = subdomain[self.dim_names["longitude"]]
658
- if straddle:
686
+ if target_coords["straddle"]:
659
687
  subdomain[self.dim_names["longitude"]] = xr.where(lon > 180, lon - 360, lon)
660
688
  else:
661
689
  subdomain[self.dim_names["longitude"]] = xr.where(lon < 0, lon + 360, lon)
662
690
 
663
- if return_subdomain:
664
- return subdomain
691
+ if return_copy:
692
+ return Dataset.from_ds(self, subdomain)
665
693
  else:
666
694
  object.__setattr__(self, "ds", subdomain)
667
695
 
696
+ def apply_lateral_fill(self):
697
+ """Apply lateral fill to variables using the dataset's mask and grid dimensions.
698
+
699
+ This method fills masked values in `self.ds` using `LateralFill` based on
700
+ the horizontal grid dimensions. A separate mask (`mask_vel`) is used for
701
+ velocity variables (e.g., `u`, `v`) if available in the dataset.
702
+
703
+ Notes
704
+ -----
705
+ Looping over `self.ds.data_vars` instead of `self.var_names` ensures that each
706
+ dataset variable is filled only once, even if multiple entries in `self.var_names`
707
+ point to the same variable in the dataset.
708
+ """
709
+ lateral_fill = LateralFill(
710
+ self.ds["mask"],
711
+ [self.dim_names["latitude"], self.dim_names["longitude"]],
712
+ )
713
+
714
+ separate_fill_for_velocities = False
715
+ if "mask_vel" in self.ds.data_vars:
716
+ lateral_fill_vel = LateralFill(
717
+ self.ds["mask_vel"],
718
+ [self.dim_names["latitude"], self.dim_names["longitude"]],
719
+ )
720
+ separate_fill_for_velocities = True
721
+
722
+ for var_name in self.ds.data_vars:
723
+ if var_name.startswith("mask"):
724
+ # Skip variables that are mask types
725
+ continue
726
+ elif (
727
+ separate_fill_for_velocities
728
+ and "u" in self.var_names
729
+ and "v" in self.var_names
730
+ and var_name in [self.var_names["u"], self.var_names["v"]]
731
+ ):
732
+ # Apply lateral fill with velocity mask for velocity variables if present
733
+ self.ds[var_name] = lateral_fill_vel.apply(self.ds[var_name])
734
+ else:
735
+ # Apply standard lateral fill for other variables
736
+ self.ds[var_name] = lateral_fill.apply(self.ds[var_name])
737
+
738
+ def extrapolate_deepest_to_bottom(self):
739
+ """Extrapolate deepest non-NaN values to fill bottom NaNs along the depth
740
+ dimension.
741
+
742
+ For each variable with a depth dimension, fills missing values at the bottom by
743
+ propagating the deepest available data downward.
744
+ """
745
+
746
+ if "depth" in self.dim_names:
747
+ for var_name in self.ds.data_vars:
748
+ if self.dim_names["depth"] in self.ds[var_name].dims:
749
+ self.ds[var_name] = one_dim_fill(
750
+ self.ds[var_name], self.dim_names["depth"], direction="forward"
751
+ )
752
+
753
+ @classmethod
754
+ def from_ds(cls, original_dataset: "Dataset", ds: xr.Dataset) -> "Dataset":
755
+ """Substitute the internal dataset of a Dataset object with a new xarray
756
+ Dataset.
757
+
758
+ This method creates a new Dataset instance, bypassing the usual `__init__`
759
+ and `__post_init__` processes. It allows for the direct assignment of the
760
+ provided xarray Dataset (`ds`) to the new instance's `ds` attribute. All
761
+ other attributes from the original dataset instance are copied to the new one.
762
+
763
+ Parameters
764
+ ----------
765
+ original_dataset : Dataset
766
+ The original Dataset instance from which attributes will be copied.
767
+ ds : xarray.Dataset
768
+ The new xarray Dataset to assign to the `ds` attribute of the new instance.
769
+
770
+ Returns
771
+ -------
772
+ Dataset
773
+ A new Dataset instance with the `ds` attribute set to the provided dataset
774
+ and other attributes copied from the original instance.
775
+ """
776
+ # Create a new Dataset instance without calling __init__ or __post_init__
777
+ dataset = cls.__new__(cls)
778
+
779
+ # Directly set the provided dataset as the 'ds' attribute
780
+ object.__setattr__(dataset, "ds", ds)
781
+
782
+ # Copy all other attributes from the original data instance
783
+ for attr in vars(original_dataset):
784
+ if attr != "ds":
785
+ object.__setattr__(dataset, attr, getattr(original_dataset, attr))
786
+
787
+ return dataset
788
+
668
789
 
669
790
  @dataclass(frozen=True, kw_only=True)
670
791
  class TPXODataset(Dataset):
@@ -803,9 +924,12 @@ class TPXODataset(Dataset):
803
924
  """
804
925
 
805
926
  if "depth" in self.var_names.keys():
927
+ ds = self.ds
806
928
  mask = xr.where(self.ds["depth"] > 0, 1, 0)
929
+ ds["mask"] = mask
930
+ ds = ds.drop_vars(["depth"])
807
931
 
808
- self.ds["mask"] = mask
932
+ object.__setattr__(self, "ds", ds)
809
933
 
810
934
  # Remove "depth" from var_names
811
935
  updated_var_names = {**self.var_names} # Create a copy of the dictionary
@@ -1261,9 +1385,13 @@ class ERA5Dataset(Dataset):
1261
1385
  )
1262
1386
  )
1263
1387
  cff = cff * qair
1264
- self.ds["qair"] = 0.62197 * (cff / (patm - 0.378 * cff))
1265
- self.ds["qair"].attrs["long_name"] = "Absolute humidity at 2m"
1266
- self.ds["qair"].attrs["units"] = "kg/kg"
1388
+
1389
+ ds = self.ds
1390
+ ds["qair"] = 0.62197 * (cff / (patm - 0.378 * cff))
1391
+ ds["qair"].attrs["long_name"] = "Absolute humidity at 2m"
1392
+ ds["qair"].attrs["units"] = "kg/kg"
1393
+ ds = ds.drop_vars([self.var_names["d2m"]])
1394
+ object.__setattr__(self, "ds", ds)
1267
1395
 
1268
1396
  # Update var_names dictionary
1269
1397
  var_names = {**self.var_names, "qair": "qair"}
@@ -1271,9 +1399,11 @@ class ERA5Dataset(Dataset):
1271
1399
  object.__setattr__(self, "var_names", var_names)
1272
1400
 
1273
1401
  if "mask" in self.var_names.keys():
1402
+ ds = self.ds
1274
1403
  mask = xr.where(self.ds[self.var_names["mask"]].isel(time=0).isnull(), 0, 1)
1275
-
1276
- self.ds["mask"] = mask
1404
+ ds["mask"] = mask
1405
+ ds = ds.drop_vars([self.var_names["mask"]])
1406
+ object.__setattr__(self, "ds", ds)
1277
1407
 
1278
1408
  # Remove mask from var_names dictionary
1279
1409
  var_names = self.var_names
roms_tools/setup/fill.py CHANGED
@@ -301,39 +301,3 @@ def stencil_grid_mod(S, grid, msk, dtype=None, format=None):
301
301
  data[4, i + diags[4]] = 0
302
302
 
303
303
  return sparse.dia_matrix((data, diags), shape=(N_v, N_v)).asformat(format)
304
-
305
-
306
- def _lateral_fill(data_vars, data):
307
- """Wrapper function to apply lateral fill to variables using the dataset's mask and
308
- grid dimensions.
309
-
310
- Parameters
311
- ----------
312
- data_vars : dict of str : xarray.DataArray
313
- Dictionary of variables to be filled.
314
- data : Dataset
315
- Dataset containing the mask and grid dimensions.
316
-
317
- Returns
318
- -------
319
- dict of str : xarray.DataArray
320
- Dictionary of filled variables.
321
- """
322
- lateral_fill = LateralFill(
323
- data.ds["mask"],
324
- [data.dim_names["latitude"], data.dim_names["longitude"]],
325
- )
326
-
327
- if "mask_vel" in data.ds.data_vars:
328
- lateral_fill_vel = LateralFill(
329
- data.ds["mask_vel"],
330
- [data.dim_names["latitude"], data.dim_names["longitude"]],
331
- )
332
-
333
- for var in data.var_names:
334
- if var in ["u", "v"]:
335
- data_vars[var] = lateral_fill_vel.apply(data_vars[var])
336
- else:
337
- data_vars[var] = lateral_fill.apply(data_vars[var])
338
-
339
- return data_vars
@@ -15,11 +15,9 @@ from roms_tools.setup.utils import (
15
15
  get_target_coords,
16
16
  rotate_velocities,
17
17
  compute_barotropic_velocity,
18
- _extrapolate_deepest_to_bottom,
19
18
  transpose_dimensions,
20
19
  )
21
- from roms_tools.setup.fill import _lateral_fill
22
- from roms_tools.setup.regrid import _lateral_regrid, _vertical_regrid
20
+ from roms_tools.setup.regrid import LateralRegrid, VerticalRegrid
23
21
  from roms_tools.setup.plot import _plot, _section_plot, _profile_plot, _line_plot
24
22
  import matplotlib.pyplot as plt
25
23
  from pathlib import Path
@@ -92,31 +90,31 @@ class InitialConditions:
92
90
 
93
91
  self._input_checks()
94
92
 
95
- data_vars = {}
96
- data_vars = self._process_data(data_vars, type="physics")
93
+ processed_fields = {}
94
+ processed_fields = self._process_data(processed_fields, type="physics")
97
95
 
98
96
  if self.bgc_source is not None:
99
- data_vars = self._process_data(data_vars, type="bgc")
97
+ processed_fields = self._process_data(processed_fields, type="bgc")
100
98
 
101
- for var in data_vars.keys():
102
- data_vars[var] = transpose_dimensions(data_vars[var])
99
+ for var_name in processed_fields.keys():
100
+ processed_fields[var_name] = transpose_dimensions(
101
+ processed_fields[var_name]
102
+ )
103
103
 
104
104
  d_meta = get_variable_metadata()
105
- ds = self._write_into_dataset(data_vars, d_meta)
105
+ ds = self._write_into_dataset(processed_fields, d_meta)
106
106
 
107
107
  ds = self._add_global_metadata(ds)
108
108
 
109
- ds["zeta"].load()
110
- # NaN values at wet points indicate that the raw data did not cover the domain, and the following will raise a ValueError
111
- nan_check(ds["zeta"].squeeze(), self.grid.ds.mask_rho)
109
+ self._validate(ds)
112
110
 
113
111
  # substitute NaNs over land by a fill value to avoid blow-up of ROMS
114
- for var in ds.data_vars:
115
- ds[var] = substitute_nans_by_fillvalue(ds[var])
112
+ for var_name in ds.data_vars:
113
+ ds[var_name] = substitute_nans_by_fillvalue(ds[var_name])
116
114
 
117
115
  object.__setattr__(self, "ds", ds)
118
116
 
119
- def _process_data(self, data_vars, type="physics"):
117
+ def _process_data(self, processed_fields, type="physics"):
120
118
 
121
119
  target_coords = get_target_coords(self.grid)
122
120
 
@@ -126,35 +124,29 @@ class InitialConditions:
126
124
  data = self._get_bgc_data()
127
125
 
128
126
  data.choose_subdomain(
129
- latitude_range=[
130
- target_coords["lat"].min().values,
131
- target_coords["lat"].max().values,
132
- ],
133
- longitude_range=[
134
- target_coords["lon"].min().values,
135
- target_coords["lon"].max().values,
136
- ],
137
- margin=2,
138
- straddle=target_coords["straddle"],
127
+ target_coords,
128
+ buffer_points=20, # lateral fill needs good buffer from data margin
139
129
  )
140
130
 
141
- variable_info = self._set_variable_info(data, type=type)
142
-
143
- data_vars = _extrapolate_deepest_to_bottom(data_vars, data)
131
+ data.extrapolate_deepest_to_bottom()
132
+ data.apply_lateral_fill()
144
133
 
145
- data_vars = _lateral_fill(data_vars, data)
134
+ variable_info = self._set_variable_info(data, type=type)
135
+ var_names = variable_info.keys()
146
136
 
147
137
  # lateral regridding
148
- var_names = variable_info.keys()
149
- data_vars = _lateral_regrid(
150
- data, target_coords["lon"], target_coords["lat"], data_vars, var_names
151
- )
138
+ lateral_regrid = LateralRegrid(target_coords, data.dim_names)
139
+ for var_name in var_names:
140
+ if var_name in data.var_names.keys():
141
+ processed_fields[var_name] = lateral_regrid.apply(
142
+ data.ds[data.var_names[var_name]]
143
+ )
152
144
 
153
145
  # rotation of velocities and interpolation to u/v points
154
146
  if "u" in variable_info and "v" in variable_info:
155
- (data_vars["u"], data_vars["v"],) = rotate_velocities(
156
- data_vars["u"],
157
- data_vars["v"],
147
+ (processed_fields["u"], processed_fields["v"],) = rotate_velocities(
148
+ processed_fields["u"],
149
+ processed_fields["v"],
158
150
  target_coords["angle"],
159
151
  interpolate=True,
160
152
  )
@@ -167,28 +159,32 @@ class InitialConditions:
167
159
  if info["location"] == location and info["is_3d"]
168
160
  ]
169
161
  if len(var_names) > 0:
170
- data_vars = _vertical_regrid(
171
- data,
162
+ vertical_regrid = VerticalRegrid(
172
163
  self.grid.ds[f"layer_depth_{location}"],
173
- data_vars,
174
- var_names,
164
+ data.ds[data.dim_names["depth"]],
175
165
  )
166
+ for var_name in var_names:
167
+ if var_name in processed_fields:
168
+ processed_fields[var_name] = vertical_regrid.apply(
169
+ processed_fields[var_name]
170
+ )
176
171
 
177
172
  # compute barotropic velocities
178
173
  if "u" in variable_info and "v" in variable_info:
179
- for var in ["u", "v"]:
180
- data_vars[f"{var}bar"] = compute_barotropic_velocity(
181
- data_vars[var], self.grid.ds[f"interface_depth_{var}"]
174
+ for var_name in ["u", "v"]:
175
+ processed_fields[f"{var_name}bar"] = compute_barotropic_velocity(
176
+ processed_fields[var_name],
177
+ self.grid.ds[f"interface_depth_{var_name}"],
182
178
  )
183
179
 
184
180
  if type == "bgc":
185
181
  # Ensure time coordinate matches that of physical variables
186
- for var in variable_info.keys():
187
- data_vars[var] = data_vars[var].assign_coords(
188
- {"time": data_vars["temp"]["time"]}
182
+ for var_name in variable_info.keys():
183
+ processed_fields[var_name] = processed_fields[var_name].assign_coords(
184
+ {"time": processed_fields["temp"]["time"]}
189
185
  )
190
186
 
191
- return data_vars
187
+ return processed_fields
192
188
 
193
189
  def _input_checks(self):
194
190
 
@@ -314,24 +310,26 @@ class InitialConditions:
314
310
  }
315
311
  elif type == "bgc":
316
312
  variable_info = {}
317
- for var in data.var_names.keys():
318
- variable_info[var] = default_info
313
+ for var_name in data.var_names.keys():
314
+ variable_info[var_name] = default_info
319
315
 
320
316
  return variable_info
321
317
 
322
- def _write_into_dataset(self, data_vars, d_meta):
318
+ def _write_into_dataset(self, processed_fields, d_meta):
323
319
 
324
320
  # save in new dataset
325
321
  ds = xr.Dataset()
326
322
 
327
- for var in data_vars.keys():
328
- ds[var] = data_vars[var].astype(np.float32)
329
- ds[var].attrs["long_name"] = d_meta[var]["long_name"]
330
- ds[var].attrs["units"] = d_meta[var]["units"]
323
+ for var_name in processed_fields.keys():
324
+ ds[var_name] = processed_fields[var_name].astype(np.float32)
325
+ ds[var_name].attrs["long_name"] = d_meta[var_name]["long_name"]
326
+ ds[var_name].attrs["units"] = d_meta[var_name]["units"]
331
327
 
332
328
  # initialize vertical velocity to zero
333
329
  ds["w"] = xr.zeros_like(
334
- self.grid.ds["interface_depth_rho"].expand_dims(time=data_vars["u"].time)
330
+ self.grid.ds["interface_depth_rho"].expand_dims(
331
+ time=processed_fields["u"].time
332
+ )
335
333
  ).astype(np.float32)
336
334
  ds["w"].attrs["long_name"] = d_meta["w"]["long_name"]
337
335
  ds["w"].attrs["units"] = d_meta["w"]["units"]
@@ -351,7 +349,7 @@ class InitialConditions:
351
349
  "layer_depth_v",
352
350
  "interface_depth_v",
353
351
  ]
354
- existing_vars = [var for var in variables_to_drop if var in ds]
352
+ existing_vars = [var_name for var_name in variables_to_drop if var_name in ds]
355
353
  ds = ds.drop_vars(existing_vars)
356
354
 
357
355
  ds["Cs_r"] = self.grid.ds["Cs_r"]
@@ -375,6 +373,29 @@ class InitialConditions:
375
373
 
376
374
  return ds
377
375
 
376
+ def _validate(self, ds):
377
+ """Validates the dataset by checking for NaN values in SSH at wet points, which
378
+ would indicate missing raw data coverage over the target domain.
379
+
380
+ Parameters
381
+ ----------
382
+ ds : xarray.Dataset
383
+ The dataset to validate.
384
+
385
+ Raises
386
+ ------
387
+ ValueError
388
+ If NaN values are found in any of the specified variables at wet points,
389
+ indicating incomplete data coverage.
390
+
391
+ Notes
392
+ -----
393
+ This check is only applied to the 2D variable SSH to improve performance.
394
+ """
395
+
396
+ ds["zeta"].load()
397
+ nan_check(ds["zeta"].squeeze(), self.grid.ds.mask_rho)
398
+
378
399
  def _add_global_metadata(self, ds):
379
400
 
380
401
  ds.attrs["title"] = "ROMS initial conditions file created by ROMS-Tools"
@@ -398,7 +419,7 @@ class InitialConditions:
398
419
 
399
420
  def plot(
400
421
  self,
401
- varname,
422
+ var_name,
402
423
  s=None,
403
424
  eta=None,
404
425
  xi=None,
@@ -409,7 +430,7 @@ class InitialConditions:
409
430
 
410
431
  Parameters
411
432
  ----------
412
- varname : str
433
+ var_name : str
413
434
  The name of the initial conditions field to plot. Options include:
414
435
 
415
436
  - "temp": Potential temperature.
@@ -480,25 +501,25 @@ class InitialConditions:
480
501
  Raises
481
502
  ------
482
503
  ValueError
483
- If the specified `varname` is not one of the valid options.
484
- If the field specified by `varname` is 3D and none of `s`, `eta`, or `xi` are specified.
485
- If the field specified by `varname` is 2D and both `eta` and `xi` are specified.
504
+ If the specified `var_name` is not one of the valid options.
505
+ If the field specified by `var_name` is 3D and none of `s`, `eta`, or `xi` are specified.
506
+ If the field specified by `var_name` is 2D and both `eta` and `xi` are specified.
486
507
  """
487
508
 
488
- if len(self.ds[varname].squeeze().dims) == 3 and not any(
509
+ if len(self.ds[var_name].squeeze().dims) == 3 and not any(
489
510
  [s is not None, eta is not None, xi is not None]
490
511
  ):
491
512
  raise ValueError(
492
513
  "For 3D fields, at least one of s, eta, or xi must be specified."
493
514
  )
494
515
 
495
- if len(self.ds[varname].squeeze().dims) == 2 and all(
516
+ if len(self.ds[var_name].squeeze().dims) == 2 and all(
496
517
  [eta is not None, xi is not None]
497
518
  ):
498
519
  raise ValueError("For 2D fields, specify either eta or xi, not both.")
499
520
 
500
- self.ds[varname].load()
501
- field = self.ds[varname].squeeze()
521
+ self.ds[var_name].load()
522
+ field = self.ds[var_name].squeeze()
502
523
 
503
524
  if all(dim in field.dims for dim in ["eta_rho", "xi_rho"]):
504
525
  interface_depth = self.grid.ds.interface_depth_rho
@@ -553,7 +574,7 @@ class InitialConditions:
553
574
  field = field.assign_coords({"layer_depth": layer_depth})
554
575
  else:
555
576
  raise ValueError(
556
- f"None of the expected dimensions (eta_rho, eta_v) found in ds[{varname}]."
577
+ f"None of the expected dimensions (eta_rho, eta_v) found in ds[{var_name}]."
557
578
  )
558
579
  if xi is not None:
559
580
  if "xi_rho" in field.dims:
@@ -572,18 +593,18 @@ class InitialConditions:
572
593
  field = field.assign_coords({"layer_depth": layer_depth})
573
594
  else:
574
595
  raise ValueError(
575
- f"None of the expected dimensions (xi_rho, xi_u) found in ds[{varname}]."
596
+ f"None of the expected dimensions (xi_rho, xi_u) found in ds[{var_name}]."
576
597
  )
577
598
 
578
599
  # chose colorbar
579
- if varname in ["u", "v", "w", "ubar", "vbar", "zeta"]:
600
+ if var_name in ["u", "v", "w", "ubar", "vbar", "zeta"]:
580
601
  vmax = max(field.max().values, -field.min().values)
581
602
  vmin = -vmax
582
603
  cmap = plt.colormaps.get_cmap("RdBu_r")
583
604
  else:
584
605
  vmax = field.max().values
585
606
  vmin = field.min().values
586
- if varname in ["temp", "salt"]:
607
+ if var_name in ["temp", "salt"]:
587
608
  cmap = plt.colormaps.get_cmap("YlOrRd")
588
609
  else:
589
610
  cmap = plt.colormaps.get_cmap("YlGn")