HydPy 6.2.dev1__cp313-cp313-win_amd64.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 (890) hide show
  1. hydpy/__init__.py +275 -0
  2. hydpy/aliases.py +2554 -0
  3. hydpy/auxs/__init__.py +0 -0
  4. hydpy/auxs/anntools.py +1305 -0
  5. hydpy/auxs/armatools.py +883 -0
  6. hydpy/auxs/calibtools.py +3337 -0
  7. hydpy/auxs/interptools.py +1094 -0
  8. hydpy/auxs/iuhtools.py +543 -0
  9. hydpy/auxs/networktools.py +597 -0
  10. hydpy/auxs/ppolytools.py +809 -0
  11. hydpy/auxs/quadtools.py +61 -0
  12. hydpy/auxs/roottools.py +228 -0
  13. hydpy/auxs/smoothtools.py +273 -0
  14. hydpy/auxs/statstools.py +2125 -0
  15. hydpy/auxs/validtools.py +81 -0
  16. hydpy/conf/HydPyConfigBase.xsd +68637 -0
  17. hydpy/conf/HydPyConfigBase.xsdt +358 -0
  18. hydpy/conf/HydPyConfigMultipleRuns.xsd +25 -0
  19. hydpy/conf/HydPyConfigSingleRun.xsd +24 -0
  20. hydpy/conf/__init__.py +0 -0
  21. hydpy/conf/a_coefficients_explicit_lobatto_sequence.npy +0 -0
  22. hydpy/conf/support_points_for_smoothpar_logistic2.npy +0 -0
  23. hydpy/config.py +42 -0
  24. hydpy/core/__init__.py +0 -0
  25. hydpy/core/aliastools.py +214 -0
  26. hydpy/core/autodoctools.py +1947 -0
  27. hydpy/core/auxfiletools.py +1169 -0
  28. hydpy/core/devicetools.py +3810 -0
  29. hydpy/core/exceptiontools.py +269 -0
  30. hydpy/core/filetools.py +1985 -0
  31. hydpy/core/hydpytools.py +3089 -0
  32. hydpy/core/importtools.py +1398 -0
  33. hydpy/core/indextools.py +345 -0
  34. hydpy/core/itemtools.py +1849 -0
  35. hydpy/core/masktools.py +460 -0
  36. hydpy/core/modeltools.py +4868 -0
  37. hydpy/core/netcdftools.py +2683 -0
  38. hydpy/core/objecttools.py +2023 -0
  39. hydpy/core/optiontools.py +1045 -0
  40. hydpy/core/parametertools.py +4674 -0
  41. hydpy/core/printtools.py +222 -0
  42. hydpy/core/propertytools.py +643 -0
  43. hydpy/core/pubtools.py +254 -0
  44. hydpy/core/selectiontools.py +1571 -0
  45. hydpy/core/sequencetools.py +4476 -0
  46. hydpy/core/seriestools.py +339 -0
  47. hydpy/core/testtools.py +2483 -0
  48. hydpy/core/timetools.py +3567 -0
  49. hydpy/core/typingtools.py +333 -0
  50. hydpy/core/variabletools.py +2615 -0
  51. hydpy/cythons/__init__.py +24 -0
  52. hydpy/cythons/annutils.pxd +33 -0
  53. hydpy/cythons/annutils.pyi +25 -0
  54. hydpy/cythons/annutils.pyx +120 -0
  55. hydpy/cythons/autogen/__init__.py +0 -0
  56. hydpy/cythons/autogen/annutils.cp313-win_amd64.pyd +0 -0
  57. hydpy/cythons/autogen/annutils.pxd +42 -0
  58. hydpy/cythons/autogen/annutils.pyx +129 -0
  59. hydpy/cythons/autogen/c_arma.cp313-win_amd64.pyd +0 -0
  60. hydpy/cythons/autogen/c_arma.pxd +179 -0
  61. hydpy/cythons/autogen/c_arma.pyx +356 -0
  62. hydpy/cythons/autogen/c_arma_rimorido.cp313-win_amd64.pyd +0 -0
  63. hydpy/cythons/autogen/c_arma_rimorido.pxd +179 -0
  64. hydpy/cythons/autogen/c_arma_rimorido.pyx +356 -0
  65. hydpy/cythons/autogen/c_conv.cp313-win_amd64.pyd +0 -0
  66. hydpy/cythons/autogen/c_conv.pxd +198 -0
  67. hydpy/cythons/autogen/c_conv.pyx +491 -0
  68. hydpy/cythons/autogen/c_conv_idw.cp313-win_amd64.pyd +0 -0
  69. hydpy/cythons/autogen/c_conv_idw.pxd +124 -0
  70. hydpy/cythons/autogen/c_conv_idw.pyx +264 -0
  71. hydpy/cythons/autogen/c_conv_idw_ed.cp313-win_amd64.pyd +0 -0
  72. hydpy/cythons/autogen/c_conv_idw_ed.pxd +197 -0
  73. hydpy/cythons/autogen/c_conv_idw_ed.pyx +481 -0
  74. hydpy/cythons/autogen/c_conv_nn.cp313-win_amd64.pyd +0 -0
  75. hydpy/cythons/autogen/c_conv_nn.pxd +120 -0
  76. hydpy/cythons/autogen/c_conv_nn.pyx +224 -0
  77. hydpy/cythons/autogen/c_dam.cp313-win_amd64.pyd +0 -0
  78. hydpy/cythons/autogen/c_dam.pxd +805 -0
  79. hydpy/cythons/autogen/c_dam.pyx +1477 -0
  80. hydpy/cythons/autogen/c_dam_llake.cp313-win_amd64.pyd +0 -0
  81. hydpy/cythons/autogen/c_dam_llake.pxd +364 -0
  82. hydpy/cythons/autogen/c_dam_llake.pyx +705 -0
  83. hydpy/cythons/autogen/c_dam_lreservoir.cp313-win_amd64.pyd +0 -0
  84. hydpy/cythons/autogen/c_dam_lreservoir.pxd +365 -0
  85. hydpy/cythons/autogen/c_dam_lreservoir.pyx +708 -0
  86. hydpy/cythons/autogen/c_dam_lretention.cp313-win_amd64.pyd +0 -0
  87. hydpy/cythons/autogen/c_dam_lretention.pxd +340 -0
  88. hydpy/cythons/autogen/c_dam_lretention.pyx +625 -0
  89. hydpy/cythons/autogen/c_dam_pump.cp313-win_amd64.pyd +0 -0
  90. hydpy/cythons/autogen/c_dam_pump.pxd +402 -0
  91. hydpy/cythons/autogen/c_dam_pump.pyx +724 -0
  92. hydpy/cythons/autogen/c_dam_pump_sluice.cp313-win_amd64.pyd +0 -0
  93. hydpy/cythons/autogen/c_dam_pump_sluice.pxd +452 -0
  94. hydpy/cythons/autogen/c_dam_pump_sluice.pyx +829 -0
  95. hydpy/cythons/autogen/c_dam_sluice.cp313-win_amd64.pyd +0 -0
  96. hydpy/cythons/autogen/c_dam_sluice.pxd +404 -0
  97. hydpy/cythons/autogen/c_dam_sluice.pyx +726 -0
  98. hydpy/cythons/autogen/c_dam_v001.cp313-win_amd64.pyd +0 -0
  99. hydpy/cythons/autogen/c_dam_v001.pxd +452 -0
  100. hydpy/cythons/autogen/c_dam_v001.pyx +816 -0
  101. hydpy/cythons/autogen/c_dam_v002.cp313-win_amd64.pyd +0 -0
  102. hydpy/cythons/autogen/c_dam_v002.pxd +394 -0
  103. hydpy/cythons/autogen/c_dam_v002.pyx +703 -0
  104. hydpy/cythons/autogen/c_dam_v003.cp313-win_amd64.pyd +0 -0
  105. hydpy/cythons/autogen/c_dam_v003.pxd +417 -0
  106. hydpy/cythons/autogen/c_dam_v003.pyx +744 -0
  107. hydpy/cythons/autogen/c_dam_v004.cp313-win_amd64.pyd +0 -0
  108. hydpy/cythons/autogen/c_dam_v004.pxd +486 -0
  109. hydpy/cythons/autogen/c_dam_v004.pyx +891 -0
  110. hydpy/cythons/autogen/c_dam_v005.cp313-win_amd64.pyd +0 -0
  111. hydpy/cythons/autogen/c_dam_v005.pxd +524 -0
  112. hydpy/cythons/autogen/c_dam_v005.pyx +928 -0
  113. hydpy/cythons/autogen/c_dummy.cp313-win_amd64.pyd +0 -0
  114. hydpy/cythons/autogen/c_dummy.pxd +151 -0
  115. hydpy/cythons/autogen/c_dummy.pyx +263 -0
  116. hydpy/cythons/autogen/c_dummy_interceptedwater.cp313-win_amd64.pyd +0 -0
  117. hydpy/cythons/autogen/c_dummy_interceptedwater.pxd +69 -0
  118. hydpy/cythons/autogen/c_dummy_interceptedwater.pyx +104 -0
  119. hydpy/cythons/autogen/c_dummy_node2node.cp313-win_amd64.pyd +0 -0
  120. hydpy/cythons/autogen/c_dummy_node2node.pxd +89 -0
  121. hydpy/cythons/autogen/c_dummy_node2node.pyx +148 -0
  122. hydpy/cythons/autogen/c_dummy_snowalbedo.cp313-win_amd64.pyd +0 -0
  123. hydpy/cythons/autogen/c_dummy_snowalbedo.pxd +69 -0
  124. hydpy/cythons/autogen/c_dummy_snowalbedo.pyx +104 -0
  125. hydpy/cythons/autogen/c_dummy_snowcover.cp313-win_amd64.pyd +0 -0
  126. hydpy/cythons/autogen/c_dummy_snowcover.pxd +69 -0
  127. hydpy/cythons/autogen/c_dummy_snowcover.pyx +104 -0
  128. hydpy/cythons/autogen/c_dummy_snowycanopy.cp313-win_amd64.pyd +0 -0
  129. hydpy/cythons/autogen/c_dummy_snowycanopy.pxd +69 -0
  130. hydpy/cythons/autogen/c_dummy_snowycanopy.pyx +104 -0
  131. hydpy/cythons/autogen/c_dummy_soilwater.cp313-win_amd64.pyd +0 -0
  132. hydpy/cythons/autogen/c_dummy_soilwater.pxd +69 -0
  133. hydpy/cythons/autogen/c_dummy_soilwater.pyx +104 -0
  134. hydpy/cythons/autogen/c_evap.cp313-win_amd64.pyd +0 -0
  135. hydpy/cythons/autogen/c_evap.pxd +1029 -0
  136. hydpy/cythons/autogen/c_evap.pyx +2601 -0
  137. hydpy/cythons/autogen/c_evap_aet_hbv96.cp313-win_amd64.pyd +0 -0
  138. hydpy/cythons/autogen/c_evap_aet_hbv96.pxd +227 -0
  139. hydpy/cythons/autogen/c_evap_aet_hbv96.pyx +584 -0
  140. hydpy/cythons/autogen/c_evap_aet_minhas.cp313-win_amd64.pyd +0 -0
  141. hydpy/cythons/autogen/c_evap_aet_minhas.pxd +193 -0
  142. hydpy/cythons/autogen/c_evap_aet_minhas.pyx +478 -0
  143. hydpy/cythons/autogen/c_evap_aet_morsim.cp313-win_amd64.pyd +0 -0
  144. hydpy/cythons/autogen/c_evap_aet_morsim.pxd +681 -0
  145. hydpy/cythons/autogen/c_evap_aet_morsim.pyx +1642 -0
  146. hydpy/cythons/autogen/c_evap_pet_ambav1.cp313-win_amd64.pyd +0 -0
  147. hydpy/cythons/autogen/c_evap_pet_ambav1.pxd +532 -0
  148. hydpy/cythons/autogen/c_evap_pet_ambav1.pyx +1296 -0
  149. hydpy/cythons/autogen/c_evap_pet_hbv96.cp313-win_amd64.pyd +0 -0
  150. hydpy/cythons/autogen/c_evap_pet_hbv96.pxd +179 -0
  151. hydpy/cythons/autogen/c_evap_pet_hbv96.pyx +328 -0
  152. hydpy/cythons/autogen/c_evap_pet_m.cp313-win_amd64.pyd +0 -0
  153. hydpy/cythons/autogen/c_evap_pet_m.pxd +124 -0
  154. hydpy/cythons/autogen/c_evap_pet_m.pyx +214 -0
  155. hydpy/cythons/autogen/c_evap_pet_mlc.cp313-win_amd64.pyd +0 -0
  156. hydpy/cythons/autogen/c_evap_pet_mlc.pxd +126 -0
  157. hydpy/cythons/autogen/c_evap_pet_mlc.pyx +214 -0
  158. hydpy/cythons/autogen/c_evap_ret_fao56.cp313-win_amd64.pyd +0 -0
  159. hydpy/cythons/autogen/c_evap_ret_fao56.pxd +305 -0
  160. hydpy/cythons/autogen/c_evap_ret_fao56.pyx +624 -0
  161. hydpy/cythons/autogen/c_evap_ret_io.cp313-win_amd64.pyd +0 -0
  162. hydpy/cythons/autogen/c_evap_ret_io.pxd +112 -0
  163. hydpy/cythons/autogen/c_evap_ret_io.pyx +176 -0
  164. hydpy/cythons/autogen/c_evap_ret_tw2002.cp313-win_amd64.pyd +0 -0
  165. hydpy/cythons/autogen/c_evap_ret_tw2002.pxd +139 -0
  166. hydpy/cythons/autogen/c_evap_ret_tw2002.pyx +273 -0
  167. hydpy/cythons/autogen/c_exch.cp313-win_amd64.pyd +0 -0
  168. hydpy/cythons/autogen/c_exch.pxd +230 -0
  169. hydpy/cythons/autogen/c_exch.pyx +462 -0
  170. hydpy/cythons/autogen/c_exch_branch_hbv96.cp313-win_amd64.pyd +0 -0
  171. hydpy/cythons/autogen/c_exch_branch_hbv96.pxd +134 -0
  172. hydpy/cythons/autogen/c_exch_branch_hbv96.pyx +255 -0
  173. hydpy/cythons/autogen/c_exch_waterlevel.cp313-win_amd64.pyd +0 -0
  174. hydpy/cythons/autogen/c_exch_waterlevel.pxd +54 -0
  175. hydpy/cythons/autogen/c_exch_waterlevel.pyx +78 -0
  176. hydpy/cythons/autogen/c_exch_weir_hbv96.cp313-win_amd64.pyd +0 -0
  177. hydpy/cythons/autogen/c_exch_weir_hbv96.pxd +156 -0
  178. hydpy/cythons/autogen/c_exch_weir_hbv96.pyx +282 -0
  179. hydpy/cythons/autogen/c_ga.cp313-win_amd64.pyd +0 -0
  180. hydpy/cythons/autogen/c_ga.pxd +353 -0
  181. hydpy/cythons/autogen/c_ga.pyx +1204 -0
  182. hydpy/cythons/autogen/c_ga_garto.cp313-win_amd64.pyd +0 -0
  183. hydpy/cythons/autogen/c_ga_garto.pxd +330 -0
  184. hydpy/cythons/autogen/c_ga_garto.pyx +1105 -0
  185. hydpy/cythons/autogen/c_ga_garto_submodel1.cp313-win_amd64.pyd +0 -0
  186. hydpy/cythons/autogen/c_ga_garto_submodel1.pxd +236 -0
  187. hydpy/cythons/autogen/c_ga_garto_submodel1.pyx +944 -0
  188. hydpy/cythons/autogen/c_gland.cp313-win_amd64.pyd +0 -0
  189. hydpy/cythons/autogen/c_gland.pxd +437 -0
  190. hydpy/cythons/autogen/c_gland.pyx +726 -0
  191. hydpy/cythons/autogen/c_gland_gr4.cp313-win_amd64.pyd +0 -0
  192. hydpy/cythons/autogen/c_gland_gr4.pxd +382 -0
  193. hydpy/cythons/autogen/c_gland_gr4.pyx +605 -0
  194. hydpy/cythons/autogen/c_gland_gr5.cp313-win_amd64.pyd +0 -0
  195. hydpy/cythons/autogen/c_gland_gr5.pxd +368 -0
  196. hydpy/cythons/autogen/c_gland_gr5.pyx +568 -0
  197. hydpy/cythons/autogen/c_gland_gr6.cp313-win_amd64.pyd +0 -0
  198. hydpy/cythons/autogen/c_gland_gr6.pxd +420 -0
  199. hydpy/cythons/autogen/c_gland_gr6.pyx +673 -0
  200. hydpy/cythons/autogen/c_hland.cp313-win_amd64.pyd +0 -0
  201. hydpy/cythons/autogen/c_hland.pxd +855 -0
  202. hydpy/cythons/autogen/c_hland.pyx +2486 -0
  203. hydpy/cythons/autogen/c_hland_96.cp313-win_amd64.pyd +0 -0
  204. hydpy/cythons/autogen/c_hland_96.pxd +631 -0
  205. hydpy/cythons/autogen/c_hland_96.pyx +1724 -0
  206. hydpy/cythons/autogen/c_hland_96c.cp313-win_amd64.pyd +0 -0
  207. hydpy/cythons/autogen/c_hland_96c.pxd +621 -0
  208. hydpy/cythons/autogen/c_hland_96c.pyx +1822 -0
  209. hydpy/cythons/autogen/c_hland_96p.cp313-win_amd64.pyd +0 -0
  210. hydpy/cythons/autogen/c_hland_96p.pxd +683 -0
  211. hydpy/cythons/autogen/c_hland_96p.pyx +1911 -0
  212. hydpy/cythons/autogen/c_kinw.cp313-win_amd64.pyd +0 -0
  213. hydpy/cythons/autogen/c_kinw.pxd +509 -0
  214. hydpy/cythons/autogen/c_kinw.pyx +965 -0
  215. hydpy/cythons/autogen/c_kinw_williams.cp313-win_amd64.pyd +0 -0
  216. hydpy/cythons/autogen/c_kinw_williams.pxd +409 -0
  217. hydpy/cythons/autogen/c_kinw_williams.pyx +763 -0
  218. hydpy/cythons/autogen/c_kinw_williams_ext.cp313-win_amd64.pyd +0 -0
  219. hydpy/cythons/autogen/c_kinw_williams_ext.pxd +220 -0
  220. hydpy/cythons/autogen/c_kinw_williams_ext.pyx +440 -0
  221. hydpy/cythons/autogen/c_lland.cp313-win_amd64.pyd +0 -0
  222. hydpy/cythons/autogen/c_lland.pxd +1386 -0
  223. hydpy/cythons/autogen/c_lland.pyx +3679 -0
  224. hydpy/cythons/autogen/c_lland_dd.cp313-win_amd64.pyd +0 -0
  225. hydpy/cythons/autogen/c_lland_dd.pxd +679 -0
  226. hydpy/cythons/autogen/c_lland_dd.pyx +1719 -0
  227. hydpy/cythons/autogen/c_lland_knauf.cp313-win_amd64.pyd +0 -0
  228. hydpy/cythons/autogen/c_lland_knauf.pxd +1096 -0
  229. hydpy/cythons/autogen/c_lland_knauf.pyx +2784 -0
  230. hydpy/cythons/autogen/c_lland_knauf_ic.cp313-win_amd64.pyd +0 -0
  231. hydpy/cythons/autogen/c_lland_knauf_ic.pxd +1369 -0
  232. hydpy/cythons/autogen/c_lland_knauf_ic.pyx +3625 -0
  233. hydpy/cythons/autogen/c_meteo.cp313-win_amd64.pyd +0 -0
  234. hydpy/cythons/autogen/c_meteo.pxd +469 -0
  235. hydpy/cythons/autogen/c_meteo.pyx +879 -0
  236. hydpy/cythons/autogen/c_meteo_clear_glob_io.cp313-win_amd64.pyd +0 -0
  237. hydpy/cythons/autogen/c_meteo_clear_glob_io.pxd +75 -0
  238. hydpy/cythons/autogen/c_meteo_clear_glob_io.pyx +107 -0
  239. hydpy/cythons/autogen/c_meteo_glob_fao56.cp313-win_amd64.pyd +0 -0
  240. hydpy/cythons/autogen/c_meteo_glob_fao56.pxd +209 -0
  241. hydpy/cythons/autogen/c_meteo_glob_fao56.pyx +339 -0
  242. hydpy/cythons/autogen/c_meteo_glob_io.cp313-win_amd64.pyd +0 -0
  243. hydpy/cythons/autogen/c_meteo_glob_io.pxd +63 -0
  244. hydpy/cythons/autogen/c_meteo_glob_io.pyx +91 -0
  245. hydpy/cythons/autogen/c_meteo_glob_morsim.cp313-win_amd64.pyd +0 -0
  246. hydpy/cythons/autogen/c_meteo_glob_morsim.pxd +289 -0
  247. hydpy/cythons/autogen/c_meteo_glob_morsim.pyx +527 -0
  248. hydpy/cythons/autogen/c_meteo_precip_io.cp313-win_amd64.pyd +0 -0
  249. hydpy/cythons/autogen/c_meteo_precip_io.pxd +112 -0
  250. hydpy/cythons/autogen/c_meteo_precip_io.pyx +176 -0
  251. hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.cp313-win_amd64.pyd +0 -0
  252. hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.pxd +87 -0
  253. hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.pyx +123 -0
  254. hydpy/cythons/autogen/c_meteo_sun_fao56.cp313-win_amd64.pyd +0 -0
  255. hydpy/cythons/autogen/c_meteo_sun_fao56.pxd +209 -0
  256. hydpy/cythons/autogen/c_meteo_sun_fao56.pyx +343 -0
  257. hydpy/cythons/autogen/c_meteo_sun_morsim.cp313-win_amd64.pyd +0 -0
  258. hydpy/cythons/autogen/c_meteo_sun_morsim.pxd +286 -0
  259. hydpy/cythons/autogen/c_meteo_sun_morsim.pyx +519 -0
  260. hydpy/cythons/autogen/c_meteo_temp_io.cp313-win_amd64.pyd +0 -0
  261. hydpy/cythons/autogen/c_meteo_temp_io.pxd +112 -0
  262. hydpy/cythons/autogen/c_meteo_temp_io.pyx +176 -0
  263. hydpy/cythons/autogen/c_musk.cp313-win_amd64.pyd +0 -0
  264. hydpy/cythons/autogen/c_musk.pxd +282 -0
  265. hydpy/cythons/autogen/c_musk.pyx +605 -0
  266. hydpy/cythons/autogen/c_musk_classic.cp313-win_amd64.pyd +0 -0
  267. hydpy/cythons/autogen/c_musk_classic.pxd +138 -0
  268. hydpy/cythons/autogen/c_musk_classic.pyx +226 -0
  269. hydpy/cythons/autogen/c_musk_mct.cp313-win_amd64.pyd +0 -0
  270. hydpy/cythons/autogen/c_musk_mct.pxd +282 -0
  271. hydpy/cythons/autogen/c_musk_mct.pyx +609 -0
  272. hydpy/cythons/autogen/c_rconc.cp313-win_amd64.pyd +0 -0
  273. hydpy/cythons/autogen/c_rconc.pxd +119 -0
  274. hydpy/cythons/autogen/c_rconc.pyx +174 -0
  275. hydpy/cythons/autogen/c_rconc_nash.cp313-win_amd64.pyd +0 -0
  276. hydpy/cythons/autogen/c_rconc_nash.pxd +111 -0
  277. hydpy/cythons/autogen/c_rconc_nash.pyx +185 -0
  278. hydpy/cythons/autogen/c_rconc_uh.cp313-win_amd64.pyd +0 -0
  279. hydpy/cythons/autogen/c_rconc_uh.pxd +92 -0
  280. hydpy/cythons/autogen/c_rconc_uh.pyx +125 -0
  281. hydpy/cythons/autogen/c_sw1d.cp313-win_amd64.pyd +0 -0
  282. hydpy/cythons/autogen/c_sw1d.pxd +511 -0
  283. hydpy/cythons/autogen/c_sw1d.pyx +1263 -0
  284. hydpy/cythons/autogen/c_sw1d_channel.cp313-win_amd64.pyd +0 -0
  285. hydpy/cythons/autogen/c_sw1d_channel.pxd +119 -0
  286. hydpy/cythons/autogen/c_sw1d_channel.pyx +300 -0
  287. hydpy/cythons/autogen/c_sw1d_gate_out.cp313-win_amd64.pyd +0 -0
  288. hydpy/cythons/autogen/c_sw1d_gate_out.pxd +240 -0
  289. hydpy/cythons/autogen/c_sw1d_gate_out.pyx +476 -0
  290. hydpy/cythons/autogen/c_sw1d_lias.cp313-win_amd64.pyd +0 -0
  291. hydpy/cythons/autogen/c_sw1d_lias.pxd +320 -0
  292. hydpy/cythons/autogen/c_sw1d_lias.pyx +619 -0
  293. hydpy/cythons/autogen/c_sw1d_lias_sluice.cp313-win_amd64.pyd +0 -0
  294. hydpy/cythons/autogen/c_sw1d_lias_sluice.pxd +325 -0
  295. hydpy/cythons/autogen/c_sw1d_lias_sluice.pyx +644 -0
  296. hydpy/cythons/autogen/c_sw1d_network.cp313-win_amd64.pyd +0 -0
  297. hydpy/cythons/autogen/c_sw1d_network.pxd +90 -0
  298. hydpy/cythons/autogen/c_sw1d_network.pyx +246 -0
  299. hydpy/cythons/autogen/c_sw1d_pump.cp313-win_amd64.pyd +0 -0
  300. hydpy/cythons/autogen/c_sw1d_pump.pxd +256 -0
  301. hydpy/cythons/autogen/c_sw1d_pump.pyx +502 -0
  302. hydpy/cythons/autogen/c_sw1d_q_in.cp313-win_amd64.pyd +0 -0
  303. hydpy/cythons/autogen/c_sw1d_q_in.pxd +224 -0
  304. hydpy/cythons/autogen/c_sw1d_q_in.pyx +383 -0
  305. hydpy/cythons/autogen/c_sw1d_q_out.cp313-win_amd64.pyd +0 -0
  306. hydpy/cythons/autogen/c_sw1d_q_out.pxd +224 -0
  307. hydpy/cythons/autogen/c_sw1d_q_out.pyx +383 -0
  308. hydpy/cythons/autogen/c_sw1d_storage.cp313-win_amd64.pyd +0 -0
  309. hydpy/cythons/autogen/c_sw1d_storage.pxd +193 -0
  310. hydpy/cythons/autogen/c_sw1d_storage.pyx +349 -0
  311. hydpy/cythons/autogen/c_sw1d_weir_out.cp313-win_amd64.pyd +0 -0
  312. hydpy/cythons/autogen/c_sw1d_weir_out.pxd +212 -0
  313. hydpy/cythons/autogen/c_sw1d_weir_out.pyx +404 -0
  314. hydpy/cythons/autogen/c_test.cp313-win_amd64.pyd +0 -0
  315. hydpy/cythons/autogen/c_test.pxd +175 -0
  316. hydpy/cythons/autogen/c_test.pyx +348 -0
  317. hydpy/cythons/autogen/c_test_discontinous.cp313-win_amd64.pyd +0 -0
  318. hydpy/cythons/autogen/c_test_discontinous.pxd +146 -0
  319. hydpy/cythons/autogen/c_test_discontinous.pyx +256 -0
  320. hydpy/cythons/autogen/c_test_stiff0d.cp313-win_amd64.pyd +0 -0
  321. hydpy/cythons/autogen/c_test_stiff0d.pxd +146 -0
  322. hydpy/cythons/autogen/c_test_stiff0d.pyx +250 -0
  323. hydpy/cythons/autogen/c_test_stiff1d.cp313-win_amd64.pyd +0 -0
  324. hydpy/cythons/autogen/c_test_stiff1d.pxd +145 -0
  325. hydpy/cythons/autogen/c_test_stiff1d.pyx +294 -0
  326. hydpy/cythons/autogen/c_whmod.cp313-win_amd64.pyd +0 -0
  327. hydpy/cythons/autogen/c_whmod.pxd +482 -0
  328. hydpy/cythons/autogen/c_whmod.pyx +1156 -0
  329. hydpy/cythons/autogen/c_whmod_rural.cp313-win_amd64.pyd +0 -0
  330. hydpy/cythons/autogen/c_whmod_rural.pxd +411 -0
  331. hydpy/cythons/autogen/c_whmod_rural.pyx +982 -0
  332. hydpy/cythons/autogen/c_whmod_urban.cp313-win_amd64.pyd +0 -0
  333. hydpy/cythons/autogen/c_whmod_urban.pxd +482 -0
  334. hydpy/cythons/autogen/c_whmod_urban.pyx +1155 -0
  335. hydpy/cythons/autogen/c_wland.cp313-win_amd64.pyd +0 -0
  336. hydpy/cythons/autogen/c_wland.pxd +842 -0
  337. hydpy/cythons/autogen/c_wland.pyx +1890 -0
  338. hydpy/cythons/autogen/c_wland_gd.cp313-win_amd64.pyd +0 -0
  339. hydpy/cythons/autogen/c_wland_gd.pxd +829 -0
  340. hydpy/cythons/autogen/c_wland_gd.pyx +1847 -0
  341. hydpy/cythons/autogen/c_wland_wag.cp313-win_amd64.pyd +0 -0
  342. hydpy/cythons/autogen/c_wland_wag.pxd +810 -0
  343. hydpy/cythons/autogen/c_wland_wag.pyx +1780 -0
  344. hydpy/cythons/autogen/c_wq.cp313-win_amd64.pyd +0 -0
  345. hydpy/cythons/autogen/c_wq.pxd +275 -0
  346. hydpy/cythons/autogen/c_wq.pyx +652 -0
  347. hydpy/cythons/autogen/c_wq_trapeze.cp313-win_amd64.pyd +0 -0
  348. hydpy/cythons/autogen/c_wq_trapeze.pxd +170 -0
  349. hydpy/cythons/autogen/c_wq_trapeze.pyx +400 -0
  350. hydpy/cythons/autogen/c_wq_trapeze_strickler.cp313-win_amd64.pyd +0 -0
  351. hydpy/cythons/autogen/c_wq_trapeze_strickler.pxd +243 -0
  352. hydpy/cythons/autogen/c_wq_trapeze_strickler.pyx +578 -0
  353. hydpy/cythons/autogen/c_wq_walrus.cp313-win_amd64.pyd +0 -0
  354. hydpy/cythons/autogen/c_wq_walrus.pxd +61 -0
  355. hydpy/cythons/autogen/c_wq_walrus.pyx +82 -0
  356. hydpy/cythons/autogen/configutils.cp313-win_amd64.pyd +0 -0
  357. hydpy/cythons/autogen/configutils.pxd +17 -0
  358. hydpy/cythons/autogen/configutils.pyx +119 -0
  359. hydpy/cythons/autogen/interfaceutils.cp313-win_amd64.pyd +0 -0
  360. hydpy/cythons/autogen/interfaceutils.pxd +31 -0
  361. hydpy/cythons/autogen/interfaceutils.pyx +82 -0
  362. hydpy/cythons/autogen/interputils.cp313-win_amd64.pyd +0 -0
  363. hydpy/cythons/autogen/interputils.pxd +42 -0
  364. hydpy/cythons/autogen/interputils.pyx +118 -0
  365. hydpy/cythons/autogen/masterinterface.cp313-win_amd64.pyd +0 -0
  366. hydpy/cythons/autogen/masterinterface.pxd +153 -0
  367. hydpy/cythons/autogen/masterinterface.pyx +222 -0
  368. hydpy/cythons/autogen/pointerutils.cp313-win_amd64.pyd +0 -0
  369. hydpy/cythons/autogen/pointerutils.pxd +31 -0
  370. hydpy/cythons/autogen/pointerutils.pyx +650 -0
  371. hydpy/cythons/autogen/ppolyutils.cp313-win_amd64.pyd +0 -0
  372. hydpy/cythons/autogen/ppolyutils.pxd +35 -0
  373. hydpy/cythons/autogen/ppolyutils.pyx +59 -0
  374. hydpy/cythons/autogen/quadutils.cp313-win_amd64.pyd +0 -0
  375. hydpy/cythons/autogen/quadutils.pxd +26 -0
  376. hydpy/cythons/autogen/quadutils.pyx +973 -0
  377. hydpy/cythons/autogen/rootutils.cp313-win_amd64.pyd +0 -0
  378. hydpy/cythons/autogen/rootutils.pxd +28 -0
  379. hydpy/cythons/autogen/rootutils.pyx +109 -0
  380. hydpy/cythons/autogen/sequenceutils.cp313-win_amd64.pyd +0 -0
  381. hydpy/cythons/autogen/sequenceutils.pxd +45 -0
  382. hydpy/cythons/autogen/sequenceutils.pyx +101 -0
  383. hydpy/cythons/autogen/smoothutils.cp313-win_amd64.pyd +0 -0
  384. hydpy/cythons/autogen/smoothutils.pxd +29 -0
  385. hydpy/cythons/autogen/smoothutils.pyx +833 -0
  386. hydpy/cythons/configutils.pxd +8 -0
  387. hydpy/cythons/configutils.pyi +5 -0
  388. hydpy/cythons/configutils.pyx +110 -0
  389. hydpy/cythons/interfaceutils.pxd +22 -0
  390. hydpy/cythons/interfaceutils.pyi +15 -0
  391. hydpy/cythons/interfaceutils.pyx +73 -0
  392. hydpy/cythons/interputils.pxd +33 -0
  393. hydpy/cythons/interputils.pyi +32 -0
  394. hydpy/cythons/interputils.pyx +109 -0
  395. hydpy/cythons/modelutils.py +2990 -0
  396. hydpy/cythons/pointerutils.pxd +22 -0
  397. hydpy/cythons/pointerutils.pyi +89 -0
  398. hydpy/cythons/pointerutils.pyx +641 -0
  399. hydpy/cythons/ppolyutils.pxd +26 -0
  400. hydpy/cythons/ppolyutils.pyi +21 -0
  401. hydpy/cythons/ppolyutils.pyx +50 -0
  402. hydpy/cythons/quadutils.pxd +17 -0
  403. hydpy/cythons/quadutils.pyi +13 -0
  404. hydpy/cythons/quadutils.pyx +964 -0
  405. hydpy/cythons/rootutils.pxd +19 -0
  406. hydpy/cythons/rootutils.pyi +21 -0
  407. hydpy/cythons/rootutils.pyx +100 -0
  408. hydpy/cythons/sequenceutils.pxd +36 -0
  409. hydpy/cythons/sequenceutils.pyi +7 -0
  410. hydpy/cythons/sequenceutils.pyx +92 -0
  411. hydpy/cythons/smoothutils.pxd +20 -0
  412. hydpy/cythons/smoothutils.pyi +15 -0
  413. hydpy/cythons/smoothutils.pyx +824 -0
  414. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_dill_assl.py +13 -0
  415. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_kalk.py +13 -0
  416. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_leun.py +14 -0
  417. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_marb.py +13 -0
  418. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_dill_assl_lahn_leun.py +5 -0
  419. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_lahn_leun_lahn_kalk.py +5 -0
  420. hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_lahn_marb_lahn_leun.py +5 -0
  421. hydpy/data/HydPy-H-Lahn/control/default/land.py +9 -0
  422. hydpy/data/HydPy-H-Lahn/control/default/land_dill_assl.py +57 -0
  423. hydpy/data/HydPy-H-Lahn/control/default/land_lahn_kalk.py +57 -0
  424. hydpy/data/HydPy-H-Lahn/control/default/land_lahn_leun.py +56 -0
  425. hydpy/data/HydPy-H-Lahn/control/default/land_lahn_marb.py +57 -0
  426. hydpy/data/HydPy-H-Lahn/control/default/stream_dill_assl_lahn_leun.py +7 -0
  427. hydpy/data/HydPy-H-Lahn/control/default/stream_lahn_leun_lahn_kalk.py +7 -0
  428. hydpy/data/HydPy-H-Lahn/control/default/stream_lahn_marb_lahn_leun.py +7 -0
  429. hydpy/data/HydPy-H-Lahn/multiple_runs.xml +309 -0
  430. hydpy/data/HydPy-H-Lahn/multiple_runs_alpha.xml +71 -0
  431. hydpy/data/HydPy-H-Lahn/network/default/headwaters.py +11 -0
  432. hydpy/data/HydPy-H-Lahn/network/default/nonheadwaters.py +11 -0
  433. hydpy/data/HydPy-H-Lahn/network/default/streams.py +8 -0
  434. hydpy/data/HydPy-H-Lahn/series/default/dill_assl_obs_q.asc +11387 -0
  435. hydpy/data/HydPy-H-Lahn/series/default/evap_pet_hbv96_input_normalairtemperature.nc +0 -0
  436. hydpy/data/HydPy-H-Lahn/series/default/evap_pet_hbv96_input_normalevapotranspiration.nc +0 -0
  437. hydpy/data/HydPy-H-Lahn/series/default/hland_96_input_p.nc +0 -0
  438. hydpy/data/HydPy-H-Lahn/series/default/hland_96_input_t.nc +0 -0
  439. hydpy/data/HydPy-H-Lahn/series/default/lahn_kalk_obs_q.asc +11387 -0
  440. hydpy/data/HydPy-H-Lahn/series/default/lahn_leun_obs_q.asc +11387 -0
  441. hydpy/data/HydPy-H-Lahn/series/default/lahn_marb_obs_q.asc +11387 -0
  442. hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
  443. hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
  444. hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_hland_96_input_p.asc +11387 -0
  445. hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_hland_96_input_t.asc +11387 -0
  446. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
  447. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
  448. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_hland_96_input_p.asc +11387 -0
  449. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_hland_96_input_t.asc +11387 -0
  450. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
  451. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
  452. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_hland_96_input_p.asc +11387 -0
  453. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_hland_96_input_t.asc +11387 -0
  454. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
  455. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
  456. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_hland_96_input_p.asc +11387 -0
  457. hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_hland_96_input_t.asc +11387 -0
  458. hydpy/data/HydPy-H-Lahn/series/default/obs_q.nc +0 -0
  459. hydpy/data/HydPy-H-Lahn/single_run.xml +152 -0
  460. hydpy/data/HydPy-H-Lahn/single_run.xmlt +143 -0
  461. hydpy/data/__init__.py +17 -0
  462. hydpy/docs/__init__.py +0 -0
  463. hydpy/docs/autofigs/__init__.py +0 -0
  464. hydpy/docs/bib/__init__.py +0 -0
  465. hydpy/docs/bib/refs.bib +566 -0
  466. hydpy/docs/combine_docversions.py +133 -0
  467. hydpy/docs/draw_model_sketches.py +1301 -0
  468. hydpy/docs/enable_autodoc.py +7 -0
  469. hydpy/docs/figs/HydPy-G-GR4.png +0 -0
  470. hydpy/docs/figs/HydPy-G-GR5.png +0 -0
  471. hydpy/docs/figs/HydPy-G-GR6.png +0 -0
  472. hydpy/docs/figs/HydPy-H-HBV96-COSERO.png +0 -0
  473. hydpy/docs/figs/HydPy-H-HBV96-PREVAH.png +0 -0
  474. hydpy/docs/figs/HydPy-H-HBV96.png +0 -0
  475. hydpy/docs/figs/HydPy-H-Lahn.png +0 -0
  476. hydpy/docs/figs/HydPy-KinW-Williams.png +0 -0
  477. hydpy/docs/figs/HydPy-L-DD.png +0 -0
  478. hydpy/docs/figs/HydPy-W-Wag.png +0 -0
  479. hydpy/docs/figs/HydPy_Logo.png +0 -0
  480. hydpy/docs/figs/HydPy_Logo_Text.png +0 -0
  481. hydpy/docs/figs/IDLE-editor.png +0 -0
  482. hydpy/docs/figs/IDLE-shell.png +0 -0
  483. hydpy/docs/figs/LAWA_river-basin-bumbers.png +0 -0
  484. hydpy/docs/figs/__init__.py +0 -0
  485. hydpy/docs/html_/__init__.py +0 -0
  486. hydpy/docs/polish_html.py +57 -0
  487. hydpy/docs/prepare.py +224 -0
  488. hydpy/docs/publish_docs.py +53 -0
  489. hydpy/docs/rst/HydPy-ARMA.rst +27 -0
  490. hydpy/docs/rst/HydPy-Conv.rst +22 -0
  491. hydpy/docs/rst/HydPy-Dam.rst +79 -0
  492. hydpy/docs/rst/HydPy-Dummy.rst +21 -0
  493. hydpy/docs/rst/HydPy-Evap.rst +26 -0
  494. hydpy/docs/rst/HydPy-Exch.rst +36 -0
  495. hydpy/docs/rst/HydPy-G.rst +40 -0
  496. hydpy/docs/rst/HydPy-GA.rst +34 -0
  497. hydpy/docs/rst/HydPy-H.rst +24 -0
  498. hydpy/docs/rst/HydPy-KinW.rst +32 -0
  499. hydpy/docs/rst/HydPy-L.rst +42 -0
  500. hydpy/docs/rst/HydPy-Meteo.rst +28 -0
  501. hydpy/docs/rst/HydPy-Musk.rst +21 -0
  502. hydpy/docs/rst/HydPy-Rconc.rst +17 -0
  503. hydpy/docs/rst/HydPy-SW1D.rst +49 -0
  504. hydpy/docs/rst/HydPy-Test.rst +19 -0
  505. hydpy/docs/rst/HydPy-W.rst +20 -0
  506. hydpy/docs/rst/HydPy-WHMod.rst +19 -0
  507. hydpy/docs/rst/HydPy-WQ.rst +20 -0
  508. hydpy/docs/rst/__init__.py +0 -0
  509. hydpy/docs/rst/additional_repositories.rst +40 -0
  510. hydpy/docs/rst/auxiliaries.rst +31 -0
  511. hydpy/docs/rst/continuous_integration.rst +75 -0
  512. hydpy/docs/rst/core.rst +75 -0
  513. hydpy/docs/rst/cythons.rst +47 -0
  514. hydpy/docs/rst/definitions.rst +506 -0
  515. hydpy/docs/rst/developer_guide.rst +54 -0
  516. hydpy/docs/rst/example_projects.rst +40 -0
  517. hydpy/docs/rst/execution.rst +22 -0
  518. hydpy/docs/rst/framework_tools.rst +56 -0
  519. hydpy/docs/rst/how_to_read_the_reference_manual.rst +156 -0
  520. hydpy/docs/rst/hydpydependencies.rst +55 -0
  521. hydpy/docs/rst/index.rst +125 -0
  522. hydpy/docs/rst/installation.rst +155 -0
  523. hydpy/docs/rst/model_families.rst +79 -0
  524. hydpy/docs/rst/model_overview.rst +291 -0
  525. hydpy/docs/rst/modelimports.rst +10 -0
  526. hydpy/docs/rst/options.rst +119 -0
  527. hydpy/docs/rst/programming_style.rst +572 -0
  528. hydpy/docs/rst/project_structure.rst +520 -0
  529. hydpy/docs/rst/quickstart.rst +304 -0
  530. hydpy/docs/rst/reference_manual.rst +29 -0
  531. hydpy/docs/rst/required_tools.rst +50 -0
  532. hydpy/docs/rst/simulation.rst +514 -0
  533. hydpy/docs/rst/submodel_interfaces.rst +32 -0
  534. hydpy/docs/rst/tests_and_documentation.rst +85 -0
  535. hydpy/docs/rst/user_guide.rst +38 -0
  536. hydpy/docs/rst/version_control.rst +116 -0
  537. hydpy/docs/rst/zbibliography.rst +8 -0
  538. hydpy/docs/sphinx/__init__.py +0 -0
  539. hydpy/docs/sphinx/_themes/basic_hydpy/changes/frameset.html +11 -0
  540. hydpy/docs/sphinx/_themes/basic_hydpy/changes/rstsource.html +15 -0
  541. hydpy/docs/sphinx/_themes/basic_hydpy/changes/versionchanges.html +33 -0
  542. hydpy/docs/sphinx/_themes/basic_hydpy/defindex.html +35 -0
  543. hydpy/docs/sphinx/_themes/basic_hydpy/domainindex.html +56 -0
  544. hydpy/docs/sphinx/_themes/basic_hydpy/genindex-single.html +63 -0
  545. hydpy/docs/sphinx/_themes/basic_hydpy/genindex-split.html +41 -0
  546. hydpy/docs/sphinx/_themes/basic_hydpy/genindex.html +76 -0
  547. hydpy/docs/sphinx/_themes/basic_hydpy/globaltoc.html +11 -0
  548. hydpy/docs/sphinx/_themes/basic_hydpy/layout.html +221 -0
  549. hydpy/docs/sphinx/_themes/basic_hydpy/localtoc.html +15 -0
  550. hydpy/docs/sphinx/_themes/basic_hydpy/opensearch.xml +13 -0
  551. hydpy/docs/sphinx/_themes/basic_hydpy/page.html +13 -0
  552. hydpy/docs/sphinx/_themes/basic_hydpy/relations.html +23 -0
  553. hydpy/docs/sphinx/_themes/basic_hydpy/search.html +65 -0
  554. hydpy/docs/sphinx/_themes/basic_hydpy/searchbox.html +21 -0
  555. hydpy/docs/sphinx/_themes/basic_hydpy/searchfield.html +23 -0
  556. hydpy/docs/sphinx/_themes/basic_hydpy/sourcelink.html +18 -0
  557. hydpy/docs/sphinx/_themes/basic_hydpy/static/basic.css_t +925 -0
  558. hydpy/docs/sphinx/_themes/basic_hydpy/static/doctools.js +156 -0
  559. hydpy/docs/sphinx/_themes/basic_hydpy/static/documentation_options.js_t +13 -0
  560. hydpy/docs/sphinx/_themes/basic_hydpy/static/file.png +0 -0
  561. hydpy/docs/sphinx/_themes/basic_hydpy/static/language_data.js_t +26 -0
  562. hydpy/docs/sphinx/_themes/basic_hydpy/static/minus.png +0 -0
  563. hydpy/docs/sphinx/_themes/basic_hydpy/static/plus.png +0 -0
  564. hydpy/docs/sphinx/_themes/basic_hydpy/static/searchtools.js +574 -0
  565. hydpy/docs/sphinx/_themes/basic_hydpy/static/sphinx_highlight.js +154 -0
  566. hydpy/docs/sphinx/_themes/basic_hydpy/theme.conf +16 -0
  567. hydpy/docs/sphinx/_themes/classic_hydpy/layout.html +23 -0
  568. hydpy/docs/sphinx/_themes/classic_hydpy/static/classic.css_t +358 -0
  569. hydpy/docs/sphinx/_themes/classic_hydpy/static/sidebar.js_t +72 -0
  570. hydpy/docs/sphinx/_themes/classic_hydpy/theme.conf +32 -0
  571. hydpy/docs/sphinx/conf.py +398 -0
  572. hydpy/docs/sphinx/defaultlinks_extension.py +36 -0
  573. hydpy/docs/sphinx/integrationtest_extension.py +104 -0
  574. hydpy/docs/sphinx/projectstructure_extension.py +58 -0
  575. hydpy/docs/sphinx/submodelgraph_extension.py +53 -0
  576. hydpy/exe/__init__.py +0 -0
  577. hydpy/exe/commandtools.py +651 -0
  578. hydpy/exe/hyd.py +277 -0
  579. hydpy/exe/modelimports.py +41 -0
  580. hydpy/exe/replacetools.py +216 -0
  581. hydpy/exe/servertools.py +2348 -0
  582. hydpy/exe/xmltools.py +3280 -0
  583. hydpy/interfaces/__init__.py +0 -0
  584. hydpy/interfaces/aetinterfaces.py +94 -0
  585. hydpy/interfaces/dischargeinterfaces.py +45 -0
  586. hydpy/interfaces/petinterfaces.py +117 -0
  587. hydpy/interfaces/precipinterfaces.py +42 -0
  588. hydpy/interfaces/radiationinterfaces.py +79 -0
  589. hydpy/interfaces/rconcinterfaces.py +30 -0
  590. hydpy/interfaces/routinginterfaces.py +324 -0
  591. hydpy/interfaces/soilinterfaces.py +96 -0
  592. hydpy/interfaces/stateinterfaces.py +98 -0
  593. hydpy/interfaces/tempinterfaces.py +46 -0
  594. hydpy/models/__init__.py +0 -0
  595. hydpy/models/arma/__init__.py +14 -0
  596. hydpy/models/arma/arma_control.py +383 -0
  597. hydpy/models/arma/arma_derived.py +204 -0
  598. hydpy/models/arma/arma_fluxes.py +41 -0
  599. hydpy/models/arma/arma_inlets.py +11 -0
  600. hydpy/models/arma/arma_logs.py +19 -0
  601. hydpy/models/arma/arma_model.py +461 -0
  602. hydpy/models/arma/arma_outlets.py +11 -0
  603. hydpy/models/arma_rimorido.py +381 -0
  604. hydpy/models/conv/__init__.py +12 -0
  605. hydpy/models/conv/conv_control.py +303 -0
  606. hydpy/models/conv/conv_derived.py +271 -0
  607. hydpy/models/conv/conv_fluxes.py +54 -0
  608. hydpy/models/conv/conv_inlets.py +11 -0
  609. hydpy/models/conv/conv_model.py +687 -0
  610. hydpy/models/conv/conv_outlets.py +11 -0
  611. hydpy/models/conv_idw.py +120 -0
  612. hydpy/models/conv_idw_ed.py +184 -0
  613. hydpy/models/conv_nn.py +112 -0
  614. hydpy/models/dam/__init__.py +16 -0
  615. hydpy/models/dam/dam_aides.py +17 -0
  616. hydpy/models/dam/dam_control.py +346 -0
  617. hydpy/models/dam/dam_derived.py +559 -0
  618. hydpy/models/dam/dam_factors.py +46 -0
  619. hydpy/models/dam/dam_fluxes.py +179 -0
  620. hydpy/models/dam/dam_inlets.py +29 -0
  621. hydpy/models/dam/dam_logs.py +52 -0
  622. hydpy/models/dam/dam_model.py +5011 -0
  623. hydpy/models/dam/dam_outlets.py +23 -0
  624. hydpy/models/dam/dam_receivers.py +41 -0
  625. hydpy/models/dam/dam_senders.py +23 -0
  626. hydpy/models/dam/dam_solver.py +75 -0
  627. hydpy/models/dam/dam_states.py +11 -0
  628. hydpy/models/dam_llake.py +499 -0
  629. hydpy/models/dam_lreservoir.py +548 -0
  630. hydpy/models/dam_lretention.py +343 -0
  631. hydpy/models/dam_pump.py +278 -0
  632. hydpy/models/dam_pump_sluice.py +339 -0
  633. hydpy/models/dam_sluice.py +319 -0
  634. hydpy/models/dam_v001.py +1127 -0
  635. hydpy/models/dam_v002.py +381 -0
  636. hydpy/models/dam_v003.py +422 -0
  637. hydpy/models/dam_v004.py +665 -0
  638. hydpy/models/dam_v005.py +479 -0
  639. hydpy/models/dummy/__init__.py +15 -0
  640. hydpy/models/dummy/dummy_control.py +22 -0
  641. hydpy/models/dummy/dummy_fluxes.py +11 -0
  642. hydpy/models/dummy/dummy_inlets.py +11 -0
  643. hydpy/models/dummy/dummy_inputs.py +41 -0
  644. hydpy/models/dummy/dummy_model.py +196 -0
  645. hydpy/models/dummy/dummy_outlets.py +11 -0
  646. hydpy/models/dummy_interceptedwater.py +85 -0
  647. hydpy/models/dummy_node2node.py +83 -0
  648. hydpy/models/dummy_snowalbedo.py +84 -0
  649. hydpy/models/dummy_snowcover.py +84 -0
  650. hydpy/models/dummy_snowycanopy.py +86 -0
  651. hydpy/models/dummy_soilwater.py +85 -0
  652. hydpy/models/evap/__init__.py +13 -0
  653. hydpy/models/evap/evap_control.py +354 -0
  654. hydpy/models/evap/evap_derived.py +236 -0
  655. hydpy/models/evap/evap_factors.py +188 -0
  656. hydpy/models/evap/evap_fixed.py +68 -0
  657. hydpy/models/evap/evap_fluxes.py +150 -0
  658. hydpy/models/evap/evap_inputs.py +54 -0
  659. hydpy/models/evap/evap_logs.py +91 -0
  660. hydpy/models/evap/evap_masks.py +48 -0
  661. hydpy/models/evap/evap_model.py +9170 -0
  662. hydpy/models/evap/evap_parameters.py +149 -0
  663. hydpy/models/evap/evap_sequences.py +32 -0
  664. hydpy/models/evap/evap_states.py +18 -0
  665. hydpy/models/evap_aet_hbv96.py +372 -0
  666. hydpy/models/evap_aet_minhas.py +331 -0
  667. hydpy/models/evap_aet_morsim.py +627 -0
  668. hydpy/models/evap_pet_ambav1.py +483 -0
  669. hydpy/models/evap_pet_hbv96.py +147 -0
  670. hydpy/models/evap_pet_m.py +94 -0
  671. hydpy/models/evap_pet_mlc.py +107 -0
  672. hydpy/models/evap_ret_fao56.py +265 -0
  673. hydpy/models/evap_ret_io.py +74 -0
  674. hydpy/models/evap_ret_tw2002.py +165 -0
  675. hydpy/models/exch/__init__.py +14 -0
  676. hydpy/models/exch/exch_control.py +262 -0
  677. hydpy/models/exch/exch_derived.py +36 -0
  678. hydpy/models/exch/exch_factors.py +26 -0
  679. hydpy/models/exch/exch_fluxes.py +48 -0
  680. hydpy/models/exch/exch_inlets.py +11 -0
  681. hydpy/models/exch/exch_logs.py +12 -0
  682. hydpy/models/exch/exch_model.py +451 -0
  683. hydpy/models/exch/exch_outlets.py +17 -0
  684. hydpy/models/exch/exch_receivers.py +17 -0
  685. hydpy/models/exch_branch_hbv96.py +186 -0
  686. hydpy/models/exch_waterlevel.py +73 -0
  687. hydpy/models/exch_weir_hbv96.py +609 -0
  688. hydpy/models/ga/__init__.py +14 -0
  689. hydpy/models/ga/ga_aides.py +17 -0
  690. hydpy/models/ga/ga_control.py +208 -0
  691. hydpy/models/ga/ga_derived.py +77 -0
  692. hydpy/models/ga/ga_fluxes.py +83 -0
  693. hydpy/models/ga/ga_inputs.py +26 -0
  694. hydpy/models/ga/ga_logs.py +17 -0
  695. hydpy/models/ga/ga_model.py +2952 -0
  696. hydpy/models/ga/ga_states.py +87 -0
  697. hydpy/models/ga_garto.py +1001 -0
  698. hydpy/models/ga_garto_submodel1.py +79 -0
  699. hydpy/models/gland/__init__.py +14 -0
  700. hydpy/models/gland/gland_control.py +90 -0
  701. hydpy/models/gland/gland_derived.py +113 -0
  702. hydpy/models/gland/gland_fluxes.py +137 -0
  703. hydpy/models/gland/gland_inputs.py +12 -0
  704. hydpy/models/gland/gland_model.py +1439 -0
  705. hydpy/models/gland/gland_outlets.py +11 -0
  706. hydpy/models/gland/gland_states.py +90 -0
  707. hydpy/models/gland_gr4.py +501 -0
  708. hydpy/models/gland_gr5.py +463 -0
  709. hydpy/models/gland_gr6.py +487 -0
  710. hydpy/models/hland/__init__.py +20 -0
  711. hydpy/models/hland/hland_aides.py +19 -0
  712. hydpy/models/hland/hland_constants.py +37 -0
  713. hydpy/models/hland/hland_control.py +1530 -0
  714. hydpy/models/hland/hland_derived.py +683 -0
  715. hydpy/models/hland/hland_factors.py +57 -0
  716. hydpy/models/hland/hland_fixed.py +42 -0
  717. hydpy/models/hland/hland_fluxes.py +279 -0
  718. hydpy/models/hland/hland_inputs.py +19 -0
  719. hydpy/models/hland/hland_masks.py +107 -0
  720. hydpy/models/hland/hland_model.py +4664 -0
  721. hydpy/models/hland/hland_outlets.py +11 -0
  722. hydpy/models/hland/hland_parameters.py +227 -0
  723. hydpy/models/hland/hland_sequences.py +382 -0
  724. hydpy/models/hland/hland_states.py +236 -0
  725. hydpy/models/hland_96.py +1812 -0
  726. hydpy/models/hland_96c.py +1196 -0
  727. hydpy/models/hland_96p.py +1204 -0
  728. hydpy/models/kinw/__init__.py +18 -0
  729. hydpy/models/kinw/kinw_aides.py +306 -0
  730. hydpy/models/kinw/kinw_control.py +270 -0
  731. hydpy/models/kinw/kinw_derived.py +197 -0
  732. hydpy/models/kinw/kinw_fixed.py +33 -0
  733. hydpy/models/kinw/kinw_fluxes.py +37 -0
  734. hydpy/models/kinw/kinw_inlets.py +11 -0
  735. hydpy/models/kinw/kinw_model.py +3026 -0
  736. hydpy/models/kinw/kinw_outlets.py +11 -0
  737. hydpy/models/kinw/kinw_solver.py +45 -0
  738. hydpy/models/kinw/kinw_states.py +17 -0
  739. hydpy/models/kinw_williams.py +1299 -0
  740. hydpy/models/kinw_williams_ext.py +768 -0
  741. hydpy/models/lland/__init__.py +42 -0
  742. hydpy/models/lland/lland_aides.py +38 -0
  743. hydpy/models/lland/lland_constants.py +88 -0
  744. hydpy/models/lland/lland_control.py +1329 -0
  745. hydpy/models/lland/lland_derived.py +380 -0
  746. hydpy/models/lland/lland_factors.py +18 -0
  747. hydpy/models/lland/lland_fixed.py +128 -0
  748. hydpy/models/lland/lland_fluxes.py +626 -0
  749. hydpy/models/lland/lland_inlets.py +12 -0
  750. hydpy/models/lland/lland_inputs.py +33 -0
  751. hydpy/models/lland/lland_logs.py +17 -0
  752. hydpy/models/lland/lland_masks.py +212 -0
  753. hydpy/models/lland/lland_model.py +7690 -0
  754. hydpy/models/lland/lland_outlets.py +12 -0
  755. hydpy/models/lland/lland_parameters.py +195 -0
  756. hydpy/models/lland/lland_sequences.py +67 -0
  757. hydpy/models/lland/lland_states.py +280 -0
  758. hydpy/models/lland_dd.py +2270 -0
  759. hydpy/models/lland_knauf.py +2156 -0
  760. hydpy/models/lland_knauf_ic.py +1920 -0
  761. hydpy/models/meteo/__init__.py +12 -0
  762. hydpy/models/meteo/meteo_control.py +154 -0
  763. hydpy/models/meteo/meteo_derived.py +159 -0
  764. hydpy/models/meteo/meteo_factors.py +88 -0
  765. hydpy/models/meteo/meteo_fixed.py +19 -0
  766. hydpy/models/meteo/meteo_fluxes.py +46 -0
  767. hydpy/models/meteo/meteo_inputs.py +47 -0
  768. hydpy/models/meteo/meteo_logs.py +30 -0
  769. hydpy/models/meteo/meteo_model.py +2904 -0
  770. hydpy/models/meteo/meteo_parameters.py +14 -0
  771. hydpy/models/meteo/meteo_sequences.py +22 -0
  772. hydpy/models/meteo_clear_glob_io.py +77 -0
  773. hydpy/models/meteo_glob_fao56.py +217 -0
  774. hydpy/models/meteo_glob_io.py +68 -0
  775. hydpy/models/meteo_glob_morsim.py +444 -0
  776. hydpy/models/meteo_precip_io.py +76 -0
  777. hydpy/models/meteo_psun_sun_glob_io.py +83 -0
  778. hydpy/models/meteo_sun_fao56.py +188 -0
  779. hydpy/models/meteo_sun_morsim.py +466 -0
  780. hydpy/models/meteo_temp_io.py +76 -0
  781. hydpy/models/musk/__init__.py +15 -0
  782. hydpy/models/musk/musk_control.py +328 -0
  783. hydpy/models/musk/musk_derived.py +32 -0
  784. hydpy/models/musk/musk_factors.py +53 -0
  785. hydpy/models/musk/musk_fluxes.py +24 -0
  786. hydpy/models/musk/musk_inlets.py +11 -0
  787. hydpy/models/musk/musk_masks.py +15 -0
  788. hydpy/models/musk/musk_model.py +838 -0
  789. hydpy/models/musk/musk_outlets.py +11 -0
  790. hydpy/models/musk/musk_sequences.py +88 -0
  791. hydpy/models/musk/musk_solver.py +68 -0
  792. hydpy/models/musk/musk_states.py +64 -0
  793. hydpy/models/musk_classic.py +228 -0
  794. hydpy/models/musk_mct.py +1247 -0
  795. hydpy/models/rconc/__init__.py +12 -0
  796. hydpy/models/rconc/rconc_control.py +473 -0
  797. hydpy/models/rconc/rconc_derived.py +76 -0
  798. hydpy/models/rconc/rconc_fluxes.py +19 -0
  799. hydpy/models/rconc/rconc_logs.py +74 -0
  800. hydpy/models/rconc/rconc_model.py +260 -0
  801. hydpy/models/rconc/rconc_states.py +11 -0
  802. hydpy/models/rconc_nash.py +48 -0
  803. hydpy/models/rconc_uh.py +53 -0
  804. hydpy/models/sw1d/__init__.py +17 -0
  805. hydpy/models/sw1d/sw1d_control.py +356 -0
  806. hydpy/models/sw1d/sw1d_derived.py +85 -0
  807. hydpy/models/sw1d/sw1d_factors.py +78 -0
  808. hydpy/models/sw1d/sw1d_fixed.py +12 -0
  809. hydpy/models/sw1d/sw1d_fluxes.py +55 -0
  810. hydpy/models/sw1d/sw1d_inlets.py +17 -0
  811. hydpy/models/sw1d/sw1d_model.py +3385 -0
  812. hydpy/models/sw1d/sw1d_outlets.py +11 -0
  813. hydpy/models/sw1d/sw1d_receivers.py +11 -0
  814. hydpy/models/sw1d/sw1d_senders.py +11 -0
  815. hydpy/models/sw1d/sw1d_states.py +23 -0
  816. hydpy/models/sw1d_channel.py +2051 -0
  817. hydpy/models/sw1d_gate_out.py +599 -0
  818. hydpy/models/sw1d_lias.py +105 -0
  819. hydpy/models/sw1d_lias_sluice.py +531 -0
  820. hydpy/models/sw1d_network.py +1219 -0
  821. hydpy/models/sw1d_pump.py +448 -0
  822. hydpy/models/sw1d_q_in.py +79 -0
  823. hydpy/models/sw1d_q_out.py +81 -0
  824. hydpy/models/sw1d_storage.py +78 -0
  825. hydpy/models/sw1d_weir_out.py +75 -0
  826. hydpy/models/test/__init__.py +14 -0
  827. hydpy/models/test/test_control.py +28 -0
  828. hydpy/models/test/test_fluxes.py +17 -0
  829. hydpy/models/test/test_model.py +201 -0
  830. hydpy/models/test/test_solver.py +48 -0
  831. hydpy/models/test/test_states.py +17 -0
  832. hydpy/models/test_discontinous.py +46 -0
  833. hydpy/models/test_stiff0d.py +47 -0
  834. hydpy/models/test_stiff1d.py +42 -0
  835. hydpy/models/whmod/__init__.py +21 -0
  836. hydpy/models/whmod/whmod_constants.py +77 -0
  837. hydpy/models/whmod/whmod_control.py +333 -0
  838. hydpy/models/whmod/whmod_derived.py +210 -0
  839. hydpy/models/whmod/whmod_factors.py +9 -0
  840. hydpy/models/whmod/whmod_fluxes.py +105 -0
  841. hydpy/models/whmod/whmod_inputs.py +15 -0
  842. hydpy/models/whmod/whmod_masks.py +178 -0
  843. hydpy/models/whmod/whmod_model.py +2091 -0
  844. hydpy/models/whmod/whmod_parameters.py +155 -0
  845. hydpy/models/whmod/whmod_sequences.py +193 -0
  846. hydpy/models/whmod/whmod_states.py +73 -0
  847. hydpy/models/whmod_rural.py +794 -0
  848. hydpy/models/whmod_urban.py +1011 -0
  849. hydpy/models/wland/__init__.py +43 -0
  850. hydpy/models/wland/wland_aides.py +55 -0
  851. hydpy/models/wland/wland_constants.py +103 -0
  852. hydpy/models/wland/wland_control.py +508 -0
  853. hydpy/models/wland/wland_derived.py +330 -0
  854. hydpy/models/wland/wland_factors.py +11 -0
  855. hydpy/models/wland/wland_fixed.py +12 -0
  856. hydpy/models/wland/wland_fluxes.py +166 -0
  857. hydpy/models/wland/wland_inputs.py +33 -0
  858. hydpy/models/wland/wland_masks.py +54 -0
  859. hydpy/models/wland/wland_model.py +3755 -0
  860. hydpy/models/wland/wland_outlets.py +11 -0
  861. hydpy/models/wland/wland_parameters.py +214 -0
  862. hydpy/models/wland/wland_sequences.py +108 -0
  863. hydpy/models/wland/wland_solver.py +45 -0
  864. hydpy/models/wland/wland_states.py +56 -0
  865. hydpy/models/wland_gd.py +888 -0
  866. hydpy/models/wland_wag.py +1244 -0
  867. hydpy/models/wq/__init__.py +14 -0
  868. hydpy/models/wq/wq_control.py +117 -0
  869. hydpy/models/wq/wq_derived.py +182 -0
  870. hydpy/models/wq/wq_factors.py +79 -0
  871. hydpy/models/wq/wq_fluxes.py +17 -0
  872. hydpy/models/wq/wq_model.py +1889 -0
  873. hydpy/models/wq_trapeze.py +168 -0
  874. hydpy/models/wq_trapeze_strickler.py +101 -0
  875. hydpy/models/wq_walrus.py +57 -0
  876. hydpy/py.typed +0 -0
  877. hydpy/tests/.coveragerc +22 -0
  878. hydpy/tests/__init__.py +0 -0
  879. hydpy/tests/check_consistency.py +32 -0
  880. hydpy/tests/hydpydoctestcustomize.pth +1 -0
  881. hydpy/tests/hydpydoctestcustomize.py +15 -0
  882. hydpy/tests/iotesting/__init__.py +0 -0
  883. hydpy/tests/run_doctests.py +233 -0
  884. hydpy-6.2.dev1.data/scripts/hyd.py +277 -0
  885. hydpy-6.2.dev1.dist-info/LICENSE +165 -0
  886. hydpy-6.2.dev1.dist-info/METADATA +163 -0
  887. hydpy-6.2.dev1.dist-info/RECORD +890 -0
  888. hydpy-6.2.dev1.dist-info/WHEEL +5 -0
  889. hydpy-6.2.dev1.dist-info/licenses_hydpy_installer.txt +42 -0
  890. hydpy-6.2.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2952 @@
1
+ """
2
+ .. _`issue 89`: https://github.com/hydpy-dev/hydpy/issues/89
3
+ """
4
+
5
+ # imports...
6
+ # ...from site-packages
7
+ import numpy
8
+
9
+ # ...from HydPy
10
+ from hydpy.core import importtools
11
+ from hydpy.core import modeltools
12
+ from hydpy.core.typingtools import *
13
+ from hydpy.cythons import modelutils
14
+ from hydpy.interfaces import soilinterfaces
15
+
16
+ # ...from hland
17
+ from hydpy.models.ga import ga_control
18
+ from hydpy.models.ga import ga_derived
19
+ from hydpy.models.ga import ga_inputs
20
+ from hydpy.models.ga import ga_fluxes
21
+ from hydpy.models.ga import ga_states
22
+ from hydpy.models.ga import ga_logs
23
+ from hydpy.models.ga import ga_aides
24
+
25
+
26
+ class Calc_SurfaceWaterSupply_V1(modeltools.Method):
27
+ r"""Take rainfall as the possible supply for infiltration through the soil's
28
+ surface.
29
+
30
+ Basic equation:
31
+ :math:`SurfaceWaterSupply = Rainfall`
32
+
33
+ Example:
34
+
35
+ >>> from hydpy.models.ga import *
36
+ >>> parameterstep()
37
+ >>> nmbsoils(2)
38
+ >>> inputs.rainfall = 2.0
39
+ >>> model.calc_surfacewatersupply_v1()
40
+ >>> fluxes.surfacewatersupply
41
+ surfacewatersupply(2.0, 2.0)
42
+ """
43
+
44
+ CONTROLPARAMETERS = (ga_control.NmbSoils,)
45
+ REQUIREDSEQUENCES = (ga_inputs.Rainfall,)
46
+ RESULTSEQUENCES = (ga_fluxes.SurfaceWaterSupply,)
47
+
48
+ @staticmethod
49
+ def __call__(model: modeltools.Model) -> None:
50
+ con = model.parameters.control.fastaccess
51
+ inp = model.sequences.inputs.fastaccess
52
+ flu = model.sequences.fluxes.fastaccess
53
+
54
+ for s in range(con.nmbsoils):
55
+ flu.surfacewatersupply[s] = inp.rainfall
56
+
57
+
58
+ class Calc_SoilWaterSupply_V1(modeltools.Method):
59
+ r"""Take capillary rise as the possible supply for water additions through the
60
+ soil's bottom.
61
+
62
+ Basic equation:
63
+ :math:`SoilWaterSupply = CapillaryRise`
64
+
65
+ Example:
66
+
67
+ >>> from hydpy.models.ga import *
68
+ >>> parameterstep()
69
+ >>> nmbsoils(2)
70
+ >>> inputs.capillaryrise = 2.0
71
+ >>> model.calc_soilwatersupply_v1()
72
+ >>> fluxes.soilwatersupply
73
+ soilwatersupply(2.0, 2.0)
74
+ """
75
+
76
+ CONTROLPARAMETERS = (ga_control.NmbSoils,)
77
+ REQUIREDSEQUENCES = (ga_inputs.CapillaryRise,)
78
+ RESULTSEQUENCES = (ga_fluxes.SoilWaterSupply,)
79
+
80
+ @staticmethod
81
+ def __call__(model: modeltools.Model) -> None:
82
+ con = model.parameters.control.fastaccess
83
+ inp = model.sequences.inputs.fastaccess
84
+ flu = model.sequences.fluxes.fastaccess
85
+
86
+ for s in range(con.nmbsoils):
87
+ flu.soilwatersupply[s] = inp.capillaryrise
88
+
89
+
90
+ class Calc_Demand_V1(modeltools.Method):
91
+ r"""Take evaporation as the demand for extracting water from the soil's surface and
92
+ body.
93
+
94
+ Basic equation:
95
+ :math:`Demand = Evaporation`
96
+
97
+ Example:
98
+
99
+ >>> from hydpy.models.ga import *
100
+ >>> parameterstep()
101
+ >>> nmbsoils(2)
102
+ >>> inputs.evaporation = 2.0
103
+ >>> model.calc_demand_v1()
104
+ >>> fluxes.demand
105
+ demand(2.0, 2.0)
106
+ """
107
+
108
+ CONTROLPARAMETERS = (ga_control.NmbSoils,)
109
+ REQUIREDSEQUENCES = (ga_inputs.Evaporation,)
110
+ RESULTSEQUENCES = (ga_fluxes.Demand,)
111
+
112
+ @staticmethod
113
+ def __call__(model: modeltools.Model) -> None:
114
+ con = model.parameters.control.fastaccess
115
+ inp = model.sequences.inputs.fastaccess
116
+ flu = model.sequences.fluxes.fastaccess
117
+
118
+ for s in range(con.nmbsoils):
119
+ flu.demand[s] = inp.evaporation
120
+
121
+
122
+ class Return_RelativeMoisture_V1(modeltools.Method):
123
+ r"""Calculate and return the relative soil water content for the given bin-soil
124
+ combination.
125
+
126
+ Basic equation (:cite:t:`ref-Lai2015`, equation 11):
127
+ :math:`RelativeMoisture =
128
+ \frac{FrontMoisture - ResidualMoisture}{SaturationMoisture - ResidualMoisture}`
129
+
130
+ Method |Return_RelativeMoisture_V1| prevents returning values smaller than zero or
131
+ larger than one that might arise due to violations of the residualor saturation
132
+ water content.
133
+
134
+ Examples:
135
+
136
+ >>> from hydpy.models.ga import *
137
+ >>> simulationstep("1h")
138
+ >>> parameterstep("1h")
139
+ >>> nmbsoils(2)
140
+ >>> nmbbins(5)
141
+ >>> residualmoisture(0.1, 0.2)
142
+ >>> saturationmoisture(0.5, 0.8)
143
+ >>> states.moisture = [[0.0, 0.0],
144
+ ... [0.1, 0.2],
145
+ ... [0.3, 0.65],
146
+ ... [0.5, 0.8],
147
+ ... [1.0, 1.0]]
148
+ >>> from hydpy import round_
149
+ >>> for soil in range(2):
150
+ ... for bin_ in range(5):
151
+ ... print(f"soil: {soil}, bin: {bin_} -> relativemoisture ", end="")
152
+ ... round_(model.return_relativemoisture_v1(bin_, soil))
153
+ soil: 0, bin: 0 -> relativemoisture 0.0
154
+ soil: 0, bin: 1 -> relativemoisture 0.0
155
+ soil: 0, bin: 2 -> relativemoisture 0.5
156
+ soil: 0, bin: 3 -> relativemoisture 1.0
157
+ soil: 0, bin: 4 -> relativemoisture 1.0
158
+ soil: 1, bin: 0 -> relativemoisture 0.0
159
+ soil: 1, bin: 1 -> relativemoisture 0.0
160
+ soil: 1, bin: 2 -> relativemoisture 0.75
161
+ soil: 1, bin: 3 -> relativemoisture 1.0
162
+ soil: 1, bin: 4 -> relativemoisture 1.0
163
+ """
164
+
165
+ CONTROLPARAMETERS = (ga_control.ResidualMoisture, ga_control.SaturationMoisture)
166
+ REQUIREDSEQUENCES = (ga_states.Moisture,)
167
+
168
+ @staticmethod
169
+ def __call__(model: modeltools.Model, b: int, s: int) -> float:
170
+ con = model.parameters.control.fastaccess
171
+ sta = model.sequences.states.fastaccess
172
+
173
+ moisture: float = min(sta.moisture[b, s], con.saturationmoisture[s])
174
+ moisture = max(moisture, con.residualmoisture[s])
175
+ return (moisture - con.residualmoisture[s]) / (
176
+ con.saturationmoisture[s] - con.residualmoisture[s]
177
+ )
178
+
179
+
180
+ class Return_Conductivity_V1(modeltools.Method):
181
+ r"""Based on the Brooks-Corey soil moisture characteristic model
182
+ :cite:p:`ref-Brooks1966`, calculate and return the conductivity for the given
183
+ bin-soil combination.
184
+
185
+ Basic equation (:cite:t:`ref-Lai2015`, equation 11):
186
+ :math:`Conductivity = SaturatedConductivity \cdot
187
+ RelativeMoisture^{3 + 2 / PoreSizeDistribution}`
188
+
189
+ Examples:
190
+
191
+ >>> from hydpy.models.ga import *
192
+ >>> simulationstep("1h")
193
+ >>> parameterstep("1h")
194
+ >>> nmbsoils(2)
195
+ >>> nmbbins(3)
196
+ >>> residualmoisture(0.1, 0.2)
197
+ >>> saturationmoisture(0.5, 0.8)
198
+ >>> poresizedistribution(0.3, 0.4)
199
+ >>> saturatedconductivity(10.0, 20.0)
200
+ >>> states.moisture = [[0.1, 0.0],
201
+ ... [0.3, 0.5],
202
+ ... [0.5, 1.0]]
203
+ >>> from hydpy import round_
204
+ >>> for soil in range(2):
205
+ ... for bin_ in range(3):
206
+ ... print(f"soil: {soil}, bin: {bin_} -> conductivity ", end="")
207
+ ... round_(model.return_conductivity_v1(bin_, soil))
208
+ soil: 0, bin: 0 -> conductivity 0.0
209
+ soil: 0, bin: 1 -> conductivity 0.012304
210
+ soil: 0, bin: 2 -> conductivity 10.0
211
+ soil: 1, bin: 0 -> conductivity 0.0
212
+ soil: 1, bin: 1 -> conductivity 0.078125
213
+ soil: 1, bin: 2 -> conductivity 20.0
214
+ """
215
+
216
+ SUBMETHODS = (Return_RelativeMoisture_V1,)
217
+ CONTROLPARAMETERS = (
218
+ ga_control.ResidualMoisture,
219
+ ga_control.SaturationMoisture,
220
+ ga_control.SaturatedConductivity,
221
+ ga_control.PoreSizeDistribution,
222
+ )
223
+ REQUIREDSEQUENCES = (ga_states.Moisture,)
224
+
225
+ @staticmethod
226
+ def __call__(model: modeltools.Model, b: int, s: int) -> float:
227
+ con = model.parameters.control.fastaccess
228
+
229
+ return con.saturatedconductivity[s] * (
230
+ model.return_relativemoisture_v1(b, s)
231
+ ** (3.0 + 2.0 / con.poresizedistribution[s])
232
+ )
233
+
234
+
235
+ class Return_CapillaryDrive_V1(modeltools.Method):
236
+ r"""Based on the Brooks-Corey soil moisture characteristic model
237
+ :cite:p:`ref-Brooks1966`, calculate and return the capillary drive between the
238
+ water contents of the given bins for the defined soil.
239
+
240
+ Basic equation (:cite:t:`ref-Lai2015`, equation 11):
241
+ :math:`CapillaryDrive_{bin1,bin2} =
242
+ \frac{AirEntryPotential}{3 \cdot PoreSizeDistribution + 1} \cdot
243
+ \begin{cases}
244
+ RelativeMoisture_{bin2}^{3 + 1 / PoreSizeDistribution} -
245
+ RelativeMoisture_{bin1}^{3 + 1 / PoreSizeDistribution}
246
+ &|\ Moisture_{bin2} < SaturationMoisture
247
+ \\
248
+ 3 \cdot PoreSizeDistribution + 2 -
249
+ RelativeMoisture_{bin1}^{3 + 1 / PoreSizeDistribution}
250
+ &|\ Moisture_{bin2} = SaturationMoisture
251
+ \end{cases}`
252
+
253
+ Examples:
254
+
255
+ >>> from hydpy.models.ga import *
256
+ >>> simulationstep("1h")
257
+ >>> parameterstep("1h")
258
+ >>> nmbsoils(2)
259
+ >>> nmbbins(3)
260
+ >>> residualmoisture(0.1, 0.2)
261
+ >>> saturationmoisture(0.5, 0.8)
262
+ >>> airentrypotential(0.1, 0.2)
263
+ >>> poresizedistribution(0.3, 0.4)
264
+ >>> saturatedconductivity(10.0, 20.0)
265
+ >>> states.moisture = [[0.1, 0.0],
266
+ ... [0.3, 0.5],
267
+ ... [0.5, 1.0]]
268
+ >>> from hydpy import round_
269
+ >>> for soil in range(2):
270
+ ... for bin_ in range(2):
271
+ ... print(f"soil: {soil}, bin: {bin_} -> capillarydrive ", end="")
272
+ ... round_(model.return_capillarydrive_v1(bin_, bin_ + 1, soil))
273
+ soil: 0, bin: 0 -> capillarydrive 0.000653
274
+ soil: 0, bin: 1 -> capillarydrive 0.151979
275
+ soil: 1, bin: 0 -> capillarydrive 0.002009
276
+ soil: 1, bin: 1 -> capillarydrive 0.2889
277
+ """
278
+
279
+ SUBMETHODS = (Return_RelativeMoisture_V1,)
280
+ CONTROLPARAMETERS = (
281
+ ga_control.ResidualMoisture,
282
+ ga_control.SaturationMoisture,
283
+ ga_control.AirEntryPotential,
284
+ ga_control.PoreSizeDistribution,
285
+ )
286
+ REQUIREDSEQUENCES = (ga_states.Moisture,)
287
+
288
+ @staticmethod
289
+ def __call__(model: modeltools.Model, b1: int, b2: int, s: int) -> float:
290
+ con = model.parameters.control.fastaccess
291
+ sta = model.sequences.states.fastaccess
292
+
293
+ exp: float = 1.0 / con.poresizedistribution[s] + 3.0
294
+ if sta.moisture[b2, s] < con.saturationmoisture[s]:
295
+ subtrahend: float = model.return_relativemoisture_v1(b2, s) ** exp
296
+ else:
297
+ subtrahend = 3.0 * con.poresizedistribution[s] + 2.0
298
+ return (
299
+ con.airentrypotential[s]
300
+ * (subtrahend - model.return_relativemoisture_v1(b1, s) ** exp)
301
+ / (3.0 * con.poresizedistribution[s] + 1.0)
302
+ )
303
+
304
+
305
+ class Percolate_FilledBin_V1(modeltools.Method):
306
+ r"""Calculate the percolation of water through the filled first bin due to
307
+ gravitational forcing.
308
+
309
+ Basic equation:
310
+ :math:`Percolation = DT \cdot Conductivity`
311
+
312
+ Example:
313
+
314
+ For simplicity, we make each soil compartment's first (and only) bin saturated
315
+ so that actual conductivity equals saturated conductivity:
316
+
317
+ >>> from hydpy.models.ga import *
318
+ >>> simulationstep("1h")
319
+ >>> parameterstep("1h")
320
+ >>> nmbsoils(3)
321
+ >>> nmbbins(2)
322
+ >>> dt(0.5)
323
+ >>> soildepth(100.0, 200.0, 300.0)
324
+ >>> residualmoisture(0.1)
325
+ >>> saturationmoisture(0.5)
326
+ >>> poresizedistribution(0.3)
327
+ >>> saturatedconductivity(6.0, 8.0, 10.0)
328
+ >>> states.moisture = 0.5
329
+ >>> aides.actualsurfacewater = 2.0, 4.0, 6.0
330
+ >>> fluxes.percolation = 1.0
331
+ >>> for soil in range(3):
332
+ ... model.percolate_filledbin_v1(soil)
333
+ >>> aides.actualsurfacewater
334
+ actualsurfacewater(0.0, 0.0, 1.0)
335
+ >>> fluxes.percolation
336
+ percolation(3.0, 5.0, 6.0)
337
+
338
+ By the way, |Percolate_FilledBin_V1| sets the first bin's front depth to the
339
+ respective soil compartment's depth:
340
+
341
+ >>> states.frontdepth
342
+ frontdepth([[100.0, 200.0, 300.0],
343
+ [nan, nan, nan]])
344
+ """
345
+
346
+ SUBMETHODS = (Return_RelativeMoisture_V1, Return_Conductivity_V1)
347
+ CONTROLPARAMETERS = (
348
+ ga_control.DT,
349
+ ga_control.SoilDepth,
350
+ ga_control.ResidualMoisture,
351
+ ga_control.SaturationMoisture,
352
+ ga_control.SaturatedConductivity,
353
+ ga_control.PoreSizeDistribution,
354
+ )
355
+ REQUIREDSEQUENCES = (ga_states.Moisture,)
356
+ UPDATEDSEQUENCES = (
357
+ ga_states.FrontDepth,
358
+ ga_aides.ActualSurfaceWater,
359
+ ga_fluxes.Percolation,
360
+ )
361
+
362
+ @staticmethod
363
+ def __call__(model: modeltools.Model, s: int) -> None:
364
+ con = model.parameters.control.fastaccess
365
+ flu = model.sequences.fluxes.fastaccess
366
+ sta = model.sequences.states.fastaccess
367
+ aid = model.sequences.aides.fastaccess
368
+
369
+ sta.frontdepth[0, s] = con.soildepth[s]
370
+ potinfiltration: float = con.dt * model.return_conductivity_v1(0, s)
371
+ if potinfiltration < aid.actualsurfacewater[s]:
372
+ aid.actualsurfacewater[s] -= potinfiltration
373
+ flu.percolation[s] += potinfiltration
374
+ else:
375
+ flu.percolation[s] += aid.actualsurfacewater[s]
376
+ aid.actualsurfacewater[s] = 0.0
377
+
378
+
379
+ class Return_DryDepth_V1(modeltools.Method):
380
+ r"""Calculate and return the "dry depth".
381
+
382
+ Basic equations (:cite:t:`ref-Lai2015`, equation 7, modified, see `issue 89`_):
383
+ :math:`
384
+ \frac{\tau + \sqrt{\tau^2 + 4 \cdot \tau \cdot EffectiveCapillarySuction}}{2}`
385
+
386
+ :math:`
387
+ \tau = DT \cdot \frac{SaturatedConductivity}{SaturationMoisture - FrontMoisture}`
388
+
389
+ Example:
390
+
391
+ >>> from hydpy.models.ga import *
392
+ >>> simulationstep("1h")
393
+ >>> parameterstep("1h")
394
+ >>> nmbsoils(3)
395
+ >>> nmbbins(2)
396
+ >>> dt(0.5)
397
+ >>> residualmoisture(0.1, 0.2, 0.2)
398
+ >>> saturationmoisture(0.5, 0.8, 0.8)
399
+ >>> poresizedistribution(0.3, 0.4, 0.4)
400
+ >>> saturatedconductivity(10.0, 20.0, 20.0)
401
+ >>> airentrypotential(0.1, 0.2, 0.2)
402
+ >>> derived.effectivecapillarysuction.update()
403
+ >>> states.moisture = [[0.3, 0.5, 0.8], [nan, nan, nan]]
404
+ >>> from hydpy import round_
405
+ >>> for soil in range(3):
406
+ ... round_(model.return_drydepth_v1(soil))
407
+ 25.151711
408
+ 33.621747
409
+ inf
410
+ """
411
+
412
+ CONTROLPARAMETERS = (
413
+ ga_control.DT,
414
+ ga_control.SaturationMoisture,
415
+ ga_control.SaturatedConductivity,
416
+ )
417
+ DERIVEDPARAMETERS = (ga_derived.EffectiveCapillarySuction,)
418
+ REQUIREDSEQUENCES = (ga_states.Moisture,)
419
+
420
+ @staticmethod
421
+ def __call__(model: modeltools.Model, s: int) -> float:
422
+ con = model.parameters.control.fastaccess
423
+ der = model.parameters.derived.fastaccess
424
+ sta = model.sequences.states.fastaccess
425
+
426
+ if sta.moisture[0, s] < con.saturationmoisture[s]:
427
+ tau: float = (
428
+ con.dt
429
+ * con.saturatedconductivity[s]
430
+ / (con.saturationmoisture[s] - sta.moisture[0, s])
431
+ )
432
+ return 0.5 * (
433
+ tau + (tau**2 + 4.0 * tau * der.effectivecapillarysuction[s]) ** 0.5
434
+ )
435
+ return modelutils.inf
436
+
437
+
438
+ class Return_LastActiveBin_V1(modeltools.Method):
439
+ r"""Find the index of the last active bin (that either contains a wetting front or
440
+ uniform moisture over the complete soil depth).
441
+
442
+ Example:
443
+
444
+ >>> from hydpy.models.ga import *
445
+ >>> simulationstep("1h")
446
+ >>> parameterstep("1h")
447
+ >>> nmbsoils(3)
448
+ >>> nmbbins(3)
449
+ >>> states.moisture = [[0.1, 0.1, 0.1],
450
+ ... [0.1, 0.5, 0.5],
451
+ ... [0.1, 1.0, 0.1]]
452
+ >>> for soil in range(3):
453
+ ... print(f"soil: {soil} -> bin: {model.return_lastactivebin_v1(soil)}")
454
+ soil: 0 -> bin: 0
455
+ soil: 1 -> bin: 2
456
+ soil: 2 -> bin: 1
457
+ """
458
+
459
+ CONTROLPARAMETERS = (ga_control.NmbBins,)
460
+ REQUIREDSEQUENCES = (ga_states.Moisture,)
461
+
462
+ @staticmethod
463
+ def __call__(model: modeltools.Model, s: int) -> int:
464
+ con = model.parameters.control.fastaccess
465
+ sta = model.sequences.states.fastaccess
466
+
467
+ for b in range(con.nmbbins - 1, 0, -1):
468
+ if sta.moisture[b, s] > sta.moisture[0, s]:
469
+ return b
470
+ return 0
471
+
472
+
473
+ class Active_Bin_V1(modeltools.Method):
474
+ r"""Activate a bin to the right of the bin with the given index.
475
+
476
+ We need to activate another bin if the current last bin's moisture decreases and
477
+ rainfall intensity exceeds saturated conductivity.
478
+
479
+ Basic equations (related to :cite:t:`ref-Lai2015`):
480
+ :math:`MoistureChange_{bin+1} =
481
+ \frac{ActualSurfaceWater - DT \cdot 2 \cdot Conductivity_{bin}}{DryDepth}`
482
+
483
+ :math:`Moisture_{bin+1} = Moisture_{bin} + MoistureChange_{bin+1}`
484
+
485
+ :math:`Infiltration_{bin+1} = DT \cdot SaturatedConductivity \cdot
486
+ \left( \frac{EffectiveCapillarySuction}{DryDepth} + 1 \right)`
487
+
488
+ :math:`FrontDepth_{bin+1} = \frac{Infiltration_{bin+1}}{MoistureChange_{bin+1}}`
489
+
490
+ The calculation of infiltration and the new front depth follows equation 4 of
491
+ :cite:t:`ref-Lai2015`, except for using :math:`Moisture_{bin}` instead of
492
+ :math:`ResidualMoisture` and :math:`Moisture_{bin+1}` instead of
493
+ :math:`SaturationMoisture`. Regarding the moisture change, :cite:t:`ref-Lai2015`
494
+ does not seem to mention the given basic equation explicitly.
495
+
496
+ Examples:
497
+
498
+ Method |Active_Bin_V1| is a little complicated, so we perform multiple test
499
+ calculations considering different special cases. We use the following setting
500
+ for all these test calculations.
501
+
502
+ >>> from hydpy.models.ga_garto import *
503
+ >>> simulationstep("1h")
504
+ >>> parameterstep("1h")
505
+ >>> nmbsoils(1)
506
+ >>> nmbbins(3)
507
+ >>> dt(0.25)
508
+ >>> sealed(False)
509
+ >>> soilarea(1.0)
510
+ >>> soildepth(1000.0)
511
+ >>> residualmoisture(0.1)
512
+ >>> saturationmoisture(0.5)
513
+ >>> airentrypotential(0.1)
514
+ >>> poresizedistribution(0.3)
515
+ >>> saturatedconductivity(10.0)
516
+ >>> derived.soilareafraction.update()
517
+ >>> derived.effectivecapillarysuction.update()
518
+
519
+ We define a test function that applies |Active_Bin_V1| for a definable initial
520
+ surface water depth. The function checks that the water volume remains
521
+ unchanged, prints the moisture change, the resulting moisture state, and the
522
+ depth of the new active front (as calculated by |Active_Bin_V1|), and
523
+ additionally prints the related infiltration (which |Active_Bin_V1| does not
524
+ calculate on its own):
525
+
526
+ >>> from hydpy.core.objecttools import repr_, repr_values
527
+ >>> def check(actualsurfacewater):
528
+ ... states.moisture = [[0.1], [0.3], [0.1]]
529
+ ... states.frontdepth = [[1000.0], [500.0], [0.0]]
530
+ ... logs.moisturechange = [[nan], [-inf], [nan]]
531
+ ... aides.actualsurfacewater = actualsurfacewater
532
+ ... old_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
533
+ ... model.active_bin_v1(1, 0)
534
+ ... new_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
535
+ ... assert old_volume == new_volume
536
+ ... infiltration = actualsurfacewater - aides.actualsurfacewater[0]
537
+ ... print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
538
+ ... print(f"moisture: {repr_values(states.moisture[:, 0])}")
539
+ ... print(f"infiltration: {repr_(infiltration)}")
540
+ ... print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
541
+
542
+ The first example deals with a moderate rainfall intensity (a relatively small
543
+ surface water depth), where everything works as described by the basic
544
+ equations defined above:
545
+
546
+ >>> check(actualsurfacewater=1.0)
547
+ moisturechange: nan, -inf, 0.155311
548
+ moisture: 0.1, 0.3, 0.455311
549
+ infiltration: 1.0
550
+ frontdepth: 1000.0, 500.0, 6.438686
551
+
552
+ For high rainfall intensities, the calculated moisture change could result in
553
+ the actual moisture exceeding the saturation moisture. In such cases,
554
+ |Active_Bin_V1| corrects the moisture but leaves the moisture change as is:
555
+
556
+ ToDo: clip the moisture change?
557
+
558
+ >>> check(actualsurfacewater=5.0)
559
+ moisturechange: nan, -inf, 0.780401
560
+ moisture: 0.1, 0.3, 0.5
561
+ infiltration: 2.55963
562
+ frontdepth: 1000.0, 500.0, 12.798152
563
+
564
+ A particularity of method |Active_Bin_V1| is to set the moisture change to its
565
+ highest possible value if the original moisture change (following the basic
566
+ equation) is negative. Such situations can arise when the pre-existing active
567
+ fronts have already infiltrated a significant amount of the rainfall available
568
+ for the given numerical timestep:
569
+
570
+ ToDo: set the moisture change to zero?
571
+
572
+ >>> check(actualsurfacewater=0.001)
573
+ moisturechange: nan, -inf, 0.2
574
+ moisture: 0.1, 0.3, 0.5
575
+ infiltration: 0.001
576
+ frontdepth: 1000.0, 500.0, 0.005
577
+
578
+
579
+ Even for zero remaining surface water, |Active_Bin_V1| activates a bin and sets
580
+ its moisture value to the saturation value (without calculating any
581
+ infiltration):
582
+
583
+ >>> check(actualsurfacewater=0.0)
584
+ moisturechange: nan, -inf, 0.2
585
+ moisture: 0.1, 0.3, 0.5
586
+ infiltration: 0.0
587
+ frontdepth: 1000.0, 500.0, 0.0
588
+
589
+ A very special case is when the initially calculated moisture change (following
590
+ the basic equation) is zero. Only then, |Active_Bin_V1| refrains from
591
+ activating another bin:
592
+
593
+ |Active_Bin_V1| checks if the initially calculated moisture change (following
594
+ the basic equation) is zero. Only then does it refrain from activating another
595
+ bin:
596
+
597
+ >>> actualsurfacewater=control.dt * 2.0 * model.return_conductivity_v1(1, 0)
598
+ >>> check(actualsurfacewater=actualsurfacewater)
599
+ moisturechange: nan, -inf, 0.0
600
+ moisture: 0.1, 0.3, 0.1
601
+ infiltration: 0.0
602
+ frontdepth: 1000.0, 500.0, 0.0
603
+
604
+ The following two examples illustrate highly deviating ways of front activation
605
+ around the "zero moisture change" case (the second example also shows that
606
+ infiltration becomes restricted when the front depth would otherwise overshoot
607
+ the soil depth):
608
+
609
+ >>> check(actualsurfacewater=actualsurfacewater-1e-5)
610
+ moisturechange: nan, -inf, 0.2
611
+ moisture: 0.1, 0.3, 0.5
612
+ infiltration: 0.006142
613
+ frontdepth: 1000.0, 500.0, 0.03071
614
+
615
+ >>> check(actualsurfacewater=actualsurfacewater+1e-5)
616
+ moisturechange: nan, -inf, 0.000002
617
+ moisture: 0.1, 0.3, 0.300002
618
+ infiltration: 0.001563
619
+ frontdepth: 1000.0, 500.0, 1000.0
620
+ """
621
+
622
+ CONTROLPARAMETERS = (
623
+ ga_control.DT,
624
+ ga_control.SoilDepth,
625
+ ga_control.SaturationMoisture,
626
+ ga_control.SaturatedConductivity,
627
+ )
628
+ DERIVEDPARAMETERS = (ga_derived.EffectiveCapillarySuction,)
629
+ UPDATEDSEQUENCES = (
630
+ ga_states.Moisture,
631
+ ga_states.FrontDepth,
632
+ ga_logs.MoistureChange,
633
+ ga_aides.ActualSurfaceWater,
634
+ )
635
+
636
+ @staticmethod
637
+ def __call__(model: modeltools.Model, b: int, s: int) -> None:
638
+ con = model.parameters.control.fastaccess
639
+ der = model.parameters.derived.fastaccess
640
+ sta = model.sequences.states.fastaccess
641
+ log = model.sequences.logs.fastaccess
642
+ aid = model.sequences.aides.fastaccess
643
+
644
+ drydepth: float = model.return_drydepth_v1(s)
645
+ conductivity: float = model.return_conductivity_v1(b, s)
646
+ log.moisturechange[b + 1, s] = (
647
+ aid.actualsurfacewater[s] - con.dt * 2.0 * conductivity
648
+ ) / drydepth
649
+ if log.moisturechange[b + 1, s] < 0.0:
650
+ log.moisturechange[b + 1, s] = (
651
+ con.saturationmoisture[s] - sta.moisture[b, s]
652
+ )
653
+ if log.moisturechange[b + 1, s] > 0.0:
654
+ sta.moisture[b + 1, s] = min(
655
+ sta.moisture[b, s] + log.moisturechange[b + 1, s],
656
+ con.saturationmoisture[s],
657
+ )
658
+ deltamoisture: float = sta.moisture[b + 1, s] - sta.moisture[b, s]
659
+ potinfiltration: float = min(
660
+ con.dt
661
+ * con.saturatedconductivity[s]
662
+ * (der.effectivecapillarysuction[s] / drydepth + 1.0),
663
+ con.soildepth[s] * deltamoisture,
664
+ )
665
+ if aid.actualsurfacewater[s] > potinfiltration:
666
+ sta.frontdepth[b + 1, s] = potinfiltration / deltamoisture
667
+ aid.actualsurfacewater[s] -= potinfiltration
668
+ else:
669
+ sta.frontdepth[b + 1, s] = aid.actualsurfacewater[s] / deltamoisture
670
+ aid.actualsurfacewater[s] = 0.0
671
+
672
+
673
+ class Shift_Front_V1(modeltools.Method):
674
+ r"""Increase the selected bin's wetting front depth without modifying its relative
675
+ moisture following a variation of the Talbot-Ogden equation
676
+ :cite:p:`ref-Talbot2008`.
677
+
678
+ Method |Shift_Front_V1| applies for active wetting front bins that are not the last
679
+ active bin or that are saturated (|Moisture| equals |SaturationMoisture|). The
680
+ latter holds only for periods with rainfall intensity exceeding saturated
681
+ conductivity.
682
+
683
+ Basic equation (:cite:t:`ref-Lai2015`, equation 8, modified):
684
+ :math:`FrontDepth_{bin, new} = FrontDepth_{bin, old} + DT \cdot
685
+ \frac{Conductivity_{bin-1} - Conductivity_{bin}}
686
+ {Moisture_{bin} - Moisture_{bin-1}} \cdot \left(1 +
687
+ \frac{CapillaryDrive_{0, LastActiveBin} + InitialSurfaceWater}{FrontDepth_{bin}}
688
+ \right)`
689
+
690
+ Note the used equation deviates from equation 8 of :cite:t:`ref-Lai2015` in adding
691
+ the initial surface water depth to the effective capillary drive, which increases
692
+ infiltration. Using |InitialSurfaceWater| instead of |ActualSurfaceWater| assures
693
+ the bin processing order does not affect the individual infiltration rates.
694
+
695
+ Examples:
696
+
697
+ For comparison, we perform the following examples similar to those of method
698
+ |Active_Bin_V1|. The general setting is identical, except that we initialise
699
+ one more bin:
700
+
701
+ >>> from hydpy.models.ga_garto import *
702
+ >>> simulationstep("1h")
703
+ >>> parameterstep("1h")
704
+ >>> nmbsoils(1)
705
+ >>> nmbbins(4)
706
+ >>> dt(0.25)
707
+ >>> sealed(False)
708
+ >>> soilarea(1.0)
709
+ >>> soildepth(1000.0)
710
+ >>> residualmoisture(0.1)
711
+ >>> saturationmoisture(0.5)
712
+ >>> airentrypotential(0.1)
713
+ >>> poresizedistribution(0.3)
714
+ >>> saturatedconductivity(10.0)
715
+ >>> derived.soilareafraction.update()
716
+ >>> derived.effectivecapillarysuction.update()
717
+
718
+ The test function also behaves similarly but allows for more modifications
719
+ of the initial states, supports selecting the considered bin, and applies
720
+ |Shift_Front_V1| instead of |Active_Bin_V1|:
721
+
722
+ >>> from hydpy.core.objecttools import repr_, repr_values
723
+ >>> def check(
724
+ ... bin_, initialsurfacewater, actualsurfacewater, frontdepth, moisture
725
+ ... ):
726
+ ... states.moisture = [[m] for m in moisture]
727
+ ... states.frontdepth = [[fd] for fd in frontdepth]
728
+ ... logs.moisturechange = nan
729
+ ... aides.initialsurfacewater = initialsurfacewater
730
+ ... aides.actualsurfacewater = actualsurfacewater
731
+ ... old_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
732
+ ... model.shift_front_v1(bin_, 0)
733
+ ... new_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
734
+ ... assert old_volume == new_volume
735
+ ... infiltration = actualsurfacewater - aides.actualsurfacewater[0]
736
+ ... print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
737
+ ... print(f"moisture: {repr_values(states.moisture[:, 0])}")
738
+ ... print(f"infiltration: {repr_(infiltration)}")
739
+ ... print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
740
+
741
+ |Shift_Front_V1| is to be applied on non-last active wetting front bins and the
742
+ last bin if it is saturated. We start with demonstrating its functionality for
743
+ the latter case.
744
+
745
+ The first example is standard so far that the given basic equation applies
746
+ without additional restrictions and initial and actual surface water depths are
747
+ identical. 2.75 mm of the available surface water infiltrate and shift the
748
+ wetting front by about 13.75 mm:
749
+
750
+ >>> check(bin_=2, initialsurfacewater=10.0, actualsurfacewater=10.0,
751
+ ... frontdepth=[1000.0, 500.0, 100.0, 0.0],
752
+ ... moisture=[0.1, 0.3, 0.5, 0.1])
753
+ moisturechange: nan, nan, nan, nan
754
+ moisture: 0.1, 0.3, 0.5, 0.1
755
+ infiltration: 2.750428
756
+ frontdepth: 1000.0, 500.0, 113.752138, 0.0
757
+
758
+ Next, we decrease the amount of available surface water to 1 mm but let the
759
+ initial surface water depth at 10 mm. Thus, the potential infiltration stays
760
+ as is, but the actual infiltration reduces to 1 mm (and the front shift to
761
+ 5 mm):
762
+
763
+ >>> check(bin_=2, initialsurfacewater=10.0, actualsurfacewater=1.0,
764
+ ... frontdepth=[1000.0, 500.0, 100.0, 0.0],
765
+ ... moisture=[0.1, 0.3, 0.5, 0.1])
766
+ moisturechange: nan, nan, nan, nan
767
+ moisture: 0.1, 0.3, 0.5, 0.1
768
+ infiltration: 1.0
769
+ frontdepth: 1000.0, 500.0, 105.0, 0.0
770
+
771
+ For small or zero initial front depths, |Shift_Front_V1| uses the method
772
+ |Return_DryDepth_V1| to advance the front instead of the basic equation:
773
+
774
+ >>> from hydpy import round_
775
+ >>> round_(model.return_drydepth_v1(0))
776
+ 6.399076
777
+ >>> check(bin_=2, initialsurfacewater=10.0, actualsurfacewater=10.0,
778
+ ... frontdepth=[1000.0, 500.0, 0.0, 0.0],
779
+ ... moisture=[0.1, 0.3, 0.5, 0.1])
780
+ moisturechange: nan, nan, nan, nan
781
+ moisture: 0.1, 0.3, 0.5, 0.1
782
+ infiltration: 1.279815
783
+ frontdepth: 1000.0, 500.0, 6.399076, 0.0
784
+
785
+ |Shift_Front_V1| prevents a wetting front from overshooting the soil depth but
786
+ not the depth of other fronts:
787
+
788
+ >>> check(bin_=2, initialsurfacewater=10.0, actualsurfacewater=10.0,
789
+ ... frontdepth=[1000.0, 999.0, 998.0, 0.0],
790
+ ... moisture=[0.1, 0.3, 0.5, 0.1])
791
+ moisturechange: nan, nan, nan, nan
792
+ moisture: 0.1, 0.3, 0.5, 0.1
793
+ infiltration: 0.4
794
+ frontdepth: 1000.0, 999.0, 1000.0, 0.0
795
+
796
+ In principle, |Shift_Front_V1| works for the active, non-last bins as described
797
+ above:
798
+
799
+ >>> check(bin_=1, initialsurfacewater=10.0, actualsurfacewater=1.0,
800
+ ... frontdepth=[1000.0, 300.0, 200.0, 100.0],
801
+ ... moisture=[0.2, 0.3, 0.4, 0.5])
802
+ moisturechange: nan, nan, nan, nan
803
+ moisture: 0.2, 0.3, 0.4, 0.5
804
+ infiltration: 0.003176
805
+ frontdepth: 1000.0, 300.031762, 200.0, 100.0
806
+
807
+ However, for these bins, it also applies to rain-free periods. Then, its front
808
+ shifts as usual while keeping its relative moisture. As the considered bin
809
+ cannot (completely) take the corrensponding absolute moisture decrease from the
810
+ surface, it takes water from the last active bin instead, decreasing its depth
811
+ but not its relative moisture:
812
+
813
+ >>> check(bin_=1, initialsurfacewater=0.0, actualsurfacewater=0.0,
814
+ ... frontdepth=[1000.0, 300.0, 200.0, 100.0],
815
+ ... moisture=[0.2, 0.3, 0.4, 0.5])
816
+ moisturechange: nan, nan, nan, nan
817
+ moisture: 0.2, 0.3, 0.4, 0.5
818
+ infiltration: 0.0
819
+ frontdepth: 1000.0, 300.030738, 200.0, 99.969262
820
+
821
+ If the last active bin does not contain enough water, the second-last bin must
822
+ help out:
823
+
824
+ >>> check(bin_=1, initialsurfacewater=0.0, actualsurfacewater=0.0,
825
+ ... frontdepth=[1000.0, 300.0, 200.0, 0.01],
826
+ ... moisture=[0.2, 0.3, 0.4, 0.5])
827
+ moisturechange: nan, nan, nan, 0.0
828
+ moisture: 0.2, 0.3, 0.4, 0.2
829
+ infiltration: 0.0
830
+ frontdepth: 1000.0, 300.030738, 199.979262, 0.0
831
+
832
+ If all bins that possess higher relative moisture than the considered bin do
833
+ not contain enough water, the shift of the wetting front becomes restricted:
834
+
835
+ >>> check(bin_=1, initialsurfacewater=0.0, actualsurfacewater=0.0,
836
+ ... frontdepth=[1000.0, 300.0, 0.02, 0.01],
837
+ ... moisture=[0.2, 0.3, 0.4, 0.5])
838
+ moisturechange: nan, nan, 0.0, 0.0
839
+ moisture: 0.2, 0.3, 0.2, 0.2
840
+ infiltration: 0.0
841
+ frontdepth: 1000.0, 300.03, 0.0, 0.0
842
+
843
+ All examples above show that |Shift_Front_V1| never modifies |MoistureChange|,
844
+ except when deactivating a bin. Then, it sets the moisture change to zero.
845
+ """
846
+
847
+ SUBMETHODS = (
848
+ Return_RelativeMoisture_V1,
849
+ Return_LastActiveBin_V1,
850
+ Return_DryDepth_V1,
851
+ Return_Conductivity_V1,
852
+ Return_CapillaryDrive_V1,
853
+ )
854
+ CONTROLPARAMETERS = (
855
+ ga_control.DT,
856
+ ga_control.NmbBins,
857
+ ga_control.SoilDepth,
858
+ ga_control.ResidualMoisture,
859
+ ga_control.SaturationMoisture,
860
+ ga_control.SaturatedConductivity,
861
+ ga_control.AirEntryPotential,
862
+ ga_control.PoreSizeDistribution,
863
+ )
864
+ DERIVEDPARAMETERS = (ga_derived.EffectiveCapillarySuction,)
865
+ REQUIREDSEQUENCES = (ga_aides.InitialSurfaceWater,)
866
+ UPDATEDSEQUENCES = (
867
+ ga_states.Moisture,
868
+ ga_states.FrontDepth,
869
+ ga_logs.MoistureChange,
870
+ ga_aides.ActualSurfaceWater,
871
+ )
872
+
873
+ @staticmethod
874
+ def __call__(model: modeltools.Model, b: int, s: int) -> None:
875
+ con = model.parameters.control.fastaccess
876
+ sta = model.sequences.states.fastaccess
877
+ aid = model.sequences.aides.fastaccess
878
+ log = model.sequences.logs.fastaccess
879
+
880
+ b_last = model.return_lastactivebin_v1(s)
881
+ drydepth: float = model.return_drydepth_v1(s)
882
+ if sta.frontdepth[b, s] < drydepth:
883
+ frontshift: float = drydepth
884
+ else:
885
+ cond1: float = model.return_conductivity_v1(b - 1, s)
886
+ cond2: float = model.return_conductivity_v1(b, s)
887
+ drive: float = model.return_capillarydrive_v1(0, b_last, s)
888
+ frontshift = (
889
+ con.dt * (cond2 - cond1) / (sta.moisture[b, s] - sta.moisture[b - 1, s])
890
+ ) * (1.0 + (drive + aid.initialsurfacewater[s]) / sta.frontdepth[b, s])
891
+ frontshift = min(frontshift, con.soildepth[s] - sta.frontdepth[b, s])
892
+
893
+ deltamoisture_b: float = sta.moisture[b, s] - sta.moisture[b - 1, s]
894
+ required: float = frontshift * deltamoisture_b
895
+ if required < aid.actualsurfacewater[s]:
896
+ sta.frontdepth[b, s] += frontshift
897
+ aid.actualsurfacewater[s] -= required
898
+ else:
899
+ required -= aid.actualsurfacewater[s]
900
+ sta.frontdepth[b, s] += aid.actualsurfacewater[s] / deltamoisture_b
901
+ aid.actualsurfacewater[s] = 0.0
902
+ for b_last in range(b_last, b, -1):
903
+ deltamoisture_bb: float = (
904
+ sta.moisture[b_last, s] - sta.moisture[b_last - 1, s]
905
+ )
906
+ available: float = deltamoisture_bb * sta.frontdepth[b_last, s]
907
+ if available < required:
908
+ required -= available
909
+ sta.frontdepth[b, s] += available / deltamoisture_b
910
+ sta.frontdepth[b_last, s] = 0.0
911
+ sta.moisture[b_last, s] = sta.moisture[0, s]
912
+ log.moisturechange[b_last, s] = 0.0
913
+ else:
914
+ sta.frontdepth[b_last, s] -= required / deltamoisture_bb
915
+ sta.frontdepth[b, s] += required / deltamoisture_b
916
+ break
917
+
918
+
919
+ class Redistribute_Front_V1(modeltools.Method):
920
+ r"""Modify the selected bin's wetting front depth and relative moisture content
921
+ based on a Green & Ampt redistribution equation.
922
+
923
+ |Redistribute_Front_V1| applies for the last active wetting front bin when rainfall
924
+ intensity does not exceed saturated conductivity.
925
+
926
+ Basic equations (:cite:t:`ref-Lai2015`, equation 6)
927
+ :math:`p = \cases{1.7 &| ActualSurfaceWater = 0 \\ 1.0 &| ActualSurfaceWater > 0}`
928
+
929
+ :math:`MoistureChange_{bin} = \frac{1}{FrontDepth_{bin}} \cdot
930
+ \left( ActualSurfaceWater - DT \cdot \left( Conductivity_{bin} -
931
+ \frac{p \cdot SaturatedConductivity \cdot CapillaryDrive_{bin-1,bin}}
932
+ {FrontDepth_{bin}} \right) \right)`
933
+
934
+ :math:`Moisture_{bin,old} = Moisture_{bin,new} + MoistureChange_{bin}`
935
+
936
+ :math:`Infiltration_{bin} = DT \cdot SaturatedConductivity \cdot
937
+ \left( 1 + \frac{EffectiveCapillarySuction}{FrontDepth_{bin}} \right)`
938
+
939
+ :math:`FrontDepth_{bin,new} = \frac{Infiltration_{bin} +
940
+ FrontDepth_{bin,old} \cdot (Moisture_{bin,old} - Moisture_{bin-1})}
941
+ {Moisture_{bin,new} - Moisture_{bin-1}}`
942
+
943
+ :cite:t:`ref-Lai2015` define only the calculation of the moisture change
944
+ explicitly. The infiltration calculation and the corresponding shift of the
945
+ wetting front depth rest on the GARTO source code provided by the authors. One
946
+ might have expected to use :math:`Conductivity_{bin}` and
947
+ :math:`CapillaryDrive_{bin-1,bin}` instead of :math:`SaturatedConductivity` and
948
+ :math:`EffectiveCapillarySuction`. There is a remark of the authors (possibly
949
+ concerning the :math:`CapillaryDrive_{bin-1,bin}` vs
950
+ :math:`EffectiveCapillarySuction` issue only) that oscillations in infiltration
951
+ rates might show up otherwise. Maybe we can discuss this with the authors or
952
+ investigate ourselves in more detail later.
953
+
954
+ If the bin's initial front depth is zero, the basic equations for calculating
955
+ moisture change and infiltration become obsolete. |Redistribute_Front_V1| then
956
+ proceeds as follows:
957
+
958
+ :math:`MoistureChange_{bin} =
959
+ (ActualSurfaceWater - DT \cdot Conductivity_{bin-1}) / DryDepth`
960
+
961
+ :math:`Infiltration_{bin} = DT \cdot SaturatedConductivity \cdot
962
+ \left( 1 + \frac{EffectiveCapillarySuction}{DryDepth} \right)`
963
+
964
+
965
+ Examples:
966
+
967
+ For comparison, we perform the following examples similar to those of method
968
+ |Shift_Front_V1|. The general setting is identical:
969
+
970
+ >>> from hydpy.models.ga_garto import *
971
+ >>> simulationstep("1h")
972
+ >>> parameterstep("1h")
973
+ >>> nmbsoils(1)
974
+ >>> nmbbins(4)
975
+ >>> dt(0.25)
976
+ >>> sealed(False)
977
+ >>> soilarea(1.0)
978
+ >>> soildepth(1000.0)
979
+ >>> residualmoisture(0.1)
980
+ >>> saturationmoisture(0.5)
981
+ >>> airentrypotential(0.1)
982
+ >>> poresizedistribution(0.3)
983
+ >>> saturatedconductivity(10.0)
984
+ >>> derived.soilareafraction.update()
985
+ >>> derived.effectivecapillarysuction.update()
986
+
987
+ The test function behaves similarly. However it neglects the initial surface
988
+ water depth, which is not a relevant input to |Redistribute_Front_V1|, and
989
+ considers percolation, which |Redistribute_Front_V1| might update when
990
+ deactivating surface wetting fronts:
991
+
992
+ >>> from hydpy.core.objecttools import repr_, repr_values
993
+ >>> def check(bin_, actualsurfacewater, frontdepth, moisture):
994
+ ... states.moisture = [[m] for m in moisture]
995
+ ... states.frontdepth = [[fd] for fd in frontdepth]
996
+ ... logs.moisturechange = nan
997
+ ... aides.actualsurfacewater = actualsurfacewater
998
+ ... fluxes.percolation[0] = 0.0
999
+ ... old_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
1000
+ ... model.redistribute_front_v1(bin_, 0)
1001
+ ... new_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
1002
+ ... assert old_volume == new_volume + fluxes.percolation[0]
1003
+ ... infiltration = actualsurfacewater - aides.actualsurfacewater[0]
1004
+ ... print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
1005
+ ... print(f"moisture: {repr_values(states.moisture[:, 0])}")
1006
+ ... print(f"infiltration: {repr_(infiltration)}")
1007
+ ... print(f"percolation: {repr_(fluxes.percolation[0])}")
1008
+ ... print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
1009
+
1010
+ In the first example, the given basic equations apply without modifications.
1011
+ Due to missing surface water, relative moisture decreases. Consequently, the
1012
+ front's depth increases to keep the bin's total water volume:
1013
+
1014
+ >>> check(bin_=2, actualsurfacewater=0.0,
1015
+ ... frontdepth=[1000.0, 500.0, 100.0, 0.0],
1016
+ ... moisture=[0.1, 0.3, 0.4, 0.1])
1017
+ moisturechange: nan, nan, -0.001553, nan
1018
+ moisture: 0.1, 0.3, 0.398447, 0.1
1019
+ infiltration: 0.0
1020
+ percolation: 0.0
1021
+ frontdepth: 1000.0, 500.0, 101.57736, 0.0
1022
+
1023
+ With enough available surface water, the bin's relative soil moisture
1024
+ increases. In the following example, this moisture increase outweighs the
1025
+ actual infiltration. So the front depth must must decrease to keep the
1026
+ absolute water volume.
1027
+
1028
+ >>> check(bin_=2, actualsurfacewater=5.0,
1029
+ ... frontdepth=[1000.0, 500.0, 100.0, 0.0],
1030
+ ... moisture=[0.1, 0.3, 0.4, 0.1])
1031
+ moisturechange: nan, nan, 0.048449, nan
1032
+ moisture: 0.1, 0.3, 0.448449, 0.1
1033
+ infiltration: 2.503816
1034
+ percolation: 0.0
1035
+ frontdepth: 1000.0, 500.0, 84.229985, 0.0
1036
+
1037
+ For zero initial front depth, |Redistribute_Front_V1| prefers the alternative
1038
+ equations for calculating moisture change and infiltration defined above:
1039
+
1040
+ >>> check(bin_=2, actualsurfacewater=0.5,
1041
+ ... frontdepth=[1000.0, 500.0, 0.0, 0.0],
1042
+ ... moisture=[0.1, 0.3, 0.4, 0.1])
1043
+ moisturechange: nan, nan, 0.077656, nan
1044
+ moisture: 0.1, 0.3, 0.477656, 0.1
1045
+ infiltration: 0.5
1046
+ percolation: 0.0
1047
+ frontdepth: 1000.0, 500.0, 2.814434, 0.0
1048
+
1049
+ |Redistribute_Front_V1| ensures the updated moisture content does not exceed
1050
+ the saturation content, even if the calculated moisture change suggests so:
1051
+
1052
+ ToDo: clip moisture change?
1053
+
1054
+ >>> check(bin_=2, actualsurfacewater=20.0,
1055
+ ... frontdepth=[1000.0, 500.0, 100.0, 0.0],
1056
+ ... moisture=[0.1, 0.3, 0.4, 0.1])
1057
+ moisturechange: nan, nan, 0.198449, nan
1058
+ moisture: 0.1, 0.3, 0.5, 0.1
1059
+ infiltration: 2.503816
1060
+ percolation: 0.0
1061
+ frontdepth: 1000.0, 500.0, 62.519079, 0.0
1062
+
1063
+ A moisture decrease that would result in falling below the moisture value of
1064
+ the left neighbour bin causes the deactivation of the affected bin. If the
1065
+ left neighbour contains an active wetting front, |Redistribute_Front_V1| adds
1066
+ the remaining soil water and infiltration to this bin by increasing its front
1067
+ depth:
1068
+
1069
+ ToDo: What if the front depth of the left neigbour bin exceeds soil depth
1070
+ afterwards?
1071
+
1072
+ >>> check(bin_=2, actualsurfacewater=0.001,
1073
+ ... frontdepth=[1000.0, 500.0, 100.0, 0.0],
1074
+ ... moisture=[0.1, 0.3, 0.30001, 0.1])
1075
+ moisturechange: nan, nan, 0.0, nan
1076
+ moisture: 0.1, 0.3, 0.1, 0.1
1077
+ infiltration: 0.001
1078
+ percolation: 0.0
1079
+ frontdepth: 1000.0, 500.01, 0.0, 0.0
1080
+
1081
+ If the left neighbour is the first, completely "filled" bin, the remaining soil
1082
+ water and infiltration increase its moisture content:
1083
+
1084
+ >>> soildepth(500.0)
1085
+ >>> check(bin_=1, actualsurfacewater=0.001,
1086
+ ... frontdepth=[500.0, 100.0, 0.0, 0.0],
1087
+ ... moisture=[0.3, 0.30001, 0.1, 0.1])
1088
+ moisturechange: nan, 0.0, nan, nan
1089
+ moisture: 0.300004, 0.300004, 0.300004, 0.300004
1090
+ infiltration: 0.001
1091
+ percolation: 0.0
1092
+ frontdepth: 500.0, 0.0, 0.0, 0.0
1093
+
1094
+ ToDo: In the original GARTO code, the remaining soil water and infiltration
1095
+ become percolation. However, when evaporation interferes with the
1096
+ original equations, this simplification can result in percolation rates
1097
+ larger than saturated conductivity. We observed this in the
1098
+ :ref:`ga_garto_24h_1000mm_evap_continuous` example, where percolation was
1099
+ 20 mm/h (the rainfall rate) in the 21st hour despite a saturated
1100
+ conductivity of 13.2 mm/h. For our assumption, the percolation rate is
1101
+ 12.8 mm/h. Nevertheless, we should keep this deviation from the original
1102
+ implementation in mind for a while; in case it brings unexpected side
1103
+ effects in future applications.
1104
+ """
1105
+
1106
+ SUBMETHODS = (
1107
+ Return_RelativeMoisture_V1,
1108
+ Return_DryDepth_V1,
1109
+ Return_Conductivity_V1,
1110
+ Return_CapillaryDrive_V1,
1111
+ )
1112
+ CONTROLPARAMETERS = (
1113
+ ga_control.NmbBins,
1114
+ ga_control.DT,
1115
+ ga_control.SoilDepth,
1116
+ ga_control.ResidualMoisture,
1117
+ ga_control.SaturationMoisture,
1118
+ ga_control.SaturatedConductivity,
1119
+ ga_control.AirEntryPotential,
1120
+ ga_control.PoreSizeDistribution,
1121
+ )
1122
+ DERIVEDPARAMETERS = (ga_derived.EffectiveCapillarySuction,)
1123
+ UPDATEDSEQUENCES = (
1124
+ ga_states.Moisture,
1125
+ ga_states.FrontDepth,
1126
+ ga_logs.MoistureChange,
1127
+ ga_aides.ActualSurfaceWater,
1128
+ )
1129
+
1130
+ @staticmethod
1131
+ def __call__(model: modeltools.Model, b: int, s: int) -> None:
1132
+ con = model.parameters.control.fastaccess
1133
+ der = model.parameters.derived.fastaccess
1134
+ sta = model.sequences.states.fastaccess
1135
+ aid = model.sequences.aides.fastaccess
1136
+ log = model.sequences.logs.fastaccess
1137
+
1138
+ if sta.frontdepth[b, s] > 0.0:
1139
+ conductivity: float = model.return_conductivity_v1(b, s)
1140
+ capillarydrive: float = model.return_capillarydrive_v1(b - 1, b, s)
1141
+ factor: float = 1.0 if aid.actualsurfacewater[s] > 0.0 else 1.7
1142
+ log.moisturechange[b, s] = (con.dt / sta.frontdepth[b, s]) * (
1143
+ max(aid.actualsurfacewater[s], 0.0) / con.dt
1144
+ - conductivity
1145
+ - (factor * con.saturatedconductivity[s] * capillarydrive)
1146
+ / sta.frontdepth[b, s]
1147
+ )
1148
+ potinfiltration: float = (
1149
+ con.dt
1150
+ * con.saturatedconductivity[s]
1151
+ * (1.0 + der.effectivecapillarysuction[s] / sta.frontdepth[b, s])
1152
+ )
1153
+ else:
1154
+ drydepth: float = model.return_drydepth_v1(s)
1155
+ conductivity = model.return_conductivity_v1(b - 1, s)
1156
+ log.moisturechange[b, s] = (
1157
+ aid.actualsurfacewater[s] - con.dt * conductivity
1158
+ ) / drydepth
1159
+ potinfiltration = (
1160
+ con.dt
1161
+ * con.saturatedconductivity[s]
1162
+ * (1.0 + der.effectivecapillarysuction[s] / drydepth)
1163
+ )
1164
+
1165
+ initialcontent: float = sta.frontdepth[b, s] * (
1166
+ sta.moisture[b, s] - sta.moisture[b - 1, s]
1167
+ )
1168
+
1169
+ sta.moisture[b, s] += log.moisturechange[b, s]
1170
+ sta.moisture[b, s] = min(sta.moisture[b, s], con.saturationmoisture[s])
1171
+ sta.moisture[b, s] = max(sta.moisture[b, s], sta.moisture[b - 1, s])
1172
+
1173
+ if aid.actualsurfacewater[s] > potinfiltration:
1174
+ volume: float = potinfiltration + initialcontent
1175
+ aid.actualsurfacewater[s] -= potinfiltration
1176
+ else:
1177
+ volume = aid.actualsurfacewater[s] + initialcontent
1178
+ aid.actualsurfacewater[s] = 0.0
1179
+
1180
+ if sta.moisture[b, s] > sta.moisture[b - 1, s]:
1181
+ sta.frontdepth[b, s] = volume / (
1182
+ sta.moisture[b, s] - sta.moisture[b - 1, s]
1183
+ )
1184
+ else:
1185
+ if b > 1:
1186
+ sta.frontdepth[b - 1, s] += volume / (
1187
+ sta.moisture[b - 1, s] - sta.moisture[b - 2, s]
1188
+ )
1189
+ sta.moisture[b, s] = sta.moisture[0, s]
1190
+ elif b == 1:
1191
+ sta.moisture[0, s] += volume / con.soildepth[s]
1192
+ for bb in range(1, con.nmbbins):
1193
+ sta.moisture[bb, s] = sta.moisture[0, s]
1194
+ sta.frontdepth[b, s] = 0.0
1195
+ log.moisturechange[b, s] = 0.0
1196
+
1197
+
1198
+ class Infiltrate_WettingFrontBins_V1(modeltools.Method):
1199
+ r"""Process infiltration into the wetting front bins.
1200
+
1201
+ |Infiltrate_WettingFrontBins_V1| does not perform any calculations itself but
1202
+ selects the proper submethods to do so. It either does nothing (if the filled bin
1203
+ is saturated) or calls |Redistribute_Front_V1|, |Shift_Front_V1|, or
1204
+ |Active_Bin_V1| (primarily depending on the initial surface water depth and the
1205
+ current moisture contents).
1206
+
1207
+ |Infiltrate_WettingFrontBins_V1| is specifically designed for |ga_garto|.
1208
+
1209
+ Examples:
1210
+
1211
+ Instead of triggering actual calculations, we try to show how
1212
+ |Infiltrate_WettingFrontBins_V1| selects the mentioned methods based on mocking
1213
+ them. Therefore, we must import the model in pure Python mode:
1214
+
1215
+ >>> from hydpy.core.importtools import reverse_model_wildcard_import
1216
+ >>> reverse_model_wildcard_import()
1217
+ >>> from hydpy import pub, print_vector
1218
+ >>> with pub.options.usecython(False):
1219
+ ... from hydpy.models.ga import *
1220
+ ... simulationstep("1h")
1221
+ ... parameterstep("1h")
1222
+
1223
+ We define only those parameters required for selecting the proper methods:
1224
+
1225
+ >>> nmbsoils(1)
1226
+ >>> nmbbins(5)
1227
+ >>> dt(0.25)
1228
+ >>> saturationmoisture(0.6)
1229
+ >>> saturatedconductivity(10.0)
1230
+
1231
+ The following test function prepares the initial surface water depth, the
1232
+ (current) relative moisture, and the (previous) moisture change. Afterwards,
1233
+ it replaces the mentioned methods with mocks, invokes
1234
+ |Infiltrate_WettingFrontBins_V1|, and prints the passed arguments of all mock
1235
+ calls:
1236
+
1237
+ >>> from unittest.mock import patch
1238
+ >>> def check(initialsurfacewater, moisture, moisturechange):
1239
+ ... states.moisture = [[m] for m in moisture]
1240
+ ... logs.moisturechange = [[mc] for mc in moisturechange]
1241
+ ... aides.initialsurfacewater = initialsurfacewater
1242
+ ... with patch.object(
1243
+ ... model, "redistribute_front_v1"
1244
+ ... ) as redistribute_front_v1, patch.object(
1245
+ ... model, "shift_front_v1"
1246
+ ... ) as shift_front_v1, patch.object(
1247
+ ... model, "active_bin_v1"
1248
+ ... ) as active_bin_v1:
1249
+ ... model.infiltrate_wettingfrontbins_v1(0)
1250
+ ... for mock in (shift_front_v1, redistribute_front_v1, active_bin_v1):
1251
+ ... if mock.called:
1252
+ ... print(mock._extract_mock_name(), end=": ")
1253
+ ... print_vector([str(call)[4:] for call in mock.mock_calls])
1254
+
1255
+ If the first (filled) bin is saturated, |Infiltrate_WettingFrontBins_V1| does
1256
+ nothing:
1257
+
1258
+ >>> check(initialsurfacewater=20.0,
1259
+ ... moisture=[0.6, 0.6, 0.6, 0.6, 0.6],
1260
+ ... moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
1261
+
1262
+ If a wetting front bin is saturated, |Infiltrate_WettingFrontBins_V1| calls
1263
+ either |Shift_Front_V1| or |Redistribute_Front_V1|, depending on whether
1264
+ the surface water depth (rainfall intensity) exceeds saturated conductivity or
1265
+ not:
1266
+
1267
+ >>> check(initialsurfacewater=20.0,
1268
+ ... moisture=[0.1, 0.6, 0.6, 0.6, 0.6],
1269
+ ... moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
1270
+ shift_front_v1: (1, 0)
1271
+
1272
+ >>> check(initialsurfacewater=2.0,
1273
+ ... moisture=[0.1, 0.6, 0.6, 0.6, 0.6],
1274
+ ... moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
1275
+ redistribute_front_v1: (1, 0)
1276
+
1277
+ If all bins are active, |Infiltrate_WettingFrontBins_V1| calls |Shift_Front_V1|
1278
+ for all bins except for the last one, for which it calls
1279
+ |Redistribute_Front_V1|:
1280
+
1281
+ >>> check(initialsurfacewater=2.0,
1282
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
1283
+ ... moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
1284
+ shift_front_v1: (1, 0), (2, 0), (3, 0)
1285
+ redistribute_front_v1: (4, 0)
1286
+
1287
+ If there is at least one inactivated bin and the last active bin is not
1288
+ saturated, |Infiltrate_WettingFrontBins_V1| either calls |Active_Bin_V1| to
1289
+ activate a new bin right to it or calls |Redistribute_Front_V1|, depending on
1290
+ whether rainfall intensity exceeds saturated conductivity and the active bin's
1291
+ relative moisture decreased previously or not:
1292
+
1293
+ >>> check(initialsurfacewater=20.0,
1294
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
1295
+ ... moisturechange=[0.0, 0.0, 0.0, -1.0, 0.0])
1296
+ shift_front_v1: (1, 0), (2, 0)
1297
+ active_bin_v1: (3, 0)
1298
+
1299
+ >>> check(initialsurfacewater=2.0,
1300
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
1301
+ ... moisturechange=[0.0, 0.0, 0.0, -1.0, 0.0])
1302
+ shift_front_v1: (1, 0), (2, 0)
1303
+ redistribute_front_v1: (3, 0)
1304
+
1305
+ >>> check(initialsurfacewater=20.0,
1306
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
1307
+ ... moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
1308
+ shift_front_v1: (1, 0), (2, 0)
1309
+ redistribute_front_v1: (3, 0)
1310
+
1311
+ >>> check(initialsurfacewater=2.0,
1312
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
1313
+ ... moisturechange=[0.0, 0.0, 0.0, 0.0, 0.0])
1314
+ shift_front_v1: (1, 0), (2, 0)
1315
+ redistribute_front_v1: (3, 0)
1316
+
1317
+ >>> reverse_model_wildcard_import()
1318
+ """
1319
+
1320
+ SUBMETHODS = (
1321
+ Return_RelativeMoisture_V1,
1322
+ Return_DryDepth_V1,
1323
+ Return_Conductivity_V1,
1324
+ Return_CapillaryDrive_V1,
1325
+ Active_Bin_V1,
1326
+ Shift_Front_V1,
1327
+ Redistribute_Front_V1,
1328
+ )
1329
+ CONTROLPARAMETERS = (
1330
+ ga_control.NmbBins,
1331
+ ga_control.DT,
1332
+ ga_control.SoilDepth,
1333
+ ga_control.ResidualMoisture,
1334
+ ga_control.SaturationMoisture,
1335
+ ga_control.SaturatedConductivity,
1336
+ ga_control.AirEntryPotential,
1337
+ ga_control.PoreSizeDistribution,
1338
+ )
1339
+ DERIVEDPARAMETERS = (ga_derived.EffectiveCapillarySuction,)
1340
+ REQUIREDSEQUENCES = (ga_aides.InitialSurfaceWater,)
1341
+ UPDATEDSEQUENCES = (
1342
+ ga_states.Moisture,
1343
+ ga_states.FrontDepth,
1344
+ ga_logs.MoistureChange,
1345
+ ga_aides.ActualSurfaceWater,
1346
+ )
1347
+
1348
+ @staticmethod
1349
+ def __call__(model: modeltools.Model, s: int) -> None:
1350
+ con = model.parameters.control.fastaccess
1351
+ sta = model.sequences.states.fastaccess
1352
+ log = model.sequences.logs.fastaccess
1353
+ aid = model.sequences.aides.fastaccess
1354
+ for b in range(1, con.nmbbins):
1355
+ if sta.moisture[0, s] >= con.saturationmoisture[s]:
1356
+ break
1357
+ if sta.moisture[b, s] >= con.saturationmoisture[s]:
1358
+ if aid.initialsurfacewater[s] < con.dt * con.saturatedconductivity[s]:
1359
+ model.redistribute_front_v1(b, s)
1360
+ else:
1361
+ model.shift_front_v1(b, s)
1362
+ break
1363
+ if b == con.nmbbins - 1:
1364
+ model.redistribute_front_v1(b, s)
1365
+ break
1366
+ if sta.moisture[0, s] < sta.moisture[b, s] < sta.moisture[b + 1, s]:
1367
+ log.moisturechange[b, s] = 0.0
1368
+ model.shift_front_v1(b, s)
1369
+ elif (
1370
+ (aid.initialsurfacewater[s] > con.dt * con.saturatedconductivity[s])
1371
+ and (log.moisturechange[b, s] < 0.0)
1372
+ and (sta.moisture[b, s] > sta.moisture[0, s])
1373
+ ):
1374
+ model.active_bin_v1(b, s)
1375
+ break
1376
+ else:
1377
+ model.redistribute_front_v1(b, s)
1378
+ break
1379
+
1380
+
1381
+ class Merge_FrontDepthOvershootings_V1(modeltools.Method):
1382
+ r"""Merge those neighbour bins where the wetting front's depth of the right
1383
+ neighbour exceeds the wetting front's depth of the left neighbour.
1384
+
1385
+ Examples:
1386
+
1387
+ For comparison, we perform the following examples similar to those of method
1388
+ |Active_Bin_V1|. However, in contrast to |Active_Bin_V1|,
1389
+ |Merge_FrontDepthOvershootings_V1| only needs to know the number of available
1390
+ bins and their current states only, making the general set-up much shorter:
1391
+
1392
+ >>> from hydpy.models.ga_garto import *
1393
+ >>> parameterstep()
1394
+ >>> nmbsoils(1)
1395
+ >>> nmbbins(5)
1396
+ >>> sealed(False)
1397
+ >>> soilarea(1.0)
1398
+ >>> soildepth(1000.0)
1399
+ >>> derived.soilareafraction.update()
1400
+
1401
+ Instead of accepting different values for the actual surface water depth, the
1402
+ test function here allows defining the respective front's depth, moisture and
1403
+ moisture change:
1404
+
1405
+ >>> from hydpy.core.objecttools import repr_, repr_values
1406
+ >>> def check(frontdepth, moisture, moisturechange):
1407
+ ... states.frontdepth = [[fd] for fd in frontdepth]
1408
+ ... states.moisture = [[m] for m in moisture]
1409
+ ... logs.moisturechange = [[mc] for mc in moisturechange]
1410
+ ... old_volume = round(model.watercontent, 12)
1411
+ ... model.merge_frontdepthovershootings_v1(0)
1412
+ ... new_volume = round(model.watercontent, 12)
1413
+ ... assert old_volume == new_volume
1414
+ ... print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
1415
+ ... print(f"moisture: {repr_values(states.moisture[:, 0])}")
1416
+ ... print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
1417
+
1418
+ Nothing happens as long as all bins have smaller front depths than their left
1419
+ neighbours. Note that |Merge_FrontDepthOvershootings_V1| also becomes active
1420
+ only if relative moisture increases from left to right. Hence, in the
1421
+ following example, there is no merging of the two inactive bins, which (as
1422
+ usual) both have zero front depths:
1423
+
1424
+ >>> check(frontdepth=[1000.0, 500.0, 100.0, 0.0, 0.0],
1425
+ ... moisture=[0.1, 0.3, 0.5, 0.1, 0.1],
1426
+ ... moisturechange=[0.2, 0.4, 0.6, 0.0, 0.0])
1427
+ frontdepth: 1000.0, 500.0, 100.0, 0.0, 0.0
1428
+ moisture: 0.1, 0.3, 0.5, 0.1, 0.1
1429
+ moisturechange: 0.2, 0.4, 0.6, 0.0, 0.0
1430
+
1431
+ For equal depths, |Merge_FrontDepthOvershootings_V1| deactivates the left
1432
+ neighbour bin and sets the moisture change of the left neighbour to zero:
1433
+
1434
+ >>> check(frontdepth=[1000.0, 500.0, 500.0, 0.0, 0.0],
1435
+ ... moisture=[0.1, 0.3, 0.5, 0.1, 0.1],
1436
+ ... moisturechange=[0.2, 0.4, 0.6, 0.0, 0.0])
1437
+ frontdepth: 1000.0, 500.0, 0.0, 0.0, 0.0
1438
+ moisture: 0.1, 0.5, 0.1, 0.1, 0.1
1439
+ moisturechange: 0.2, 0.0, 0.0, 0.0, 0.0
1440
+
1441
+ In case of an overshooting, |Merge_FrontDepthOvershootings_V1| must add the
1442
+ (additional) water content of the (deactivated) right neighbour to the
1443
+ (preserved) left neighbour:
1444
+
1445
+ >>> check(frontdepth=[1000.0, 500.0, 600.0, 0.0, 0.0],
1446
+ ... moisture=[0.1, 0.3, 0.5, 0.1, 0.1],
1447
+ ... moisturechange=[0.2, 0.4, 0.6, 0.0, 0.0])
1448
+ frontdepth: 1000.0, 550.0, 0.0, 0.0, 0.0
1449
+ moisture: 0.1, 0.5, 0.1, 0.1, 0.1
1450
+ moisturechange: 0.2, 0.0, 0.0, 0.0, 0.0
1451
+
1452
+ All right neighbours of a deactivated bin move (at least) one place to the
1453
+ left:
1454
+
1455
+ >>> check(frontdepth=[1000.0, 500.0, 600.0, 400.0, 0.0],
1456
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
1457
+ ... moisturechange=[0.2, 0.4, 0.6, 0.8, 0.0])
1458
+ frontdepth: 1000.0, 550.0, 400.0, 0.0, 0.0
1459
+ moisture: 0.1, 0.3, 0.4, 0.1, 0.1
1460
+ moisturechange: 0.2, 0.0, 0.8, 0.0, 0.0
1461
+
1462
+ If the last bin is active, it gets properly deactivated:
1463
+
1464
+ >>> check(frontdepth=[1000.0, 500.0, 600.0, 400.0, 300.0],
1465
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
1466
+ ... moisturechange=[0.2, 0.4, 0.6, 0.8, 1.0])
1467
+ frontdepth: 1000.0, 550.0, 400.0, 300.0, 0.0
1468
+ moisture: 0.1, 0.3, 0.4, 0.5, 0.1
1469
+ moisturechange: 0.2, 0.0, 0.8, 1.0, 0.0
1470
+
1471
+ The two last examples demonstrate that the underlying algorithm works stably in
1472
+ case multiple mergings are necessary:
1473
+
1474
+ >>> check(frontdepth=[1000.0, 500.0, 600.0, 700.0, 0.0],
1475
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
1476
+ ... moisturechange=[0.2, 0.4, 0.6, 0.8, 0.0])
1477
+ frontdepth: 1000.0, 600.0, 0.0, 0.0, 0.0
1478
+ moisture: 0.1, 0.4, 0.1, 0.1, 0.1
1479
+ moisturechange: 0.2, 0.0, 0.0, 0.0, 0.0
1480
+
1481
+ >>> check(frontdepth=[1000.0, 500.0, 600.0, 400.0, 500.0],
1482
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
1483
+ ... moisturechange=[0.2, 0.4, 0.6, 0.8, 1.0])
1484
+ frontdepth: 1000.0, 550.0, 450.0, 0.0, 0.0
1485
+ moisture: 0.1, 0.3, 0.5, 0.1, 0.1
1486
+ moisturechange: 0.2, 0.0, 0.0, 0.0, 0.0
1487
+ """
1488
+
1489
+ CONTROLPARAMETERS = (ga_control.NmbBins,)
1490
+ UPDATEDSEQUENCES = (
1491
+ ga_states.Moisture,
1492
+ ga_states.FrontDepth,
1493
+ ga_logs.MoistureChange,
1494
+ )
1495
+
1496
+ @staticmethod
1497
+ def __call__(model: modeltools.Model, s: int) -> None:
1498
+ con = model.parameters.control.fastaccess
1499
+ sta = model.sequences.states.fastaccess
1500
+ log = model.sequences.logs.fastaccess
1501
+ b = con.nmbbins - 1
1502
+ while b > 1:
1503
+ if (sta.frontdepth[b, s] >= sta.frontdepth[b - 1, s]) and (
1504
+ sta.moisture[b, s] > sta.moisture[b - 1, s]
1505
+ ):
1506
+ content_thisbin: float = sta.frontdepth[b, s] * (
1507
+ sta.moisture[b, s] - sta.moisture[b - 1, s]
1508
+ )
1509
+ content_lastbin: float = sta.frontdepth[b - 1, s] * (
1510
+ sta.moisture[b - 1, s] - sta.moisture[b - 2, s]
1511
+ )
1512
+ sta.frontdepth[b - 1, s] = (content_thisbin + content_lastbin) / (
1513
+ sta.moisture[b, s] - sta.moisture[b - 2, s]
1514
+ )
1515
+ sta.moisture[b - 1, s] = sta.moisture[b, s]
1516
+ sta.frontdepth[b, s] = 0.0
1517
+ sta.moisture[b, s] = sta.moisture[0, s]
1518
+ log.moisturechange[b - 1, s] = 0.0
1519
+ log.moisturechange[b, s] = 0.0
1520
+ for bb in range(b + 1, con.nmbbins):
1521
+ if sta.moisture[bb, s] > sta.moisture[0, s]:
1522
+ sta.moisture[bb - 1, s] = sta.moisture[bb, s]
1523
+ sta.moisture[bb, s] = sta.moisture[0, s]
1524
+ sta.frontdepth[bb - 1, s] = sta.frontdepth[bb, s]
1525
+ sta.frontdepth[bb, s] = 0.0
1526
+ log.moisturechange[bb - 1, s] = log.moisturechange[bb, s]
1527
+ log.moisturechange[bb, s] = 0.0
1528
+ b += 1
1529
+ b -= 1
1530
+
1531
+
1532
+ class Merge_SoilDepthOvershootings_V1(modeltools.Method):
1533
+ r"""Merge bins with wetting front depth larger than soil depth with their
1534
+ left neighbour bins and add their water excess to percolation.
1535
+
1536
+ |Merge_SoilDepthOvershootings_V1| assumes proper sorting of wetting front depths
1537
+ (decreasing from left to right), as ensured by |Merge_FrontDepthOvershootings_V1|.
1538
+
1539
+ Examples:
1540
+
1541
+ For comparison, we perform the following examples similar to those of the
1542
+ related method |Merge_FrontDepthOvershootings_V1|. The general setting is
1543
+ identical:
1544
+
1545
+ >>> from hydpy.models.ga_garto import *
1546
+ >>> parameterstep()
1547
+ >>> nmbsoils(1)
1548
+ >>> nmbbins(5)
1549
+ >>> sealed(False)
1550
+ >>> soilarea(1.0)
1551
+ >>> soildepth(1000.0)
1552
+ >>> derived.soilareafraction.update()
1553
+
1554
+ The test function is similar but must also consider percolation:
1555
+
1556
+ >>> from hydpy.core.objecttools import repr_, repr_values
1557
+ >>> def check(frontdepth, moisture, moisturechange):
1558
+ ... states.frontdepth = [[fd] for fd in frontdepth]
1559
+ ... states.moisture = [[m] for m in moisture]
1560
+ ... logs.moisturechange = [[mc] for mc in moisturechange]
1561
+ ... fluxes.percolation = 0.0
1562
+ ... old_volume = round(model.watercontent, 12)
1563
+ ... model.merge_soildepthovershootings_v1(0)
1564
+ ... new_volume = round(model.watercontent + fluxes.percolation[0], 12)
1565
+ ... assert old_volume == new_volume
1566
+ ... print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
1567
+ ... print(f"moisture: {repr_values(states.moisture[:, 0])}")
1568
+ ... print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
1569
+ ... print(f"percolation: {repr_(fluxes.percolation[0])}")
1570
+
1571
+ Nothing happens as long as all bins have smaller front depths than their left
1572
+ neighbours. Note that |Merge_SoilDepthOvershootings_V1| also becomes active
1573
+ only if relative moisture increases from left to right. Hence, in the
1574
+ following example, there is no merging of the two inactive bins, which (as
1575
+ usual) both have zero front depths:
1576
+
1577
+ >>> check(frontdepth=[1000.0, 900.0, 800.0, 0.0, 0.0],
1578
+ ... moisture=[0.1, 0.2, 0.3, 0.1, 0.1],
1579
+ ... moisturechange=[0.0, 1.0, 2.0, 0.0, 0.0])
1580
+ frontdepth: 1000.0, 900.0, 800.0, 0.0, 0.0
1581
+ moisture: 0.1, 0.2, 0.3, 0.1, 0.1
1582
+ moisturechange: 0.0, 1.0, 2.0, 0.0, 0.0
1583
+ percolation: 0.0
1584
+
1585
+ If a single front's depth reaches the soil bottom exactly,
1586
+ |Merge_SoilDepthOvershootings_V1| deactivates the affected bin and takes its
1587
+ relative moisture value as the new initial moisture:
1588
+
1589
+ >>> check(frontdepth=[1000.0, 1000.0, 0.0, 0.0, 0.0],
1590
+ ... moisture=[0.1, 0.2, 0.1, 0.1, 0.1],
1591
+ ... moisturechange=[0.0, 1.0, 0.0, 0.0, 0.0])
1592
+ frontdepth: 1000.0, 0.0, 0.0, 0.0, 0.0
1593
+ moisture: 0.2, 0.2, 0.2, 0.2, 0.2
1594
+ moisturechange: 0.0, 0.0, 0.0, 0.0, 0.0
1595
+ percolation: 0.0
1596
+
1597
+ Parts of the front lying below the soil's bottom become percolation:
1598
+
1599
+ >>> check(frontdepth=[1000.0, 1100.0, 0.0, 0.0, 0.0],
1600
+ ... moisture=[0.1, 0.2, 0.1, 0.1, 0.1],
1601
+ ... moisturechange=[0.0, 1.0, 0.0, 0.0, 0.0])
1602
+ frontdepth: 1000.0, 0.0, 0.0, 0.0, 0.0
1603
+ moisture: 0.2, 0.2, 0.2, 0.2, 0.2
1604
+ moisturechange: 0.0, 0.0, 0.0, 0.0, 0.0
1605
+ percolation: 10.0
1606
+
1607
+ All remaining active wetting front bins move (at least) one place to the left:
1608
+
1609
+ >>> check(frontdepth=[1000.0, 1100.0, 800.0, 700.0, 600.0],
1610
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
1611
+ ... moisturechange=[0.0, 1.0, 2.0, 3.0, 4.0])
1612
+ frontdepth: 1000.0, 800.0, 700.0, 600.0, 0.0
1613
+ moisture: 0.2, 0.3, 0.4, 0.5, 0.2
1614
+ moisturechange: 0.0, 2.0, 3.0, 4.0, 0.0
1615
+ percolation: 10.0
1616
+
1617
+ The two last examples demonstrate that the underlying algorithm works stably in
1618
+ case multiple mergings are necessary:
1619
+
1620
+ >>> check(frontdepth=[1000.0, 1200.0, 1100.0, 700.0, 0.0],
1621
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.1],
1622
+ ... moisturechange=[0.0, 1.0, 2.0, 3.0, 0.0])
1623
+ frontdepth: 1000.0, 700.0, 0.0, 0.0, 0.0
1624
+ moisture: 0.3, 0.4, 0.3, 0.3, 0.3
1625
+ moisturechange: 0.0, 3.0, 0.0, 0.0, 0.0
1626
+ percolation: 30.0
1627
+
1628
+ >>> check(frontdepth=[1000.0, 1200.0, 1200.0, 1100.0, 1100.0],
1629
+ ... moisture=[0.1, 0.2, 0.3, 0.4, 0.5],
1630
+ ... moisturechange=[0.0, 1.0, 2.0, 3.0, 4.0])
1631
+ frontdepth: 1000.0, 0.0, 0.0, 0.0, 0.0
1632
+ moisture: 0.5, 0.5, 0.5, 0.5, 0.5
1633
+ moisturechange: 0.0, 0.0, 0.0, 0.0, 0.0
1634
+ percolation: 60.0
1635
+ """
1636
+
1637
+ CONTROLPARAMETERS = (ga_control.NmbBins, ga_control.SoilDepth)
1638
+ UPDATEDSEQUENCES = (
1639
+ ga_states.FrontDepth,
1640
+ ga_states.Moisture,
1641
+ ga_logs.MoistureChange,
1642
+ ga_fluxes.Percolation,
1643
+ )
1644
+
1645
+ @staticmethod
1646
+ def __call__(model: modeltools.Model, s: int) -> None:
1647
+ con = model.parameters.control.fastaccess
1648
+ flu = model.sequences.fluxes.fastaccess
1649
+ sta = model.sequences.states.fastaccess
1650
+ log = model.sequences.logs.fastaccess
1651
+
1652
+ while (sta.frontdepth[1, s] >= con.soildepth[s]) and (
1653
+ sta.moisture[1, s] > sta.moisture[0, s]
1654
+ ):
1655
+ flu.percolation[s] += (sta.frontdepth[1, s] - con.soildepth[s]) * (
1656
+ sta.moisture[1, s] - sta.moisture[0, s]
1657
+ )
1658
+ sta.frontdepth[1, s] = 0.0
1659
+ log.moisturechange[1, s] = 0.0
1660
+ sta.moisture[0, s] = sta.moisture[1, s]
1661
+ for b in range(2, con.nmbbins):
1662
+ if sta.moisture[b, s] > sta.moisture[0, s]:
1663
+ sta.frontdepth[b - 1, s] = sta.frontdepth[b, s]
1664
+ log.moisturechange[b - 1, s] = log.moisturechange[b, s]
1665
+ sta.moisture[b - 1, s] = sta.moisture[b, s]
1666
+ sta.frontdepth[b, s] = 0.0
1667
+ log.moisturechange[b, s] = 0.0
1668
+ sta.moisture[b, s] = sta.moisture[0, s]
1669
+
1670
+
1671
+ class Water_AllBins_V1(modeltools.Method):
1672
+ r"""Water the soil's body by (potentially) adding water to all active bins.
1673
+
1674
+ The soil water addition calculated by |Water_AllBins_V1| equals the defined soil
1675
+ water supply, except adding the complete supply would exceed the saturation water
1676
+ content.
1677
+
1678
+ Note that the caller needs to pass the supply as a method parameter, which allows
1679
+ him to decide whether to add everything in one simulation step or multiple
1680
+ numerical substeps.
1681
+
1682
+ Examples:
1683
+
1684
+ We prepare a single shallow soil compartment divided into four bins:
1685
+
1686
+ >>> from hydpy.models.ga_garto import *
1687
+ >>> simulationstep("1d")
1688
+ >>> parameterstep("1d")
1689
+ >>> nmbsoils(1)
1690
+ >>> nmbbins(4)
1691
+ >>> dt(0.5)
1692
+ >>> sealed(False)
1693
+ >>> soilarea(1.0)
1694
+ >>> soildepth(100.0)
1695
+ >>> saturationmoisture(0.5)
1696
+ >>> derived.soilareafraction.update()
1697
+
1698
+ The following test function works similar to the one defined for demonstrating
1699
+ |Active_Bin_V1| but considers the soil water addition instead of infiltration:
1700
+
1701
+ >>> from hydpy.core.objecttools import repr_, repr_values
1702
+ >>> def check(soilwatersupply, moisture, frontdepth):
1703
+ ... fluxes.soilwatersupply[0] = soilwatersupply
1704
+ ... states.moisture = [[m] for m in moisture]
1705
+ ... states.frontdepth = [[fd] for fd in frontdepth]
1706
+ ... logs.moisturechange = [[1.0], [2.0], [3.0], [4.0]]
1707
+ ... fluxes.soilwateraddition[0] = 0.0
1708
+ ... old_volume = round(model.watercontent, 12)
1709
+ ... model.water_allbins_v1(0, soilwatersupply)
1710
+ ... new_volume = round(model.watercontent, 12)
1711
+ ... assert old_volume + fluxes.soilwateraddition[0] == new_volume
1712
+ ... print(f"soilwatersupply: {repr_(fluxes.soilwatersupply[0])}")
1713
+ ... print(f"moisture: {repr_values(states.moisture[:, 0])}")
1714
+ ... print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
1715
+ ... print(f"moisturechange: {repr_values(logs.moisturechange[:, 0])}")
1716
+ ... print(f"soilwateraddition: {repr_(fluxes.soilwateraddition[0])}")
1717
+
1718
+ For zero soil water supply, |Water_AllBins_V1| does nothing:
1719
+
1720
+ >>> check(soilwatersupply=0.0,
1721
+ ... moisture=[0.1, 0.3, 0.1, 0.1],
1722
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0])
1723
+ soilwatersupply: 0.0
1724
+ moisture: 0.1, 0.3, 0.1, 0.1
1725
+ frontdepth: 100.0, 50.0, 0.0, 0.0
1726
+ moisturechange: 1.0, 2.0, 3.0, 4.0
1727
+ soilwateraddition: 0.0
1728
+
1729
+ |Water_AllBins_V1| tries to add the supply to the dryest bin by increasing its
1730
+ relative moisture content:
1731
+
1732
+ >>> check(soilwatersupply=5.0,
1733
+ ... moisture=[0.1, 0.3, 0.1, 0.1],
1734
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0])
1735
+ soilwatersupply: 5.0
1736
+ moisture: 0.2, 0.3, 0.2, 0.2
1737
+ frontdepth: 100.0, 50.0, 0.0, 0.0
1738
+ moisturechange: 0.0, 2.0, 3.0, 4.0
1739
+ soilwateraddition: 5.0
1740
+
1741
+ If a bin is not the last active bin, its highest possible moisture content is
1742
+ restricted by the relative moisture value of its right neighbour bin. If two
1743
+ bins get the same moisture, one of them becomes obsolete, so we can remove it
1744
+ and shift all its right neighbours one place to the left:
1745
+
1746
+ >>> check(soilwatersupply=10.0,
1747
+ ... moisture=[0.1, 0.3, 0.1, 0.1],
1748
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0])
1749
+ soilwatersupply: 10.0
1750
+ moisture: 0.3, 0.3, 0.3, 0.3
1751
+ frontdepth: 100.0, 0.0, 0.0, 0.0
1752
+ moisturechange: 0.0, 3.0, 4.0, 0.0
1753
+ soilwateraddition: 10.0
1754
+
1755
+ If the first bin cannot take enough water, |Water_AllBins_V1| updates the front
1756
+ depth and increases the water content of the second bin:
1757
+
1758
+ >>> check(soilwatersupply=20.0,
1759
+ ... moisture=[0.1, 0.3, 0.1, 0.1],
1760
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0])
1761
+ soilwatersupply: 20.0
1762
+ moisture: 0.4, 0.4, 0.4, 0.4
1763
+ frontdepth: 100.0, 0.0, 0.0, 0.0
1764
+ moisturechange: 0.0, 3.0, 4.0, 0.0
1765
+ soilwateraddition: 20.0
1766
+
1767
+ However, no bin can possess relative moisture higher than indicated by
1768
+ saturation moisture:
1769
+
1770
+ >>> check(soilwatersupply=40.0,
1771
+ ... moisture=[0.1, 0.3, 0.1, 0.1],
1772
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0])
1773
+ soilwatersupply: 40.0
1774
+ moisture: 0.5, 0.5, 0.5, 0.5
1775
+ frontdepth: 100.0, 0.0, 0.0, 0.0
1776
+ moisturechange: 0.0, 3.0, 4.0, 0.0
1777
+ soilwateraddition: 30.0
1778
+
1779
+ |Water_AllBins_V1| deactivates multiple bins when necessary:
1780
+
1781
+ >>> check(soilwatersupply=40.0,
1782
+ ... moisture=[0.1, 0.3, 0.5, 0.1],
1783
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0])
1784
+ soilwatersupply: 40.0
1785
+ moisture: 0.5, 0.5, 0.5, 0.5
1786
+ frontdepth: 100.0, 0.0, 0.0, 0.0
1787
+ moisturechange: 0.0, 4.0, 0.0, 0.0
1788
+ soilwateraddition: 30.0
1789
+
1790
+ >>> check(soilwatersupply=10.0,
1791
+ ... moisture=[0.1, 0.2, 0.3, 0.4],
1792
+ ... frontdepth=[100.0, 75.0, 50.0, 25.0])
1793
+ soilwatersupply: 10.0
1794
+ moisture: 0.333333, 0.4, 0.333333, 0.333333
1795
+ frontdepth: 100.0, 25.0, 0.0, 0.0
1796
+ moisturechange: 0.0, 4.0, 0.0, 0.0
1797
+ soilwateraddition: 10.0
1798
+
1799
+ >>> check(soilwatersupply=30.0,
1800
+ ... moisture=[0.1, 0.2, 0.3, 0.4],
1801
+ ... frontdepth=[100.0, 75.0, 50.0, 25.0])
1802
+ soilwatersupply: 30.0
1803
+ moisture: 0.5, 0.5, 0.5, 0.5
1804
+ frontdepth: 100.0, 0.0, 0.0, 0.0
1805
+ moisturechange: 0.0, 0.0, 0.0, 0.0
1806
+ soilwateraddition: 25.0
1807
+
1808
+ The last two examples demonstrate, similar to the first example, that
1809
+ |Water_AllBins_V1| adjusts the relative moisture value of all non-active bins
1810
+ after increasing the moisture of the first bin:
1811
+
1812
+ >>> check(soilwatersupply=10.0,
1813
+ ... moisture=[0.1, 0.1, 0.1, 0.1],
1814
+ ... frontdepth=[100.0, 0.0, 0.0, 0.0])
1815
+ soilwatersupply: 10.0
1816
+ moisture: 0.2, 0.2, 0.2, 0.2
1817
+ frontdepth: 100.0, 0.0, 0.0, 0.0
1818
+ moisturechange: 0.0, 2.0, 3.0, 4.0
1819
+ soilwateraddition: 10.0
1820
+
1821
+ >>> check(soilwatersupply=50.0,
1822
+ ... moisture=[0.1, 0.1, 0.1, 0.1],
1823
+ ... frontdepth=[100.0, 0.0, 0.0, 0.0])
1824
+ soilwatersupply: 50.0
1825
+ moisture: 0.5, 0.5, 0.5, 0.5
1826
+ frontdepth: 100.0, 0.0, 0.0, 0.0
1827
+ moisturechange: 0.0, 2.0, 3.0, 4.0
1828
+ soilwateraddition: 40.0
1829
+ """
1830
+
1831
+ CONTROLPARAMETERS = (
1832
+ ga_control.NmbBins,
1833
+ ga_control.SoilDepth,
1834
+ ga_control.SaturationMoisture,
1835
+ )
1836
+ UPDATEDSEQUENCES = (
1837
+ ga_states.Moisture,
1838
+ ga_states.FrontDepth,
1839
+ ga_logs.MoistureChange,
1840
+ ga_fluxes.SoilWaterAddition,
1841
+ )
1842
+
1843
+ @staticmethod
1844
+ def __call__(model: modeltools.Model, s: int, supply: float) -> None:
1845
+ con = model.parameters.control.fastaccess
1846
+ flu = model.sequences.fluxes.fastaccess
1847
+ sta = model.sequences.states.fastaccess
1848
+ log = model.sequences.logs.fastaccess
1849
+
1850
+ if supply <= 0.0:
1851
+ return
1852
+
1853
+ rest: float = supply
1854
+ bl = model.return_lastactivebin_v1(s)
1855
+ for b in range(bl):
1856
+ freedepth: float = con.soildepth[s] - sta.frontdepth[b + 1, s]
1857
+ freecontent: float = freedepth * (
1858
+ sta.moisture[b + 1, s] - sta.moisture[b, s]
1859
+ )
1860
+ if rest <= freecontent:
1861
+ flu.soilwateraddition[s] += supply
1862
+ sta.moisture[b, s] += rest / freedepth
1863
+ rest = 0.0
1864
+ initmoisture: float = sta.moisture[b, s]
1865
+ break
1866
+ rest -= freecontent
1867
+ sta.frontdepth[b + 1, s] = con.soildepth[s]
1868
+ initmoisture = sta.moisture[b + 1, s]
1869
+
1870
+ if rest > 0.0:
1871
+ freecontent = con.soildepth[s] * (
1872
+ con.saturationmoisture[s] - sta.moisture[bl, s]
1873
+ )
1874
+ if rest <= freecontent:
1875
+ flu.soilwateraddition[s] += supply
1876
+ sta.moisture[bl, s] += rest / con.soildepth[s]
1877
+ else:
1878
+ rest -= freecontent
1879
+ flu.soilwateraddition[s] += supply - rest
1880
+ sta.moisture[bl, s] = con.saturationmoisture[s]
1881
+ initmoisture = sta.moisture[bl, s]
1882
+
1883
+ for b in range(con.nmbbins):
1884
+ if sta.moisture[b, s] <= initmoisture:
1885
+ sta.moisture[b, s] = initmoisture
1886
+
1887
+ for b in range(bl):
1888
+ while (sta.moisture[b, s] == sta.moisture[b + 1, s]) and (
1889
+ sta.frontdepth[b + 1, s] > 0.0
1890
+ ):
1891
+ sta.frontdepth[b + 1] = sta.frontdepth[b]
1892
+ for bb in range(b, con.nmbbins - 1):
1893
+ sta.moisture[bb, s] = sta.moisture[bb + 1, s]
1894
+ sta.frontdepth[bb, s] = sta.frontdepth[bb + 1, s]
1895
+ log.moisturechange[bb, s] = log.moisturechange[bb + 1, s]
1896
+ sta.moisture[con.nmbbins - 1, s] = sta.moisture[0, s]
1897
+ sta.frontdepth[con.nmbbins - 1, s] = 0.0
1898
+ log.moisturechange[con.nmbbins - 1, s] = 0.0
1899
+ log.moisturechange[0, s] = 0.0
1900
+
1901
+ return
1902
+
1903
+
1904
+ class Withdraw_AllBins_V1(modeltools.Method):
1905
+ r"""Take withdrawal from the available surface water and (potentially) from all
1906
+ active bins.
1907
+
1908
+ The withdrawal calculated by |Withdraw_AllBins_V1| equals the defined demand,
1909
+ except no water exceeding the residual moisture is left. Hence, for example,
1910
+ actual evaporation is more suitable for specifying the demand than potential
1911
+ evaporation.
1912
+
1913
+ Note that the caller needs to pass the demand as a method parameter, which allows
1914
+ him to decide whether to subtract everything in one simulation step or multiple
1915
+ numerical substeps.
1916
+
1917
+ Examples:
1918
+
1919
+ We prepare a single shallow soil compartment divided into four bins:
1920
+
1921
+ >>> from hydpy.models.ga_garto import *
1922
+ >>> simulationstep("1d")
1923
+ >>> parameterstep("1d")
1924
+ >>> nmbsoils(1)
1925
+ >>> nmbbins(4)
1926
+ >>> dt(0.5)
1927
+ >>> sealed(False)
1928
+ >>> soilarea(1.0)
1929
+ >>> soildepth(100.0)
1930
+ >>> residualmoisture(0.1)
1931
+ >>> derived.soilareafraction.update()
1932
+
1933
+ The following test function works similar to the one defined for demonstrating
1934
+ |Active_Bin_V1| but considers the withdrawal instead of infiltration:
1935
+
1936
+ >>> from hydpy.core.objecttools import repr_, repr_values
1937
+ >>> def check(demand, actualsurfacewater, frontdepth, moisture):
1938
+ ... states.moisture = [[m] for m in moisture]
1939
+ ... states.frontdepth = [[fd] for fd in frontdepth]
1940
+ ... logs.moisturechange = nan
1941
+ ... aides.actualsurfacewater = actualsurfacewater
1942
+ ... fluxes.withdrawal[0] = 0.0
1943
+ ... old_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
1944
+ ... model.withdraw_allbins_v1(0, control.dt * demand)
1945
+ ... new_volume = round(model.watercontent + aides.actualsurfacewater[0], 12)
1946
+ ... assert old_volume == new_volume + fluxes.withdrawal[0]
1947
+ ... print(f"withdrawal: {repr_(fluxes.withdrawal[0])}")
1948
+ ... print(f"actualsurfacewater: {repr_(aides.actualsurfacewater[0])}")
1949
+ ... print(f"moisture: {repr_values(states.moisture[:, 0])}")
1950
+ ... print(f"frontdepth: {repr_values(states.frontdepth[:, 0])}")
1951
+
1952
+ For zero demand, |Withdraw_AllBins_V1| does nothing:
1953
+
1954
+ >>> check(demand=0.0, actualsurfacewater=20.0,
1955
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0],
1956
+ ... moisture=[0.1, 0.3, 0.1, 0.1])
1957
+ withdrawal: 0.0
1958
+ actualsurfacewater: 20.0
1959
+ moisture: 0.1, 0.3, 0.1, 0.1
1960
+ frontdepth: 100.0, 50.0, 0.0, 0.0
1961
+
1962
+ If possible, |Withdraw_AllBins_V1| withdraws only surface water:
1963
+
1964
+ >>> check(demand=10.0, actualsurfacewater=20.0,
1965
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0],
1966
+ ... moisture=[0.1, 0.3, 0.1, 0.1])
1967
+ withdrawal: 5.0
1968
+ actualsurfacewater: 15.0
1969
+ moisture: 0.1, 0.3, 0.1, 0.1
1970
+ frontdepth: 100.0, 50.0, 0.0, 0.0
1971
+
1972
+ If no surface water is available, |Withdraw_AllBins_V1| tries to take all
1973
+ withdrawal from the wettest bin by reducing its relative moisture content:
1974
+
1975
+ >>> check(demand=10.0, actualsurfacewater=0.0,
1976
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0],
1977
+ ... moisture=[0.1, 0.3, 0.1, 0.1])
1978
+ withdrawal: 5.0
1979
+ actualsurfacewater: 0.0
1980
+ moisture: 0.1, 0.2, 0.1, 0.1
1981
+ frontdepth: 100.0, 50.0, 0.0, 0.0
1982
+
1983
+ The following example shows that |Withdraw_AllBins_V1| still prefers surface
1984
+ water over soil water if the demand exceeds the available surface water:
1985
+
1986
+ >>> check(demand=10.0, actualsurfacewater=2.5,
1987
+ ... frontdepth=[100.0, 50.0, 0.0, 0.0],
1988
+ ... moisture=[0.1, 0.3, 0.1, 0.1])
1989
+ withdrawal: 5.0
1990
+ actualsurfacewater: 0.0
1991
+ moisture: 0.1, 0.25, 0.1, 0.1
1992
+ frontdepth: 100.0, 50.0, 0.0, 0.0
1993
+
1994
+ If the wettest bin does not contain enough water, |Withdraw_AllBins_V1|
1995
+ proceeds from right to left in taking the remaining demand:
1996
+
1997
+ >>> check(demand=10.0, actualsurfacewater=0.0,
1998
+ ... frontdepth=[100.0, 75.0, 50.0, 25.0],
1999
+ ... moisture=[0.1, 0.2, 0.3, 0.4])
2000
+ withdrawal: 5.0
2001
+ actualsurfacewater: 0.0
2002
+ moisture: 0.1, 0.2, 0.25, 0.1
2003
+ frontdepth: 100.0, 75.0, 50.0, 0.0
2004
+
2005
+ However, |Withdraw_AllBins_V1| never takes more water than indicated by soil's
2006
+ residual moisture:
2007
+
2008
+ >>> check(demand=40.0, actualsurfacewater=0.0,
2009
+ ... frontdepth=[100.0, 75.0, 50.0, 25.0],
2010
+ ... moisture=[0.1, 0.2, 0.3, 0.4])
2011
+ withdrawal: 15.0
2012
+ actualsurfacewater: 0.0
2013
+ moisture: 0.1, 0.1, 0.1, 0.1
2014
+ frontdepth: 100.0, 0.0, 0.0, 0.0
2015
+
2016
+ The last two examples show that |Withdraw_AllBins_V1| can also take water from
2017
+ the filled bin (if it is not already dry, as in the previous example):
2018
+
2019
+ >>> check(demand=10.0, actualsurfacewater=0.0,
2020
+ ... frontdepth=[100.0, 0.0, 0.0, 0.0],
2021
+ ... moisture=[0.2, 0.2, 0.2, 0.2])
2022
+ withdrawal: 5.0
2023
+ actualsurfacewater: 0.0
2024
+ moisture: 0.15, 0.2, 0.2, 0.2
2025
+ frontdepth: 100.0, 0.0, 0.0, 0.0
2026
+
2027
+ >>> check(demand=40.0, actualsurfacewater=0.0,
2028
+ ... frontdepth=[100.0, 0.0, 0.0, 0.0],
2029
+ ... moisture=[0.2, 0.2, 0.2, 0.2])
2030
+ withdrawal: 10.0
2031
+ actualsurfacewater: 0.0
2032
+ moisture: 0.1, 0.2, 0.2, 0.2
2033
+ frontdepth: 100.0, 0.0, 0.0, 0.0
2034
+
2035
+ As the last examples show, |Withdraw_AllBins_V1| does not update the other
2036
+ bins' moisture after removing water from the filled bin, which is surprising
2037
+ but agrees with the author's GARTO source code and gave better results for
2038
+ shallow soils in some comparisons.
2039
+ """
2040
+
2041
+ CONTROLPARAMETERS = (
2042
+ ga_control.NmbBins,
2043
+ ga_control.SoilDepth,
2044
+ ga_control.ResidualMoisture,
2045
+ )
2046
+ UPDATEDSEQUENCES = (
2047
+ ga_states.Moisture,
2048
+ ga_states.FrontDepth,
2049
+ ga_aides.ActualSurfaceWater,
2050
+ ga_fluxes.Withdrawal,
2051
+ )
2052
+
2053
+ @staticmethod
2054
+ def __call__(model: modeltools.Model, s: int, demand: float) -> None:
2055
+ con = model.parameters.control.fastaccess
2056
+ flu = model.sequences.fluxes.fastaccess
2057
+ sta = model.sequences.states.fastaccess
2058
+ aid = model.sequences.aides.fastaccess
2059
+
2060
+ if demand <= 0.0:
2061
+ return
2062
+
2063
+ if demand < aid.actualsurfacewater[s]:
2064
+ aid.actualsurfacewater[s] -= demand
2065
+ flu.withdrawal[s] += demand
2066
+ return
2067
+ demand -= aid.actualsurfacewater[s]
2068
+ flu.withdrawal[s] += aid.actualsurfacewater[s]
2069
+ aid.actualsurfacewater[s] = 0.0
2070
+
2071
+ for b in range(con.nmbbins - 1, 0, -1):
2072
+ if sta.moisture[b, s] > sta.moisture[0, s]:
2073
+ available: float = sta.frontdepth[b, s] * (
2074
+ sta.moisture[b, s] - sta.moisture[b - 1, s]
2075
+ )
2076
+ if demand <= available:
2077
+ sta.moisture[b, s] -= demand / sta.frontdepth[b, s]
2078
+ flu.withdrawal[s] += demand
2079
+ return
2080
+ flu.withdrawal[s] += available
2081
+ demand -= available
2082
+ sta.moisture[b, s] = sta.moisture[0, s]
2083
+ sta.frontdepth[b, s] = 0.0
2084
+
2085
+ if sta.moisture[0, s] <= con.residualmoisture[s]:
2086
+ return
2087
+
2088
+ available = con.soildepth[s] * (sta.moisture[0, s] - con.residualmoisture[s])
2089
+ if demand <= available:
2090
+ sta.moisture[0, s] -= demand / con.soildepth[s]
2091
+ flu.withdrawal[s] += demand
2092
+ else:
2093
+ flu.withdrawal[s] += available
2094
+ sta.moisture[0, s] = con.residualmoisture[s]
2095
+ return
2096
+
2097
+
2098
+ class Perform_GARTO_V1(modeltools.Method):
2099
+ r"""Perform the GARTO algorithm for the numerical substeps and aggregate their
2100
+ results.
2101
+
2102
+ Method |Perform_GARTO_V1| executes its submethods |Percolate_FilledBin_V1|,
2103
+ |Infiltrate_WettingFrontBins_V1|, |Merge_FrontDepthOvershootings_V1|,
2104
+ |Merge_SoilDepthOvershootings_V1|, |Water_AllBins_V1|, and |Withdraw_AllBins_V1| in
2105
+ the order of mentioning on all non-sealed soil compartments. Additionally, it
2106
+ converts surface water that cannot infiltrate (or evaporate) during a numerical
2107
+ substep immediately to surface runoff (no ponding). So, it provides all core
2108
+ functionalities of application model |ga_garto|, and the explanations and test
2109
+ results for |ga_garto| essentially apply to |Perform_GARTO_V1|, too.
2110
+ """
2111
+
2112
+ SUBMETHODS = (
2113
+ Return_LastActiveBin_V1,
2114
+ Return_Conductivity_V1,
2115
+ Return_DryDepth_V1,
2116
+ Return_CapillaryDrive_V1,
2117
+ Percolate_FilledBin_V1,
2118
+ Infiltrate_WettingFrontBins_V1,
2119
+ Merge_FrontDepthOvershootings_V1,
2120
+ Merge_SoilDepthOvershootings_V1,
2121
+ Water_AllBins_V1,
2122
+ Withdraw_AllBins_V1,
2123
+ )
2124
+ CONTROLPARAMETERS = (
2125
+ ga_control.NmbSoils,
2126
+ ga_control.NmbBins,
2127
+ ga_control.DT,
2128
+ ga_control.SoilDepth,
2129
+ ga_control.Sealed,
2130
+ ga_control.ResidualMoisture,
2131
+ ga_control.SaturationMoisture,
2132
+ ga_control.SaturatedConductivity,
2133
+ ga_control.AirEntryPotential,
2134
+ ga_control.PoreSizeDistribution,
2135
+ )
2136
+ DERIVEDPARAMETERS = (ga_derived.NmbSubsteps, ga_derived.EffectiveCapillarySuction)
2137
+ REQUIREDSEQUENCES = (
2138
+ ga_fluxes.SurfaceWaterSupply,
2139
+ ga_fluxes.SoilWaterSupply,
2140
+ ga_fluxes.Demand,
2141
+ )
2142
+ UPDATEDSEQUENCES = (
2143
+ ga_aides.InitialSurfaceWater,
2144
+ ga_aides.ActualSurfaceWater,
2145
+ ga_states.Moisture,
2146
+ ga_states.FrontDepth,
2147
+ ga_logs.MoistureChange,
2148
+ )
2149
+ RESULTSEQUENCES = (
2150
+ ga_fluxes.Infiltration,
2151
+ ga_fluxes.Percolation,
2152
+ ga_fluxes.SoilWaterAddition,
2153
+ ga_fluxes.Withdrawal,
2154
+ ga_fluxes.SurfaceRunoff,
2155
+ )
2156
+
2157
+ @staticmethod
2158
+ def __call__(model: modeltools.Model) -> None:
2159
+ con = model.parameters.control.fastaccess
2160
+ der = model.parameters.derived.fastaccess
2161
+ flu = model.sequences.fluxes.fastaccess
2162
+ aid = model.sequences.aides.fastaccess
2163
+ for s in range(con.nmbsoils):
2164
+ flu.percolation[s] = 0.0
2165
+ flu.infiltration[s] = 0.0
2166
+ flu.soilwateraddition[s] = 0.0
2167
+ if con.sealed[s]:
2168
+ if flu.demand[s] < flu.surfacewatersupply[s]:
2169
+ flu.withdrawal[s] = flu.demand[s]
2170
+ flu.surfacerunoff[s] = flu.surfacewatersupply[s] - flu.demand[s]
2171
+ else:
2172
+ flu.withdrawal[s] = flu.surfacewatersupply[s]
2173
+ flu.surfacerunoff[s] = 0.0
2174
+ else:
2175
+ aid.initialsurfacewater[s] = con.dt * flu.surfacewatersupply[s]
2176
+ flu.withdrawal[s] = 0.0
2177
+ flu.surfacerunoff[s] = 0.0
2178
+ for _ in range(der.nmbsubsteps):
2179
+ aid.actualsurfacewater[s] = aid.initialsurfacewater[s]
2180
+ model.percolate_filledbin_v1(s)
2181
+ model.infiltrate_wettingfrontbins_v1(s)
2182
+ flu.infiltration[s] += (
2183
+ aid.initialsurfacewater[s] - aid.actualsurfacewater[s]
2184
+ )
2185
+ model.merge_frontdepthovershootings_v1(s)
2186
+ model.merge_soildepthovershootings_v1(s)
2187
+ model.water_allbins_v1(s, con.dt * flu.soilwatersupply[s])
2188
+ model.withdraw_allbins_v1(s, con.dt * flu.demand[s])
2189
+ flu.surfacerunoff[s] += aid.actualsurfacewater[s]
2190
+
2191
+
2192
+ class Calc_TotalInfiltration_V1(modeltools.Method):
2193
+ r"""Calculate the average infiltration from all soil compartments.
2194
+
2195
+ Basic equation:
2196
+ :math:`TotalInfiltration =
2197
+ \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot Infiltration_i`
2198
+
2199
+ Example:
2200
+
2201
+ >>> from hydpy.models.ga import *
2202
+ >>> parameterstep()
2203
+ >>> nmbsoils(2)
2204
+ >>> derived.soilareafraction(0.8, 0.2)
2205
+ >>> fluxes.infiltration = 1.0, 2.0
2206
+ >>> model.calc_totalinfiltration_v1()
2207
+ >>> fluxes.totalinfiltration
2208
+ totalinfiltration(1.2)
2209
+ """
2210
+
2211
+ CONTROLPARAMETERS = (ga_control.NmbSoils,)
2212
+ DERIVEDPARAMETERS = (ga_derived.SoilAreaFraction,)
2213
+ REQUIREDSEQUENCES = (ga_fluxes.Infiltration,)
2214
+ RESULTSEQUENCES = (ga_fluxes.TotalInfiltration,)
2215
+
2216
+ @staticmethod
2217
+ def __call__(model: modeltools.Model) -> None:
2218
+ con = model.parameters.control.fastaccess
2219
+ der = model.parameters.derived.fastaccess
2220
+ flu = model.sequences.fluxes.fastaccess
2221
+
2222
+ flu.totalinfiltration = 0.0
2223
+ for s in range(con.nmbsoils):
2224
+ flu.totalinfiltration += der.soilareafraction[s] * flu.infiltration[s]
2225
+
2226
+
2227
+ class Calc_TotalPercolation_V1(modeltools.Method):
2228
+ r"""Calculate the average percolation from all soil compartments.
2229
+
2230
+ Basic equation:
2231
+ :math:`TotalPercolation =
2232
+ \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot Percolation_i`
2233
+
2234
+ Example:
2235
+
2236
+ >>> from hydpy.models.ga import *
2237
+ >>> parameterstep()
2238
+ >>> nmbsoils(2)
2239
+ >>> derived.soilareafraction(0.8, 0.2)
2240
+ >>> fluxes.percolation = 1.0, 2.0
2241
+ >>> model.calc_totalpercolation_v1()
2242
+ >>> fluxes.totalpercolation
2243
+ totalpercolation(1.2)
2244
+ """
2245
+
2246
+ CONTROLPARAMETERS = (ga_control.NmbSoils,)
2247
+ DERIVEDPARAMETERS = (ga_derived.SoilAreaFraction,)
2248
+ REQUIREDSEQUENCES = (ga_fluxes.Percolation,)
2249
+ RESULTSEQUENCES = (ga_fluxes.TotalPercolation,)
2250
+
2251
+ @staticmethod
2252
+ def __call__(model: modeltools.Model) -> None:
2253
+ con = model.parameters.control.fastaccess
2254
+ der = model.parameters.derived.fastaccess
2255
+ flu = model.sequences.fluxes.fastaccess
2256
+
2257
+ flu.totalpercolation = 0.0
2258
+ for s in range(con.nmbsoils):
2259
+ flu.totalpercolation += der.soilareafraction[s] * flu.percolation[s]
2260
+
2261
+
2262
+ class Calc_TotalSoilWaterAddition_V1(modeltools.Method):
2263
+ r"""Calculate the average soil water addition to all soil compartments.
2264
+
2265
+ Basic equation:
2266
+ :math:`TotalSoilWaterAddition =
2267
+ \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot SoilWaterAddition_i`
2268
+
2269
+ Example:
2270
+
2271
+ >>> from hydpy.models.ga import *
2272
+ >>> parameterstep()
2273
+ >>> nmbsoils(2)
2274
+ >>> derived.soilareafraction(0.8, 0.2)
2275
+ >>> fluxes.soilwateraddition = 1.0, 2.0
2276
+ >>> model.calc_totalsoilwateraddition_v1()
2277
+ >>> fluxes.totalsoilwateraddition
2278
+ totalsoilwateraddition(1.2)
2279
+ """
2280
+
2281
+ CONTROLPARAMETERS = (ga_control.NmbSoils,)
2282
+ DERIVEDPARAMETERS = (ga_derived.SoilAreaFraction,)
2283
+ REQUIREDSEQUENCES = (ga_fluxes.SoilWaterAddition,)
2284
+ RESULTSEQUENCES = (ga_fluxes.TotalSoilWaterAddition,)
2285
+
2286
+ @staticmethod
2287
+ def __call__(model: modeltools.Model) -> None:
2288
+ con = model.parameters.control.fastaccess
2289
+ der = model.parameters.derived.fastaccess
2290
+ flu = model.sequences.fluxes.fastaccess
2291
+
2292
+ flu.totalsoilwateraddition = 0.0
2293
+ for s in range(con.nmbsoils):
2294
+ flu.totalsoilwateraddition += (
2295
+ der.soilareafraction[s] * flu.soilwateraddition[s]
2296
+ )
2297
+
2298
+
2299
+ class Calc_TotalWithdrawal_V1(modeltools.Method):
2300
+ r"""Calculate the average withdrawal from all soil compartments.
2301
+
2302
+ Basic equation:
2303
+ :math:`TotalWithdrawal =
2304
+ \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot Withdrawal_i`
2305
+
2306
+ Example:
2307
+
2308
+ >>> from hydpy.models.ga import *
2309
+ >>> parameterstep()
2310
+ >>> nmbsoils(2)
2311
+ >>> derived.soilareafraction(0.8, 0.2)
2312
+ >>> fluxes.withdrawal = 1.0, 2.0
2313
+ >>> model.calc_totalwithdrawal_v1()
2314
+ >>> fluxes.totalwithdrawal
2315
+ totalwithdrawal(1.2)
2316
+ """
2317
+
2318
+ CONTROLPARAMETERS = (ga_control.NmbSoils,)
2319
+ DERIVEDPARAMETERS = (ga_derived.SoilAreaFraction,)
2320
+ REQUIREDSEQUENCES = (ga_fluxes.Withdrawal,)
2321
+ RESULTSEQUENCES = (ga_fluxes.TotalWithdrawal,)
2322
+
2323
+ @staticmethod
2324
+ def __call__(model: modeltools.Model) -> None:
2325
+ con = model.parameters.control.fastaccess
2326
+ der = model.parameters.derived.fastaccess
2327
+ flu = model.sequences.fluxes.fastaccess
2328
+
2329
+ flu.totalwithdrawal = 0.0
2330
+ for s in range(con.nmbsoils):
2331
+ flu.totalwithdrawal += der.soilareafraction[s] * flu.withdrawal[s]
2332
+
2333
+
2334
+ class Calc_TotalSurfaceRunoff_V1(modeltools.Method):
2335
+ r"""Calculate the average surface runoff from all soil compartments.
2336
+
2337
+ Basic equation:
2338
+ :math:`TotalSurfaceRunoff =
2339
+ \sum_{i=1}^{NmbSoils} SoilAreaFraction_i \cdot SurfaceRunoff_i`
2340
+
2341
+ Example:
2342
+
2343
+ >>> from hydpy.models.ga import *
2344
+ >>> parameterstep()
2345
+ >>> nmbsoils(2)
2346
+ >>> derived.soilareafraction(0.8, 0.2)
2347
+ >>> fluxes.surfacerunoff = 1.0, 2.0
2348
+ >>> model.calc_totalsurfacerunoff_v1()
2349
+ >>> fluxes.totalsurfacerunoff
2350
+ totalsurfacerunoff(1.2)
2351
+ """
2352
+
2353
+ CONTROLPARAMETERS = (ga_control.NmbSoils,)
2354
+ DERIVEDPARAMETERS = (ga_derived.SoilAreaFraction,)
2355
+ REQUIREDSEQUENCES = (ga_fluxes.SurfaceRunoff,)
2356
+ RESULTSEQUENCES = (ga_fluxes.TotalSurfaceRunoff,)
2357
+
2358
+ @staticmethod
2359
+ def __call__(model: modeltools.Model) -> None:
2360
+ con = model.parameters.control.fastaccess
2361
+ der = model.parameters.derived.fastaccess
2362
+ flu = model.sequences.fluxes.fastaccess
2363
+
2364
+ flu.totalsurfacerunoff = 0.0
2365
+ for s in range(con.nmbsoils):
2366
+ flu.totalsurfacerunoff += der.soilareafraction[s] * flu.surfacerunoff[s]
2367
+
2368
+
2369
+ class Set_InitialSurfaceWater_V1(modeltools.Method):
2370
+ """Set the given initial surface water depth for the selected soil compartment.
2371
+
2372
+ Example:
2373
+
2374
+ Note that |Set_InitialSurfaceWater_V1| multiplies the given value with |DT| to
2375
+ adjust it to the numerical substep width:
2376
+
2377
+ >>> from hydpy.models.ga import *
2378
+ >>> parameterstep()
2379
+ >>> nmbsoils(2)
2380
+ >>> dt.value = 0.5
2381
+ >>> model.set_initialsurfacewater_v1(0, 2.0)
2382
+ >>> model.set_initialsurfacewater_v1(1, 4.0)
2383
+ >>> aides.initialsurfacewater
2384
+ initialsurfacewater(1.0, 2.0)
2385
+ """
2386
+
2387
+ CONTROLPARAMETERS = (ga_control.DT,)
2388
+ RESULTSEQUENCES = (ga_aides.InitialSurfaceWater,)
2389
+
2390
+ @staticmethod
2391
+ def __call__(model: modeltools.Model, s: int, v: float) -> None:
2392
+ con = model.parameters.control.fastaccess
2393
+ aid = model.sequences.aides.fastaccess
2394
+
2395
+ aid.initialsurfacewater[s] = con.dt * v
2396
+
2397
+
2398
+ class Set_ActualSurfaceWater_V1(modeltools.Method):
2399
+ """Set the given actual surface water depth for the selected soil compartment.
2400
+
2401
+ Example:
2402
+
2403
+ Note that |Set_ActualSurfaceWater_V1| multiplies the given value with |DT| to
2404
+ adjust it to the numerical substep width:
2405
+
2406
+ >>> from hydpy.models.ga import *
2407
+ >>> parameterstep()
2408
+ >>> nmbsoils(2)
2409
+ >>> dt.value = 0.5
2410
+ >>> model.set_actualsurfacewater_v1(0, 2.0)
2411
+ >>> model.set_actualsurfacewater_v1(1, 4.0)
2412
+ >>> aides.actualsurfacewater
2413
+ actualsurfacewater(1.0, 2.0)
2414
+ """
2415
+
2416
+ CONTROLPARAMETERS = (ga_control.DT,)
2417
+ RESULTSEQUENCES = (ga_aides.ActualSurfaceWater,)
2418
+
2419
+ @staticmethod
2420
+ def __call__(model: modeltools.Model, s: int, v: float) -> None:
2421
+ con = model.parameters.control.fastaccess
2422
+ aid = model.sequences.aides.fastaccess
2423
+
2424
+ aid.actualsurfacewater[s] = con.dt * v
2425
+
2426
+
2427
+ class Set_SoilWaterSupply_V1(modeltools.Method):
2428
+ """Set the (potential) water supply to the soil's body.
2429
+
2430
+ Example:
2431
+
2432
+ >>> from hydpy.models.ga import *
2433
+ >>> parameterstep()
2434
+ >>> nmbsoils(2)
2435
+ >>> model.set_soilwatersupply_v1(0, 2.0)
2436
+ >>> model.set_soilwatersupply_v1(1, 4.0)
2437
+ >>> fluxes.soilwatersupply
2438
+ soilwatersupply(2.0, 4.0)
2439
+ """
2440
+
2441
+ RESULTSEQUENCES = (ga_fluxes.SoilWaterSupply,)
2442
+
2443
+ @staticmethod
2444
+ def __call__(model: modeltools.Model, s: int, v: float) -> None:
2445
+ flu = model.sequences.fluxes.fastaccess
2446
+
2447
+ flu.soilwatersupply[s] = v
2448
+
2449
+
2450
+ class Set_SoilWaterDemand_V1(modeltools.Method):
2451
+ """Set the (potential) water withdrawal from the soil's surface and body.
2452
+
2453
+ Example:
2454
+
2455
+ >>> from hydpy.models.ga import *
2456
+ >>> parameterstep()
2457
+ >>> nmbsoils(2)
2458
+ >>> model.set_soilwaterdemand_v1(0, 2.0)
2459
+ >>> model.set_soilwaterdemand_v1(1, 4.0)
2460
+ >>> fluxes.demand
2461
+ demand(2.0, 4.0)
2462
+ """
2463
+
2464
+ RESULTSEQUENCES = (ga_fluxes.Demand,)
2465
+
2466
+ @staticmethod
2467
+ def __call__(model: modeltools.Model, s: int, v: float) -> None:
2468
+ flu = model.sequences.fluxes.fastaccess
2469
+
2470
+ flu.demand[s] = v
2471
+
2472
+
2473
+ class Execute_Infiltration_V1(modeltools.Method):
2474
+ """Calculate infiltration (and percolation).
2475
+
2476
+ The interface method |Execute_Infiltration_V1| subsequently executes the GARTO
2477
+ methods |Percolate_FilledBin_V1|, |Infiltrate_WettingFrontBins_V1|,
2478
+ |Merge_FrontDepthOvershootings_V1|, and |Merge_SoilDepthOvershootings_V1| for all
2479
+ numerical substeps.
2480
+ """
2481
+
2482
+ SUBMETHODS = (
2483
+ Return_LastActiveBin_V1,
2484
+ Return_Conductivity_V1,
2485
+ Return_DryDepth_V1,
2486
+ Return_CapillaryDrive_V1,
2487
+ Percolate_FilledBin_V1,
2488
+ Infiltrate_WettingFrontBins_V1,
2489
+ Merge_FrontDepthOvershootings_V1,
2490
+ Merge_SoilDepthOvershootings_V1,
2491
+ )
2492
+ CONTROLPARAMETERS = (
2493
+ ga_control.NmbBins,
2494
+ ga_control.DT,
2495
+ ga_control.SoilDepth,
2496
+ ga_control.ResidualMoisture,
2497
+ ga_control.SaturationMoisture,
2498
+ ga_control.SaturatedConductivity,
2499
+ ga_control.AirEntryPotential,
2500
+ ga_control.PoreSizeDistribution,
2501
+ )
2502
+ DERIVEDPARAMETERS = (ga_derived.NmbSubsteps, ga_derived.EffectiveCapillarySuction)
2503
+ REQUIREDSEQUENCES = (ga_aides.InitialSurfaceWater,)
2504
+ UPDATEDSEQUENCES = (
2505
+ ga_aides.ActualSurfaceWater,
2506
+ ga_states.Moisture,
2507
+ ga_states.FrontDepth,
2508
+ ga_logs.MoistureChange,
2509
+ )
2510
+ RESULTSEQUENCES = (
2511
+ ga_fluxes.Infiltration,
2512
+ ga_fluxes.Percolation,
2513
+ ga_fluxes.SurfaceRunoff,
2514
+ )
2515
+
2516
+ @staticmethod
2517
+ def __call__(model: modeltools.Model, s: int) -> None:
2518
+ der = model.parameters.derived.fastaccess
2519
+ flu = model.sequences.fluxes.fastaccess
2520
+ aid = model.sequences.aides.fastaccess
2521
+
2522
+ initialactualsurfacewater: float = aid.actualsurfacewater[s]
2523
+ flu.infiltration[s] = 0.0
2524
+ flu.percolation[s] = 0.0
2525
+ flu.surfacerunoff[s] = 0.0
2526
+ for _ in range(der.nmbsubsteps):
2527
+ aid.actualsurfacewater[s] = initialactualsurfacewater
2528
+ model.percolate_filledbin_v1(s)
2529
+ model.infiltrate_wettingfrontbins_v1(s)
2530
+ flu.infiltration[s] += initialactualsurfacewater - aid.actualsurfacewater[s]
2531
+ model.merge_frontdepthovershootings_v1(s)
2532
+ model.merge_soildepthovershootings_v1(s)
2533
+ flu.surfacerunoff[s] += aid.actualsurfacewater[s]
2534
+ aid.actualsurfacewater[s] = 0.0
2535
+
2536
+
2537
+ class Add_SoilWater_V1(modeltools.Method):
2538
+ """Add the (direct) soil water supply to the soil's body.
2539
+
2540
+ The interface method |Add_SoilWater_V1| only calls |Withdraw_AllBins_V1|.
2541
+ """
2542
+
2543
+ SUBMETHODS = (Water_AllBins_V1,)
2544
+ CONTROLPARAMETERS = (
2545
+ ga_control.NmbBins,
2546
+ ga_control.SoilDepth,
2547
+ ga_control.SaturationMoisture,
2548
+ )
2549
+ REQUIREDSEQUENCES = (ga_fluxes.SoilWaterSupply,)
2550
+ UPDATEDSEQUENCES = (
2551
+ ga_states.FrontDepth,
2552
+ ga_states.Moisture,
2553
+ ga_logs.MoistureChange,
2554
+ )
2555
+ RESULTSEQUENCES = (ga_fluxes.SoilWaterAddition,)
2556
+
2557
+ @staticmethod
2558
+ def __call__(model: modeltools.Model, s: int) -> None:
2559
+ flu = model.sequences.fluxes.fastaccess
2560
+
2561
+ flu.soilwateraddition[s] = 0.0
2562
+ model.water_allbins_v1(s, flu.soilwatersupply[s])
2563
+
2564
+
2565
+ class Remove_SoilWater_V1(modeltools.Method):
2566
+ """Remove the water demand from the soil's body and eventually from the soil's
2567
+ surface.
2568
+
2569
+ The interface method |Remove_SoilWater_V1| only calls |Withdraw_AllBins_V1|.
2570
+ Hence, whether |Remove_SoilWater_V1| can remove surface water depends on the order
2571
+ the different interface methods are applied and is thus a decision of the calling
2572
+ model.
2573
+ """
2574
+
2575
+ SUBMETHODS = (Withdraw_AllBins_V1,)
2576
+ CONTROLPARAMETERS = (
2577
+ ga_control.NmbBins,
2578
+ ga_control.SoilDepth,
2579
+ ga_control.ResidualMoisture,
2580
+ )
2581
+ REQUIREDSEQUENCES = (ga_fluxes.Demand,)
2582
+ UPDATEDSEQUENCES = (
2583
+ ga_aides.ActualSurfaceWater,
2584
+ ga_states.FrontDepth,
2585
+ ga_states.Moisture,
2586
+ )
2587
+ RESULTSEQUENCES = (ga_fluxes.Withdrawal,)
2588
+
2589
+ @staticmethod
2590
+ def __call__(model: modeltools.Model, s: int) -> None:
2591
+ flu = model.sequences.fluxes.fastaccess
2592
+ aid = model.sequences.aides.fastaccess
2593
+
2594
+ aid.actualsurfacewater[s] = 0.0
2595
+ flu.withdrawal[s] = 0.0
2596
+ model.withdraw_allbins_v1(s, flu.demand[s])
2597
+
2598
+
2599
+ class Get_Infiltration_V1(modeltools.Method):
2600
+ """Get the current infiltration to the selected soil compartment.
2601
+
2602
+ Example:
2603
+
2604
+ >>> from hydpy.models.ga import *
2605
+ >>> parameterstep()
2606
+ >>> nmbsoils(2)
2607
+ >>> fluxes.infiltration = 2.0, 4.0
2608
+ >>> from hydpy import round_
2609
+ >>> round_(model.get_infiltration_v1(0))
2610
+ 2.0
2611
+ >>> round_(model.get_infiltration_v1(1))
2612
+ 4.0
2613
+ """
2614
+
2615
+ RESULTSEQUENCES = (ga_fluxes.Infiltration,)
2616
+
2617
+ @staticmethod
2618
+ def __call__(model: modeltools.Model, s: int) -> float:
2619
+ flu = model.sequences.fluxes.fastaccess
2620
+
2621
+ return flu.infiltration[s]
2622
+
2623
+
2624
+ class Get_Percolation_V1(modeltools.Method):
2625
+ """Get the current percolation from the selected soil compartment.
2626
+
2627
+ Example:
2628
+
2629
+ >>> from hydpy.models.ga import *
2630
+ >>> parameterstep()
2631
+ >>> nmbsoils(2)
2632
+ >>> fluxes.percolation = 2.0, 4.0
2633
+ >>> from hydpy import round_
2634
+ >>> round_(model.get_percolation_v1(0))
2635
+ 2.0
2636
+ >>> round_(model.get_percolation_v1(1))
2637
+ 4.0
2638
+ """
2639
+
2640
+ RESULTSEQUENCES = (ga_fluxes.Percolation,)
2641
+
2642
+ @staticmethod
2643
+ def __call__(model: modeltools.Model, s: int) -> float:
2644
+ flu = model.sequences.fluxes.fastaccess
2645
+
2646
+ return flu.percolation[s]
2647
+
2648
+
2649
+ class Get_SoilWaterAddition_V1(modeltools.Method):
2650
+ """Get the current soil water addition to the selected soil compartment.
2651
+
2652
+ Example:
2653
+
2654
+ >>> from hydpy.models.ga import *
2655
+ >>> parameterstep()
2656
+ >>> nmbsoils(2)
2657
+ >>> fluxes.soilwateraddition = 2.0, 4.0
2658
+ >>> from hydpy import round_
2659
+ >>> round_(model.get_soilwateraddition_v1(0))
2660
+ 2.0
2661
+ >>> round_(model.get_soilwateraddition_v1(1))
2662
+ 4.0
2663
+ """
2664
+
2665
+ RESULTSEQUENCES = (ga_fluxes.SoilWaterAddition,)
2666
+
2667
+ @staticmethod
2668
+ def __call__(model: modeltools.Model, s: int) -> float:
2669
+ flu = model.sequences.fluxes.fastaccess
2670
+
2671
+ return flu.soilwateraddition[s]
2672
+
2673
+
2674
+ class Get_SoilWaterRemoval_V1(modeltools.Method):
2675
+ """Get the current soil (and surface water) withdrawal from the selected soil
2676
+ compartment.
2677
+
2678
+ Example:
2679
+
2680
+ >>> from hydpy.models.ga import *
2681
+ >>> parameterstep()
2682
+ >>> nmbsoils(2)
2683
+ >>> fluxes.withdrawal = 2.0, 4.0
2684
+ >>> from hydpy import round_
2685
+ >>> round_(model.get_soilwaterremoval_v1(0))
2686
+ 2.0
2687
+ >>> round_(model.get_soilwaterremoval_v1(1))
2688
+ 4.0
2689
+ """
2690
+
2691
+ RESULTSEQUENCES = (ga_fluxes.Withdrawal,)
2692
+
2693
+ @staticmethod
2694
+ def __call__(model: modeltools.Model, s: int) -> float:
2695
+ flu = model.sequences.fluxes.fastaccess
2696
+
2697
+ return flu.withdrawal[s]
2698
+
2699
+
2700
+ class Get_SoilWaterContent_V1(modeltools.Method):
2701
+ r"""Get the current soil water content of the selected soil compartment.
2702
+
2703
+ Basic equation:
2704
+ :math:`SoilWaterContent = Moisture_1 \cdot SoilDepth +
2705
+ \sum_{i=2}^{NmbBins} (Moisture_i - Moisture_{i-1}) \cdot FrontDepth_i`
2706
+
2707
+ Example:
2708
+
2709
+ >>> from hydpy.models.ga import *
2710
+ >>> parameterstep()
2711
+ >>> nmbsoils(3)
2712
+ >>> nmbbins(4)
2713
+ >>> sealed(False, False, True)
2714
+ >>> soilarea(1.0, 2.0, 3.0)
2715
+ >>> soildepth(100.0, 200, nan)
2716
+ >>> residualmoisture(0.1, 0.2, nan)
2717
+ >>> saturationmoisture(0.5, 0.8, nan)
2718
+ >>> states.moisture = [[0.3, 0.2, nan],
2719
+ ... [0.3, 0.3, nan],
2720
+ ... [0.3, 0.5, nan],
2721
+ ... [0.3, 0.8, nan]]
2722
+ >>> states.frontdepth = [[100.0, 200.0, nan],
2723
+ ... [0.0, 150.0, nan],
2724
+ ... [0.0, 100.0, nan],
2725
+ ... [0.0, 50.0, nan]]
2726
+ >>> from hydpy import round_
2727
+ >>> round_(model.get_soilwatercontent_v1(0))
2728
+ 30.0
2729
+ >>> round_(model.get_soilwatercontent_v1(1))
2730
+ 90.0
2731
+ >>> round_(model.get_soilwatercontent_v1(2))
2732
+ 0.0
2733
+ """
2734
+
2735
+ CONTROLPARAMETERS = (ga_control.NmbBins, ga_control.Sealed, ga_control.SoilDepth)
2736
+ REQUIREDSEQUENCES = (ga_states.Moisture, ga_states.FrontDepth)
2737
+
2738
+ @staticmethod
2739
+ def __call__(model: modeltools.Model, s: int) -> float:
2740
+ con = model.parameters.control.fastaccess
2741
+ sta = model.sequences.states.fastaccess
2742
+
2743
+ if con.sealed[s]:
2744
+ return 0.0
2745
+ wc: float = con.soildepth[s] * sta.moisture[0, s]
2746
+ for b in range(1, con.nmbbins):
2747
+ if sta.moisture[b, s] == sta.moisture[0, s]:
2748
+ break
2749
+ wc += sta.frontdepth[b, s] * (sta.moisture[b, s] - sta.moisture[b - 1, s])
2750
+ return wc
2751
+
2752
+
2753
+ class Model(modeltools.AdHocModel):
2754
+ """|ga.DOCNAME.complete|."""
2755
+
2756
+ DOCNAME = modeltools.DocName(short="GA")
2757
+ __HYDPY_ROOTMODEL__ = None
2758
+
2759
+ INLET_METHODS = ()
2760
+ RECEIVER_METHODS = ()
2761
+ RUN_METHODS = (
2762
+ Calc_SurfaceWaterSupply_V1,
2763
+ Calc_SoilWaterSupply_V1,
2764
+ Calc_Demand_V1,
2765
+ Perform_GARTO_V1,
2766
+ Calc_TotalInfiltration_V1,
2767
+ Calc_TotalPercolation_V1,
2768
+ Calc_TotalSoilWaterAddition_V1,
2769
+ Calc_TotalWithdrawal_V1,
2770
+ Calc_TotalSurfaceRunoff_V1,
2771
+ )
2772
+ INTERFACE_METHODS = (
2773
+ Set_InitialSurfaceWater_V1,
2774
+ Set_ActualSurfaceWater_V1,
2775
+ Set_SoilWaterSupply_V1,
2776
+ Set_SoilWaterDemand_V1,
2777
+ Execute_Infiltration_V1,
2778
+ Add_SoilWater_V1,
2779
+ Remove_SoilWater_V1,
2780
+ Get_Infiltration_V1,
2781
+ Get_Percolation_V1,
2782
+ Get_SoilWaterAddition_V1,
2783
+ Get_SoilWaterRemoval_V1,
2784
+ Get_SoilWaterContent_V1,
2785
+ )
2786
+ ADD_METHODS = (
2787
+ Return_RelativeMoisture_V1,
2788
+ Return_Conductivity_V1,
2789
+ Return_CapillaryDrive_V1,
2790
+ Return_DryDepth_V1,
2791
+ Return_LastActiveBin_V1,
2792
+ Active_Bin_V1,
2793
+ Percolate_FilledBin_V1,
2794
+ Shift_Front_V1,
2795
+ Redistribute_Front_V1,
2796
+ Infiltrate_WettingFrontBins_V1,
2797
+ Merge_FrontDepthOvershootings_V1,
2798
+ Merge_SoilDepthOvershootings_V1,
2799
+ Water_AllBins_V1,
2800
+ Withdraw_AllBins_V1,
2801
+ )
2802
+ OUTLET_METHODS = ()
2803
+ SENDER_METHODS = ()
2804
+ SUBMODELINTERFACES = ()
2805
+ SUBMODELS = ()
2806
+
2807
+
2808
+ class BaseModel(modeltools.AdHocModel):
2809
+ """General base class for GARTO-like Green-Ampt models."""
2810
+
2811
+ def check_waterbalance(self, initial_conditions: ConditionsModel) -> float:
2812
+ r"""Determine the water balance error of the previous simulation run in mm.
2813
+
2814
+ Method |ga_model.BaseModel.check_waterbalance| calculates the balance error as
2815
+ follows:
2816
+
2817
+ :math:`\sum_{t=t0}^{t1} \big(
2818
+ Rainfall_t - TotalPercolation_t + TotalSoilWaterAddition_t - TotalWithdrawal_t
2819
+ - Percolation_t \big) +b\big( WaterVolume_{t0} - WaterVolume_{t1} \big)`
2820
+
2821
+ The returned error should always be in scale with numerical precision so that
2822
+ it does not affect the simulation results in any relevant manner.
2823
+
2824
+ Pick the required initial conditions before starting the simulation via
2825
+ property |Sequences.conditions|. See the integration tests of the application
2826
+ model |ga_garto| for some examples.
2827
+ """
2828
+ inputs = self.sequences.inputs
2829
+ fluxes = self.sequences.fluxes
2830
+ first = initial_conditions["model"]["states"]
2831
+ old_watercontent = self._calc_watercontent(
2832
+ frontdepth=first["frontdepth"], # type: ignore[arg-type]
2833
+ moisture=first["moisture"], # type: ignore[arg-type]
2834
+ )
2835
+ return float(
2836
+ numpy.sum(inputs.rainfall.evalseries)
2837
+ + numpy.sum(fluxes.totalsoilwateraddition.evalseries)
2838
+ - numpy.sum(fluxes.totalpercolation.evalseries)
2839
+ - numpy.sum(fluxes.totalwithdrawal.evalseries)
2840
+ - numpy.sum(fluxes.totalsurfacerunoff.evalseries)
2841
+ + (old_watercontent - self.watercontent)
2842
+ )
2843
+
2844
+ @property
2845
+ def watercontents(self) -> NDArrayFloat:
2846
+ """The unique water content of each soil compartment in mm.
2847
+
2848
+ Property |ga_model.BaseModel.watercontents| generally returns zero values for
2849
+ sealed soil compartments:
2850
+
2851
+ >>> from hydpy.models.ga_garto import *
2852
+ >>> parameterstep()
2853
+ >>> nmbsoils(3)
2854
+ >>> nmbbins(4)
2855
+ >>> sealed(False, False, True)
2856
+ >>> soilarea(1.0, 2.0, 3.0)
2857
+ >>> soildepth(100.0, 200, nan)
2858
+ >>> residualmoisture(0.1, 0.2, nan)
2859
+ >>> saturationmoisture(0.5, 0.8, nan)
2860
+ >>> derived.soilareafraction.update()
2861
+ >>> states.moisture = [[0.3, 0.2, nan],
2862
+ ... [0.3, 0.3, nan],
2863
+ ... [0.3, 0.5, nan],
2864
+ ... [0.3, 0.8, nan]]
2865
+ >>> states.frontdepth = [[100.0, 200.0, nan],
2866
+ ... [0.0, 150.0, nan],
2867
+ ... [0.0, 100.0, nan],
2868
+ ... [0.0, 50.0, nan]]
2869
+ >>> from hydpy import print_vector
2870
+ >>> print_vector(model.watercontents)
2871
+ 30.0, 90.0, 0.0
2872
+ """
2873
+ states = self.sequences.states
2874
+ return self._calc_watercontents(
2875
+ frontdepth=states.frontdepth.values, moisture=states.moisture.values
2876
+ )
2877
+
2878
+ @property
2879
+ def watercontent(self) -> float:
2880
+ """The average water content of all soil compartments in mm.
2881
+
2882
+ Property |ga_model.BaseModel.watercontent| includes sealed soil compartments in
2883
+ the average, which is why the presence of sealing reduces the returned value:
2884
+
2885
+ >>> from hydpy.models.ga_garto import *
2886
+ >>> parameterstep()
2887
+ >>> nmbsoils(3)
2888
+ >>> nmbbins(4)
2889
+ >>> sealed(False, False, True)
2890
+ >>> soilarea(1.0, 2.0, 3.0)
2891
+ >>> soildepth(100.0, 200, nan)
2892
+ >>> residualmoisture(0.1, 0.2, nan)
2893
+ >>> saturationmoisture(0.5, 0.8, nan)
2894
+ >>> derived.soilareafraction.update()
2895
+ >>> states.moisture = [[0.3, 0.2, nan],
2896
+ ... [0.3, 0.3, nan],
2897
+ ... [0.3, 0.5, nan],
2898
+ ... [0.3, 0.8, nan]]
2899
+ >>> states.frontdepth = [[100.0, 200.0, nan],
2900
+ ... [0.0, 150.0, nan],
2901
+ ... [0.0, 100.0, nan],
2902
+ ... [0.0, 50.0, nan]]
2903
+ >>> from hydpy import round_
2904
+ >>> round_(model.watercontent)
2905
+ 35.0
2906
+
2907
+ >>> soilarea(1.0, 2.0, 0.0)
2908
+ >>> derived.soilareafraction.update()
2909
+ >>> round_(model.watercontent)
2910
+ 70.0
2911
+ """
2912
+ states = self.sequences.states
2913
+ return self._calc_watercontent(
2914
+ frontdepth=states.frontdepth.values, moisture=states.moisture.values
2915
+ )
2916
+
2917
+ def _calc_watercontents(
2918
+ self, frontdepth: NDArrayFloat, moisture: NDArrayFloat
2919
+ ) -> NDArrayFloat:
2920
+ frontdepth = frontdepth.copy()
2921
+ frontdepth[0, :] = self.parameters.control.soildepth.values
2922
+ deltamoisture = numpy.diff(moisture, axis=0, prepend=0.0)
2923
+ deltamoisture = numpy.clip(deltamoisture, 0.0, numpy.inf)
2924
+ watercontents = numpy.sum(frontdepth * deltamoisture, axis=0)
2925
+ watercontents[self.parameters.control.sealed.values] = 0.0
2926
+ return watercontents
2927
+
2928
+ def _calc_watercontent(
2929
+ self, frontdepth: NDArrayFloat, moisture: NDArrayFloat
2930
+ ) -> float:
2931
+ weights = self.parameters.derived.soilareafraction.values
2932
+ watercontents = self._calc_watercontents(
2933
+ frontdepth=frontdepth, moisture=moisture
2934
+ )
2935
+ return numpy.nansum(weights * watercontents)
2936
+
2937
+
2938
+ class Base_SoilModel_V1(BaseModel, soilinterfaces.SoilModel_V1):
2939
+ """Base class for |ga.DOCNAME.long| models that comply with the |SoilModel_V1|
2940
+ submodel interface."""
2941
+
2942
+ @importtools.define_targetparameter(ga_control.NmbSoils)
2943
+ def prepare_nmbzones(self, nmbzones: int) -> None:
2944
+ """Set the number of soil compartments.
2945
+
2946
+ >>> from hydpy.models.ga_garto_submodel1 import *
2947
+ >>> parameterstep()
2948
+ >>> model.prepare_nmbzones(2)
2949
+ >>> nmbsoils
2950
+ nmbsoils(2)
2951
+ """
2952
+ self.parameters.control.nmbsoils(nmbzones)