roms-tools 3.2.0__py3-none-any.whl → 3.4.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 (318) hide show
  1. roms_tools/__init__.py +1 -1
  2. roms_tools/analysis/cdr_ensemble.py +10 -13
  3. roms_tools/analysis/roms_output.py +5 -304
  4. roms_tools/{download.py → datasets/download.py} +1 -0
  5. roms_tools/{setup/datasets.py → datasets/lat_lon_datasets.py} +85 -854
  6. roms_tools/datasets/river_datasets.py +532 -0
  7. roms_tools/datasets/roms_dataset.py +767 -0
  8. roms_tools/datasets/utils.py +475 -0
  9. roms_tools/{setup/fill.py → fill.py} +110 -13
  10. roms_tools/plot.py +42 -34
  11. roms_tools/setup/boundary_forcing.py +52 -44
  12. roms_tools/setup/cdr_release.py +2 -4
  13. roms_tools/setup/grid.py +42 -17
  14. roms_tools/setup/initial_conditions.py +23 -23
  15. roms_tools/setup/nesting.py +270 -94
  16. roms_tools/setup/river_forcing.py +5 -5
  17. roms_tools/setup/surface_forcing.py +17 -12
  18. roms_tools/setup/tides.py +1 -1
  19. roms_tools/setup/topography.py +13 -7
  20. roms_tools/setup/utils.py +103 -294
  21. roms_tools/tests/test_analysis/test_cdr_ensemble.py +4 -6
  22. roms_tools/tests/test_analysis/test_roms_output.py +1 -220
  23. roms_tools/tests/{test_setup/test_datasets.py → test_datasets/test_lat_lon_datasets.py} +25 -64
  24. roms_tools/tests/test_datasets/test_river_datasets.py +48 -0
  25. roms_tools/tests/test_datasets/test_roms_dataset.py +539 -0
  26. roms_tools/tests/test_datasets/test_utils.py +527 -0
  27. roms_tools/tests/{test_setup/test_fill.py → test_fill.py} +72 -9
  28. roms_tools/tests/test_setup/test_boundary_forcing.py +57 -138
  29. roms_tools/tests/test_setup/test_cdr_release.py +4 -5
  30. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/c/0/0/0 +0 -0
  31. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_north/c/0/0/0 +0 -0
  32. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/c/0/0/0 +0 -0
  33. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_north/c/0/0/0 +0 -0
  34. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/c/0/0/0 +0 -0
  35. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_north/c/0/0/0 +0 -0
  36. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/c/0/0/0 +0 -0
  37. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_north/c/0/0/0 +0 -0
  38. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/c/0/0/0 +0 -0
  39. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_north/c/0/0/0 +0 -0
  40. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/c/0/0/0 +0 -0
  41. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_north/c/0/0/0 +0 -0
  42. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/c/0/0/0 +0 -0
  43. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_north/c/0/0/0 +0 -0
  44. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/c/0/0/0 +0 -0
  45. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_north/c/0/0/0 +0 -0
  46. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/c/0/0/0 +0 -0
  47. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_north/c/0/0/0 +0 -0
  48. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/c/0/0/0 +0 -0
  49. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_north/c/0/0/0 +0 -0
  50. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/c/0/0/0 +0 -0
  51. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_north/c/0/0/0 +0 -0
  52. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/c/0/0/0 +0 -0
  53. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_north/c/0/0/0 +0 -0
  54. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/c/0/0/0 +0 -0
  55. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_north/c/0/0/0 +0 -0
  56. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/c/0/0/0 +0 -0
  57. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_north/c/0/0/0 +0 -0
  58. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/c/0/0/0 +0 -0
  59. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_north/c/0/0/0 +0 -0
  60. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/c/0/0/0 +0 -0
  61. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_north/c/0/0/0 +0 -0
  62. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/c/0/0/0 +0 -0
  63. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_north/c/0/0/0 +0 -0
  64. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/c/0/0/0 +0 -0
  65. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_north/c/0/0/0 +0 -0
  66. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/c/0/0/0 +0 -0
  67. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_north/c/0/0/0 +0 -0
  68. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/c/0/0/0 +0 -0
  69. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_north/c/0/0/0 +0 -0
  70. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/c/0/0/0 +0 -0
  71. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_north/c/0/0/0 +0 -0
  72. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/c/0/0/0 +0 -0
  73. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_north/c/0/0/0 +0 -0
  74. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/c/0/0/0 +0 -0
  75. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_north/c/0/0/0 +0 -0
  76. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/c/0/0/0 +0 -0
  77. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_north/c/0/0/0 +0 -0
  78. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/c/0/0/0 +0 -0
  79. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_north/c/0/0/0 +0 -0
  80. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/c/0/0/0 +0 -0
  81. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_north/c/0/0/0 +0 -0
  82. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/c/0/0/0 +0 -0
  83. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_north/c/0/0/0 +0 -0
  84. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/c/0/0/0 +0 -0
  85. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_north/c/0/0/0 +0 -0
  86. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/c/0/0/0 +0 -0
  87. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_north/c/0/0/0 +0 -0
  88. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/c/0/0/0 +0 -0
  89. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_north/c/0/0/0 +0 -0
  90. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/c/0/0/0 +0 -0
  91. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_north/c/0/0/0 +0 -0
  92. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zarr.json +289 -2017
  93. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/c/0/0/0 +0 -0
  94. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_north/c/0/0/0 +0 -0
  95. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/zarr.json +294 -2022
  96. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/c/0/0/0 +0 -0
  97. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_north/c/0/0/0 +0 -0
  98. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/c/0/0/0 +0 -0
  99. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_west/c/0/0/0 +0 -0
  100. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/c/0/0/0 +0 -0
  101. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_north/c/0/0/0 +0 -0
  102. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/c/0/0/0 +0 -0
  103. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_west/c/0/0/0 +0 -0
  104. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/c/0/0/0 +0 -0
  105. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/c/0/0/0 +0 -0
  106. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/c/0/0/0 +0 -0
  107. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/c/0/0/0 +0 -0
  108. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/c/0/0 +0 -0
  109. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/c/0/0 +0 -0
  110. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/c/0/0 +0 -0
  111. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/c/0/0 +0 -0
  112. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/c/0/0/0 +0 -0
  113. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/c/0/0/0 +0 -0
  114. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/c/0/0/0 +0 -0
  115. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/c/0/0/0 +0 -0
  116. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/c/0/0 +0 -0
  117. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/c/0/0 +0 -0
  118. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/c/0/0 +0 -0
  119. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/c/0/0 +0 -0
  120. roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zarr.json +182 -182
  121. roms_tools/tests/test_setup/test_data/grid.zarr/h/c/0/0 +0 -0
  122. roms_tools/tests/test_setup/test_data/grid.zarr/zarr.json +191 -191
  123. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/c/0/0 +0 -0
  124. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/zarr.json +210 -210
  125. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK/c/0/0/0/0 +0 -0
  126. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK_ALT_CO2/c/0/0/0/0 +0 -0
  127. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC/c/0/0/0/0 +0 -0
  128. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC_ALT_CO2/c/0/0/0/0 +0 -0
  129. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOC/c/0/0/0/0 +0 -0
  130. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOCr/c/0/0/0/0 +0 -0
  131. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DON/c/0/0/0/0 +0 -0
  132. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DONr/c/0/0/0/0 +0 -0
  133. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOP/c/0/0/0/0 +0 -0
  134. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOPr/c/0/0/0/0 +0 -0
  135. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Fe/c/0/0/0/0 +0 -0
  136. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Lig/c/0/0/0/0 +0 -0
  137. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NH4/c/0/0/0/0 +0 -0
  138. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NO3/c/0/0/0/0 +0 -0
  139. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/O2/c/0/0/0/0 +0 -0
  140. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/PO4/c/0/0/0/0 +0 -0
  141. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/SiO3/c/0/0/0/0 +0 -0
  142. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatC/c/0/0/0/0 +0 -0
  143. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatChl/c/0/0/0/0 +0 -0
  144. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatFe/c/0/0/0/0 +0 -0
  145. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatP/c/0/0/0/0 +0 -0
  146. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatSi/c/0/0/0/0 +0 -0
  147. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazC/c/0/0/0/0 +0 -0
  148. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazChl/c/0/0/0/0 +0 -0
  149. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazFe/c/0/0/0/0 +0 -0
  150. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazP/c/0/0/0/0 +0 -0
  151. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/salt/c/0/0/0/0 +0 -0
  152. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spC/c/0/0/0/0 +0 -0
  153. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spCaCO3/c/0/0/0/0 +0 -0
  154. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spChl/c/0/0/0/0 +0 -0
  155. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spFe/c/0/0/0/0 +0 -0
  156. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spP/c/0/0/0/0 +0 -0
  157. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/temp/c/0/0/0/0 +0 -0
  158. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/u/c/0/0/0/0 +0 -0
  159. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ubar/c/0/0/0 +0 -0
  160. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/v/c/0/0/0/0 +0 -0
  161. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/vbar/c/0/0/0 +0 -0
  162. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zarr.json +182 -182
  163. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zooC/c/0/0/0/0 +0 -0
  164. roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/salt/c/0/0/0/0 +0 -0
  165. roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/temp/c/0/0/0/0 +0 -0
  166. roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/u/c/0/0/0/0 +0 -0
  167. roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/ubar/c/0/0/0 +0 -0
  168. roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/v/c/0/0/0/0 +0 -0
  169. roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/vbar/c/0/0/0 +0 -0
  170. roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/zarr.json +187 -187
  171. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Im/c/0/0/0 +0 -0
  172. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Re/c/0/0/0 +0 -0
  173. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Im/c/0/0/0 +0 -0
  174. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/c/0/0/0 +0 -0
  175. roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/zarr.json +66 -66
  176. roms_tools/tests/test_setup/test_grid.py +56 -1
  177. roms_tools/tests/test_setup/test_initial_conditions.py +3 -94
  178. roms_tools/tests/test_setup/test_nesting.py +119 -30
  179. roms_tools/tests/test_setup/test_surface_forcing.py +2 -2
  180. roms_tools/tests/test_setup/test_tides.py +1 -1
  181. roms_tools/tests/test_setup/test_utils.py +100 -15
  182. roms_tools/tests/test_tiling/test_partition.py +63 -15
  183. roms_tools/tests/test_utils.py +78 -0
  184. roms_tools/tiling/partition.py +81 -211
  185. roms_tools/utils.py +193 -0
  186. {roms_tools-3.2.0.dist-info → roms_tools-3.4.0.dist-info}/METADATA +1 -1
  187. {roms_tools-3.2.0.dist-info → roms_tools-3.4.0.dist-info}/RECORD +190 -312
  188. {roms_tools-3.2.0.dist-info → roms_tools-3.4.0.dist-info}/WHEEL +1 -1
  189. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/c/0/0/0 +0 -0
  190. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/zarr.json +0 -54
  191. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/c/0/0/0 +0 -0
  192. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/zarr.json +0 -54
  193. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/c/0/0/0 +0 -0
  194. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/zarr.json +0 -54
  195. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/c/0/0/0 +0 -0
  196. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/zarr.json +0 -54
  197. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/c/0/0/0 +0 -0
  198. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/zarr.json +0 -54
  199. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/c/0/0/0 +0 -0
  200. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/zarr.json +0 -54
  201. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/c/0/0/0 +0 -0
  202. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/zarr.json +0 -54
  203. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/c/0/0/0 +0 -0
  204. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/zarr.json +0 -54
  205. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/c/0/0/0 +0 -0
  206. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/zarr.json +0 -54
  207. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/c/0/0/0 +0 -0
  208. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/zarr.json +0 -54
  209. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/c/0/0/0 +0 -0
  210. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/zarr.json +0 -54
  211. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/c/0/0/0 +0 -0
  212. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/zarr.json +0 -54
  213. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/c/0/0/0 +0 -0
  214. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/zarr.json +0 -54
  215. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/c/0/0/0 +0 -0
  216. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/zarr.json +0 -54
  217. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/c/0/0/0 +0 -0
  218. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/zarr.json +0 -54
  219. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/c/0/0/0 +0 -0
  220. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/zarr.json +0 -54
  221. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/c/0/0/0 +0 -0
  222. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/zarr.json +0 -54
  223. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/c/0/0/0 +0 -0
  224. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/zarr.json +0 -54
  225. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/c/0/0/0 +0 -0
  226. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/zarr.json +0 -54
  227. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/c/0/0/0 +0 -0
  228. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/zarr.json +0 -54
  229. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/c/0/0/0 +0 -0
  230. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/zarr.json +0 -54
  231. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/c/0/0/0 +0 -0
  232. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/zarr.json +0 -54
  233. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/c/0/0/0 +0 -0
  234. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/zarr.json +0 -54
  235. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/c/0/0/0 +0 -0
  236. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/zarr.json +0 -54
  237. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/c/0/0/0 +0 -0
  238. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/zarr.json +0 -54
  239. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/c/0/0/0 +0 -0
  240. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/zarr.json +0 -54
  241. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/c/0/0/0 +0 -0
  242. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/zarr.json +0 -54
  243. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/c/0/0/0 +0 -0
  244. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/zarr.json +0 -54
  245. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/c/0/0/0 +0 -0
  246. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/zarr.json +0 -54
  247. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/c/0/0/0 +0 -0
  248. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/zarr.json +0 -54
  249. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/c/0/0/0 +0 -0
  250. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/zarr.json +0 -54
  251. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/c/0/0/0 +0 -0
  252. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/zarr.json +0 -54
  253. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/ALK_ALT_CO2_west/c/0/0/0 +0 -0
  254. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/ALK_ALT_CO2_west/zarr.json +0 -54
  255. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/ALK_west/c/0/0/0 +0 -0
  256. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/ALK_west/zarr.json +0 -54
  257. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DIC_ALT_CO2_west/c/0/0/0 +0 -0
  258. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DIC_ALT_CO2_west/zarr.json +0 -54
  259. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DIC_west/c/0/0/0 +0 -0
  260. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DIC_west/zarr.json +0 -54
  261. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DOC_west/c/0/0/0 +0 -0
  262. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DOC_west/zarr.json +0 -54
  263. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DOCr_west/c/0/0/0 +0 -0
  264. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DOCr_west/zarr.json +0 -54
  265. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DON_west/c/0/0/0 +0 -0
  266. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DON_west/zarr.json +0 -54
  267. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DONr_west/c/0/0/0 +0 -0
  268. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DONr_west/zarr.json +0 -54
  269. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DOP_west/c/0/0/0 +0 -0
  270. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DOP_west/zarr.json +0 -54
  271. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DOPr_west/c/0/0/0 +0 -0
  272. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/DOPr_west/zarr.json +0 -54
  273. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/Fe_west/c/0/0/0 +0 -0
  274. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/Fe_west/zarr.json +0 -54
  275. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/Lig_west/c/0/0/0 +0 -0
  276. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/Lig_west/zarr.json +0 -54
  277. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/NH4_west/c/0/0/0 +0 -0
  278. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/NH4_west/zarr.json +0 -54
  279. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/NO3_west/c/0/0/0 +0 -0
  280. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/NO3_west/zarr.json +0 -54
  281. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/O2_west/c/0/0/0 +0 -0
  282. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/O2_west/zarr.json +0 -54
  283. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/PO4_west/c/0/0/0 +0 -0
  284. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/PO4_west/zarr.json +0 -54
  285. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/SiO3_west/c/0/0/0 +0 -0
  286. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/SiO3_west/zarr.json +0 -54
  287. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatC_west/c/0/0/0 +0 -0
  288. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatC_west/zarr.json +0 -54
  289. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatChl_west/c/0/0/0 +0 -0
  290. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatChl_west/zarr.json +0 -54
  291. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatFe_west/c/0/0/0 +0 -0
  292. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatFe_west/zarr.json +0 -54
  293. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatP_west/c/0/0/0 +0 -0
  294. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatP_west/zarr.json +0 -54
  295. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatSi_west/c/0/0/0 +0 -0
  296. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diatSi_west/zarr.json +0 -54
  297. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diazC_west/c/0/0/0 +0 -0
  298. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diazC_west/zarr.json +0 -54
  299. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diazChl_west/c/0/0/0 +0 -0
  300. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diazChl_west/zarr.json +0 -54
  301. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diazFe_west/c/0/0/0 +0 -0
  302. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diazFe_west/zarr.json +0 -54
  303. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diazP_west/c/0/0/0 +0 -0
  304. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/diazP_west/zarr.json +0 -54
  305. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spC_west/c/0/0/0 +0 -0
  306. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spC_west/zarr.json +0 -54
  307. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spCaCO3_west/c/0/0/0 +0 -0
  308. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spCaCO3_west/zarr.json +0 -54
  309. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spChl_west/c/0/0/0 +0 -0
  310. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spChl_west/zarr.json +0 -54
  311. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spFe_west/c/0/0/0 +0 -0
  312. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spFe_west/zarr.json +0 -54
  313. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spP_west/c/0/0/0 +0 -0
  314. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/spP_west/zarr.json +0 -54
  315. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/zooC_west/c/0/0/0 +0 -0
  316. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_unified_climatology.zarr/zooC_west/zarr.json +0 -54
  317. {roms_tools-3.2.0.dist-info → roms_tools-3.4.0.dist-info}/licenses/LICENSE +0 -0
  318. {roms_tools-3.2.0.dist-info → roms_tools-3.4.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from collections.abc import Callable
2
3
  from dataclasses import dataclass, field
3
4
  from pathlib import Path
4
5
  from typing import Any
@@ -12,16 +13,16 @@ from roms_tools.plot import plot_nesting
12
13
  from roms_tools.setup.topography import clip_depth
13
14
  from roms_tools.setup.utils import (
14
15
  Timed,
16
+ check_and_set_boundaries,
15
17
  from_yaml,
16
18
  get_boundary_coords,
17
19
  interpolate_from_rho_to_u,
18
20
  interpolate_from_rho_to_v,
19
21
  pop_grid_data,
20
22
  to_dict,
21
- wrap_longitudes,
22
23
  write_to_yaml,
23
24
  )
24
- from roms_tools.utils import save_datasets
25
+ from roms_tools.utils import save_datasets, wrap_longitudes
25
26
 
26
27
 
27
28
  @dataclass(kw_only=True)
@@ -42,8 +43,8 @@ class ChildGrid(Grid):
42
43
  parent_grid : Grid
43
44
  The parent grid object, providing the reference for the topography and mask of the child grid.
44
45
  boundaries : Dict[str, bool]
45
- Specifies which child grid boundaries (south, east, north, west) should be adjusted for topography/mask
46
- and included in `ds_nesting`. Defaults to all `True`.
46
+ Specifies which child grid boundaries ('south', 'east', 'north', 'west') should be adjusted for topography/mask
47
+ and included in `ds_nesting`. If not provided, valid (non-land) boundaries are enabled automatically.
47
48
  metadata : Dict[str, Any]
48
49
  Dictionary configuring the boundary nesting process, including:
49
50
 
@@ -80,17 +81,16 @@ class ChildGrid(Grid):
80
81
  """An xarray Dataset containing boundary mappings, where child grid boundaries are
81
82
  mapped onto parent grid indices."""
82
83
 
83
- def __post_init__(self):
84
- super().__post_init__()
85
- self._map_child_boundaries_onto_parent_grid_indices(verbose=self.verbose)
86
- self._modify_child_topography_and_mask(verbose=self.verbose)
87
-
88
84
  def _map_child_boundaries_onto_parent_grid_indices(self, verbose: bool = False):
89
85
  """Maps child grid boundary points onto absolute indices of the parent grid."""
90
86
  with Timed(
91
87
  "=== Mapping the child grid boundary points onto the indices of the parent grid ===",
92
88
  verbose=verbose,
93
89
  ):
90
+ self.boundaries = check_and_set_boundaries(
91
+ self.boundaries, self.ds.mask_rho
92
+ )
93
+
94
94
  # Prepare parent and child grid datasets by adjusting longitudes for dateline crossing
95
95
  parent_grid_ds, child_grid_ds = self._prepare_grid_datasets()
96
96
 
@@ -105,66 +105,124 @@ class ChildGrid(Grid):
105
105
 
106
106
  self.ds_nesting = ds_nesting
107
107
 
108
- def _modify_child_topography_and_mask(self, verbose: bool = False):
109
- """Adjust the topography and mask of the child grid to align with the parent grid.
110
-
111
- Uses a weighted sum based on boundary distance and clips depth values to a
112
- minimum.
113
- """
114
- with Timed("=== Modifying child topography and mask ===", verbose=verbose):
115
- # Prepare parent and child grid datasets by adjusting longitudes for dateline crossing
108
+ def _apply_child_modification(
109
+ self,
110
+ modifier: Callable,
111
+ modifier_name: str,
112
+ verbose: bool = False,
113
+ ):
114
+ """Shared logic for modifying child mask/topography."""
115
+ with Timed(f"=== Modifying the child {modifier_name} ===", verbose=verbose):
116
+ # Prepare datasets (fix dateline)
116
117
  parent_grid_ds, child_grid_ds = self._prepare_grid_datasets()
117
- child_grid_ds = modify_child_topography_and_mask(
118
- parent_grid_ds, child_grid_ds, self.boundaries, self.hmin
119
- )
120
118
 
121
- # Finalize grid datasets by adjusting longitudes back to [0, 360] range
122
- parent_grid_ds, child_grid_ds = self._finalize_grid_datasets(
119
+ # Apply modification function
120
+ child_grid_ds = modifier(parent_grid_ds, child_grid_ds)
121
+
122
+ # Restore longitudes to 0-360
123
+ _, child_grid_ds = self._finalize_grid_datasets(
123
124
  parent_grid_ds, child_grid_ds
124
125
  )
125
126
 
126
127
  self.ds = child_grid_ds
127
128
 
129
+ def _modify_child_mask(self, verbose: bool = False) -> None:
130
+ """Adjust child grid mask to align with the parent grid."""
131
+ self._apply_child_modification(
132
+ modifier=lambda p, c: modify_child_mask(p, c, self.boundaries),
133
+ modifier_name="mask",
134
+ verbose=verbose,
135
+ )
136
+
137
+ def _modify_child_topography(self, hmin: float, verbose: bool = False) -> None:
138
+ """Adjust child grid topography to align with the parent grid."""
139
+ self._apply_child_modification(
140
+ modifier=lambda p, c: modify_child_topography(p, c, self.boundaries, hmin),
141
+ modifier_name="topography",
142
+ verbose=verbose,
143
+ )
144
+
145
+ def update_mask(
146
+ self, mask_shapefile: str | Path | None = None, verbose: bool = False
147
+ ) -> None:
148
+ """
149
+ Update the child grid mask and ensure consistency with the parent grid.
150
+
151
+ This method performs the following steps:
152
+
153
+ 1. Derives the child mask from the provided ``mask_shapefile`` (or from the
154
+ default Natural Earth 10m coastline if ``None``).
155
+ 2. Updates the mapping of child boundaries to parent-grid indices.
156
+ This mapping depends on the updated mask, since masked (land) points may
157
+ extend outside the parent grid.
158
+ 3. Adjusts the child mask to ensure consistency with the parent mask.
159
+
160
+ Parameters
161
+ ----------
162
+ mask_shapefile : str or Path, optional
163
+ Path to a coastal shapefile used to derive the land mask. If ``None``,
164
+ a default coastline dataset is used.
165
+ verbose : bool, default False
166
+ If True, prints timing and progress information.
167
+
168
+ Returns
169
+ -------
170
+ None
171
+ Updates the internal datasets (``self.ds`` and ``self.ds_nesting``) in place,
172
+ modifying the mask and ensuring consistent parent-child boundary mapping.
173
+ """
174
+ super().update_mask(mask_shapefile=mask_shapefile, verbose=verbose)
175
+ self._map_child_boundaries_onto_parent_grid_indices(verbose=verbose)
176
+ self._modify_child_mask(verbose=verbose)
177
+
128
178
  def update_topography(
129
- self, topography_source=None, hmin=None, verbose=False
179
+ self,
180
+ topography_source: dict | None = None,
181
+ hmin: float | None = None,
182
+ verbose: bool = False,
130
183
  ) -> None:
131
- """Update the child grid topography via the following steps.
184
+ """
185
+ Update the child grid topography and ensure consistency with the parent grid.
186
+
187
+ This method performs the following operations:
132
188
 
133
- - Regrids the topography based on the specified source.
134
- - Applies global and local smoothing.
135
- - Adjusts the child grid topography and mask to match the parent grid.
136
- - Ensures the minimum depth constraint (`hmin`) is enforced.
137
- - Updates the internal dataset (`self.ds`) with the processed topography.
189
+ 1. Regrids the topography from the specified source.
190
+ 2. Applies domain-wide and local smoothing.
191
+ 3. Enforces the minimum depth constraint ``hmin``.
192
+ 4. Adjusts the child grid topography to maintain consistency with the
193
+ parent grid.
194
+ 5. Updates the internal dataset (``self.ds``) with the processed bathymetry.
138
195
 
139
196
  Parameters
140
197
  ----------
141
198
  topography_source : dict, optional
142
- A dictionary specifying the source of the topography data. Expected keys:
143
- - `"name"` (str): Name of the topography dataset (e.g., `"SRTM15"`).
144
- - `"path"` (str or Path): File path to the topography dataset.
199
+ Dictionary describing the topography data source. Expected keys:
145
200
 
146
- If not provided, the existing topography source remains unchanged.
201
+ - ``"name"`` (str): Name of the source dataset (e.g., ``"SRTM15"``).
202
+ - ``"path"`` (str or Path): Path to the dataset file.
203
+
204
+ If ``None``, the previously configured topography source is used.
147
205
 
148
206
  hmin : float, optional
149
- The minimum allowable ocean depth (in meters). If not provided, the existing
150
- value remains unchanged.
207
+ Minimum allowable ocean depth (meters). If ``None``, the existing value
208
+ is retained.
151
209
 
152
- verbose : bool, optional
153
- If `True`, prints detailed information about each processing step, including
154
- timing and modifications. Defaults to `False`.
210
+ verbose : bool, default False
211
+ If ``True``, prints progress messages and timing information.
155
212
 
156
213
  Returns
157
214
  -------
158
215
  None
159
- This method updates the internal dataset (`self.ds`) in place, modifying the
160
- topography variable. It does not return a value.
216
+ Updates ``self.ds`` in place by modifying the topography field. Nothing
217
+ is returned.
161
218
  """
219
+ hmin = hmin or self.hmin
162
220
  super().update_topography(
163
- topography_source=topography_source, hmin=hmin, verbose=verbose
221
+ topography_source=topography_source,
222
+ hmin=hmin,
223
+ verbose=verbose,
164
224
  )
165
-
166
- # Modify child topography and mask to match the parent grid
167
- self._modify_child_topography_and_mask(verbose=verbose)
225
+ self._modify_child_topography(hmin=hmin, verbose=verbose)
168
226
 
169
227
  def plot_nesting(self, with_dim_names=False) -> None:
170
228
  """Plot the parent and child grids in a single figure.
@@ -268,9 +326,12 @@ class ChildGrid(Grid):
268
326
  - The modified child grid dataset.
269
327
  """
270
328
  parent_grid_ds = wrap_longitudes(
271
- self.parent_grid.ds, straddle=self.parent_grid.straddle
329
+ self.parent_grid.ds.copy(), straddle=self.parent_grid.straddle
272
330
  )
273
- child_grid_ds = wrap_longitudes(self.ds, straddle=self.parent_grid.straddle)
331
+ child_grid_ds = wrap_longitudes(
332
+ self.ds.copy(), straddle=self.parent_grid.straddle
333
+ )
334
+
274
335
  return parent_grid_ds, child_grid_ds
275
336
 
276
337
  def _finalize_grid_datasets(
@@ -318,12 +379,12 @@ class ChildGrid(Grid):
318
379
 
319
380
 
320
381
  def map_child_boundaries_onto_parent_grid_indices(
321
- parent_grid_ds,
322
- child_grid_ds,
323
- boundaries={"south": True, "east": True, "north": True, "west": True},
324
- prefix="child",
325
- period=3600.0,
326
- update_land_indices=True,
382
+ parent_grid_ds: xr.Dataset,
383
+ child_grid_ds: xr.Dataset,
384
+ boundaries: dict = {"south": True, "east": True, "north": True, "west": True},
385
+ prefix: str = "child",
386
+ period: float = 3600.0,
387
+ update_land_indices: bool = True,
327
388
  ):
328
389
  """Maps child grid boundary points onto absolute indices of the parent grid.
329
390
 
@@ -369,6 +430,7 @@ def map_child_boundaries_onto_parent_grid_indices(
369
430
  bdry_coords_dict = get_boundary_coords()
370
431
 
371
432
  # add angles at u- and v-points
433
+
372
434
  child_grid_ds["angle_u"] = interpolate_from_rho_to_u(child_grid_ds["angle"])
373
435
  child_grid_ds["angle_v"] = interpolate_from_rho_to_v(child_grid_ds["angle"])
374
436
 
@@ -399,10 +461,10 @@ def map_child_boundaries_onto_parent_grid_indices(
399
461
  mask_child = child_grid_ds[names["mask"]].isel(**bdry_coords[direction])
400
462
 
401
463
  i_eta, i_xi = interpolate_indices(
402
- parent_grid_ds, lon_child, lat_child, mask_child
464
+ parent_grid_ds, lon_child, lat_child, mask_child, direction
403
465
  )
404
466
 
405
- if update_land_indices:
467
+ if update_land_indices and mask_child.sum() > 0:
406
468
  i_eta, i_xi = update_indices_if_on_parent_land(
407
469
  i_eta, i_xi, grid_location, parent_grid_ds
408
470
  )
@@ -445,8 +507,22 @@ def map_child_boundaries_onto_parent_grid_indices(
445
507
  return ds
446
508
 
447
509
 
448
- def interpolate_indices(parent_grid_ds, lon, lat, mask):
449
- """Interpolate the parent indices to the child grid.
510
+ def interpolate_indices(
511
+ parent_grid_ds: xr.Dataset,
512
+ lon: xr.DataArray,
513
+ lat: xr.DataArray,
514
+ mask: xr.DataArray,
515
+ direction: str,
516
+ ) -> tuple[xr.DataArray, xr.DataArray]:
517
+ """Interpolate the parent indices to the child grid boundary.
518
+
519
+ Uses the parent grid ``lon_rho``/``lat_rho`` coordinates to compute
520
+ fractional i/j indices at child-boundary longitude/latitude points using
521
+ linear interpolation. The function verifies that all ocean child points
522
+ (based on ``mask``) lie within the parent grid and warns if child
523
+ boundary points fall near the parent-grid edges. Land child points that fall
524
+ outside the parent grid (i.e., interpolation returns NaN) are filled with
525
+ ``-1e5``.
450
526
 
451
527
  Parameters
452
528
  ----------
@@ -458,6 +534,9 @@ def interpolate_indices(parent_grid_ds, lon, lat, mask):
458
534
  Latitudes of the child grid where interpolation is desired.
459
535
  mask: xarray.DataArray
460
536
  Mask for the child longitudes and latitudes under consideration.
537
+ direction : str
538
+ Boundary identifier (``"south"``, ``"north"``, ``"east"``, ``"west"``).
539
+ Used for generating informative warnings or errors.
461
540
  Returns
462
541
  -------
463
542
  i : xarray.DataArray
@@ -492,27 +571,67 @@ def interpolate_indices(parent_grid_ds, lon, lat, mask):
492
571
  i = xr.DataArray(i, dims=lon.dims)
493
572
  j = xr.DataArray(j, dims=lon.dims)
494
573
 
495
- # Check for NaN values
496
- if np.sum(np.isnan(i)) > 0 or np.sum(np.isnan(j)) > 0:
574
+ # Check whether ocean child points fall outside the parent grid
575
+ if (
576
+ i.where(mask, other=0.0).isnull().any()
577
+ or j.where(mask, other=0.0).isnull().any()
578
+ ):
497
579
  raise ValueError(
498
- "Some points are outside the grid. Please choose either a bigger parent grid or a smaller child grid."
580
+ f"Some wet points on the {direction}ern boundary of the child grid lie "
581
+ "outside the parent grid. Please use a larger parent grid or a smaller child grid."
499
582
  )
500
583
 
501
- # Check whether indices are close to border of parent grid
584
+ # Try to fix NaNs if there only a few per boundary. Fix with out-of-bounds points is not valid.
502
585
  nxp, nyp = lon_parent.shape
503
- if np.min(i) < 0 or np.max(i) > nxp - 2:
504
- logging.warning(
505
- "Some boundary points of the child grid are very close to the boundary of the parent grid."
586
+ nan_idx = (
587
+ i.isnull() | j.isnull() | (i > nxp - 2) | (i < 0) | (j > nyp - 2) | (j < 0)
588
+ )
589
+
590
+ idx = xr.DataArray(np.arange(i.size), dims=i.dims)
591
+
592
+ # Interpolate indices for points that are invalid (NaN or out-of-bounds)
593
+ if nan_idx.any() and not nan_idx.all():
594
+ idx_tmp = idx.where(~nan_idx, drop=True) # valid poins
595
+ i_tmp = i.where(~nan_idx, drop=True) # valid points
596
+ j_tmp = j.where(~nan_idx, drop=True) # valid points
597
+
598
+ interp_i = interp1d(
599
+ idx_tmp.values, i_tmp.values, kind="nearest", fill_value="extrapolate"
600
+ )
601
+ interp_j = interp1d(
602
+ idx_tmp.values, j_tmp.values, kind="nearest", fill_value="extrapolate"
603
+ )
604
+
605
+ i[nan_idx.values] = interp_i(idx[nan_idx].values)
606
+ j[nan_idx.values] = interp_j(idx[nan_idx].values)
607
+
608
+ # This should only occur in rare edge cases
609
+ if i.isnull().any() or j.isnull().any():
610
+ raise ValueError(
611
+ f"Mapping failed: the {direction}ern boundary of the child grid could not be "
612
+ "mapped onto parent-grid indices. Please adjust the parent/child grid configuration."
506
613
  )
507
- if np.min(j) < 0 or np.max(j) > nyp - 2:
614
+
615
+ # Warn if child boundary points are near the edges of the parent grid
616
+ if (
617
+ i.where(mask).min() < 0
618
+ or i.where(mask).max() > nxp - 2
619
+ or j.where(mask).min() < 0
620
+ or j.where(mask).max() > nyp - 2
621
+ ):
508
622
  logging.warning(
509
- "Some boundary points of the child grid are very close to the boundary of the parent grid."
623
+ f"Some wet points on the {direction}ern boundary of the child grid lie very close to the edges of the parent grid."
510
624
  )
511
625
 
512
626
  return i, j
513
627
 
514
628
 
515
- def update_indices_if_on_parent_land(i_eta, i_xi, grid_location, parent_grid_ds):
629
+ def update_indices_if_on_parent_land(
630
+ i_eta: xr.DataArray,
631
+ i_xi: xr.DataArray,
632
+ grid_location: str,
633
+ parent_grid_ds: xr.Dataset,
634
+ ) -> tuple[xr.DataArray, xr.DataArray]:
516
635
  """Finds points that are in the parent land mask but not land masked in the child
517
636
  and replaces parent indices with nearest neighbor wet points.
518
637
 
@@ -606,13 +725,88 @@ def update_indices_if_on_parent_land(i_eta, i_xi, grid_location, parent_grid_ds)
606
725
  return i_eta, i_xi
607
726
 
608
727
 
609
- def modify_child_topography_and_mask(
728
+ def _interpolate_parent(
729
+ parent_da: xr.DataArray, child_da: xr.DataArray
730
+ ) -> xr.DataArray:
731
+ """
732
+ Interpolate data from a parent grid onto a child grid using linear interpolation.
733
+
734
+ Parameters
735
+ ----------
736
+ parent_da : xr.DataArray
737
+ The data array on the parent grid. Must have coordinates `lon_rho` and `lat_rho`.
738
+ child_da : xr.DataArray
739
+ The target child grid data array. Must have coordinates `lon_rho` and `lat_rho`.
740
+
741
+ Returns
742
+ -------
743
+ xr.DataArray
744
+ The interpolated data on the child grid, with dimensions ("eta_rho", "xi_rho").
745
+ """
746
+ points = np.column_stack(
747
+ (parent_da.lon_rho.values.ravel(), parent_da.lat_rho.values.ravel())
748
+ )
749
+ xi = (child_da.lon_rho.values, child_da.lat_rho.values)
750
+ values = parent_da.values.ravel()
751
+
752
+ parent_interpolated = griddata(points, values, xi, method="linear")
753
+ return xr.DataArray(parent_interpolated, dims=("eta_rho", "xi_rho"))
754
+
755
+
756
+ def modify_child_mask(
757
+ parent_grid_ds: xr.Dataset,
758
+ child_grid_ds: xr.Dataset,
759
+ boundaries: dict = {"south": True, "east": True, "north": True, "west": True},
760
+ ):
761
+ """Adjust the child gridmask to align with the parent grid.
762
+
763
+ The mask of the child grid is adjusted using a weighted sum based on the boundary distance.
764
+
765
+ Parameters
766
+ ----------
767
+ parent_grid_ds : xarray.Dataset
768
+ The parent grid dataset containing `mask_rho` (land-sea mask).
769
+
770
+ child_grid_ds : xarray.Dataset
771
+ The child grid dataset whose `mask_rho` will be modified.
772
+
773
+ boundaries : dict, optional
774
+ A dictionary specifying which boundaries should be modified. Expected keys:
775
+ - `"south"` (bool): Whether to adjust the southern boundary.
776
+ - `"east"` (bool): Whether to adjust the eastern boundary.
777
+ - `"north"` (bool): Whether to adjust the northern boundary.
778
+ - `"west"` (bool): Whether to adjust the western boundary.
779
+ Defaults to modifying all boundaries.
780
+
781
+ Returns
782
+ -------
783
+ xarray.Dataset
784
+ The updated child grid dataset with modified mask (`mask_rho`).
785
+ """
786
+ # regrid parent mask onto child grid
787
+ mask_parent_interpolated = _interpolate_parent(
788
+ parent_grid_ds["mask_rho"], child_grid_ds["mask_rho"]
789
+ )
790
+
791
+ # compute weight based on distance
792
+ alpha = compute_boundary_distance(child_grid_ds["mask_rho"], boundaries)
793
+
794
+ # update child mask to be weighted sum between original child and interpolated parent
795
+ child_mask = (
796
+ alpha * child_grid_ds["mask_rho"] + (1 - alpha) * mask_parent_interpolated
797
+ )
798
+ child_grid_ds["mask_rho"] = xr.where(child_mask >= 0.5, 1, 0)
799
+
800
+ return child_grid_ds
801
+
802
+
803
+ def modify_child_topography(
610
804
  parent_grid_ds,
611
805
  child_grid_ds,
612
806
  boundaries={"south": True, "east": True, "north": True, "west": True},
613
807
  hmin=5.0,
614
808
  ):
615
- """Adjust the child grid topography and mask to align with the parent grid.
809
+ """Adjust the child grid topography to align with the parent grid.
616
810
 
617
811
  The topography of the child grid is adjusted using a weighted sum based on the boundary distance,
618
812
  and the depth values are clipped to enforce a minimum depth constraint.
@@ -620,10 +814,10 @@ def modify_child_topography_and_mask(
620
814
  Parameters
621
815
  ----------
622
816
  parent_grid_ds : xarray.Dataset
623
- The parent grid dataset containing `h` (topography) and `mask_rho` (land-sea mask).
817
+ The parent grid dataset containing `h` (topography).
624
818
 
625
819
  child_grid_ds : xarray.Dataset
626
- The child grid dataset whose `h` and `mask_rho` will be modified.
820
+ The child grid dataset whose `h` will be modified.
627
821
 
628
822
  boundaries : dict, optional
629
823
  A dictionary specifying which boundaries should be modified. Expected keys:
@@ -641,40 +835,22 @@ def modify_child_topography_and_mask(
641
835
  Returns
642
836
  -------
643
837
  xarray.Dataset
644
- The updated child grid dataset with modified topography (`h`) and mask (`mask_rho`).
838
+ The updated child grid dataset with modified topography (`h`).
645
839
  """
646
- # regrid parent topography and mask onto child grid
647
- points = np.column_stack(
648
- (parent_grid_ds.lon_rho.values.ravel(), parent_grid_ds.lat_rho.values.ravel())
649
- )
650
- xi = (child_grid_ds.lon_rho.values, child_grid_ds.lat_rho.values)
651
-
652
- values = parent_grid_ds["h"].values.ravel()
653
- h_parent_interpolated = griddata(points, values, xi, method="linear")
654
- h_parent_interpolated = xr.DataArray(
655
- h_parent_interpolated, dims=("eta_rho", "xi_rho")
656
- )
657
-
658
- values = parent_grid_ds["mask_rho"].values.ravel()
659
- mask_parent_interpolated = griddata(points, values, xi, method="linear")
660
- mask_parent_interpolated = xr.DataArray(
661
- mask_parent_interpolated, dims=("eta_rho", "xi_rho")
662
- )
840
+ # regrid parent mask onto child grid
841
+ h_parent_interpolated = _interpolate_parent(parent_grid_ds["h"], child_grid_ds["h"])
663
842
 
664
843
  # compute weight based on distance
665
844
  alpha = compute_boundary_distance(child_grid_ds["mask_rho"], boundaries)
666
- # update child topography and mask to be weighted sum between original child and interpolated parent
845
+
846
+ # update child topography to be weighted sum between original child and interpolated parent
667
847
  child_grid_ds["h"] = (
668
848
  alpha * child_grid_ds["h"] + (1 - alpha) * h_parent_interpolated
669
849
  )
850
+
670
851
  # Clip depth on modified child topography
671
852
  child_grid_ds["h"] = clip_depth(child_grid_ds["h"], hmin)
672
853
 
673
- child_mask = (
674
- alpha * child_grid_ds["mask_rho"] + (1 - alpha) * mask_parent_interpolated
675
- )
676
- child_grid_ds["mask_rho"] = xr.where(child_mask >= 0.5, 1, 0)
677
-
678
854
  return child_grid_ds
679
855
 
680
856
 
@@ -11,18 +11,18 @@ import xarray as xr
11
11
 
12
12
  from roms_tools import Grid
13
13
  from roms_tools.constants import MAX_DISTINCT_COLORS
14
+ from roms_tools.datasets.river_datasets import (
15
+ DaiRiverDataset,
16
+ get_indices_of_nearest_grid_cell_for_rivers,
17
+ )
14
18
  from roms_tools.plot import (
15
19
  assign_category_colors,
16
20
  get_projection,
17
21
  plot_2d_horizontal_field,
18
22
  plot_location,
19
23
  )
20
- from roms_tools.setup.datasets import (
21
- DaiRiverDataset,
22
- RawDataSource,
23
- get_indices_of_nearest_grid_cell_for_rivers,
24
- )
25
24
  from roms_tools.setup.utils import (
25
+ RawDataSource,
26
26
  add_time_info_to_ds,
27
27
  add_tracer_metadata_to_ds,
28
28
  from_yaml,
@@ -8,25 +8,24 @@ import numpy as np
8
8
  import xarray as xr
9
9
 
10
10
  from roms_tools import Grid
11
- from roms_tools.plot import plot
12
- from roms_tools.regrid import LateralRegridToROMS
13
- from roms_tools.setup.datasets import (
11
+ from roms_tools.datasets.lat_lon_datasets import (
14
12
  CESMBGCSurfaceForcingDataset,
15
- Dataset,
16
13
  ERA5ARCODataset,
17
14
  ERA5Correction,
18
15
  ERA5Dataset,
19
- RawDataSource,
16
+ LatLonDataset,
20
17
  UnifiedBGCSurfaceDataset,
21
18
  )
19
+ from roms_tools.plot import plot
20
+ from roms_tools.regrid import LateralRegridToROMS
22
21
  from roms_tools.setup.utils import (
22
+ RawDataSource,
23
23
  add_time_info_to_ds,
24
24
  compute_missing_surface_bgc_variables,
25
25
  from_yaml,
26
26
  get_target_coords,
27
27
  get_variable_metadata,
28
28
  group_dataset,
29
- interpolate_from_climatology,
30
29
  min_dist_to_land,
31
30
  nan_check,
32
31
  rotate_velocities,
@@ -34,7 +33,11 @@ from roms_tools.setup.utils import (
34
33
  to_dict,
35
34
  write_to_yaml,
36
35
  )
37
- from roms_tools.utils import save_datasets, transpose_dimensions
36
+ from roms_tools.utils import (
37
+ interpolate_from_climatology,
38
+ save_datasets,
39
+ transpose_dimensions,
40
+ )
38
41
 
39
42
  DEFAULT_ERA5_ARCO_PATH = (
40
43
  "gs://gcp-public-data-arco-era5/ar/full_37-1h-0p25deg-chunk-1.zarr-v3"
@@ -420,7 +423,7 @@ class SurfaceForcing:
420
423
  self.variable_info = variable_info
421
424
 
422
425
  def _apply_radiation_correction(
423
- self, radiation: xr.DataArray, data: Dataset
426
+ self, radiation: xr.DataArray, data: LatLonDataset
424
427
  ) -> xr.DataArray:
425
428
  """Apply a climatological correction to shortwave radiation.
426
429
 
@@ -461,8 +464,9 @@ class SurfaceForcing:
461
464
  corr_factor = xr.concat(
462
465
  [
463
466
  interpolate_from_climatology(
464
- correction_data.ds[correction_data.var_names["swr_corr"]],
465
- correction_data.dim_names["time"],
467
+ field=correction_data.ds[correction_data.var_names["swr_corr"]],
468
+ time_dim=correction_data.dim_names["time"],
469
+ time_coord=correction_data.dim_names["time"],
466
470
  time=time,
467
471
  )
468
472
  for time in radiation.time
@@ -472,8 +476,9 @@ class SurfaceForcing:
472
476
  else:
473
477
  # Interpolate across all time steps at once
474
478
  corr_factor = interpolate_from_climatology(
475
- correction_data.ds[correction_data.var_names["swr_corr"]],
476
- correction_data.dim_names["time"],
479
+ field=correction_data.ds[correction_data.var_names["swr_corr"]],
480
+ time_dim=correction_data.dim_names["time"],
481
+ time_coord=correction_data.dim_names["time"],
477
482
  time=radiation.time,
478
483
  )
479
484
 
roms_tools/setup/tides.py CHANGED
@@ -7,9 +7,9 @@ import numpy as np
7
7
  import xarray as xr
8
8
 
9
9
  from roms_tools import Grid
10
+ from roms_tools.datasets.lat_lon_datasets import TPXOManager
10
11
  from roms_tools.plot import plot
11
12
  from roms_tools.regrid import LateralRegridToROMS
12
- from roms_tools.setup.datasets import TPXOManager
13
13
  from roms_tools.setup.utils import (
14
14
  from_yaml,
15
15
  get_target_coords,