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,4664 @@
1
+ """
2
+ .. _`issue 68`: https://github.com/hydpy-dev/hydpy/issues/68
3
+ """
4
+
5
+ # imports...
6
+ # ...from site-packages
7
+ import numpy
8
+
9
+ # ...from HydPy
10
+ from hydpy import config
11
+ from hydpy.core import importtools
12
+ from hydpy.core import modeltools
13
+ from hydpy.cythons import modelutils
14
+ from hydpy.core.typingtools import *
15
+ from hydpy.interfaces import aetinterfaces
16
+ from hydpy.interfaces import precipinterfaces
17
+ from hydpy.interfaces import rconcinterfaces
18
+ from hydpy.interfaces import tempinterfaces
19
+ from hydpy.interfaces import stateinterfaces
20
+
21
+ # ...from hland
22
+ from hydpy.models.hland import hland_constants
23
+ from hydpy.models.hland.hland_constants import FIELD, FOREST, GLACIER, ILAKE, SEALED
24
+ from hydpy.models.hland import hland_control
25
+ from hydpy.models.hland import hland_derived
26
+ from hydpy.models.hland import hland_fixed
27
+ from hydpy.models.hland import hland_inputs
28
+ from hydpy.models.hland import hland_factors
29
+ from hydpy.models.hland import hland_fluxes
30
+ from hydpy.models.hland import hland_states
31
+ from hydpy.models.hland import hland_aides
32
+ from hydpy.models.hland import hland_outlets
33
+
34
+
35
+ class Calc_TC_V1(modeltools.Method):
36
+ r"""Adjust the measured air temperature to the altitude of the individual zones.
37
+
38
+ Basic equation:
39
+ :math:`TC = T + TCorr - TCAlt \cdot (ZoneZ - Z)`
40
+
41
+ Examples:
42
+
43
+ Prepare two zones, the first lying at the reference height and the second 200
44
+ meters above:
45
+
46
+ >>> from hydpy.models.hland import *
47
+ >>> simulationstep("12h")
48
+ >>> parameterstep("1d")
49
+ >>> nmbzones(2)
50
+ >>> zonez(2.0, 4.0)
51
+ >>> derived.z(2.0)
52
+
53
+ Applying the usual temperature lapse rate of 0.6°C/100m does not affect the
54
+ first zone but reduces the temperature of the second zone by 1.2°C:
55
+
56
+ >>> tcorr(1.0)
57
+ >>> tcalt(0.6)
58
+ >>> inputs.t = 5.0
59
+ >>> model.calc_tc_v1()
60
+ >>> factors.tc
61
+ tc(6.0, 4.8)
62
+ """
63
+
64
+ CONTROLPARAMETERS = (
65
+ hland_control.NmbZones,
66
+ hland_control.TCorr,
67
+ hland_control.TCAlt,
68
+ hland_control.ZoneZ,
69
+ )
70
+ DERIVEDPARAMETERS = (hland_derived.Z,)
71
+ REQUIREDSEQUENCES = (hland_inputs.T,)
72
+ RESULTSEQUENCES = (hland_factors.TC,)
73
+
74
+ @staticmethod
75
+ def __call__(model: modeltools.Model) -> None:
76
+ con = model.parameters.control.fastaccess
77
+ der = model.parameters.derived.fastaccess
78
+ inp = model.sequences.inputs.fastaccess
79
+ fac = model.sequences.factors.fastaccess
80
+ for k in range(con.nmbzones):
81
+ fac.tc[k] = inp.t + con.tcorr[k] - con.tcalt[k] * (con.zonez[k] - der.z)
82
+
83
+
84
+ class Calc_FracRain_V1(modeltools.Method):
85
+ r"""Determine the temperature-dependent fraction of (liquid) rainfall
86
+ and (total) precipitation.
87
+
88
+ Basic equation:
89
+ :math:`FracRain = \frac{TC-(TT-\frac{TTInt}{2})}{TTInt}`
90
+
91
+ Restriction:
92
+ :math:`0 \leq FracRain \leq 1`
93
+
94
+ Examples:
95
+
96
+ The threshold temperature of seven zones is 0°C, and the corresponding
97
+ temperature interval of mixed precipitation 2°C:
98
+
99
+ >>> from hydpy.models.hland import *
100
+ >>> simulationstep("12h")
101
+ >>> parameterstep("1d")
102
+ >>> nmbzones(7)
103
+ >>> tt(0.0)
104
+ >>> ttint(2.0)
105
+
106
+ The fraction of rainfall is zero below -1°C, is one above 1°C, and increases
107
+ linearly in between:
108
+
109
+ >>> factors.tc = -10.0, -1.0, -0.5, 0.0, 0.5, 1.0, 10.0
110
+ >>> model.calc_fracrain_v1()
111
+ >>> factors.fracrain
112
+ fracrain(0.0, 0.0, 0.25, 0.5, 0.75, 1.0, 1.0)
113
+
114
+ Note the particular case of a zero temperature interval. With an actual
115
+ temperature being equal to the threshold temperature, the rainfall fraction
116
+ is one:
117
+
118
+ >>> ttint(0.0)
119
+ >>> model.calc_fracrain_v1()
120
+ >>> factors.fracrain
121
+ fracrain(0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0)
122
+ """
123
+
124
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.TT, hland_control.TTInt)
125
+ REQUIREDSEQUENCES = (hland_factors.TC,)
126
+ RESULTSEQUENCES = (hland_factors.FracRain,)
127
+
128
+ @staticmethod
129
+ def __call__(model: modeltools.Model) -> None:
130
+ con = model.parameters.control.fastaccess
131
+ fac = model.sequences.factors.fastaccess
132
+ for k in range(con.nmbzones):
133
+ d_dt = con.ttint[k] / 2.0
134
+ if fac.tc[k] >= (con.tt[k] + d_dt):
135
+ fac.fracrain[k] = 1.0
136
+ elif fac.tc[k] <= (con.tt[k] - d_dt):
137
+ fac.fracrain[k] = 0.0
138
+ else:
139
+ fac.fracrain[k] = (fac.tc[k] - (con.tt[k] - d_dt)) / con.ttint[k]
140
+
141
+
142
+ class Calc_RFC_SFC_V1(modeltools.Method):
143
+ r"""Calculate the corrected fractions of rainfall/snowfall and total precipitation.
144
+
145
+ Basic equations:
146
+ :math:`RfC = RfCF \cdot FracRain`
147
+
148
+ :math:`SfC = SfCF \cdot (1 - FracRain)`
149
+
150
+ Examples:
151
+
152
+ Assume five zones with different temperatures and hence different fractions of
153
+ rainfall and total precipitation:
154
+
155
+ >>> from hydpy.models.hland import *
156
+ >>> simulationstep("12h")
157
+ >>> parameterstep("1d")
158
+ >>> nmbzones(5)
159
+ >>> factors.fracrain = 0.0, 0.25, 0.5, 0.75, 1.0
160
+
161
+ With no rainfall and no snowfall correction (due to the respective factors
162
+ being one), the corrected fraction related to rain is identical to the original
163
+ fraction, while the corrected fraction related to snow behaves the opposite:
164
+
165
+ >>> rfcf(1.0)
166
+ >>> sfcf(1.0)
167
+ >>> model.calc_rfc_sfc_v1()
168
+ >>> factors.rfc
169
+ rfc(0.0, 0.25, 0.5, 0.75, 1.0)
170
+ >>> factors.sfc
171
+ sfc(1.0, 0.75, 0.5, 0.25, 0.0)
172
+
173
+ With a rainfall reduction of 20% and a snowfall increase of 20 %, the corrected
174
+ fractions are as follows:
175
+
176
+ >>> rfcf(0.8)
177
+ >>> sfcf(1.2)
178
+ >>> model.calc_rfc_sfc_v1()
179
+ >>> factors.rfc
180
+ rfc(0.0, 0.2, 0.4, 0.6, 0.8)
181
+ >>> factors.sfc
182
+ sfc(1.2, 0.9, 0.6, 0.3, 0.0)
183
+ """
184
+
185
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.RfCF, hland_control.SfCF)
186
+ REQUIREDSEQUENCES = (hland_factors.FracRain,)
187
+ RESULTSEQUENCES = (hland_factors.RfC, hland_factors.SfC)
188
+
189
+ @staticmethod
190
+ def __call__(model: modeltools.Model) -> None:
191
+ con = model.parameters.control.fastaccess
192
+ fac = model.sequences.factors.fastaccess
193
+ for k in range(con.nmbzones):
194
+ fac.rfc[k] = fac.fracrain[k] * con.rfcf[k]
195
+ fac.sfc[k] = (1.0 - fac.fracrain[k]) * con.sfcf[k]
196
+
197
+
198
+ class Calc_PC_V1(modeltools.Method):
199
+ r"""Apply the precipitation correction factors and adjust precipitation to the
200
+ altitude of the individual zones.
201
+
202
+ Basic equation:
203
+ :math:`PC = P \cdot PCorr \cdot (1 + PCAlt \cdot (ZoneZ - Z)) \cdot (RfC + SfC)`
204
+
205
+ Examples:
206
+
207
+ Five zones are at an elevation of 200 m. A precipitation value of 5 mm has
208
+ been measured at a gauge at an elevation of 300 m:
209
+
210
+ >>> from hydpy.models.hland import *
211
+ >>> simulationstep("12h")
212
+ >>> parameterstep("1d")
213
+ >>> nmbzones(5)
214
+ >>> zonez(3.0)
215
+ >>> inputs.p = 5.0
216
+ >>> derived.z(2.0)
217
+
218
+ The first four zones illustrate the individual precipitation corrections due to
219
+ the general (|PCorr|, first zone), the altitude (|PCAlt|, second zone), the
220
+ rainfall (|RfC|, third zone), and the snowfall adjustment (|SfC|, fourth zone).
221
+ The fifth zone illustrates the interaction between all corrections:
222
+
223
+ >>> pcorr(1.3, 1.0, 1.0, 1.0, 1.3)
224
+ >>> pcalt(0.0, 0.1, 0.0, 0.0, 0.1)
225
+ >>> factors.rfc = 0.5, 0.5, 0.4, 0.5, 0.4
226
+ >>> factors.sfc = 0.5, 0.5, 0.5, 0.7, 0.7
227
+ >>> model.calc_pc_v1()
228
+ >>> fluxes.pc
229
+ pc(6.5, 5.5, 4.5, 6.0, 7.865)
230
+
231
+ Usually, one would set zero or positive values for parameter |PCAlt|. But it
232
+ is also allowed to assign negative values to reflect possible negative
233
+ relationships between precipitation and altitude. Method |Calc_PC_V1| performs
234
+ the required truncations to prevent negative precipitation values:
235
+
236
+
237
+ >>> pcalt(-1.0)
238
+ >>> model.calc_pc_v1()
239
+ >>> fluxes.pc
240
+ pc(0.0, 0.0, 0.0, 0.0, 0.0)
241
+ """
242
+
243
+ CONTROLPARAMETERS = (
244
+ hland_control.NmbZones,
245
+ hland_control.PCAlt,
246
+ hland_control.ZoneZ,
247
+ hland_control.PCorr,
248
+ )
249
+ DERIVEDPARAMETERS = (hland_derived.Z,)
250
+ REQUIREDSEQUENCES = (hland_inputs.P, hland_factors.RfC, hland_factors.SfC)
251
+ RESULTSEQUENCES = (hland_fluxes.PC,)
252
+
253
+ @staticmethod
254
+ def __call__(model: modeltools.Model) -> None:
255
+ con = model.parameters.control.fastaccess
256
+ der = model.parameters.derived.fastaccess
257
+ inp = model.sequences.inputs.fastaccess
258
+ fac = model.sequences.factors.fastaccess
259
+ flu = model.sequences.fluxes.fastaccess
260
+ for k in range(con.nmbzones):
261
+ flu.pc[k] = inp.p * (1.0 + con.pcalt[k] * (con.zonez[k] - der.z))
262
+ if flu.pc[k] <= 0.0:
263
+ flu.pc[k] = 0.0
264
+ else:
265
+ flu.pc[k] *= con.pcorr[k] * (fac.rfc[k] + fac.sfc[k])
266
+
267
+
268
+ class Calc_TF_Ic_V1(modeltools.Method):
269
+ r"""Calculate throughfall and update the interception storage accordingly.
270
+
271
+ Basic equation:
272
+ .. math::
273
+ TF =
274
+ \begin{cases}
275
+ PC &|\ Ic = IcMax
276
+ \\
277
+ 0 &|\ Ic < IcMax
278
+ \end{cases}
279
+
280
+ Examples:
281
+
282
+ Initialise seven zones of different types. Assume a general interception
283
+ capacity of 2 mm. All zones receive a precipitation input of 0.5 mm:
284
+
285
+ >>> from hydpy.models.hland import *
286
+ >>> simulationstep("12h")
287
+ >>> parameterstep("1d")
288
+ >>> nmbzones(7)
289
+ >>> zonetype(GLACIER, ILAKE, FIELD, FOREST, SEALED, SEALED, SEALED)
290
+ >>> icmax(2.0)
291
+ >>> fluxes.pc = 0.5
292
+ >>> states.ic = 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0
293
+ >>> model.calc_tf_ic_v1()
294
+
295
+ The interception routine does not apply to glaciers (first zone) and internal
296
+ lakes (second zone). Hence, all precipitation becomes throughfall. For fields,
297
+ forests, and sealed areas, the interception routine works identical, so the
298
+ results of zone three to five are equal. The last three zones demonstrate that
299
+ all precipitation is stored until the intercepted water reaches the available
300
+ capacity; afterwards, all precipitation becomes throughfall. Initial storage
301
+ reduces the effective capacity of the respective simulation step:
302
+
303
+ >>> states.ic
304
+ ic(0.0, 0.0, 0.5, 0.5, 0.5, 1.5, 2.0)
305
+ >>> fluxes.tf
306
+ tf(0.5, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5)
307
+
308
+ A zero precipitation example:
309
+
310
+ >>> fluxes.pc = 0.0
311
+ >>> states.ic = 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0
312
+ >>> model.calc_tf_ic_v1()
313
+ >>> states.ic
314
+ ic(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0)
315
+ >>> fluxes.tf
316
+ tf(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
317
+
318
+ A high precipitation example:
319
+
320
+ >>> fluxes.pc = 5.0
321
+ >>> states.ic = 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0
322
+ >>> model.calc_tf_ic_v1()
323
+ >>> states.ic
324
+ ic(0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 2.0)
325
+ >>> fluxes.tf
326
+ tf(5.0, 5.0, 3.0, 3.0, 3.0, 4.0, 5.0)
327
+ """
328
+
329
+ CONTROLPARAMETERS = (
330
+ hland_control.NmbZones,
331
+ hland_control.ZoneType,
332
+ hland_control.IcMax,
333
+ )
334
+ REQUIREDSEQUENCES = (hland_fluxes.PC,)
335
+ UPDATEDSEQUENCES = (hland_states.Ic,)
336
+ RESULTSEQUENCES = (hland_fluxes.TF,)
337
+
338
+ @staticmethod
339
+ def __call__(model: modeltools.Model) -> None:
340
+ con = model.parameters.control.fastaccess
341
+ flu = model.sequences.fluxes.fastaccess
342
+ sta = model.sequences.states.fastaccess
343
+ for k in range(con.nmbzones):
344
+ if con.zonetype[k] in (FIELD, FOREST, SEALED):
345
+ flu.tf[k] = max(flu.pc[k] - (con.icmax[k] - sta.ic[k]), 0.0)
346
+ sta.ic[k] += flu.pc[k] - flu.tf[k]
347
+ else:
348
+ flu.tf[k] = flu.pc[k]
349
+ sta.ic[k] = 0.0
350
+
351
+
352
+ class Calc_EI_Ic_AETModel_V1(modeltools.Method):
353
+ r"""Let a submodel that follows the |AETModel_V1| submodel interface calculate
354
+ interception evaporation and adjust the amount of intercepted water.
355
+
356
+ Basic equation:
357
+ :math:`\frac{dIc_i}{dt} = -EI_i`
358
+
359
+ Examples:
360
+
361
+ We build an example based on |evap_aet_hbv96| for calculating interception
362
+ evaporation, which uses |evap_ret_io| for querying potential
363
+ evapotranspiration:
364
+
365
+ >>> from hydpy.models.hland_96 import *
366
+ >>> parameterstep("1h")
367
+ >>> nmbzones(5)
368
+ >>> zonetype(GLACIER, SEALED, FIELD, FOREST, ILAKE)
369
+ >>> area(1.0)
370
+ >>> zonearea(0.05, 0.1, 0.2, 0.3, 0.35)
371
+ >>> zonez(5.0)
372
+ >>> icmax(3.0)
373
+ >>> fc(50.0)
374
+ >>> fluxes.tf = 0.5
375
+ >>> with model.add_aetmodel_v1("evap_aet_hbv96"):
376
+ ... with model.add_petmodel_v1("evap_ret_io"):
377
+ ... evapotranspirationfactor(0.6, 0.8, 1.0, 1.2, 1.4)
378
+ ... inputs.referenceevapotranspiration = 1.0
379
+
380
+ |Calc_EI_Ic_AETModel_V1| uses the flux returned by the submodel to adjust |Ic|:
381
+
382
+ >>> states.ic = 2.0
383
+ >>> model.calc_ei_ic_v1()
384
+ >>> fluxes.ei
385
+ ei(0.0, 0.8, 1.0, 1.2, 0.0)
386
+ >>> states.ic
387
+ ic(0.0, 1.2, 1.0, 0.8, 0.0)
388
+ >>> fluxes.tf
389
+ tf(0.5, 0.5, 0.5, 0.5, 0.5)
390
+
391
+ |Calc_EI_Ic_AETModel_V1| eventually reduces |EI| so that |Ic| does not become
392
+ negative:
393
+
394
+ >>> model.aetmodel.petmodel.sequences.inputs.referenceevapotranspiration = 5.0
395
+ >>> states.ic = 2.0
396
+ >>> model.calc_ei_ic_v1()
397
+ >>> fluxes.ei
398
+ ei(0.0, 2.0, 2.0, 2.0, 0.0)
399
+ >>> states.ic
400
+ ic(0.0, 0.0, 0.0, 0.0, 0.0)
401
+ >>> fluxes.tf
402
+ tf(0.5, 0.5, 0.5, 0.5, 0.5)
403
+
404
+ In contrast, |Calc_EI_Ic_AETModel_V1| does not reduce negative |EI| values
405
+ (condensation) that cause an overshoot of the interception storage capacity:
406
+
407
+ >>> model.aetmodel.petmodel.sequences.inputs.referenceevapotranspiration = -3.0
408
+ >>> states.ic = 2.0
409
+ >>> model.calc_ei_ic_v1()
410
+ >>> fluxes.ei
411
+ ei(0.0, -2.4, -3.0, -3.6, 0.0)
412
+ >>> states.ic
413
+ ic(0.0, 4.4, 5.0, 5.6, 0.0)
414
+ >>> fluxes.tf
415
+ tf(0.5, 0.5, 0.5, 0.5, 0.5)
416
+ """
417
+
418
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
419
+ UPDATEDSEQUENCES = (hland_states.Ic,)
420
+ RESULTSEQUENCES = (hland_fluxes.EI,)
421
+
422
+ @staticmethod
423
+ def __call__(model: modeltools.Model, submodel: aetinterfaces.AETModel_V1) -> None:
424
+ con = model.parameters.control.fastaccess
425
+ flu = model.sequences.fluxes.fastaccess
426
+ sta = model.sequences.states.fastaccess
427
+ submodel.determine_interceptionevaporation()
428
+ for k in range(con.nmbzones):
429
+ if con.zonetype[k] in (FIELD, FOREST, SEALED):
430
+ flu.ei[k] = min(submodel.get_interceptionevaporation(k), sta.ic[k])
431
+ sta.ic[k] -= flu.ei[k]
432
+ else:
433
+ flu.ei[k] = 0.0
434
+ sta.ic[k] = 0.0
435
+
436
+
437
+ class Calc_EI_Ic_V1(modeltools.Method):
438
+ """Let a submodel that follows the |AETModel_V1| submodel interface calculate
439
+ interception evaporation and adjust the amount of intercepted water."""
440
+
441
+ SUBMODELINTERFACES = (aetinterfaces.AETModel_V1,)
442
+ SUBMETHODS = (Calc_EI_Ic_AETModel_V1,)
443
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
444
+ UPDATEDSEQUENCES = (hland_states.Ic,)
445
+ RESULTSEQUENCES = (hland_fluxes.EI,)
446
+
447
+ @staticmethod
448
+ def __call__(model: modeltools.Model) -> None:
449
+ if model.aetmodel_typeid == 1:
450
+ model.calc_ei_ic_aetmodel_v1(
451
+ cast(aetinterfaces.AETModel_V1, model.aetmodel)
452
+ )
453
+ # ToDo:
454
+ # else:
455
+ # assert_never(model.petmodel)
456
+
457
+
458
+ class Calc_SP_WC_V1(modeltools.Method):
459
+ r"""Add throughfall to the snow layer.
460
+
461
+ Basic equations:
462
+ :math:`\frac{dSP}{dt} = SFDist \cdot TF \cdot \frac{SfC}{SfC + RfC}`
463
+
464
+ :math:`\frac{dWC}{dt} = SFDist \cdot TF \cdot \frac{RfC}{SfC + RfC}`
465
+
466
+ Examples:
467
+
468
+ Consider the following setting, in which nine zones of different types receive
469
+ a throughfall of 10 mm:
470
+
471
+ >>> from hydpy.models.hland import *
472
+ >>> simulationstep("12h")
473
+ >>> parameterstep("1d")
474
+ >>> nmbzones(9)
475
+ >>> sclass(1)
476
+ >>> zonetype(ILAKE, GLACIER, FIELD, FOREST, SEALED, FIELD, FIELD, FIELD, FIELD)
477
+ >>> sfdist(0.2)
478
+ >>> fluxes.tf = 10.0
479
+ >>> factors.sfc = 0.5, 0.5, 0.5, 0.5, 0.5, 0.2, 0.8, 1.0, 4.0
480
+ >>> factors.rfc = 0.5, 0.5, 0.5, 0.5, 0.5, 0.8, 0.2, 4.0, 1.0
481
+ >>> states.sp = 2.0
482
+ >>> states.wc = 1.0
483
+ >>> model.calc_sp_wc_v1()
484
+ >>> states.sp
485
+ sp(0.0, 7.0, 7.0, 7.0, 7.0, 4.0, 10.0, 4.0, 10.0)
486
+ >>> states.wc
487
+ wc(0.0, 6.0, 6.0, 6.0, 6.0, 9.0, 3.0, 9.0, 3.0)
488
+
489
+ The snow routine does not apply to internal lakes, which is why both the ice
490
+ storage and the water storage of the first zone remain unchanged. The snow
491
+ routine is identical for fields, forests, sealed areas, and glaciers (besides
492
+ the additional glacier melt), which is why the results zone three to five are
493
+ equal. The last four zones illustrate that method |Calc_SP_WC_V1| applies the
494
+ corrected snowfall and rainfall fractions "relatively", considering that the
495
+ throughfall is already corrected.
496
+
497
+ When both factors are zero, neither the water nor the ice content of the snow
498
+ layer changes:
499
+
500
+ >>> factors.sfc = 0.0
501
+ >>> factors.rfc = 0.0
502
+ >>> states.sp = 2.0
503
+ >>> states.wc = 1.0
504
+ >>> model.calc_sp_wc_v1()
505
+ >>> states.sp
506
+ sp(0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0)
507
+ >>> states.wc
508
+ wc(0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)
509
+
510
+ In the above examples, we did not divide the zones into snow classes. If we do
511
+ so, method |Calc_SP_WC_V1| adds different amounts of snow and rainfall to the
512
+ individual snow classes based on the current values of parameter |SFDist|:
513
+
514
+ >>> sclass(2)
515
+ >>> sfdist(0.0, 2.0)
516
+ >>> factors.sfc = 0.5, 0.5, 0.5, 0.5, 0.5, 0.2, 0.8, 1.0, 4.0
517
+ >>> factors.rfc = 0.5, 0.5, 0.5, 0.5, 0.5, 0.8, 0.2, 4.0, 1.0
518
+ >>> states.sp = 2.0
519
+ >>> states.wc = 1.0
520
+ >>> model.calc_sp_wc_v1()
521
+ >>> states.sp
522
+ sp([[0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0],
523
+ [0.0, 12.0, 12.0, 12.0, 12.0, 6.0, 18.0, 6.0, 18.0]])
524
+ >>> states.wc
525
+ wc([[0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
526
+ [0.0, 11.0, 11.0, 11.0, 11.0, 17.0, 5.0, 17.0, 5.0]])
527
+ """
528
+
529
+ CONTROLPARAMETERS = (
530
+ hland_control.NmbZones,
531
+ hland_control.SClass,
532
+ hland_control.ZoneType,
533
+ hland_control.SFDist,
534
+ )
535
+ REQUIREDSEQUENCES = (hland_fluxes.TF, hland_factors.RfC, hland_factors.SfC)
536
+ UPDATEDSEQUENCES = (hland_states.WC, hland_states.SP)
537
+
538
+ @staticmethod
539
+ def __call__(model: modeltools.Model) -> None:
540
+ con = model.parameters.control.fastaccess
541
+ fac = model.sequences.factors.fastaccess
542
+ flu = model.sequences.fluxes.fastaccess
543
+ sta = model.sequences.states.fastaccess
544
+ for k in range(con.nmbzones):
545
+ if con.zonetype[k] != ILAKE:
546
+ d_denom = fac.rfc[k] + fac.sfc[k]
547
+ if d_denom > 0.0:
548
+ d_rain = flu.tf[k] * fac.rfc[k] / d_denom
549
+ d_snow = flu.tf[k] * fac.sfc[k] / d_denom
550
+ for c in range(con.sclass):
551
+ sta.wc[c, k] += con.sfdist[c] * d_rain
552
+ sta.sp[c, k] += con.sfdist[c] * d_snow
553
+ else:
554
+ for c in range(con.sclass):
555
+ sta.wc[c, k] = 0.0
556
+ sta.sp[c, k] = 0.0
557
+
558
+
559
+ class Calc_SPL_WCL_SP_WC_V1(modeltools.Method):
560
+ r"""Calculate the subbasin-internal redistribution losses of the snow layer.
561
+
562
+ Basic equations:
563
+ :math:`\frac{dSP}{dt} = -SPL`
564
+
565
+ :math:`\frac{dWC}{dt} = -WCL`
566
+
567
+ :math:`SPL = SP \cdot RelExcess`
568
+
569
+ :math:`WCL = WC \cdot RelExcess`
570
+
571
+ :math:`RelExcess = \frac{max(SP + WC - SMax, 0)}{SP + WC}`
572
+
573
+ Examples:
574
+
575
+ We prepare eight zones. We use the first five to show the identical behaviour
576
+ of the land-use types |GLACIER|, |FIELD|, |FOREST|, and |SEALED| and the unique
577
+ behaviour of type |ILAKE|. Zones six to eight serve to demonstrate the effects
578
+ of different initial states:
579
+
580
+ >>> from hydpy.models.hland import *
581
+ >>> simulationstep("12h")
582
+ >>> parameterstep("1d")
583
+ >>> nmbzones(8)
584
+ >>> sclass(1)
585
+ >>> zonetype(ILAKE, GLACIER, FIELD, FOREST, SEALED, FIELD, FIELD, FIELD)
586
+ >>> smax(500.0)
587
+
588
+ Internal lakes do not possess a snow module and cannot redistribute any snow.
589
+ Hence, |Calc_SPL_WCL_SP_WC_V1| sets the loss (|SPL| and |WCL|) and state (|SP|
590
+ and |WC|) sequences to zero. For all other zones, the total amount of snow
591
+ redistribution depends on how much the total water equivalent exceeds the
592
+ threshold parameter |SMax| (consistently set to 500 m). The fraction between
593
+ the liquid (|WCL|) and frozen (|SPL|) loss depends on the fraction between
594
+ the actual storage of liquid (|WC|) and frozen (|SP|) water in the snow layer:
595
+
596
+ >>> states.sp = 600.0, 600.0, 600.0, 600.0, 600.0, 60.0, 800.0, 0.0
597
+ >>> states.wc = 200.0, 200.0, 200.0, 200.0, 200.0, 20.0, 0.0, 800.0
598
+ >>> model.calc_spl_wcl_sp_wc_v1()
599
+ >>> fluxes.spl
600
+ spl(0.0, 225.0, 225.0, 225.0, 225.0, 0.0, 300.0, 0.0)
601
+ >>> fluxes.wcl
602
+ wcl(0.0, 75.0, 75.0, 75.0, 75.0, 0.0, 0.0, 300.0)
603
+ >>> states.sp
604
+ sp(0.0, 375.0, 375.0, 375.0, 375.0, 60.0, 500.0, 0.0)
605
+ >>> states.wc
606
+ wc(0.0, 125.0, 125.0, 125.0, 125.0, 20.0, 0.0, 500.0)
607
+
608
+ The above example deals with a single snow class. Here, we add a second snow
609
+ class to illustrate that the total snow loss of each zone does not depend on
610
+ its average snow storage but the degree of exceedance of |SMax| within its
611
+ individual snow classes:
612
+
613
+ >>> sclass(2)
614
+ >>> states.sp = [[600.0, 600.0, 600.0, 600.0, 600.0, 60.0, 800.0, 0.0],
615
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]
616
+ >>> states.wc = [[200.0, 200.0, 200.0, 200.0, 200.0, 20.0, 0.0, 800.0],
617
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]
618
+ >>> model.calc_spl_wcl_sp_wc_v1()
619
+ >>> fluxes.spl
620
+ spl(0.0, 112.5, 112.5, 112.5, 112.5, 0.0, 150.0, 0.0)
621
+ >>> fluxes.wcl
622
+ wcl(0.0, 37.5, 37.5, 37.5, 37.5, 0.0, 0.0, 150.0)
623
+ >>> states.sp
624
+ sp([[0.0, 375.0, 375.0, 375.0, 375.0, 60.0, 500.0, 0.0],
625
+ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])
626
+ >>> states.wc
627
+ wc([[0.0, 125.0, 125.0, 125.0, 125.0, 20.0, 0.0, 500.0],
628
+ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])
629
+ """
630
+
631
+ CONTROLPARAMETERS = (
632
+ hland_control.NmbZones,
633
+ hland_control.SClass,
634
+ hland_control.ZoneType,
635
+ hland_control.SMax,
636
+ )
637
+ UPDATEDSEQUENCES = (hland_states.WC, hland_states.SP)
638
+ RESULTSEQUENCES = (hland_fluxes.SPL, hland_fluxes.WCL)
639
+
640
+ @staticmethod
641
+ def __call__(model: modeltools.Model) -> None:
642
+ con = model.parameters.control.fastaccess
643
+ flu = model.sequences.fluxes.fastaccess
644
+ sta = model.sequences.states.fastaccess
645
+ for k in range(con.nmbzones):
646
+ flu.spl[k] = 0.0
647
+ flu.wcl[k] = 0.0
648
+ if con.zonetype[k] == ILAKE:
649
+ for c in range(con.sclass):
650
+ sta.sp[c, k] = 0.0
651
+ sta.wc[c, k] = 0.0
652
+ elif not modelutils.isinf(con.smax[k]):
653
+ for c in range(con.sclass):
654
+ d_snow = sta.sp[c, k] + sta.wc[c, k]
655
+ d_excess = d_snow - con.smax[k]
656
+ if d_excess > 0.0:
657
+ d_excess_sp = d_excess * sta.sp[c, k] / d_snow
658
+ d_excess_wc = d_excess * sta.wc[c, k] / d_snow
659
+ flu.spl[k] += d_excess_sp / con.sclass
660
+ flu.wcl[k] += d_excess_wc / con.sclass
661
+ sta.sp[c, k] -= d_excess_sp
662
+ sta.wc[c, k] -= d_excess_wc
663
+
664
+
665
+ class Calc_SPG_WCG_SP_WC_V1(modeltools.Method):
666
+ r"""Calculate the subbasin-internal redistribution gains of the snow layer.
667
+
668
+ Basic equations:
669
+ :math:`\frac{dSP}{dt} = -SPG`
670
+
671
+ :math:`\frac{dWC}{dt} = -WCG`
672
+
673
+ Examples:
674
+
675
+ We prepare an example consisting of seven zones, sorted by (non-strictly)
676
+ descending elevation. For now, there is a single snow class per zone, and the
677
+ zones' areas are identical (1.0 km²). The last zone is of type |ILAKE| and
678
+ does not participate in snow redistribution. We use the same configuration for
679
+ |SMax| (the maximum snow storage) and |SRed| (defining the redistribution
680
+ paths) throughout all examples:
681
+
682
+ >>> from hydpy.models.hland import *
683
+ >>> simulationstep("12h")
684
+ >>> parameterstep("1d")
685
+ >>> area(7.0)
686
+ >>> nmbzones(7)
687
+ >>> sclass(1)
688
+ >>> zonetype(GLACIER, FIELD, FOREST, SEALED, FOREST, FIELD, ILAKE)
689
+ >>> zonez(30.0, 25.0, 20.0, 15.0, 10.0, 10.0, 5.0)
690
+ >>> zonearea(1.0)
691
+ >>> psi(1.0)
692
+ >>> sfdist(1.0)
693
+ >>> smax(500.0)
694
+ >>> sred([[0.0, 0.2, 0.2, 0.2, 0.2, 0.2, 0.0],
695
+ ... [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
696
+ ... [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0],
697
+ ... [0.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.0],
698
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
699
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
700
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])
701
+
702
+ For convenience, we prepare a function that updates all relevant derived
703
+ parameters:
704
+
705
+ >>> def update():
706
+ ... derived.rellandarea.update()
707
+ ... derived.relzoneareas.update()
708
+ ... derived.rellowerzonearea.update()
709
+ ... derived.zonearearatios.update()
710
+ ... derived.indiceszonez.update()
711
+ ... derived.sredorder.update()
712
+ ... derived.srednumber.update()
713
+ ... derived.sredend.update()
714
+ >>> update()
715
+
716
+ In the first example, the total snow water equivalent (300 mm) is way below
717
+ |SRed| (500 mm). Hence, all frozen (|SPL|) and liquid (|WCL|) water released
718
+ deposits completely in the target zones:
719
+
720
+ >>> states.sp = 200.0
721
+ >>> states.wc = 100.0
722
+ >>> fluxes.spl = 20.0, 20.0, 20.0, 20.0, 0.0, 0.0, 0.0
723
+ >>> fluxes.wcl = 10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 0.0
724
+ >>> model.calc_spg_wcg_sp_wc_v1()
725
+ >>> fluxes.spg
726
+ spg(0.0, 4.0, 24.0, 24.0, 14.0, 14.0, 0.0)
727
+ >>> fluxes.wcg
728
+ wcg(0.0, 2.0, 12.0, 12.0, 7.0, 7.0, 0.0)
729
+ >>> states.sp
730
+ sp(200.0, 204.0, 224.0, 224.0, 214.0, 214.0, 0.0)
731
+ >>> states.wc
732
+ wc(100.0, 102.0, 112.0, 112.0, 107.0, 107.0, 0.0)
733
+
734
+ The following test function checks that method |Calc_SPG_WCG_SP_WC_V1| does not
735
+ introduce any water balance errors:
736
+
737
+ >>> from hydpy import repr_
738
+ >>> def check(sp_old, wc_old):
739
+ ... def check_vector(deltas):
740
+ ... return numpy.max(numpy.abs(numpy.sum(deltas, axis=0)))
741
+ ... sp_new = states.sp.average_values()
742
+ ... sp_delta_l = fluxes.spl.average_values()
743
+ ... sp_delta_g = fluxes.spg.average_values()
744
+ ... sp_old_array = numpy.array(6 * [sp_old] + [0.0])
745
+ ... wc_new = states.wc.average_values()
746
+ ... wc_delta_l = fluxes.wcl.average_values()
747
+ ... wc_delta_g = fluxes.wcg.average_values()
748
+ ... wc_old_array = numpy.array(6 * [wc_old] + [0.0])
749
+ ... errors = [sp_old + sp_delta_l - sp_new,
750
+ ... sp_delta_l - sp_delta_g,
751
+ ... check_vector(sp_old_array + fluxes.spg - states.sp),
752
+ ... wc_old + wc_delta_l - wc_new,
753
+ ... wc_delta_l - wc_delta_g,
754
+ ... check_vector(wc_old_array + fluxes.wcg - states.wc)]
755
+ ... print(*(repr_(error) for error in errors), sep=", ")
756
+
757
+ The possible errors related to different aspects of the frozen and the liquid
758
+ water content of the snow layer are all within the range of the given numerical
759
+ precision:
760
+
761
+ >>> check(sp_old=200.0, wc_old=100.0)
762
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
763
+
764
+ Next, we increase the size of the first area and decrease the size of the
765
+ second area by the same amount. The different results for |SPG| and |WCG|
766
+ reflect that the loss terms (|SPL| and |WCL|) relate to the sizes of the
767
+ supplying zones while the gain terms (|SPG| and |WCG|) relate to the sizes of
768
+ the receiving zones:
769
+
770
+ >>> zonearea(1.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0)
771
+ >>> update()
772
+ >>> states.sp = 200.0
773
+ >>> states.wc = 100.0
774
+ >>> model.calc_spg_wcg_sp_wc_v1()
775
+ >>> fluxes.spg
776
+ spg(0.0, 12.0, 16.0, 26.0, 16.0, 16.0, 0.0)
777
+ >>> fluxes.wcg
778
+ wcg(0.0, 6.0, 8.0, 13.0, 8.0, 8.0, 0.0)
779
+ >>> states.sp
780
+ sp(200.0, 212.0, 216.0, 226.0, 216.0, 216.0, 0.0)
781
+ >>> states.wc
782
+ wc(100.0, 106.0, 108.0, 113.0, 108.0, 108.0, 0.0)
783
+ >>> check(sp_old=200.0, wc_old=100.0)
784
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
785
+
786
+ When modelling high mountain areas, even the lowest zones (the so-called
787
+ "dead-ends") can receive substantial amounts of redistributed snow. Therefore,
788
+ the simple "from top to bottom" approach described so far can result in
789
+ unrealistic snow towers for these dead-ends, especially if their size is small
790
+ compared to the size of the snow-delivering area. To prevent such artefacts,
791
+ method |Calc_SPG_WCG_SP_WC_V1| takes the total snow amount of all dead-ends
792
+ exceeding the |Smax| threshold and distributes it gradually to the other zones,
793
+ starting from the lowest in the order defined by parameter |IndicesZoneZ|:
794
+
795
+ >>> zonearea(1.0)
796
+ >>> update()
797
+ >>> states.sp = 400.0
798
+ >>> states.wc = 75.0
799
+ >>> model.calc_spg_wcg_sp_wc_v1()
800
+ >>> fluxes.spg
801
+ spg(0.0, 13.333333, 16.666667, 16.666667, 16.666667, 16.666667, 0.0)
802
+ >>> fluxes.wcg
803
+ wcg(0.0, 6.666667, 8.333333, 8.333333, 8.333333, 8.333333, 0.0)
804
+ >>> states.sp
805
+ sp(400.0, 413.333333, 416.666667, 416.666667, 416.666667, 416.666667,
806
+ 0.0)
807
+ >>> states.wc
808
+ wc(75.0, 81.666667, 83.333333, 83.333333, 83.333333, 83.333333, 0.0)
809
+ >>> check(sp_old=400.0, wc_old=75.0)
810
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
811
+
812
+ If the total snow amount of all zone reaches |SMax|, |Calc_SPG_WCG_SP_WC_V1|
813
+ distributes all remaining excess evenly to all non-lake zones:
814
+
815
+ >>> states.sp = 400.0
816
+ >>> states.wc = 90.0
817
+ >>> model.calc_spg_wcg_sp_wc_v1()
818
+ >>> fluxes.spg
819
+ spg(13.333333, 13.333333, 13.333333, 13.333333, 13.333333, 13.333333,
820
+ 0.0)
821
+ >>> fluxes.wcg
822
+ wcg(6.666667, 6.666667, 6.666667, 6.666667, 6.666667, 6.666667, 0.0)
823
+ >>> states.sp
824
+ sp(413.333333, 413.333333, 413.333333, 413.333333, 413.333333,
825
+ 413.333333, 0.0)
826
+ >>> states.wc
827
+ wc(96.666667, 96.666667, 96.666667, 96.666667, 96.666667, 96.666667, 0.0)
828
+ >>> check(sp_old=400.0, wc_old=90.0)
829
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
830
+
831
+ Introducing multiple snow classes within each zone complicates things. We
832
+ repeat some of the above examples with an increased number of snow classes:
833
+
834
+ >>> sclass(2)
835
+ >>> update()
836
+
837
+ The "normal" snow redistribution relies similarly on parameter |SFDist| as the
838
+ snowfall accumulation does. We show this by repeating the first example with
839
+ the most extreme configuration of |SFDist|, where the second snow class
840
+ receives the entire amount of incoming snow:
841
+
842
+ >>> sfdist(0.0, 2.0)
843
+ >>> states.sp = 200.0
844
+ >>> states.wc = 100.0
845
+ >>> fluxes.spl = 20.0, 20.0, 20.0, 20.0, 0.0, 0.0, 0.0
846
+ >>> fluxes.wcl = 10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 0.0
847
+ >>> model.calc_spg_wcg_sp_wc_v1()
848
+ >>> fluxes.spg
849
+ spg(0.0, 4.0, 24.0, 24.0, 14.0, 14.0, 0.0)
850
+ >>> fluxes.wcg
851
+ wcg(0.0, 2.0, 12.0, 12.0, 7.0, 7.0, 0.0)
852
+ >>> states.sp
853
+ sp([[200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 0.0],
854
+ [200.0, 208.0, 248.0, 248.0, 228.0, 228.0, 0.0]])
855
+ >>> states.wc
856
+ wc([[100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 0.0],
857
+ [100.0, 104.0, 124.0, 124.0, 114.0, 114.0, 0.0]])
858
+
859
+ During the eventual "bottom to top" re-redistribution, on the other hand,
860
+ the fractions between the gains of individual snow classes do not depend on
861
+ |SFDist| but their remaining capacities:
862
+
863
+ >>> states.sp = 400.0
864
+ >>> states.wc = 75.0
865
+ >>> model.calc_spg_wcg_sp_wc_v1()
866
+ >>> fluxes.spg
867
+ spg(0.0, 13.333333, 16.666667, 16.666667, 16.666667, 16.666667, 0.0)
868
+ >>> fluxes.wcg
869
+ wcg(0.0, 6.666667, 8.333333, 8.333333, 8.333333, 8.333333, 0.0)
870
+ >>> states.sp
871
+ sp([[400.0, 412.280702, 416.666667, 416.666667, 416.666667, 416.666667,
872
+ 0.0],
873
+ [400.0, 414.385965, 416.666667, 416.666667, 416.666667, 416.666667,
874
+ 0.0]])
875
+ >>> states.wc
876
+ wc([[75.0, 81.140351, 83.333333, 83.333333, 83.333333, 83.333333, 0.0],
877
+ [75.0, 82.192982, 83.333333, 83.333333, 83.333333, 83.333333, 0.0]])
878
+ >>> check(sp_old=400.0, wc_old=75.0)
879
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
880
+
881
+ During a subbasin-wide excess of |SMax|, all snow classes of a specific zone
882
+ handle the same total snow water equivalent:
883
+
884
+ >>> states.sp = 400.0
885
+ >>> states.wc = 90.0
886
+ >>> model.calc_spg_wcg_sp_wc_v1()
887
+ >>> fluxes.spg
888
+ spg(13.333333, 13.333333, 13.333333, 13.333333, 13.333333, 13.333333,
889
+ 0.0)
890
+ >>> fluxes.wcg
891
+ wcg(6.666667, 6.666667, 6.666667, 6.666667, 6.666667, 6.666667, 0.0)
892
+ >>> states.sp
893
+ sp([[413.333333, 413.333333, 413.333333, 413.333333, 413.333333,
894
+ 413.333333, 0.0],
895
+ [413.333333, 413.333333, 413.333333, 413.333333, 413.333333,
896
+ 413.333333, 0.0]])
897
+ >>> states.wc
898
+ wc([[96.666667, 96.666667, 96.666667, 96.666667, 96.666667, 96.666667,
899
+ 0.0],
900
+ [96.666667, 96.666667, 96.666667, 96.666667, 96.666667, 96.666667,
901
+ 0.0]])
902
+ >>> check(sp_old=400.0, wc_old=90.0)
903
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
904
+ """
905
+
906
+ CONTROLPARAMETERS = (
907
+ hland_control.NmbZones,
908
+ hland_control.SClass,
909
+ hland_control.ZoneType,
910
+ hland_control.SFDist,
911
+ hland_control.SMax,
912
+ hland_control.SRed,
913
+ )
914
+ DERIVEDPARAMETERS = (
915
+ hland_derived.RelLandArea,
916
+ hland_derived.RelZoneAreas,
917
+ hland_derived.ZoneAreaRatios,
918
+ hland_derived.IndicesZoneZ,
919
+ hland_derived.SRedNumber,
920
+ hland_derived.SRedOrder,
921
+ hland_derived.SRedEnd,
922
+ )
923
+ REQUIREDSEQUENCES = (hland_fluxes.SPL, hland_fluxes.WCL)
924
+ UPDATEDSEQUENCES = (hland_states.WC, hland_states.SP)
925
+ RESULTSEQUENCES = (
926
+ hland_aides.SPE,
927
+ hland_aides.WCE,
928
+ hland_fluxes.SPG,
929
+ hland_fluxes.WCG,
930
+ )
931
+
932
+ @staticmethod
933
+ def __call__(model: modeltools.Model) -> None:
934
+ con = model.parameters.control.fastaccess
935
+ der = model.parameters.derived.fastaccess
936
+ flu = model.sequences.fluxes.fastaccess
937
+ sta = model.sequences.states.fastaccess
938
+ aid = model.sequences.aides.fastaccess
939
+
940
+ # initialise gain and excess:
941
+ for i in range(con.nmbzones):
942
+ flu.spg[i] = 0.0
943
+ flu.wcg[i] = 0.0
944
+ aid.spe[i] = 0.0
945
+ aid.wce[i] = 0.0
946
+ if con.zonetype[i] == ILAKE:
947
+ for c in range(con.sclass):
948
+ sta.sp[c, i] = 0.0
949
+ sta.wc[c, i] = 0.0
950
+
951
+ # redistribute losses from top to bottom:
952
+ for i in range(der.srednumber):
953
+ # f: from, t: to
954
+ f, t = der.sredorder[i, 0], der.sredorder[i, 1]
955
+ d_f = der.zonearearatios[f, t] * con.sred[f, t]
956
+ d_gain_frozen = d_f * (flu.spl[f] + aid.spe[f])
957
+ d_gain_liquid = d_f * (flu.wcl[f] + aid.wce[f])
958
+ d_gain_total = d_gain_frozen + d_gain_liquid
959
+ for c in range(con.sclass):
960
+ d_gain_pot = con.sfdist[c] * d_gain_total
961
+ if d_gain_pot > 0.0:
962
+ d_gain_max = con.smax[t] - sta.sp[c, t] - sta.wc[c, t]
963
+ d_fraction_gain = min(d_gain_max / d_gain_pot, 1.0)
964
+ d_factor_gain = d_fraction_gain * con.sfdist[c]
965
+ flu.spg[t] += d_factor_gain * d_gain_frozen / con.sclass
966
+ flu.wcg[t] += d_factor_gain * d_gain_liquid / con.sclass
967
+ sta.sp[c, t] += d_factor_gain * d_gain_frozen
968
+ sta.wc[c, t] += d_factor_gain * d_gain_liquid
969
+ d_factor_excess = (1.0 - d_fraction_gain) * con.sfdist[c]
970
+ aid.spe[t] += d_factor_excess * d_gain_frozen / con.sclass
971
+ aid.wce[t] += d_factor_excess * d_gain_liquid / con.sclass
972
+
973
+ # check for remaining excess at the dead ends:
974
+ d_excess_frozen_basin, d_excess_liquid_basin = 0.0, 0.0
975
+ for i in range(con.nmbzones):
976
+ if der.sredend[i]:
977
+ d_excess_frozen_basin += der.relzoneareas[i] * (aid.spe[i] + flu.spl[i])
978
+ d_excess_liquid_basin += der.relzoneareas[i] * (aid.wce[i] + flu.wcl[i])
979
+ if (d_excess_frozen_basin + d_excess_liquid_basin) <= 0.0:
980
+ return
981
+
982
+ # redistribute the remaining excess from bottom to top:
983
+ for i in range(con.nmbzones):
984
+ t = der.indiceszonez[i]
985
+ if con.zonetype[t] == ILAKE:
986
+ continue
987
+ d_excess_frozen_zone = d_excess_frozen_basin / der.relzoneareas[t]
988
+ d_excess_liquid_zone = d_excess_liquid_basin / der.relzoneareas[t]
989
+ d_excess_total_zone = d_excess_frozen_zone + d_excess_liquid_zone
990
+ d_gain_max_cum = 0.0
991
+ for c in range(con.sclass):
992
+ d_gain_max_cum += con.smax[t] - sta.sp[c, t] - sta.wc[c, t]
993
+ if d_gain_max_cum <= 0.0:
994
+ continue
995
+ d_fraction_gain_zone = min(
996
+ d_gain_max_cum / con.sclass / d_excess_total_zone, 1.0
997
+ )
998
+ d_excess_frozen_zone_actual = d_fraction_gain_zone * d_excess_frozen_zone
999
+ d_excess_liquid_zone_actual = d_fraction_gain_zone * d_excess_liquid_zone
1000
+ for c in range(con.sclass):
1001
+ d_fraction_gain_class = (
1002
+ con.smax[t] - sta.sp[c, t] - sta.wc[c, t]
1003
+ ) / d_gain_max_cum
1004
+ d_delta_sp_zone = d_fraction_gain_class * d_excess_frozen_zone_actual
1005
+ d_delta_wc_zone = d_fraction_gain_class * d_excess_liquid_zone_actual
1006
+ flu.spg[t] += d_delta_sp_zone
1007
+ flu.wcg[t] += d_delta_wc_zone
1008
+ sta.sp[c, t] += d_delta_sp_zone * con.sclass
1009
+ sta.wc[c, t] += d_delta_wc_zone * con.sclass
1010
+ d_excess_frozen_basin -= d_excess_frozen_zone_actual * der.relzoneareas[t]
1011
+ d_excess_liquid_basin -= d_excess_liquid_zone_actual * der.relzoneareas[t]
1012
+ if (d_excess_frozen_basin + d_excess_liquid_basin) <= 0.0:
1013
+ return
1014
+
1015
+ # redistribute the still remaining excess evenly:
1016
+ d_excess_frozen_land = d_excess_frozen_basin / der.rellandarea
1017
+ d_excess_liquid_land = d_excess_liquid_basin / der.rellandarea
1018
+ for t in range(con.nmbzones):
1019
+ if con.zonetype[t] != ILAKE:
1020
+ flu.spg[t] += d_excess_frozen_land
1021
+ flu.wcg[t] += d_excess_liquid_land
1022
+ for c in range(con.sclass):
1023
+ sta.sp[c, t] += d_excess_frozen_land
1024
+ sta.wc[c, t] += d_excess_liquid_land
1025
+ return
1026
+
1027
+
1028
+ class Calc_CFAct_V1(modeltools.Method):
1029
+ r"""Adjust the day degree factor for snow to the current day of the year.
1030
+
1031
+ Basic equations:
1032
+ :math:`CFAct = max( CFMax + f \cdot CFVar, 0 )`
1033
+
1034
+ :math:`f = sin(2 \cdot Pi \cdot (DOY + 1) / 366) / 2`
1035
+
1036
+ Examples:
1037
+
1038
+ We initialise five zones of different types but the same values for |CFMax| and
1039
+ |CFVar|. For internal lakes, |CFAct| is always zero. In all other cases,
1040
+ results are identical and follow a sinusoid curve throughout the year (of which
1041
+ we show only selected points as the maximum around June 20 and the minimum
1042
+ around December 20):
1043
+
1044
+ >>> from hydpy.models.hland import *
1045
+ >>> simulationstep("12h")
1046
+ >>> parameterstep("1d")
1047
+ >>> nmbzones(5)
1048
+ >>> zonetype(ILAKE, GLACIER, FIELD, FOREST, SEALED)
1049
+ >>> cfmax(4.0)
1050
+ >>> cfvar(3.0)
1051
+ >>> from hydpy import UnitTest
1052
+ >>> test = UnitTest(model=model,
1053
+ ... method=model.calc_cfact_v1,
1054
+ ... last_example=10,
1055
+ ... parseqs=(derived.doy, factors.cfact))
1056
+ >>> test.nexts.doy = 0, 1, 170, 171, 172, 353, 354, 355, 364, 365
1057
+ >>> test()
1058
+ | ex. | doy | cfact |
1059
+ -------------------------------------------------------------------------------
1060
+ | 1 | 0 0 0 0 0 | 0.0 1.264648 1.264648 1.264648 1.264648 |
1061
+ | 2 | 1 1 1 1 1 | 0.0 1.267289 1.267289 1.267289 1.267289 |
1062
+ | 3 | 170 170 170 170 170 | 0.0 2.749762 2.749762 2.749762 2.749762 |
1063
+ | 4 | 171 171 171 171 171 | 0.0 2.749976 2.749976 2.749976 2.749976 |
1064
+ | 5 | 172 172 172 172 172 | 0.0 2.749969 2.749969 2.749969 2.749969 |
1065
+ | 6 | 353 353 353 353 353 | 0.0 1.250238 1.250238 1.250238 1.250238 |
1066
+ | 7 | 354 354 354 354 354 | 0.0 1.250024 1.250024 1.250024 1.250024 |
1067
+ | 8 | 355 355 355 355 355 | 0.0 1.250031 1.250031 1.250031 1.250031 |
1068
+ | 9 | 364 364 364 364 364 | 0.0 1.260018 1.260018 1.260018 1.260018 |
1069
+ | 10 | 365 365 365 365 365 | 0.0 1.262224 1.262224 1.262224 1.262224 |
1070
+
1071
+ Now, we convert all zones to type |FIELD| and vary |CFVar|. If we set |CFVar|
1072
+ to zero, |CFAct| always equals |CFMax| (see zone one). If we change the sign
1073
+ of |CFVar|, the sinusoid curve shifts a half year to reflect the southern
1074
+ hemisphere's annual cycle of radiation (compare zone two and three). Finally,
1075
+ |Calc_CFAct_V1| prevents negative values of |CFAct| by setting them to zero
1076
+ (see zone four and five):
1077
+
1078
+ >>> zonetype(FIELD)
1079
+ >>> cfvar(0.0, 3.0, -3.0, 10.0, -10.0)
1080
+ >>> test()
1081
+ | ex. | doy | cfact |
1082
+ -------------------------------------------------------------------------------
1083
+ | 1 | 0 0 0 0 0 | 2.0 1.264648 2.735352 0.0 4.451173 |
1084
+ | 2 | 1 1 1 1 1 | 2.0 1.267289 2.732711 0.0 4.442371 |
1085
+ | 3 | 170 170 170 170 170 | 2.0 2.749762 1.250238 4.499206 0.0 |
1086
+ | 4 | 171 171 171 171 171 | 2.0 2.749976 1.250024 4.499919 0.0 |
1087
+ | 5 | 172 172 172 172 172 | 2.0 2.749969 1.250031 4.499896 0.0 |
1088
+ | 6 | 353 353 353 353 353 | 2.0 1.250238 2.749762 0.0 4.499206 |
1089
+ | 7 | 354 354 354 354 354 | 2.0 1.250024 2.749976 0.0 4.499919 |
1090
+ | 8 | 355 355 355 355 355 | 2.0 1.250031 2.749969 0.0 4.499896 |
1091
+ | 9 | 364 364 364 364 364 | 2.0 1.260018 2.739982 0.0 4.466606 |
1092
+ | 10 | 365 365 365 365 365 | 2.0 1.262224 2.737776 0.0 4.459252 |
1093
+ """
1094
+
1095
+ CONTROLPARAMETERS = (
1096
+ hland_control.NmbZones,
1097
+ hland_control.ZoneType,
1098
+ hland_control.CFMax,
1099
+ hland_control.CFVar,
1100
+ )
1101
+ FIXEDPARAMETERS = (hland_fixed.Pi,)
1102
+ DERIVEDPARAMETERS = (hland_derived.DOY,)
1103
+ RESULTSEQUENCES = (hland_factors.CFAct,)
1104
+
1105
+ @staticmethod
1106
+ def __call__(model: modeltools.Model) -> None:
1107
+ con = model.parameters.control.fastaccess
1108
+ der = model.parameters.derived.fastaccess
1109
+ fix = model.parameters.fixed.fastaccess
1110
+ fac = model.sequences.factors.fastaccess
1111
+ d_factor = 0.5 * modelutils.sin(
1112
+ 2 * fix.pi * (der.doy[model.idx_sim] + 1) / 366 - 1.39
1113
+ )
1114
+ for k in range(con.nmbzones):
1115
+ if con.zonetype[k] != ILAKE:
1116
+ fac.cfact[k] = max(con.cfmax[k] + d_factor * con.cfvar[k], 0.0)
1117
+ else:
1118
+ fac.cfact[k] = 0.0
1119
+
1120
+
1121
+ class Calc_Melt_SP_WC_V1(modeltools.Method):
1122
+ r"""Calculate the melting of the ice content within the snow layer and update both
1123
+ the snow layers' ice and the water content.
1124
+
1125
+ Basic equations:
1126
+ :math:`\frac{dSP}{dt} = - Melt`
1127
+
1128
+ :math:`\frac{dWC}{dt} = + Melt`
1129
+
1130
+ :math:`Melt = min(CFAct \cdot (TC - TTM), SP)`
1131
+
1132
+ Examples:
1133
+
1134
+ We initialise seven zones with the same threshold temperature and degree-day
1135
+ factor but different zone types and initial ice contents:
1136
+
1137
+ >>> from hydpy.models.hland import *
1138
+ >>> simulationstep("12h")
1139
+ >>> parameterstep("1d")
1140
+ >>> nmbzones(7)
1141
+ >>> sclass(1)
1142
+ >>> zonetype(ILAKE, GLACIER, FIELD, FOREST, SEALED, SEALED, SEALED)
1143
+ >>> derived.ttm = 2.0
1144
+ >>> factors.cfact(2.0)
1145
+ >>> states.sp = 0.0, 10.0, 10.0, 10.0, 10.0, 5.0, 0.0
1146
+ >>> states.wc = 2.0
1147
+
1148
+ When the actual temperature equals the threshold temperature for melting and
1149
+ refreezing, no melting occurs, and the states remain unchanged:
1150
+
1151
+ >>> factors.tc = 2.0
1152
+ >>> model.calc_melt_sp_wc_v1()
1153
+ >>> fluxes.melt
1154
+ melt(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1155
+ >>> states.sp
1156
+ sp(0.0, 10.0, 10.0, 10.0, 10.0, 5.0, 0.0)
1157
+ >>> states.wc
1158
+ wc(0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0)
1159
+
1160
+ The same holds for an actual temperature lower than the threshold temperature:
1161
+
1162
+ >>> states.sp = 0.0, 10.0, 10.0, 10.0, 10.0, 5.0, 0.0
1163
+ >>> states.wc = 2.0
1164
+ >>> factors.tc = -1.0
1165
+ >>> model.calc_melt_sp_wc_v1()
1166
+ >>> fluxes.melt
1167
+ melt(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1168
+ >>> states.sp
1169
+ sp(0.0, 10.0, 10.0, 10.0, 10.0, 5.0, 0.0)
1170
+ >>> states.wc
1171
+ wc(0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0)
1172
+
1173
+ With an actual temperature of 3°C above the threshold temperature, melting can
1174
+ occur. The actual melting is consistent with potential melting, except for the
1175
+ first zone, an internal lake, and the last two zones, for which potential
1176
+ melting exceeds the available frozen water content of the snow layer:
1177
+
1178
+ >>> states.sp = 0.0, 10.0, 10.0, 10.0, 10.0, 5.0, 0.0
1179
+ >>> states.wc = 2.0
1180
+ >>> factors.tc = 5.0
1181
+ >>> model.calc_melt_sp_wc_v1()
1182
+ >>> fluxes.melt
1183
+ melt(0.0, 6.0, 6.0, 6.0, 6.0, 5.0, 0.0)
1184
+ >>> states.sp
1185
+ sp(0.0, 4.0, 4.0, 4.0, 4.0, 0.0, 0.0)
1186
+ >>> states.wc
1187
+ wc(0.0, 8.0, 8.0, 8.0, 8.0, 7.0, 2.0)
1188
+
1189
+ In the above examples, we did not divide the zones into snow classes. If we do
1190
+ so, method |Calc_Melt_SP_WC_V1| assumes a uniform distribution of the
1191
+ potential melting among the individual classes. This assumption implies that
1192
+ if a single snow class does not provide enough frozen water, the actual melting
1193
+ of the total zone must be smaller than its potential melt rate:
1194
+
1195
+ >>> sclass(2)
1196
+ >>> states.sp = [[0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 0.0],
1197
+ ... [0.0, 10.0, 10.0, 10.0, 10.0, 10.0, 0.0]]
1198
+ >>> states.wc = [[0.0], [2.0]]
1199
+ >>> model.calc_melt_sp_wc_v1()
1200
+ >>> fluxes.melt
1201
+ melt([[0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 0.0],
1202
+ [0.0, 6.0, 6.0, 6.0, 6.0, 6.0, 0.0]])
1203
+ >>> states.sp
1204
+ sp([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
1205
+ [0.0, 4.0, 4.0, 4.0, 4.0, 4.0, 0.0]])
1206
+ >>> states.wc
1207
+ wc([[0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 0.0],
1208
+ [0.0, 8.0, 8.0, 8.0, 8.0, 8.0, 2.0]])
1209
+ """
1210
+
1211
+ CONTROLPARAMETERS = (
1212
+ hland_control.NmbZones,
1213
+ hland_control.SClass,
1214
+ hland_control.ZoneType,
1215
+ )
1216
+ DERIVEDPARAMETERS = (hland_derived.TTM,)
1217
+ REQUIREDSEQUENCES = (hland_factors.TC, hland_factors.CFAct)
1218
+ UPDATEDSEQUENCES = (hland_states.WC, hland_states.SP)
1219
+ RESULTSEQUENCES = (hland_fluxes.Melt,)
1220
+
1221
+ @staticmethod
1222
+ def __call__(model: modeltools.Model) -> None:
1223
+ con = model.parameters.control.fastaccess
1224
+ der = model.parameters.derived.fastaccess
1225
+ fac = model.sequences.factors.fastaccess
1226
+ flu = model.sequences.fluxes.fastaccess
1227
+ sta = model.sequences.states.fastaccess
1228
+ for k in range(con.nmbzones):
1229
+ if con.zonetype[k] != ILAKE:
1230
+ if fac.tc[k] > der.ttm[k]:
1231
+ d_potmelt = fac.cfact[k] * (fac.tc[k] - der.ttm[k])
1232
+ for c in range(con.sclass):
1233
+ flu.melt[c, k] = min(d_potmelt, sta.sp[c, k])
1234
+ sta.sp[c, k] -= flu.melt[c, k]
1235
+ sta.wc[c, k] += flu.melt[c, k]
1236
+ else:
1237
+ for c in range(con.sclass):
1238
+ flu.melt[c, k] = 0.0
1239
+ else:
1240
+ for c in range(con.sclass):
1241
+ flu.melt[c, k] = 0.0
1242
+ sta.wc[c, k] = 0.0
1243
+ sta.sp[c, k] = 0.0
1244
+
1245
+
1246
+ class Calc_Refr_SP_WC_V1(modeltools.Method):
1247
+ r"""Calculate refreezing of the water content within the snow layer and
1248
+ update both the snow layers' ice and the water content.
1249
+
1250
+ Basic equations:
1251
+ :math:`\frac{dSP}{dt} = + Refr`
1252
+
1253
+ :math:`\frac{dWC}{dt} = - Refr`
1254
+
1255
+ :math:`Refr = min(cfr \cdot cfmax \cdot (TTM - TC), WC)`
1256
+
1257
+ Examples:
1258
+
1259
+ We initialise seven zones with the same threshold temperature, degree-day factor
1260
+ and refreezing coefficient but different zone types and initial states:
1261
+
1262
+ >>> from hydpy.models.hland import *
1263
+ >>> simulationstep("12h")
1264
+ >>> parameterstep("1d")
1265
+ >>> nmbzones(7)
1266
+ >>> sclass(1)
1267
+ >>> zonetype(ILAKE, GLACIER, FIELD, FOREST, SEALED, SEALED, SEALED)
1268
+ >>> cfmax(4.0)
1269
+ >>> cfr(0.1)
1270
+ >>> derived.ttm = 2.0
1271
+ >>> states.sp = 2.0
1272
+ >>> states.wc = 0.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.0
1273
+
1274
+ Note that the assumed length of the simulation step is half a day. Hence the
1275
+ effective value of the degree-day factor is not 4 but 2:
1276
+
1277
+ >>> cfmax
1278
+ cfmax(4.0)
1279
+ >>> from hydpy import round_
1280
+ >>> round_(cfmax.values[0])
1281
+ 2.0
1282
+
1283
+ When the actual temperature equals the threshold temperature for melting and
1284
+ refreezing, no refreezing occurs, and the states remain unchanged:
1285
+
1286
+ >>> factors.tc = 2.0
1287
+ >>> model.calc_refr_sp_wc_v1()
1288
+ >>> fluxes.refr
1289
+ refr(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1290
+ >>> states.sp
1291
+ sp(0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0)
1292
+ >>> states.wc
1293
+ wc(0.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.0)
1294
+
1295
+ The same holds for an actual temperature higher than the threshold temperature:
1296
+
1297
+ >>> states.sp = 2.0
1298
+ >>> states.wc = 0.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.0
1299
+ >>> factors.tc = 2.0
1300
+ >>> model.calc_refr_sp_wc_v1()
1301
+ >>> fluxes.refr
1302
+ refr(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1303
+ >>> states.sp
1304
+ sp(0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0)
1305
+ >>> states.wc
1306
+ wc(0.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.0)
1307
+
1308
+ With an actual temperature of 3°C above the threshold temperature, there is no
1309
+ refreezing:
1310
+
1311
+ >>> states.sp = 2.0
1312
+ >>> states.wc = 0.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.0
1313
+ >>> factors.tc = 5.0
1314
+ >>> model.calc_refr_sp_wc_v1()
1315
+ >>> fluxes.refr
1316
+ refr(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1317
+ >>> states.sp
1318
+ sp(0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0)
1319
+ >>> states.wc
1320
+ wc(0.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.0)
1321
+
1322
+ With an actual temperature of 3°C below the threshold temperature, refreezing
1323
+ can occur. Actual refreezing is consistent with potential refreezing, except
1324
+ for the first zone, an internal lake, and the last two zones, for which
1325
+ potential refreezing exceeds the available liquid water content of the snow
1326
+ layer:
1327
+
1328
+ >>> states.sp = 2.0
1329
+ >>> states.wc = 0.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.0
1330
+ >>> factors.tc = -1.0
1331
+ >>> model.calc_refr_sp_wc_v1()
1332
+ >>> fluxes.refr
1333
+ refr(0.0, 0.6, 0.6, 0.6, 0.6, 0.5, 0.0)
1334
+ >>> states.sp
1335
+ sp(0.0, 2.6, 2.6, 2.6, 2.6, 2.5, 2.0)
1336
+ >>> states.wc
1337
+ wc(0.0, 0.4, 0.4, 0.4, 0.4, 0.0, 0.0)
1338
+
1339
+ In the above examples, we did not divide the zones into snow classes. If we do
1340
+ so, method |Calc_Refr_SP_WC_V1| assumes a uniform distribution of the potential
1341
+ refreezing among the individual classes. This assumption implies that if a
1342
+ single snow class does not provide enough liquid water, the actual refreezing
1343
+ of the total zone must be smaller than its potential refreezing rate:
1344
+
1345
+ >>> sclass(2)
1346
+ >>> states.sp = [[0.0], [2.0]]
1347
+ >>> states.wc = [[0.0, 0.0, 0.1, 0.2, 0.3, 0.4, 0.0],
1348
+ ... [0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0]]
1349
+ >>> model.calc_refr_sp_wc_v1()
1350
+ >>> fluxes.refr
1351
+ refr([[0.0, 0.0, 0.1, 0.2, 0.3, 0.4, 0.0],
1352
+ [0.0, 0.6, 0.6, 0.6, 0.6, 0.6, 0.0]])
1353
+ >>> states.sp
1354
+ sp([[0.0, 0.0, 0.1, 0.2, 0.3, 0.4, 0.0],
1355
+ [0.0, 2.6, 2.6, 2.6, 2.6, 2.6, 2.0]])
1356
+ >>> states.wc
1357
+ wc([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
1358
+ [0.0, 0.4, 0.4, 0.4, 0.4, 0.4, 0.0]])
1359
+ """
1360
+
1361
+ CONTROLPARAMETERS = (
1362
+ hland_control.NmbZones,
1363
+ hland_control.SClass,
1364
+ hland_control.ZoneType,
1365
+ hland_control.CFR,
1366
+ hland_control.CFMax,
1367
+ )
1368
+ DERIVEDPARAMETERS = (hland_derived.TTM,)
1369
+ REQUIREDSEQUENCES = (hland_factors.TC,)
1370
+ UPDATEDSEQUENCES = (hland_states.WC, hland_states.SP)
1371
+ RESULTSEQUENCES = (hland_fluxes.Refr,)
1372
+
1373
+ @staticmethod
1374
+ def __call__(model: modeltools.Model) -> None:
1375
+ con = model.parameters.control.fastaccess
1376
+ der = model.parameters.derived.fastaccess
1377
+ fac = model.sequences.factors.fastaccess
1378
+ flu = model.sequences.fluxes.fastaccess
1379
+ sta = model.sequences.states.fastaccess
1380
+ for k in range(con.nmbzones):
1381
+ if con.zonetype[k] != ILAKE:
1382
+ if fac.tc[k] < der.ttm[k]:
1383
+ d_potrefr = con.cfr[k] * con.cfmax[k] * (der.ttm[k] - fac.tc[k])
1384
+ for c in range(con.sclass):
1385
+ flu.refr[c, k] = min(d_potrefr, sta.wc[c, k])
1386
+ sta.sp[c, k] += flu.refr[c, k]
1387
+ sta.wc[c, k] -= flu.refr[c, k]
1388
+ else:
1389
+ for c in range(con.sclass):
1390
+ flu.refr[c, k] = 0.0
1391
+ else:
1392
+ for c in range(con.sclass):
1393
+ flu.refr[c, k] = 0.0
1394
+ sta.wc[c, k] = 0.0
1395
+ sta.sp[c, k] = 0.0
1396
+
1397
+
1398
+ class Calc_In_WC_V1(modeltools.Method):
1399
+ r"""Calculate the actual water release from the snow layer due to the exceedance of
1400
+ the snow layers' capacity for (liquid) water.
1401
+
1402
+ Basic equations:
1403
+ :math:`\frac{dWC}{dt} = -In`
1404
+
1405
+ :math:`-In = max(WC - WHC \cdot SP, 0)`
1406
+
1407
+ Examples:
1408
+
1409
+ We initialise seven zones of different types with different frozen water
1410
+ contents of the snow layer and set the relative water holding capacity to 20 %:
1411
+
1412
+ >>> from hydpy.models.hland import *
1413
+ >>> simulationstep("12h")
1414
+ >>> parameterstep("1d")
1415
+ >>> nmbzones(7)
1416
+ >>> sclass(1)
1417
+ >>> zonetype(ILAKE, GLACIER, FIELD, FOREST, SEALED, SEALED, SEALED)
1418
+ >>> whc(0.2)
1419
+ >>> states.sp = 0.0, 10.0, 10.0, 10.0, 10.0, 5.0, 0.0
1420
+
1421
+ Also, we set the actual value of stand precipitation to 5 mm/d:
1422
+
1423
+ >>> fluxes.tf = 5.0
1424
+
1425
+ When there is no (liquid) water content in the snow layer, no water can be
1426
+ released:
1427
+
1428
+ >>> states.wc = 0.0
1429
+ >>> model.calc_in_wc_v1()
1430
+ >>> fluxes.in_
1431
+ in_(5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1432
+ >>> states.wc
1433
+ wc(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1434
+
1435
+ When there is a (liquid) water content in the snow layer, the water release
1436
+ depends on the frozen water content. Note the special cases of the first zone
1437
+ being an internal lake, for which the snow routine does not apply, and of the
1438
+ last zone, which has no ice content and thus effectively is not a snow layer:
1439
+
1440
+ >>> states.wc = 5.0
1441
+ >>> model.calc_in_wc_v1()
1442
+ >>> fluxes.in_
1443
+ in_(5.0, 3.0, 3.0, 3.0, 3.0, 4.0, 5.0)
1444
+ >>> states.wc
1445
+ wc(0.0, 2.0, 2.0, 2.0, 2.0, 1.0, 0.0)
1446
+
1447
+ For a relative water holding capacity of zero, the snow layer releases all
1448
+ liquid water immediately:
1449
+
1450
+ >>> whc(0.0)
1451
+ >>> states.wc = 5.0
1452
+ >>> model.calc_in_wc_v1()
1453
+ >>> fluxes.in_
1454
+ in_(5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0)
1455
+ >>> states.wc
1456
+ wc(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1457
+
1458
+ In the above examples, we did not divide the zones into snow classes. If we do
1459
+ so, method |Calc_In_WC_V1| averages the water release of all snow classes of
1460
+ each zone:
1461
+
1462
+ >>> sclass(2)
1463
+ >>> whc(0.0)
1464
+ >>> states.sp = 0.0, 10.0, 10.0, 10.0, 10.0, 5.0, 0.0
1465
+ >>> states.wc = [[2.0], [3.0]]
1466
+ >>> model.calc_in_wc_v1()
1467
+ >>> fluxes.in_
1468
+ in_(5.0, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5)
1469
+ >>> states.wc
1470
+ wc([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
1471
+ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])
1472
+
1473
+ For the single lake zone, method |Calc_In_WC_V1| passed the stand precipitation
1474
+ directly to |In_| in all examples.
1475
+ """
1476
+
1477
+ CONTROLPARAMETERS = (
1478
+ hland_control.NmbZones,
1479
+ hland_control.SClass,
1480
+ hland_control.ZoneType,
1481
+ hland_control.WHC,
1482
+ )
1483
+ REQUIREDSEQUENCES = (hland_fluxes.TF, hland_states.SP)
1484
+ UPDATEDSEQUENCES = (hland_states.WC,)
1485
+ RESULTSEQUENCES = (hland_fluxes.In_,)
1486
+
1487
+ @staticmethod
1488
+ def __call__(model: modeltools.Model) -> None:
1489
+ con = model.parameters.control.fastaccess
1490
+ flu = model.sequences.fluxes.fastaccess
1491
+ sta = model.sequences.states.fastaccess
1492
+ for k in range(con.nmbzones):
1493
+ flu.in_[k] = 0.0
1494
+ if con.zonetype[k] != ILAKE:
1495
+ for c in range(con.sclass):
1496
+ d_wc_old = sta.wc[c, k]
1497
+ sta.wc[c, k] = min(d_wc_old, con.whc[k] * sta.sp[c, k])
1498
+ flu.in_[k] += (d_wc_old - sta.wc[c, k]) / con.sclass
1499
+ else:
1500
+ flu.in_[k] = flu.tf[k]
1501
+ for c in range(con.sclass):
1502
+ sta.wc[c, k] = 0.0
1503
+
1504
+
1505
+ class Calc_SWE_V1(modeltools.Method):
1506
+ r"""Calculate the total snow water equivalent.
1507
+
1508
+ Basic equation:
1509
+ :math:`SWE = SP + WC`
1510
+
1511
+ Example:
1512
+
1513
+ We initialise five zones of different types, each one with two snow classes.
1514
+ For internal lakes, |Calc_SWE_V1| generally sets the snow water equivalent to
1515
+ zero. For all others, the given basic equation applies:
1516
+
1517
+ >>> from hydpy.models.hland import *
1518
+ >>> parameterstep()
1519
+ >>> nmbzones(5)
1520
+ >>> sclass(2)
1521
+ >>> zonetype(ILAKE, GLACIER, FIELD, FOREST, SEALED)
1522
+ >>> states.wc = [[0.1, 0.2, 0.3, 0.4, 0.5], [0.6, 0.7, 0.8, 0.9, 1.0]]
1523
+ >>> states.sp = [[1.0, 2.0, 3.0, 4.0, 5.0], [6.0, 7.0, 8.0, 9.0, 10.0]]
1524
+ >>> model.calc_swe_v1()
1525
+ >>> factors.swe
1526
+ swe([[0.0, 2.2, 3.3, 4.4, 5.5],
1527
+ [0.0, 7.7, 8.8, 9.9, 11.0]])
1528
+ """
1529
+
1530
+ CONTROLPARAMETERS = (
1531
+ hland_control.NmbZones,
1532
+ hland_control.SClass,
1533
+ hland_control.ZoneType,
1534
+ )
1535
+ REQUIREDSEQUENCES = (hland_states.SP, hland_states.WC)
1536
+ RESULTSEQUENCES = (hland_factors.SWE,)
1537
+
1538
+ @staticmethod
1539
+ def __call__(model: modeltools.Model) -> None:
1540
+ con = model.parameters.control.fastaccess
1541
+ fac = model.sequences.factors.fastaccess
1542
+ sta = model.sequences.states.fastaccess
1543
+ for k in range(con.nmbzones):
1544
+ if con.zonetype[k] != ILAKE:
1545
+ for c in range(con.sclass):
1546
+ fac.swe[c, k] = sta.sp[c, k] + sta.wc[c, k]
1547
+ else:
1548
+ for c in range(con.sclass):
1549
+ fac.swe[c, k] = 0.0
1550
+
1551
+
1552
+ class Calc_SR_V1(modeltools.Method):
1553
+ r"""Calculate the sealed surface runoff.
1554
+
1555
+ Basic equations:
1556
+ .. math::
1557
+ SR =
1558
+ \begin{cases}
1559
+ In &|\ ZoneType_k = SEALED
1560
+ \\
1561
+ 0 &|\ ZoneType_k \neq SEALED
1562
+ \end{cases}
1563
+
1564
+ Example:
1565
+
1566
+ >>> from hydpy.models.hland import *
1567
+ >>> parameterstep()
1568
+ >>> nmbzones(5)
1569
+ >>> zonetype(ILAKE, GLACIER, FIELD, FOREST, SEALED)
1570
+ >>> fluxes.in_ = 1.0
1571
+ >>> fluxes.sr = 2.0
1572
+ >>> model.calc_sr_v1()
1573
+ >>> fluxes.sr
1574
+ sr(0.0, 0.0, 0.0, 0.0, 1.0)
1575
+ """
1576
+
1577
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
1578
+ REQUIREDSEQUENCES = (hland_fluxes.In_,)
1579
+ RESULTSEQUENCES = (hland_fluxes.SR,)
1580
+
1581
+ @staticmethod
1582
+ def __call__(model: modeltools.Model) -> None:
1583
+ con = model.parameters.control.fastaccess
1584
+ flu = model.sequences.fluxes.fastaccess
1585
+ for k in range(con.nmbzones):
1586
+ if con.zonetype[k] == SEALED:
1587
+ flu.sr[k] = flu.in_[k]
1588
+ else:
1589
+ flu.sr[k] = 0.0
1590
+
1591
+
1592
+ class Calc_GAct_V1(modeltools.Method):
1593
+ r"""Adjust the day degree factor for glacier ice to the current day of the year.
1594
+
1595
+ Basic equations:
1596
+ :math:`GAct = max( GMelt + f \cdot GVar, 0 )`
1597
+
1598
+ :math:`f = sin(2 \cdot Pi \cdot (DOY + 1) / 366) / 2`
1599
+
1600
+ Examples:
1601
+
1602
+ The following examples agree with the ones |Calc_CFAct_V1|, except that method
1603
+ |Calc_GAct_V1| applies the given basic equations only for zones of types
1604
+ |GLACIER| and sets |GAct| to zero for all other zone types:
1605
+
1606
+ >>> from hydpy.models.hland import *
1607
+ >>> simulationstep("12h")
1608
+ >>> parameterstep("1d")
1609
+ >>> nmbzones(5)
1610
+ >>> zonetype(ILAKE, GLACIER, FIELD, FOREST, SEALED)
1611
+ >>> gmelt(4.0)
1612
+ >>> gvar(3.0)
1613
+ >>> from hydpy import UnitTest
1614
+ >>> test = UnitTest(model=model,
1615
+ ... method=model.calc_gact_v1,
1616
+ ... last_example=10,
1617
+ ... parseqs=(derived.doy, factors.gact))
1618
+ >>> test.nexts.doy = 0, 1, 170, 171, 172, 353, 354, 355, 364, 365
1619
+ >>> test()
1620
+ | ex. | doy | gact |
1621
+ -----------------------------------------------------------------
1622
+ | 1 | 0 0 0 0 0 | 0.0 1.264648 0.0 0.0 0.0 |
1623
+ | 2 | 1 1 1 1 1 | 0.0 1.267289 0.0 0.0 0.0 |
1624
+ | 3 | 170 170 170 170 170 | 0.0 2.749762 0.0 0.0 0.0 |
1625
+ | 4 | 171 171 171 171 171 | 0.0 2.749976 0.0 0.0 0.0 |
1626
+ | 5 | 172 172 172 172 172 | 0.0 2.749969 0.0 0.0 0.0 |
1627
+ | 6 | 353 353 353 353 353 | 0.0 1.250238 0.0 0.0 0.0 |
1628
+ | 7 | 354 354 354 354 354 | 0.0 1.250024 0.0 0.0 0.0 |
1629
+ | 8 | 355 355 355 355 355 | 0.0 1.250031 0.0 0.0 0.0 |
1630
+ | 9 | 364 364 364 364 364 | 0.0 1.260018 0.0 0.0 0.0 |
1631
+ | 10 | 365 365 365 365 365 | 0.0 1.262224 0.0 0.0 0.0 |
1632
+
1633
+ >>> zonetype(GLACIER)
1634
+ >>> gvar(0.0, 3.0, -3.0, 10.0, -10.0)
1635
+ >>> test()
1636
+ | ex. | doy | gact |
1637
+ -------------------------------------------------------------------------------
1638
+ | 1 | 0 0 0 0 0 | 2.0 1.264648 2.735352 0.0 4.451173 |
1639
+ | 2 | 1 1 1 1 1 | 2.0 1.267289 2.732711 0.0 4.442371 |
1640
+ | 3 | 170 170 170 170 170 | 2.0 2.749762 1.250238 4.499206 0.0 |
1641
+ | 4 | 171 171 171 171 171 | 2.0 2.749976 1.250024 4.499919 0.0 |
1642
+ | 5 | 172 172 172 172 172 | 2.0 2.749969 1.250031 4.499896 0.0 |
1643
+ | 6 | 353 353 353 353 353 | 2.0 1.250238 2.749762 0.0 4.499206 |
1644
+ | 7 | 354 354 354 354 354 | 2.0 1.250024 2.749976 0.0 4.499919 |
1645
+ | 8 | 355 355 355 355 355 | 2.0 1.250031 2.749969 0.0 4.499896 |
1646
+ | 9 | 364 364 364 364 364 | 2.0 1.260018 2.739982 0.0 4.466606 |
1647
+ | 10 | 365 365 365 365 365 | 2.0 1.262224 2.737776 0.0 4.459252 |
1648
+ """
1649
+
1650
+ CONTROLPARAMETERS = (
1651
+ hland_control.NmbZones,
1652
+ hland_control.ZoneType,
1653
+ hland_control.GMelt,
1654
+ hland_control.GVar,
1655
+ )
1656
+ FIXEDPARAMETERS = (hland_fixed.Pi,)
1657
+ DERIVEDPARAMETERS = (hland_derived.DOY,)
1658
+ RESULTSEQUENCES = (hland_factors.GAct,)
1659
+
1660
+ @staticmethod
1661
+ def __call__(model: modeltools.Model) -> None:
1662
+ con = model.parameters.control.fastaccess
1663
+ der = model.parameters.derived.fastaccess
1664
+ fix = model.parameters.fixed.fastaccess
1665
+ fac = model.sequences.factors.fastaccess
1666
+ d_factor = 0.5 * modelutils.sin(
1667
+ 2 * fix.pi * (der.doy[model.idx_sim] + 1) / 366 - 1.39
1668
+ )
1669
+ for k in range(con.nmbzones):
1670
+ if con.zonetype[k] == GLACIER:
1671
+ fac.gact[k] = max(con.gmelt[k] + d_factor * con.gvar[k], 0.0)
1672
+ else:
1673
+ fac.gact[k] = 0.0
1674
+
1675
+
1676
+ class Calc_GlMelt_In_V1(modeltools.Method):
1677
+ r"""Calculate the melting of non-snow-covered glaciers and add it to the water
1678
+ release of the snow module.
1679
+
1680
+ Basic equation:
1681
+ .. math::
1682
+ GlMelt =
1683
+ \begin{cases}
1684
+ max(GMelt \cdot (TC - TTM), 0) &|\ SP = 0
1685
+ \\
1686
+ 0 &|\ SP > 0
1687
+ \end{cases}
1688
+
1689
+ Examples:
1690
+
1691
+ We prepare eight zones. The first four zones are no glaciers, a snow layer
1692
+ covers the sixth zone, and the last two zones actual temperature is not above
1693
+ the threshold temperature. Hence, glacier melting occurs only in the fifth
1694
+ zone:
1695
+
1696
+ >>> from hydpy.models.hland import *
1697
+ >>> simulationstep("12h")
1698
+ >>> parameterstep("1d")
1699
+ >>> nmbzones(8)
1700
+ >>> sclass(1)
1701
+ >>> zonetype(FIELD, FOREST, ILAKE, SEALED, GLACIER, GLACIER, GLACIER, GLACIER)
1702
+ >>> derived.ttm(2.0)
1703
+ >>> factors.tc = 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 2.0, 1.0
1704
+ >>> factors.gact = 2.0
1705
+ >>> states.sp = 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0
1706
+ >>> fluxes.in_ = 3.0
1707
+ >>> model.calc_glmelt_in_v1()
1708
+ >>> fluxes.glmelt
1709
+ glmelt(0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0)
1710
+ >>> fluxes.in_
1711
+ in_(3.0, 3.0, 3.0, 3.0, 5.0, 3.0, 3.0, 3.0)
1712
+
1713
+ In the above examples, we did not divide the zones into snow classes. If we do
1714
+ so, method |Calc_GlMelt_In_V1| sums the glacier melt of all non-snow-covered
1715
+ snow classes of each glacier zone. This assumption implies that if there is a
1716
+ single snow-covered snow class, the actual glacier melting of the total zone
1717
+ must be smaller than its potential melt rate:
1718
+
1719
+ >>> sclass(2)
1720
+ >>> factors.tc = 3.0
1721
+ >>> fluxes.in_ = 3.0
1722
+ >>> states.sp = [[0.0, 0.0, 0.1, 0.1, 0.0, 0.0, 0.1, 0.1],
1723
+ ... [0.0, 0.1, 0.0, 0.1, 0.0, 0.1, 0.0, 0.1]]
1724
+ >>> model.calc_glmelt_in_v1()
1725
+ >>> fluxes.glmelt
1726
+ glmelt(0.0, 0.0, 0.0, 0.0, 2.0, 1.0, 1.0, 0.0)
1727
+ >>> fluxes.in_
1728
+ in_(3.0, 3.0, 3.0, 3.0, 5.0, 4.0, 4.0, 3.0)
1729
+ """
1730
+
1731
+ CONTROLPARAMETERS = (
1732
+ hland_control.NmbZones,
1733
+ hland_control.SClass,
1734
+ hland_control.ZoneType,
1735
+ )
1736
+ DERIVEDPARAMETERS = (hland_derived.TTM,)
1737
+ REQUIREDSEQUENCES = (hland_states.SP, hland_factors.TC, hland_factors.GAct)
1738
+ UPDATEDSEQUENCES = (hland_fluxes.In_,)
1739
+ RESULTSEQUENCES = (hland_fluxes.GlMelt,)
1740
+
1741
+ @staticmethod
1742
+ def __call__(model: modeltools.Model) -> None:
1743
+ con = model.parameters.control.fastaccess
1744
+ der = model.parameters.derived.fastaccess
1745
+ fac = model.sequences.factors.fastaccess
1746
+ flu = model.sequences.fluxes.fastaccess
1747
+ sta = model.sequences.states.fastaccess
1748
+ for k in range(con.nmbzones):
1749
+ flu.glmelt[k] = 0.0
1750
+ if (con.zonetype[k] == GLACIER) and (fac.tc[k] > der.ttm[k]):
1751
+ d_glmeltpot = fac.gact[k] / con.sclass * (fac.tc[k] - der.ttm[k])
1752
+ for c in range(con.sclass):
1753
+ if sta.sp[c, k] <= 0.0:
1754
+ flu.glmelt[k] += d_glmeltpot
1755
+ flu.in_[k] += d_glmeltpot
1756
+
1757
+
1758
+ class Calc_R_SM_V1(modeltools.Method):
1759
+ r"""Calculate effective precipitation and update the soil moisture.
1760
+
1761
+ Basic equations:
1762
+ :math:`\frac{dSM}{dt} = IN - R`
1763
+
1764
+ :math:`R = IN \cdot \left( \frac{SM}{FC} \right)^{Beta}`
1765
+
1766
+
1767
+ Examples:
1768
+
1769
+ We initialise seven zones of different types. The field capacity of all fields
1770
+ and forests is 200 mm, the input of each zone is 10 mm:
1771
+
1772
+ >>> from hydpy.models.hland import *
1773
+ >>> simulationstep("12h")
1774
+ >>> parameterstep("1d")
1775
+ >>> nmbzones(7)
1776
+ >>> zonetype(ILAKE, GLACIER, SEALED, FIELD, FIELD, FOREST, FOREST)
1777
+ >>> fc(200.0)
1778
+ >>> fluxes.in_ = 10.0
1779
+
1780
+ With the typical nonlinearity parameter value of 2, relative soil moisture of
1781
+ 50 % (zones five and six) results in a discharge coefficient of 25 %. For
1782
+ a completely dried (zone four) or saturated soil (zone seven), the discharge
1783
+ coefficient is generally 0 % and 100 %, respectively. Glaciers, internal lakes
1784
+ and sealed areas always route 100% of their input as effective precipitation:
1785
+
1786
+ >>> beta(2.0)
1787
+ >>> states.sm = 0.0, 0.0, 0.0, 0.0, 100.0, 100.0, 200.0
1788
+ >>> model.calc_r_sm_v1()
1789
+ >>> fluxes.r
1790
+ r(10.0, 10.0, 10.0, 0.0, 2.5, 2.5, 10.0)
1791
+ >>> states.sm
1792
+ sm(0.0, 0.0, 0.0, 10.0, 107.5, 107.5, 200.0)
1793
+
1794
+ By decreasing the nonlinearity parameter, the discharge coefficient increases.
1795
+ A parameter value of zero leads to a discharge coefficient of 100 % for any
1796
+ soil moisture:
1797
+
1798
+ >>> beta(0.0)
1799
+ >>> states.sm = 0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 200.0
1800
+ >>> model.calc_r_sm_v1()
1801
+ >>> fluxes.r
1802
+ r(10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0)
1803
+ >>> states.sm
1804
+ sm(0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 200.0)
1805
+
1806
+ Also, with a field capacity of zero, the discharge coefficient always equates
1807
+ to 100 %:
1808
+
1809
+ >>> fc(0.0)
1810
+ >>> beta(2.0)
1811
+ >>> states.sm = 0.0
1812
+ >>> model.calc_r_sm_v1()
1813
+ >>> fluxes.r
1814
+ r(10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0)
1815
+ >>> states.sm
1816
+ sm(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1817
+ """
1818
+
1819
+ CONTROLPARAMETERS = (
1820
+ hland_control.NmbZones,
1821
+ hland_control.ZoneType,
1822
+ hland_control.FC,
1823
+ hland_control.Beta,
1824
+ )
1825
+ REQUIREDSEQUENCES = (hland_fluxes.In_,)
1826
+ UPDATEDSEQUENCES = (hland_states.SM,)
1827
+ RESULTSEQUENCES = (hland_fluxes.R,)
1828
+
1829
+ @staticmethod
1830
+ def __call__(model: modeltools.Model) -> None:
1831
+ con = model.parameters.control.fastaccess
1832
+ flu = model.sequences.fluxes.fastaccess
1833
+ sta = model.sequences.states.fastaccess
1834
+ for k in range(con.nmbzones):
1835
+ if con.zonetype[k] in (FIELD, FOREST):
1836
+ if con.fc[k] > 0.0:
1837
+ flu.r[k] = flu.in_[k] * (sta.sm[k] / con.fc[k]) ** con.beta[k]
1838
+ flu.r[k] = max(flu.r[k], sta.sm[k] + flu.in_[k] - con.fc[k])
1839
+ else:
1840
+ flu.r[k] = flu.in_[k]
1841
+ sta.sm[k] += flu.in_[k] - flu.r[k]
1842
+ else:
1843
+ flu.r[k] = flu.in_[k]
1844
+ sta.sm[k] = 0.0
1845
+
1846
+
1847
+ class Calc_CF_SM_V1(modeltools.Method):
1848
+ r"""Calculate capillary flow and update the soil moisture.
1849
+
1850
+ Basic equations:
1851
+ :math:`\frac{dSM}{dt} = CF`
1852
+
1853
+ :math:`CF = CFLUX \cdot (1 - \frac{SM}{FC})`
1854
+
1855
+ Examples:
1856
+
1857
+ We initialise seven zones of different types. For all fields and forests, the
1858
+ field capacity is 200 mm and the maximum capillary flow rate is 4 mm/d:
1859
+
1860
+ >>> from hydpy.models.hland import *
1861
+ >>> simulationstep("12h")
1862
+ >>> parameterstep("1d")
1863
+ >>> nmbzones(7)
1864
+ >>> zonetype(ILAKE, GLACIER, SEALED, FIELD, FOREST, FOREST, FOREST)
1865
+ >>> fc(200.0)
1866
+ >>> cflux(4.0)
1867
+
1868
+ Note that the assumed length of the simulation step is only half a day. Hence
1869
+ the maximum capillary flow per simulation step is 2 instead of 4:
1870
+
1871
+ >>> cflux
1872
+ cflux(4.0)
1873
+ >>> from hydpy import round_
1874
+ >>> round_(cflux.values[0])
1875
+ 2.0
1876
+
1877
+ For fields and forests, the actual capillary return flow depends only on the
1878
+ relative soil moisture deficit, provided that the upper zone layer stores
1879
+ enough water or that enough "routable" effective precipitation is available:
1880
+
1881
+ >>> fluxes.r = 0.0
1882
+ >>> states.sm = 0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 200.0
1883
+ >>> states.uz = 20.0
1884
+ >>> model.calc_cf_sm_v1()
1885
+ >>> fluxes.cf
1886
+ cf(0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 0.0)
1887
+ >>> states.sm
1888
+ sm(0.0, 0.0, 0.0, 101.0, 101.0, 2.0, 200.0)
1889
+
1890
+ >>> states.sm = 0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 200.0
1891
+ >>> states.uz = 0.0
1892
+ >>> model.calc_cf_sm_v1()
1893
+ >>> fluxes.cf
1894
+ cf(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1895
+ >>> states.sm
1896
+ sm(0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 200.0)
1897
+
1898
+ If the upper zone layer is empty and no effective precipitation is available,
1899
+ capillary flow is zero:
1900
+
1901
+ >>> fluxes.r = 0.0
1902
+ >>> states.sm = 0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 200.0
1903
+ >>> states.uz = 0.0
1904
+ >>> model.calc_cf_sm_v1()
1905
+ >>> fluxes.cf
1906
+ cf(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1907
+ >>> states.sm
1908
+ sm(0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 200.0)
1909
+
1910
+ In the following example, both the upper zone layer and effective precipitation
1911
+ provide water for the capillary flow but less than the maximum flow rate times
1912
+ the relative soil moisture:
1913
+
1914
+ >>> fluxes.r = 0.1
1915
+ >>> states.sm = 0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 200.0
1916
+ >>> states.uz = 0.2
1917
+ >>> model.calc_cf_sm_v1()
1918
+ >>> fluxes.cf
1919
+ cf(0.0, 0.0, 0.0, 0.3, 0.3, 0.3, 0.0)
1920
+ >>> states.sm
1921
+ sm(0.0, 0.0, 0.0, 100.3, 100.3, 0.3, 200.0)
1922
+
1923
+ Even unrealistic high maximum capillary flow rates do not result in overfilled
1924
+ soils:
1925
+
1926
+ >>> cflux(1000.0)
1927
+ >>> fluxes.r = 200.0
1928
+ >>> states.sm = 0.0, 0.0, 0.0, 100.0, 100.0, 0.0, 200.0
1929
+ >>> states.uz = 200.0
1930
+ >>> model.calc_cf_sm_v1()
1931
+ >>> fluxes.cf
1932
+ cf(0.0, 0.0, 0.0, 100.0, 100.0, 200.0, 0.0)
1933
+ >>> states.sm
1934
+ sm(0.0, 0.0, 0.0, 200.0, 200.0, 200.0, 200.0)
1935
+
1936
+ For soils with zero field capacity, capillary flow is always zero:
1937
+
1938
+ >>> fc(0.0)
1939
+ >>> states.sm = 0.0
1940
+ >>> model.calc_cf_sm_v1()
1941
+ >>> fluxes.cf
1942
+ cf(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1943
+ >>> states.sm
1944
+ sm(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
1945
+ """
1946
+
1947
+ CONTROLPARAMETERS = (
1948
+ hland_control.NmbZones,
1949
+ hland_control.ZoneType,
1950
+ hland_control.FC,
1951
+ hland_control.CFlux,
1952
+ )
1953
+ REQUIREDSEQUENCES = (hland_fluxes.R, hland_states.UZ)
1954
+ UPDATEDSEQUENCES = (hland_states.SM,)
1955
+ RESULTSEQUENCES = (hland_fluxes.CF,)
1956
+
1957
+ @staticmethod
1958
+ def __call__(model: modeltools.Model) -> None:
1959
+ con = model.parameters.control.fastaccess
1960
+ flu = model.sequences.fluxes.fastaccess
1961
+ sta = model.sequences.states.fastaccess
1962
+ for k in range(con.nmbzones):
1963
+ if con.zonetype[k] in (FIELD, FOREST):
1964
+ if con.fc[k] > 0.0:
1965
+ flu.cf[k] = con.cflux[k] * (1.0 - sta.sm[k] / con.fc[k])
1966
+ flu.cf[k] = min(flu.cf[k], sta.uz + flu.r[k])
1967
+ flu.cf[k] = min(flu.cf[k], con.fc[k] - sta.sm[k])
1968
+ else:
1969
+ flu.cf[k] = 0.0
1970
+ sta.sm[k] += flu.cf[k]
1971
+ else:
1972
+ flu.cf[k] = 0.0
1973
+ sta.sm[k] = 0.0
1974
+
1975
+
1976
+ class Calc_EA_SM_AETModel_V1(modeltools.Method):
1977
+ r"""Let a submodel that follows the |AETModel_V1| submodel interface calculate
1978
+ soil evapotranspiration and adjust the soil water content.
1979
+
1980
+ Basic equation:
1981
+ :math:`\frac{dSM_i}{dt} = -EA_i`
1982
+
1983
+ Examples:
1984
+
1985
+ We build an example based on |evap_aet_hbv96| for calculating soil
1986
+ evapotranspiration:
1987
+
1988
+ >>> from hydpy.models.hland_96 import *
1989
+ >>> parameterstep("1h")
1990
+ >>> nmbzones(5)
1991
+ >>> zonetype(GLACIER, SEALED, FIELD, FOREST, ILAKE)
1992
+ >>> area(1.0)
1993
+ >>> zonearea(0.05, 0.1, 0.2, 0.3, 0.35)
1994
+ >>> zonez(5.0)
1995
+ >>> fc(50.0)
1996
+ >>> fluxes.r = 0.5
1997
+ >>> with model.add_aetmodel_v1("evap_aet_hbv96"):
1998
+ ... soilmoisturelimit(0.0)
1999
+ ... excessreduction(field=0.5, forest=0.0)
2000
+
2001
+ |Calc_EA_SM_AETModel_V1| uses the flux returned by the submodel to adjust |SM|:
2002
+
2003
+ >>> model.aetmodel.sequences.fluxes.potentialinterceptionevaporation = 1.0
2004
+ >>> model.aetmodel.sequences.fluxes.potentialsoilevapotranspiration = 1.0
2005
+ >>> model.aetmodel.sequences.fluxes.interceptionevaporation = 1.0
2006
+ >>> states.sm = 3.0
2007
+ >>> model.calc_ea_sm_v1()
2008
+ >>> fluxes.ea
2009
+ ea(0.0, 0.0, 0.5, 1.0, 0.0)
2010
+ >>> states.sm
2011
+ sm(0.0, 0.0, 2.5, 2.0, 0.0)
2012
+ >>> fluxes.r
2013
+ r(0.5, 0.5, 0.5, 0.5, 0.5)
2014
+
2015
+ |Calc_EA_SM_AETModel_V1| eventually reduces |EA| so that |SM| does not become
2016
+ negative:
2017
+
2018
+ >>> model.aetmodel.sequences.fluxes.potentialinterceptionevaporation = 5.0
2019
+ >>> model.aetmodel.sequences.fluxes.potentialsoilevapotranspiration = 5.0
2020
+ >>> model.aetmodel.sequences.fluxes.interceptionevaporation = 5.0
2021
+ >>> states.sm = 3.0
2022
+ >>> model.calc_ea_sm_v1()
2023
+ >>> fluxes.ea
2024
+ ea(0.0, 0.0, 2.5, 3.0, 0.0)
2025
+ >>> states.sm
2026
+ sm(0.0, 0.0, 0.5, 0.0, 0.0)
2027
+ >>> fluxes.r
2028
+ r(0.5, 0.5, 0.5, 0.5, 0.5)
2029
+
2030
+ |Calc_EA_SM_AETModel_V1| converts any amounts of condensation (negative |EA|)
2031
+ that would cause soil water to exceed field capacity to the effective soil
2032
+ response (|R|):
2033
+
2034
+ >>> model.aetmodel.sequences.fluxes.potentialinterceptionevaporation = -5.0
2035
+ >>> model.aetmodel.sequences.fluxes.potentialsoilevapotranspiration = -5.0
2036
+ >>> model.aetmodel.sequences.fluxes.interceptionevaporation = -5.0
2037
+ >>> states.sm = 47.0
2038
+ >>> model.calc_ea_sm_v1()
2039
+ >>> fluxes.ea
2040
+ ea(0.0, 0.0, -2.5, -5.0, 0.0)
2041
+ >>> states.sm
2042
+ sm(0.0, 0.0, 49.5, 50.0, 0.0)
2043
+ >>> fluxes.r
2044
+ r(0.5, 0.5, 0.5, 2.5, 0.5)
2045
+ """
2046
+
2047
+ CONTROLPARAMETERS = (
2048
+ hland_control.NmbZones,
2049
+ hland_control.ZoneType,
2050
+ hland_control.FC,
2051
+ )
2052
+ UPDATEDSEQUENCES = (hland_states.SM, hland_fluxes.R)
2053
+ RESULTSEQUENCES = (hland_fluxes.EA,)
2054
+
2055
+ @staticmethod
2056
+ def __call__(model: modeltools.Model, submodel: aetinterfaces.AETModel_V1) -> None:
2057
+ con = model.parameters.control.fastaccess
2058
+ flu = model.sequences.fluxes.fastaccess
2059
+ sta = model.sequences.states.fastaccess
2060
+ submodel.determine_soilevapotranspiration()
2061
+ for k in range(con.nmbzones):
2062
+ if con.zonetype[k] in (FIELD, FOREST):
2063
+ flu.ea[k] = min(submodel.get_soilevapotranspiration(k), sta.sm[k])
2064
+ sta.sm[k] -= flu.ea[k]
2065
+ if sta.sm[k] > con.fc[k]:
2066
+ flu.r[k] += sta.sm[k] - con.fc[k]
2067
+ sta.sm[k] = con.fc[k]
2068
+ else:
2069
+ flu.ea[k] = 0.0
2070
+ sta.sm[k] = 0.0
2071
+
2072
+
2073
+ class Calc_EA_SM_V1(modeltools.Method):
2074
+ """Let a submodel that follows the |AETModel_V1| submodel interface calculate soil
2075
+ evapotranspiration and adjust the soil water content."""
2076
+
2077
+ SUBMODELINTERFACES = (aetinterfaces.AETModel_V1,)
2078
+ SUBMETHODS = (Calc_EA_SM_AETModel_V1,)
2079
+ CONTROLPARAMETERS = (
2080
+ hland_control.NmbZones,
2081
+ hland_control.ZoneType,
2082
+ hland_control.FC,
2083
+ )
2084
+ UPDATEDSEQUENCES = (hland_states.SM, hland_fluxes.R)
2085
+ RESULTSEQUENCES = (hland_fluxes.EA,)
2086
+
2087
+ @staticmethod
2088
+ def __call__(model: modeltools.Model) -> None:
2089
+ if model.aetmodel_typeid == 1:
2090
+ model.calc_ea_sm_aetmodel_v1(
2091
+ cast(aetinterfaces.AETModel_V1, model.aetmodel)
2092
+ )
2093
+ # ToDo:
2094
+ # else:
2095
+ # assert_never(model.petmodel)
2096
+
2097
+
2098
+ class Calc_InUZ_V1(modeltools.Method):
2099
+ r"""Accumulate the total inflow into the upper zone layer.
2100
+
2101
+ Basic equation:
2102
+ .. math::
2103
+ InUZ = \sum_{k=1}^{NmbZones} \frac{RelZoneAreas_k}{RelUpperZoneArea} \cdot
2104
+ \begin{cases}
2105
+ R-CF &|\ ZoneType_k \in \{FIELD, FOREST, GLACIER \}
2106
+ \\
2107
+ 0 &|\ ZoneType_k \notin \{FIELD, FOREST, GLACIER \}
2108
+ \end{cases}
2109
+
2110
+ Examples:
2111
+
2112
+ We initialise five zones of different land-use types and sizes. Method
2113
+ |Calc_InUZ_V1| takes only those of type |FIELD|, |FOREST|, and |GLACIER| into
2114
+ account:
2115
+
2116
+ >>> from hydpy.models.hland import *
2117
+ >>> simulationstep("12h")
2118
+ >>> parameterstep("1d")
2119
+ >>> nmbzones(5)
2120
+ >>> zonetype(FIELD, FOREST, ILAKE, GLACIER, SEALED)
2121
+ >>> derived.relzoneareas = 0.25, 0.2, 0.4, 0.05, 0.1
2122
+ >>> derived.relupperzonearea = 0.5
2123
+ >>> fluxes.r = 2.0, 4.0, 1.0, 6.0, 1.0
2124
+ >>> fluxes.cf = 1.0, 2.0, 0.5, 3.0, 0.5
2125
+ >>> model.calc_inuz_v1()
2126
+ >>> fluxes.inuz
2127
+ inuz(1.6)
2128
+
2129
+ Internal lakes and sealed areas do not contribute to the upper zone layer.
2130
+ Hence, for a subbasin consisting only of such zones, |InUZ| is zero:
2131
+
2132
+ >>> zonetype(ILAKE, ILAKE, ILAKE, SEALED, SEALED)
2133
+ >>> model.calc_inuz_v1()
2134
+ >>> fluxes.inuz
2135
+ inuz(0.0)
2136
+ """
2137
+
2138
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
2139
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelUpperZoneArea)
2140
+ REQUIREDSEQUENCES = (hland_fluxes.R, hland_fluxes.CF)
2141
+ RESULTSEQUENCES = (hland_fluxes.InUZ,)
2142
+
2143
+ @staticmethod
2144
+ def __call__(model: modeltools.Model) -> None:
2145
+ con = model.parameters.control.fastaccess
2146
+ der = model.parameters.derived.fastaccess
2147
+ flu = model.sequences.fluxes.fastaccess
2148
+ flu.inuz = 0.0
2149
+ for k in range(con.nmbzones):
2150
+ if con.zonetype[k] in (FIELD, FOREST, GLACIER):
2151
+ flu.inuz += (
2152
+ der.relzoneareas[k] / der.relupperzonearea * (flu.r[k] - flu.cf[k])
2153
+ )
2154
+
2155
+
2156
+ class Calc_SUZ_V1(modeltools.Method):
2157
+ r"""Add the effective precipitation to the upper storage reservoir.
2158
+
2159
+ Basic equation:
2160
+ :math:`\frac{SUZ}{dt} = R`
2161
+
2162
+ Example:
2163
+
2164
+ For internal lakes and sealed areas, method |Calc_SUZ_V1| always sets |SUZ| to
2165
+ zero:
2166
+
2167
+ >>> from hydpy.models.hland import *
2168
+ >>> simulationstep("12h")
2169
+ >>> parameterstep()
2170
+ >>> nmbzones(4)
2171
+ >>> zonetype(FIELD, ILAKE, GLACIER, SEALED)
2172
+ >>> states.suz = 1.0, 0.0, 2.0, 0.0
2173
+ >>> fluxes.r = 2.0
2174
+ >>> model.calc_suz_v1()
2175
+ >>> states.suz
2176
+ suz(3.0, 0.0, 4.0, 0.0)
2177
+ """
2178
+
2179
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
2180
+ REQUIREDSEQUENCES = (hland_fluxes.R,)
2181
+ UPDATEDSEQUENCES = (hland_states.SUZ,)
2182
+
2183
+ @staticmethod
2184
+ def __call__(model: modeltools.Model) -> None:
2185
+ con = model.parameters.control.fastaccess
2186
+ flu = model.sequences.fluxes.fastaccess
2187
+ sta = model.sequences.states.fastaccess
2188
+ for k in range(con.nmbzones):
2189
+ if con.zonetype[k] in (FIELD, FOREST, GLACIER):
2190
+ sta.suz[k] += flu.r[k]
2191
+ else:
2192
+ sta.suz[k] = 0.0
2193
+
2194
+
2195
+ class Calc_ContriArea_V1(modeltools.Method):
2196
+ r"""Determine the relative size of the contributing area of the whole subbasin.
2197
+
2198
+ Basic equation:
2199
+ :math:`ContriArea = \left( \frac{SM}{FC} \right)^{Beta}`
2200
+
2201
+ Examples:
2202
+
2203
+ We initialise five zones. Method |Calc_ContriArea_V1| takes only the first two
2204
+ zones of type field and forest into account (even though glaciers also
2205
+ contribute to the inflow of the upper zone layer):
2206
+
2207
+ >>> from hydpy.models.hland import *
2208
+ >>> simulationstep("12h")
2209
+ >>> parameterstep("1d")
2210
+ >>> nmbzones(5)
2211
+ >>> zonetype(FIELD, FOREST, GLACIER, ILAKE, SEALED)
2212
+ >>> beta(2.0)
2213
+ >>> fc(200.0)
2214
+ >>> resparea(True)
2215
+ >>> derived.relzoneareas(1.0/6.0, 2.0/6.0, 1.0/6.0, 1.0/6.0, 1.0/6.0)
2216
+ >>> derived.relsoilarea(0.5)
2217
+
2218
+ With relative soil moisture of 100 % in the whole subbasin, the contributing
2219
+ area is also 100 %:
2220
+
2221
+ >>> states.sm = 200.0
2222
+ >>> model.calc_contriarea_v1()
2223
+ >>> factors.contriarea
2224
+ contriarea(1.0)
2225
+
2226
+ Relative soil moistures of 0 % result in a contributing area of 0 %:
2227
+
2228
+ >>> states.sm = 0.0
2229
+ >>> model.calc_contriarea_v1()
2230
+ >>> factors.contriarea
2231
+ contriarea(0.0)
2232
+
2233
+ For the given value 2 of the nonlinearity parameter |Beta|, soil moisture of
2234
+ 50 % corresponds to contributing area of 25 %:
2235
+
2236
+ >>> states.sm = 100.0
2237
+ >>> model.calc_contriarea_v1()
2238
+ >>> factors.contriarea
2239
+ contriarea(0.25)
2240
+
2241
+ Setting the |RespArea| option to |False|, the soil area (total area of all
2242
+ field and forest zones in the subbasin) to zero, or all field capacities to
2243
+ zero, results in contributing area values of 100 %:
2244
+
2245
+ >>> resparea(False)
2246
+ >>> model.calc_contriarea_v1()
2247
+ >>> factors.contriarea
2248
+ contriarea(1.0)
2249
+
2250
+ >>> resparea(True)
2251
+ >>> derived.relsoilarea(0.0)
2252
+ >>> model.calc_contriarea_v1()
2253
+ >>> factors.contriarea
2254
+ contriarea(1.0)
2255
+
2256
+ >>> derived.relsoilarea(0.5)
2257
+ >>> fc(0.0)
2258
+ >>> states.sm = 0.0
2259
+ >>> model.calc_contriarea_v1()
2260
+ >>> factors.contriarea
2261
+ contriarea(1.0)
2262
+ """
2263
+
2264
+ CONTROLPARAMETERS = (
2265
+ hland_control.RespArea,
2266
+ hland_control.NmbZones,
2267
+ hland_control.ZoneType,
2268
+ hland_control.FC,
2269
+ hland_control.Beta,
2270
+ )
2271
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelSoilArea)
2272
+ REQUIREDSEQUENCES = (hland_states.SM,)
2273
+ RESULTSEQUENCES = (hland_factors.ContriArea,)
2274
+
2275
+ @staticmethod
2276
+ def __call__(model: modeltools.Model) -> None:
2277
+ con = model.parameters.control.fastaccess
2278
+ der = model.parameters.derived.fastaccess
2279
+ fac = model.sequences.factors.fastaccess
2280
+ sta = model.sequences.states.fastaccess
2281
+ fac.contriarea = 1.0
2282
+ if con.resparea and (der.relsoilarea > 0.0):
2283
+ for k in range(con.nmbzones):
2284
+ if con.zonetype[k] in (FIELD, FOREST):
2285
+ if con.fc[k] > 0.0:
2286
+ d_weight = der.relzoneareas[k] / der.relsoilarea
2287
+ fac.contriarea *= (sta.sm[k] / con.fc[k]) ** d_weight
2288
+ fac.contriarea **= con.beta[k]
2289
+
2290
+
2291
+ class Calc_Q0_Perc_UZ_V1(modeltools.Method):
2292
+ r"""Calculate the percolation and direct runoff leaving the upper zone storage
2293
+ and update it accordingly.
2294
+
2295
+ Basic equations:
2296
+ :math:`\frac{dUZ}{dt} = InUZ - Perc - Q0`
2297
+
2298
+ :math:`Perc = PercMax \cdot ContriArea`
2299
+
2300
+ :math:`Q0 = K \cdot \left( \frac{UZ}{ContriArea} \right)^{1+Alpha}`
2301
+
2302
+ Note that the system behaviour of this method depends strongly on the
2303
+ specifications of the options |RespArea| and |RecStep|.
2304
+
2305
+ Examples:
2306
+
2307
+ First, we prepare a small helper function for checking if method
2308
+ |Calc_Q0_Perc_UZ_V1| always complies with the water balance equation, assuming
2309
+ an initial content of the upper zone storage of 1 mm:
2310
+
2311
+ >>> from hydpy import round_
2312
+ >>> def check():
2313
+ ... error = 1.0 + fluxes.inuz - fluxes.perc - fluxes.q0 - states.uz
2314
+ ... assert round(error, 12) == 0
2315
+
2316
+ The upper zone layer routine is an exception compared to the other subroutines
2317
+ of |hland| regarding numerical accuracy. Method |Calc_Q0_Perc_UZ_V1| divides
2318
+ each simulation step into substeps and solves each substep with the explicit
2319
+ Euler method. The more substeps involved, the more precise the numerical
2320
+ integration of the underlying ordinary differential equations. In the first
2321
+ example, we omit this option by setting the |RecStep| parameter, which defines
2322
+ the number of substeps, to one:
2323
+
2324
+ >>> from hydpy.models.hland import *
2325
+ >>> simulationstep("12h")
2326
+ >>> parameterstep("1d")
2327
+ >>> recstep(2)
2328
+ >>> derived.dt = 1/recstep
2329
+ >>> percmax(2.0)
2330
+ >>> alpha(1.0)
2331
+ >>> k(2.0)
2332
+ >>> factors.contriarea = 1.0
2333
+ >>> fluxes.inuz = 0.0
2334
+ >>> states.uz = 1.0
2335
+ >>> model.calc_q0_perc_uz_v1()
2336
+ >>> fluxes.perc
2337
+ perc(1.0)
2338
+ >>> fluxes.q0
2339
+ q0(0.0)
2340
+ >>> states.uz
2341
+ uz(0.0)
2342
+ >>> check()
2343
+
2344
+ Due to the sequential calculation of the upper zone routine, the upper zone
2345
+ storage drains completely through percolation, and no water remains for fast
2346
+ discharge response. By dividing the simulation step into 100 substeps, method
2347
+ |Calc_Q0_Perc_UZ_V1| also calculates a considerable amount of direct runoff:
2348
+
2349
+ >>> recstep(200)
2350
+ >>> derived.dt = 1.0/recstep
2351
+ >>> states.uz = 1.0
2352
+ >>> model.calc_q0_perc_uz_v1()
2353
+ >>> fluxes.perc
2354
+ perc(0.786934)
2355
+ >>> fluxes.q0
2356
+ q0(0.213066)
2357
+ >>> states.uz
2358
+ uz(0.0)
2359
+ >>> check()
2360
+
2361
+ Note that the assumed length of the simulation step is half a day. Hence the
2362
+ effective values of the maximum percolation rate and the storage coefficient
2363
+ are not 2 but 1:
2364
+
2365
+ >>> percmax
2366
+ percmax(2.0)
2367
+ >>> k
2368
+ k(2.0)
2369
+ >>> percmax.value
2370
+ 1.0
2371
+ >>> k.value
2372
+ 1.0
2373
+
2374
+ By decreasing the contributing area, one reduces percolation but increases the
2375
+ fast discharge response:
2376
+
2377
+ >>> factors.contriarea = 0.5
2378
+ >>> states.uz = 1.0
2379
+ >>> model.calc_q0_perc_uz_v1()
2380
+ >>> fluxes.perc
2381
+ perc(0.434108)
2382
+ >>> fluxes.q0
2383
+ q0(0.565892)
2384
+ >>> states.uz
2385
+ uz(0.0)
2386
+ >>> check()
2387
+
2388
+ Without any contributing area, the complete amount of water stored in the upper
2389
+ zone layer is released as direct discharge immediately:
2390
+
2391
+ >>> factors.contriarea = 0.0
2392
+ >>> states.uz = 1.0
2393
+ >>> model.calc_q0_perc_uz_v1()
2394
+ >>> fluxes.perc
2395
+ perc(0.0)
2396
+ >>> fluxes.q0
2397
+ q0(1.0)
2398
+ >>> states.uz
2399
+ uz(0.0)
2400
+ >>> check()
2401
+
2402
+ Resetting |RecStep| leads to more transparent results. Note that direct
2403
+ discharge drains the rest of the upper zone storage due to the storage
2404
+ coefficient's large value and the numerical approximation's low accuracy:
2405
+
2406
+ >>> recstep(2)
2407
+ >>> factors.contriarea = 0.5
2408
+ >>> derived.dt = 1.0/recstep
2409
+ >>> states.uz = 1.0
2410
+ >>> model.calc_q0_perc_uz_v1()
2411
+ >>> fluxes.perc
2412
+ perc(0.5)
2413
+ >>> fluxes.q0
2414
+ q0(0.5)
2415
+ >>> states.uz
2416
+ uz(0.0)
2417
+ >>> check()
2418
+
2419
+ Applying a more reasonable storage coefficient leads to the following results:
2420
+
2421
+ >>> k(0.5)
2422
+ >>> states.uz = 1.0
2423
+ >>> model.calc_q0_perc_uz_v1()
2424
+ >>> fluxes.perc
2425
+ perc(0.5)
2426
+ >>> fluxes.q0
2427
+ q0(0.25)
2428
+ >>> states.uz
2429
+ uz(0.25)
2430
+ >>> check()
2431
+
2432
+ Adding an input of 0.3 mm results in the same percolation value (which here is
2433
+ determined by the maximum percolation rate only) but increases the direct
2434
+ response (which always depends on the actual upper zone storage):
2435
+
2436
+ >>> fluxes.inuz = 0.3
2437
+ >>> states.uz = 1.0
2438
+ >>> model.calc_q0_perc_uz_v1()
2439
+ >>> fluxes.perc
2440
+ perc(0.5)
2441
+ >>> fluxes.q0
2442
+ q0(0.64)
2443
+ >>> states.uz
2444
+ uz(0.16)
2445
+ >>> check()
2446
+
2447
+ Due to the same reasons, another increase in numerical accuracy has no impact
2448
+ on percolation but decreases the direct response:
2449
+
2450
+ >>> recstep(200)
2451
+ >>> derived.dt = 1.0/recstep
2452
+ >>> states.uz = 1.0
2453
+ >>> model.calc_q0_perc_uz_v1()
2454
+ >>> fluxes.perc
2455
+ perc(0.5)
2456
+ >>> fluxes.q0
2457
+ q0(0.421708)
2458
+ >>> states.uz
2459
+ uz(0.378292)
2460
+ >>> check()
2461
+
2462
+ If phases of capillary rise, |InUZ| is negative and constant throughout the
2463
+ complete simulation interval. However, if |UZ| runs dry during the simulation
2464
+ interval, it can no contribute to the capillary rise. To always comply with
2465
+ the water balance equation, method |Calc_Q0_Perc_UZ_V1| reduces both |Perc|
2466
+ and |Q0| by the same factor in such situations. Reducing |InUZ| would be more
2467
+ reasonable but would also require modifying |CF| and |SM| (and others?), which
2468
+ is way too much effort given the minor impact of this manipulation on the
2469
+ general simulation results. The following two examples show how the
2470
+ manipulation works if the capillary rise requires all (first example) or half
2471
+ (second example) of the available water.
2472
+
2473
+ >>> fluxes.inuz = -1.0
2474
+ >>> states.uz = 1.0
2475
+ >>> model.calc_q0_perc_uz_v1()
2476
+ >>> fluxes.perc
2477
+ perc(0.0)
2478
+ >>> fluxes.q0
2479
+ q0(0.0)
2480
+ >>> states.uz
2481
+ uz(0.0)
2482
+ >>> check()
2483
+
2484
+ >>> fluxes.inuz = -0.5
2485
+ >>> states.uz = 1.0
2486
+ >>> model.calc_q0_perc_uz_v1()
2487
+ >>> fluxes.perc
2488
+ perc(0.323912)
2489
+ >>> fluxes.q0
2490
+ q0(0.176088)
2491
+ >>> states.uz
2492
+ uz(0.0)
2493
+ >>> check()
2494
+ """
2495
+
2496
+ CONTROLPARAMETERS = (
2497
+ hland_control.RecStep,
2498
+ hland_control.PercMax,
2499
+ hland_control.K,
2500
+ hland_control.Alpha,
2501
+ )
2502
+ DERIVEDPARAMETERS = (hland_derived.DT,)
2503
+ REQUIREDSEQUENCES = (hland_factors.ContriArea, hland_fluxes.InUZ)
2504
+ UPDATEDSEQUENCES = (hland_states.UZ,)
2505
+ RESULTSEQUENCES = (hland_fluxes.Perc, hland_fluxes.Q0)
2506
+
2507
+ @staticmethod
2508
+ def __call__(model: modeltools.Model) -> None:
2509
+ con = model.parameters.control.fastaccess
2510
+ der = model.parameters.derived.fastaccess
2511
+ fac = model.sequences.factors.fastaccess
2512
+ flu = model.sequences.fluxes.fastaccess
2513
+ sta = model.sequences.states.fastaccess
2514
+ uz_old: float = sta.uz
2515
+ flu.perc = 0.0
2516
+ flu.q0 = 0.0
2517
+ for _ in range(con.recstep):
2518
+ sta.uz = max(sta.uz + der.dt * flu.inuz, 0.0)
2519
+ perc: float = min(der.dt * con.percmax * fac.contriarea, sta.uz)
2520
+ sta.uz -= perc
2521
+ flu.perc += perc
2522
+ if sta.uz > 0.0:
2523
+ if fac.contriarea > 0.0:
2524
+ q0: float = min(
2525
+ der.dt * con.k * (sta.uz / fac.contriarea) ** (1.0 + con.alpha),
2526
+ sta.uz,
2527
+ )
2528
+ else:
2529
+ q0 = sta.uz
2530
+ sta.uz -= q0
2531
+ flu.q0 += q0
2532
+ error: float = sta.uz - (uz_old + flu.inuz - flu.perc - flu.q0)
2533
+ if error > 0.0:
2534
+ factor: float = 1.0 - error / (flu.perc + flu.q0)
2535
+ flu.perc *= factor
2536
+ flu.q0 *= factor
2537
+
2538
+
2539
+ class Calc_DP_SUZ_V1(modeltools.Method):
2540
+ r"""Calculate the deep percolation and remove it from the upper storage reservoir.
2541
+
2542
+ Basic equation:
2543
+ :math:`DP = min(PERCMax, SUZ)`
2544
+
2545
+ :math:`\frac{SUZ}{dt} = -DP`
2546
+
2547
+ :math:`\frac{SUZ}{dt} = -RS -RI`
2548
+
2549
+ Example:
2550
+
2551
+ For internal lakes and sealed areas, method |Calc_DP_SUZ_V1| always sets the
2552
+ values of |DP| and |SUZ| to zero:
2553
+
2554
+ >>> from hydpy.models.hland import *
2555
+ >>> simulationstep("1h")
2556
+ >>> parameterstep("1d")
2557
+ >>> nmbzones(9)
2558
+ >>> zonetype(FIELD, FIELD, FIELD, FIELD, FIELD, FOREST, GLACIER, ILAKE, SEALED)
2559
+ >>> percmax(4.8)
2560
+ >>> states.suz = 0.0, 0.1, 0.2, 0.3, 0.4, 0.4, 0.4, 0.4, 0.4
2561
+ >>> model.calc_dp_suz_v1()
2562
+ >>> fluxes.dp
2563
+ dp(0.0, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, 0.0, 0.0)
2564
+ >>> states.suz
2565
+ suz(0.0, 0.0, 0.0, 0.1, 0.2, 0.2, 0.2, 0.0, 0.0)
2566
+ """
2567
+
2568
+ CONTROLPARAMETERS = (
2569
+ hland_control.NmbZones,
2570
+ hland_control.ZoneType,
2571
+ hland_control.PercMax,
2572
+ )
2573
+ UPDATEDSEQUENCES = (hland_states.SUZ,)
2574
+ RESULTSEQUENCES = (hland_fluxes.DP,)
2575
+
2576
+ @staticmethod
2577
+ def __call__(model: modeltools.Model) -> None:
2578
+ con = model.parameters.control.fastaccess
2579
+ flu = model.sequences.fluxes.fastaccess
2580
+ sta = model.sequences.states.fastaccess
2581
+ for k in range(con.nmbzones):
2582
+ if con.zonetype[k] in (FIELD, FOREST, GLACIER):
2583
+ flu.dp[k] = min(sta.suz[k], con.percmax)
2584
+ sta.suz[k] -= flu.dp[k]
2585
+ else:
2586
+ flu.dp[k] = 0.0
2587
+ sta.suz[k] = 0.0
2588
+
2589
+
2590
+ class Calc_QAb_QVs_BW_V1(modeltools.Method):
2591
+ """Calculate the flow and the percolation from a two-outlet reservoir and update it.
2592
+
2593
+ Method |Calc_QAb_QVs_BW_V1| is an "additional method" used by the "run methods"
2594
+ |Calc_QAb1_QVs1_BW1_V1| and |Calc_QAb2_QVs2_BW2_V1| for calculating the flow and
2595
+ the percolation from the surface water reservoir and the interflow reservoir,
2596
+ respectively. See the documentation on method |Calc_QAb1_QVs1_BW1_V1| for further
2597
+ information.
2598
+ """
2599
+
2600
+ # positional arguments required for consistency with the cythonized extension class:
2601
+ @staticmethod
2602
+ def __call__( # pylint: disable=too-many-positional-arguments
2603
+ model: modeltools.Model,
2604
+ k: int,
2605
+ h: VectorFloat,
2606
+ k1: VectorFloat,
2607
+ k2: VectorFloat,
2608
+ s0: VectorFloat,
2609
+ qz: VectorFloat,
2610
+ qa1: VectorFloat,
2611
+ qa2: VectorFloat,
2612
+ t0: float,
2613
+ /,
2614
+ ) -> None:
2615
+ d_h = h[k]
2616
+ d_k1 = k1[k]
2617
+ d_k2 = k2[k]
2618
+ d_qz = qz[k]
2619
+ d_s0 = s0[k]
2620
+ if (d_k1 == 0.0) and (d_s0 > d_h):
2621
+ qa1[k] += d_s0 - d_h
2622
+ s0[k] = d_s0 = d_h
2623
+ if (d_k1 == 0.0) and (d_s0 == d_h) and (d_qz > d_h / d_k2):
2624
+ d_qa2 = d_h / d_k2
2625
+ d_dt = 1.0 - t0
2626
+ qa2[k] += d_dt * d_qa2
2627
+ qa1[k] += d_dt * (d_qz - d_qa2)
2628
+ elif d_k2 == 0.0:
2629
+ qa2[k] += d_s0 + d_qz
2630
+ s0[k] = 0.0
2631
+ elif (d_s0 < d_h) or (d_s0 == d_h and d_qz <= d_h / d_k2):
2632
+ if (d_s0 == d_h) or (d_qz <= d_h / d_k2):
2633
+ d_t1 = 1.0
2634
+ elif modelutils.isinf(d_k2):
2635
+ d_t1 = (d_h - d_s0) / d_qz
2636
+ else:
2637
+ d_t1 = t0 + d_k2 * modelutils.log(
2638
+ (d_qz - d_s0 / d_k2) / (d_qz - d_h / d_k2)
2639
+ )
2640
+ if 0.0 < d_t1 < 1.0:
2641
+ qa2[k] += (d_t1 - t0) * d_qz - (d_h - d_s0)
2642
+ s0[k] = d_h
2643
+ model.calc_qab_qvs_bw_v1(k, h, k1, k2, s0, qz, qa1, qa2, d_t1)
2644
+ elif modelutils.isinf(d_k2):
2645
+ s0[k] += (1.0 - t0) * d_qz
2646
+ else:
2647
+ d_dt = 1.0 - t0
2648
+ d_k2qz = d_k2 * d_qz
2649
+ s0[k] = d_k2qz - (d_k2qz - d_s0) * modelutils.exp(-d_dt / d_k2)
2650
+ qa2[k] += d_s0 - s0[k] + d_dt * d_qz
2651
+ else:
2652
+ d_v1 = 1.0 / d_k1 + 1.0 / d_k2
2653
+ d_v2 = d_qz + d_h / d_k1
2654
+ d_nom = d_v2 - d_h * d_v1
2655
+ d_denom = d_v2 - d_s0 * d_v1
2656
+ if (d_s0 == d_h) or (d_denom == 0.0) or (not 0 < d_nom / d_denom <= 1):
2657
+ d_t1 = 1.0
2658
+ else:
2659
+ d_t1 = t0 - 1.0 / d_v1 * modelutils.log(d_nom / d_denom)
2660
+ d_t1 = min(d_t1, 1.0)
2661
+ d_dt = d_t1 - t0
2662
+ d_v3 = (d_v2 * d_dt) / d_v1
2663
+ d_v4 = d_denom / d_v1**2 * (1.0 - modelutils.exp(-d_dt * d_v1))
2664
+ d_qa1 = (d_v3 - d_v4 - d_h * d_dt) / d_k1
2665
+ d_qa2 = (d_v3 - d_v4) / d_k2
2666
+ qa1[k] += d_qa1
2667
+ qa2[k] += d_qa2
2668
+ if d_t1 == 1.0:
2669
+ s0[k] += d_dt * d_qz - d_qa1 - d_qa2
2670
+ else:
2671
+ s0[k] = d_h
2672
+ if d_t1 < 1.0:
2673
+ model.calc_qab_qvs_bw_v1(k, h, k1, k2, s0, qz, qa1, qa2, d_t1)
2674
+
2675
+
2676
+ class Calc_QAb1_QVs1_BW1_V1(modeltools.Method):
2677
+ r"""Calculate the flow and the percolation from the surface flow reservoir and
2678
+ update it.
2679
+
2680
+ Basic equations:
2681
+ :math:`\frac{dBW1}{dt} = R - QAb1 - QVs1`
2682
+
2683
+ :math:`QAb1 = \frac{max(BW1 - H1, 0)}{TAb1}`
2684
+
2685
+ :math:`QVs1 = \frac{BW1}{TVs1}`
2686
+
2687
+ We follow the new COSERO implementation described in :cite:t:`ref-Kling2005` and
2688
+ :cite:t:`ref-Kling2006` and solve the given ordinary differential equation under the
2689
+ assumption of constant inflow (|R|). Despite the simple appearance of the short
2690
+ equation, its solution is quite complicated due to the threshold |H1| used
2691
+ (:cite:t:`ref-Kling2005` and :cite:t:`ref-Kling2006` explain the math in some
2692
+ detail).
2693
+ Additionally, we allow setting either |TAb1| or |TVs1| to |numpy.inf| or zero,
2694
+ allowing for disabling certain surface flow reservoir functionalities.
2695
+ Consequently, our source code includes many branches, and extensive testing is
2696
+ required to get some confidence in its robustness. We verified each of the
2697
+ following tests with numerical integration results. You can find this independent
2698
+ test code in `issue 68`_. Please tell us if you encounter a plausible combination
2699
+ of parameter values not adequately covered by our tests or source code.
2700
+
2701
+ Examples:
2702
+
2703
+ We prepare eight zones with identical values for the control parameters |H1|,
2704
+ |TAb1|, and |TVs1|. We only vary the inflow (|R|) and the initial state
2705
+ (|BW1|). For the first and the second zone, |BW1| changes but remains
2706
+ permanently below |H1|. Hence, all water leaving the storage leaves via
2707
+ percolation. For the third and the fourth zone, |BW1| also changes but is
2708
+ permanently above |H1|. Hence, there is a continuous generation of percolation
2709
+ and surface runoff. For the fifth and sixth zone, |BW1| starts below and ends
2710
+ above |H1| and the other way round. For the seventh and the eighth zone,
2711
+ inflow and outflow are balanced:
2712
+
2713
+ >>> from hydpy.models.hland import *
2714
+ >>> simulationstep("12h")
2715
+ >>> parameterstep("1d")
2716
+ >>> nmbzones(8)
2717
+ >>> zonetype(FIELD)
2718
+ >>> h1(4.0)
2719
+ >>> tab1(1.0)
2720
+ >>> tvs1(2.0)
2721
+ >>> fluxes.r = 0.0, 2.0, 0.0, 2.0, 5.0, 0.1, 0.5, 2.5
2722
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2723
+ >>> model.calc_qab1_qvs1_bw1_v1()
2724
+ >>> fluxes.qab1
2725
+ qab1(0.0, 0.0, 1.561119, 1.956437, 0.246114, 0.181758, 0.0, 1.0)
2726
+ >>> fluxes.qvs1
2727
+ qvs1(0.442398, 0.672805, 1.780559, 1.978219, 1.007586, 1.086805, 0.5,
2728
+ 1.5)
2729
+ >>> states.bw1
2730
+ bw1(1.557602, 3.327195, 5.658322, 7.065344, 5.7463, 3.831437, 2.0, 6.0)
2731
+
2732
+ In the following examples, we keep the general configuration but set either
2733
+ |TAb1| or |TVs1| to |numpy.inf| or zero (you can replace |numpy.inf| with a
2734
+ high value and zero with a low value to confirm the correct "direction" of our
2735
+ handling of these special cases):
2736
+
2737
+ >>> infinity = inf
2738
+ >>> zero = 0.0
2739
+
2740
+ Setting |TAb1| to |numpy.inf| disables the surface runoff:
2741
+
2742
+ >>> tab1(infinity)
2743
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2744
+ >>> model.calc_qab1_qvs1_bw1_v1()
2745
+ >>> fluxes.qab1
2746
+ qab1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2747
+ >>> fluxes.qvs1
2748
+ qvs1(0.442398, 0.672805, 1.990793, 2.221199, 1.018414, 1.117516, 0.5,
2749
+ 1.615203)
2750
+ >>> states.bw1
2751
+ bw1(1.557602, 3.327195, 7.009207, 8.778801, 5.981586, 3.982484, 2.0,
2752
+ 6.884797)
2753
+
2754
+ Setting |TAb1| to zero enforces that all water exceeding |H1| becomes surface
2755
+ runoff immediately:
2756
+
2757
+ >>> tab1(zero)
2758
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2759
+ >>> model.calc_qab1_qvs1_bw1_v1()
2760
+ >>> fluxes.qab1
2761
+ qab1(0.0, 0.0, 5.0, 6.0, 2.115471, 1.0, 0.0, 3.5)
2762
+ >>> fluxes.qvs1
2763
+ qvs1(0.442398, 0.672805, 0.884797, 1.0, 0.884529, 0.896317, 0.5, 1.0)
2764
+ >>> states.bw1
2765
+ bw1(1.557602, 3.327195, 3.115203, 4.0, 4.0, 3.203683, 2.0, 4.0)
2766
+
2767
+ Setting |TVs1| to |numpy.inf| disables the percolation:
2768
+
2769
+ >>> tab1(1.0)
2770
+ >>> tvs1(infinity)
2771
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2772
+ >>> model.calc_qab1_qvs1_bw1_v1()
2773
+ >>> fluxes.qab1
2774
+ qab1(0.0, 0.0, 1.967347, 2.393469, 0.408182, 0.414775, 0.0, 1.319592)
2775
+ >>> fluxes.qvs1
2776
+ qvs1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2777
+ >>> states.bw1
2778
+ bw1(2.0, 4.0, 7.032653, 8.606531, 6.591818, 4.685225, 2.5, 7.180408)
2779
+
2780
+ Setting |TAb1| to zero ensures that all availalbe water becomes percolation
2781
+ immediately:
2782
+
2783
+ >>> tvs1(zero)
2784
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2785
+ >>> model.calc_qab1_qvs1_bw1_v1()
2786
+ >>> fluxes.qab1
2787
+ qab1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2788
+ >>> fluxes.qvs1
2789
+ qvs1(2.0, 4.0, 9.0, 11.0, 7.0, 5.1, 2.5, 8.5)
2790
+ >>> states.bw1
2791
+ bw1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2792
+
2793
+ The following examples repeat the ones above for the edge case where the
2794
+ threshold value |H1| is zero:
2795
+
2796
+ >>> h1(0.0)
2797
+ >>> tvs1(2.0)
2798
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2799
+ >>> model.calc_qab1_qvs1_bw1_v1()
2800
+ >>> fluxes.qab1
2801
+ qab1(0.703511, 1.09883, 3.165801, 3.561119, 1.691807, 1.778544,
2802
+ 0.802341, 2.604682)
2803
+ >>> fluxes.qvs1
2804
+ qvs1(0.351756, 0.549415, 1.5829, 1.780559, 0.845904, 0.889272, 0.40117,
2805
+ 1.302341)
2806
+ >>> states.bw1
2807
+ bw1(0.944733, 2.351756, 4.251299, 5.658322, 4.462289, 2.432184,
2808
+ 1.296489, 4.592977)
2809
+
2810
+ >>> tab1(infinity)
2811
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2812
+ >>> model.calc_qab1_qvs1_bw1_v1()
2813
+ >>> fluxes.qab1
2814
+ qab1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2815
+ >>> fluxes.qvs1
2816
+ qvs1(0.442398, 0.672805, 1.990793, 2.221199, 1.018414, 1.117516, 0.5,
2817
+ 1.615203)
2818
+ >>> states.bw1
2819
+ bw1(1.557602, 3.327195, 7.009207, 8.778801, 5.981586, 3.982484, 2.0,
2820
+ 6.884797)
2821
+
2822
+ >>> tab1(zero)
2823
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2824
+ >>> model.calc_qab1_qvs1_bw1_v1()
2825
+ >>> fluxes.qab1
2826
+ qab1(2.0, 4.0, 9.0, 11.0, 7.0, 5.1, 2.5, 8.5)
2827
+ >>> fluxes.qvs1
2828
+ qvs1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2829
+ >>> states.bw1
2830
+ bw1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2831
+
2832
+ >>> tab1(1.0)
2833
+ >>> tvs1(infinity)
2834
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2835
+ >>> model.calc_qab1_qvs1_bw1_v1()
2836
+ >>> fluxes.qab1
2837
+ qab1(0.786939, 1.213061, 3.541224, 3.967347, 1.852245, 1.988653,
2838
+ 0.893469, 2.893469)
2839
+ >>> fluxes.qvs1
2840
+ qvs1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2841
+ >>> states.bw1
2842
+ bw1(1.213061, 2.786939, 5.458776, 7.032653, 5.147755, 3.111347,
2843
+ 1.606531, 5.606531)
2844
+
2845
+ >>> tvs1(zero)
2846
+ >>> states.bw1 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2847
+ >>> model.calc_qab1_qvs1_bw1_v1()
2848
+ >>> fluxes.qab1
2849
+ qab1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2850
+ >>> fluxes.qvs1
2851
+ qvs1(2.0, 4.0, 9.0, 11.0, 7.0, 5.1, 2.5, 8.5)
2852
+ >>> states.bw1
2853
+ bw1(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
2854
+
2855
+ |Calc_QAb1_QVs1_BW1_V1| processes forest and glacier zones like field zones but
2856
+ sets the values of |QAb1|, |QVs1|, and |BW1| to zero for internal lakes and
2857
+ sealed areas:
2858
+
2859
+ >>> zonetype(FOREST, GLACIER, ILAKE, SEALED, FOREST, GLACIER, ILAKE, SEALED)
2860
+ >>> h1(4.0)
2861
+ >>> tab1(1.0)
2862
+ >>> tvs1(2.0)
2863
+ >>> fluxes.r = 2.0, 2.0, 2.0, 2.0, 2.5, 2.5, 2.5, 2.5
2864
+ >>> states.bw1 = 2.0, 2.0, 2.0, 2.0, 6.0, 6.0, 6.0, 6.0
2865
+ >>> model.calc_qab1_qvs1_bw1_v1()
2866
+ >>> fluxes.qab1
2867
+ qab1(0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0)
2868
+ >>> fluxes.qvs1
2869
+ qvs1(0.672805, 0.672805, 0.0, 0.0, 1.5, 1.5, 0.0, 0.0)
2870
+ >>> states.bw1
2871
+ bw1(3.327195, 3.327195, 0.0, 0.0, 6.0, 6.0, 0.0, 0.0)
2872
+ """
2873
+
2874
+ CONTROLPARAMETERS = (
2875
+ hland_control.NmbZones,
2876
+ hland_control.ZoneType,
2877
+ hland_control.H1,
2878
+ hland_control.TAb1,
2879
+ hland_control.TVs1,
2880
+ )
2881
+ REQUIREDSEQUENCES = (hland_fluxes.R,)
2882
+ UPDATEDSEQUENCES = (hland_states.BW1,)
2883
+ RESULTSEQUENCES = (hland_fluxes.QAb1, hland_fluxes.QVs1)
2884
+ SUBMETHODS = (Calc_QAb_QVs_BW_V1,)
2885
+
2886
+ @staticmethod
2887
+ def __call__(model: modeltools.Model) -> None:
2888
+ con = model.parameters.control.fastaccess
2889
+ flu = model.sequences.fluxes.fastaccess
2890
+ sta = model.sequences.states.fastaccess
2891
+ for k in range(con.nmbzones):
2892
+ flu.qab1[k] = 0.0
2893
+ flu.qvs1[k] = 0.0
2894
+ if con.zonetype[k] in (FIELD, FOREST, GLACIER):
2895
+ model.calc_qab_qvs_bw_v1(
2896
+ k,
2897
+ con.h1,
2898
+ con.tab1,
2899
+ con.tvs1,
2900
+ sta.bw1,
2901
+ flu.r,
2902
+ flu.qab1,
2903
+ flu.qvs1,
2904
+ 0.0,
2905
+ )
2906
+ else:
2907
+ sta.bw1[k] = 0.0
2908
+
2909
+
2910
+ class Calc_QAb2_QVs2_BW2_V1(modeltools.Method):
2911
+ r"""Calculate the flow and the percolation from the interflow reservoir and update
2912
+ it.
2913
+
2914
+ Basic equations:
2915
+ :math:`\frac{dBW2}{dt} = QVs1 - QAb2 - QVs2`
2916
+
2917
+ :math:`QAb2 = \frac{max(BW2 - H2, 0)}{TAb2}`
2918
+
2919
+ :math:`QVs2 = \frac{BW2}{TVs2}`
2920
+
2921
+ Method |Calc_QAb2_QVs2_BW2_V1| is functionally identical with method
2922
+ |Calc_QAb1_QVs1_BW1_V1| and also relies on the "additional method"
2923
+ |Calc_QAb_QVs_BW_V1|. Please see the documentation on method
2924
+ |Calc_QAb1_QVs1_BW1_V1|, which provides more information and exhaustive example
2925
+ calculations.
2926
+
2927
+ Example:
2928
+
2929
+ We only repeat the first and the last example of the documentation on method
2930
+ |Calc_QAb1_QVs1_BW1_V1| to verify that method |Calc_QAb2_QVs2_BW2_V1| calls
2931
+ method |Calc_QAb_QVs_BW_V1| correctly:
2932
+
2933
+ >>> from hydpy.models.hland import *
2934
+ >>> simulationstep("12h")
2935
+ >>> parameterstep("1d")
2936
+ >>> nmbzones(8)
2937
+ >>> zonetype(FIELD)
2938
+ >>> h2(4.0)
2939
+ >>> tab2(1.0)
2940
+ >>> tvs2(2.0)
2941
+ >>> fluxes.qvs1 = 0.0, 2.0, 0.0, 2.0, 5.0, 0.1, 0.5, 2.5
2942
+ >>> states.bw2 = 2.0, 2.0, 9.0, 9.0, 2.0, 5.0, 2.0, 6.0
2943
+ >>> model.calc_qab2_qvs2_bw2_v1()
2944
+ >>> fluxes.qab2
2945
+ qab2(0.0, 0.0, 1.561119, 1.956437, 0.246114, 0.181758, 0.0, 1.0)
2946
+ >>> fluxes.qvs2
2947
+ qvs2(0.442398, 0.672805, 1.780559, 1.978219, 1.007586, 1.086805, 0.5,
2948
+ 1.5)
2949
+ >>> states.bw2
2950
+ bw2(1.557602, 3.327195, 5.658322, 7.065344, 5.7463, 3.831437, 2.0, 6.0)
2951
+
2952
+ |Calc_QAb2_QVs2_BW2_V1| processes forest and glacier zones like field zones but
2953
+ sets the values of |QAb2|, |QVs2|, and |BW2| to zero for internal lakes and
2954
+ sealed areas:
2955
+
2956
+ >>> zonetype(FOREST, GLACIER, ILAKE, SEALED, FOREST, GLACIER, ILAKE, SEALED)
2957
+ >>> fluxes.qvs1 = 2.0, 2.0, 2.0, 2.0, 2.5, 2.5, 2.5, 2.5
2958
+ >>> states.bw2 = 2.0, 2.0, 2.0, 2.0, 6.0, 6.0, 6.0, 6.0
2959
+ >>> model.calc_qab2_qvs2_bw2_v1()
2960
+ >>> fluxes.qab2
2961
+ qab2(0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0)
2962
+ >>> fluxes.qvs2
2963
+ qvs2(0.672805, 0.672805, 0.0, 0.0, 1.5, 1.5, 0.0, 0.0)
2964
+ >>> states.bw2
2965
+ bw2(3.327195, 3.327195, 0.0, 0.0, 6.0, 6.0, 0.0, 0.0)
2966
+ """
2967
+
2968
+ CONTROLPARAMETERS = (
2969
+ hland_control.NmbZones,
2970
+ hland_control.ZoneType,
2971
+ hland_control.H2,
2972
+ hland_control.TAb2,
2973
+ hland_control.TVs2,
2974
+ )
2975
+ REQUIREDSEQUENCES = (hland_fluxes.QVs1,)
2976
+ UPDATEDSEQUENCES = (hland_states.BW2,)
2977
+ RESULTSEQUENCES = (hland_fluxes.QAb2, hland_fluxes.QVs2)
2978
+ SUBMETHODS = (Calc_QAb_QVs_BW_V1,)
2979
+
2980
+ @staticmethod
2981
+ def __call__(model: modeltools.Model) -> None:
2982
+ con = model.parameters.control.fastaccess
2983
+ flu = model.sequences.fluxes.fastaccess
2984
+ sta = model.sequences.states.fastaccess
2985
+ for k in range(con.nmbzones):
2986
+ flu.qab2[k] = 0.0
2987
+ flu.qvs2[k] = 0.0
2988
+ if con.zonetype[k] in (FIELD, FOREST, GLACIER):
2989
+ model.calc_qab_qvs_bw_v1(
2990
+ k,
2991
+ con.h2,
2992
+ con.tab2,
2993
+ con.tvs2,
2994
+ sta.bw2,
2995
+ flu.qvs1,
2996
+ flu.qab2,
2997
+ flu.qvs2,
2998
+ 0.0,
2999
+ )
3000
+ else:
3001
+ sta.bw2[k] = 0.0
3002
+
3003
+
3004
+ class Calc_RS_RI_SUZ_V1(modeltools.Method):
3005
+ r"""Calculate the surface runoff and the interflow and remove them from the upper
3006
+ storage reservoir.
3007
+
3008
+ Basic equation:
3009
+ :math:`RS = (SUZ - SGR) \cdot (1 - W0)`
3010
+
3011
+ :math:`RI = SUZ \cdot (1 - W1)`
3012
+
3013
+ :math:`\frac{SUZ}{dt} = -(RS + RI)`
3014
+
3015
+ Examples:
3016
+
3017
+ For internal lakes and sealed areas, method |Calc_RS_RI_SUZ_V1| always sets the
3018
+ values of |RS|, |RI|, and |SUZ| to zero:
3019
+
3020
+ >>> from hydpy.models.hland import *
3021
+ >>> simulationstep("12h")
3022
+ >>> parameterstep()
3023
+ >>> nmbzones(9)
3024
+ >>> zonetype(FIELD, FIELD, FIELD, FIELD, FIELD, FOREST, GLACIER, ILAKE, SEALED)
3025
+ >>> sgr(10.0)
3026
+ >>> derived.w0 = 0.4
3027
+ >>> derived.w1 = 0.8
3028
+ >>> states.suz = 0.0, 5.0, 10.0, 15.0, 20.0, 20.0, 20.0, 20.0, 20.0
3029
+ >>> model.calc_rs_ri_suz_v1()
3030
+ >>> fluxes.rs
3031
+ rs(0.0, 0.0, 0.0, 3.0, 6.0, 6.0, 6.0, 0.0, 0.0)
3032
+ >>> fluxes.ri
3033
+ ri(0.0, 1.0, 2.0, 3.0, 4.0, 4.0, 4.0, 0.0, 0.0)
3034
+ >>> states.suz
3035
+ suz(0.0, 4.0, 8.0, 9.0, 10.0, 10.0, 10.0, 0.0, 0.0)
3036
+
3037
+ Theoretically, the parallel calculation of |RS| and |RI| can result in negative
3038
+ values of |SUZ|. The checks implemented for the parameter classes |K0| and
3039
+ |K1| should prevent this problem. However, to be definitely on the safe side,
3040
+ method |Calc_RS_RI_SUZ_V1| also checks if the final state of |SUZ| is negative
3041
+ and, when necessary, resets it to zero and reduces |RS| and |RI| accordingly
3042
+ (with the same fraction):
3043
+
3044
+ >>> derived.w0 = 0.1
3045
+ >>> derived.w1 = 0.2
3046
+ >>> states.suz = 0.0, 5.0, 10.0, 15.0, 20.0, 20.0, 20.0, 20.0, 20.0
3047
+ >>> model.calc_rs_ri_suz_v1()
3048
+ >>> fluxes.rs
3049
+ rs(0.0, 0.0, 0.0, 4.909091, 10.8, 10.8, 10.8, 0.0, 0.0)
3050
+ >>> fluxes.ri
3051
+ ri(0.0, 4.0, 8.0, 13.090909, 19.2, 19.2, 19.2, 0.0, 0.0)
3052
+ >>> states.suz
3053
+ suz(0.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
3054
+ """
3055
+
3056
+ CONTROLPARAMETERS = (
3057
+ hland_control.NmbZones,
3058
+ hland_control.ZoneType,
3059
+ hland_control.SGR,
3060
+ )
3061
+ DERIVEDPARAMETERS = (hland_derived.W0, hland_derived.W1)
3062
+ UPDATEDSEQUENCES = (hland_states.SUZ,)
3063
+ RESULTSEQUENCES = (hland_fluxes.RS, hland_fluxes.RI)
3064
+
3065
+ @staticmethod
3066
+ def __call__(model: modeltools.Model) -> None:
3067
+ con = model.parameters.control.fastaccess
3068
+ der = model.parameters.derived.fastaccess
3069
+ flu = model.sequences.fluxes.fastaccess
3070
+ sta = model.sequences.states.fastaccess
3071
+ for k in range(con.nmbzones):
3072
+ if con.zonetype[k] in (FIELD, FOREST, GLACIER):
3073
+ if sta.suz[k] > con.sgr[k]:
3074
+ flu.rs[k] = (sta.suz[k] - con.sgr[k]) * (1.0 - der.w0[k])
3075
+ else:
3076
+ flu.rs[k] = 0.0
3077
+ flu.ri[k] = sta.suz[k] * (1.0 - der.w1[k])
3078
+ sta.suz[k] -= flu.rs[k] + flu.ri[k]
3079
+ if sta.suz[k] < 0.0:
3080
+ d_f = 1.0 - sta.suz[k] / (flu.rs[k] + flu.ri[k])
3081
+ flu.rs[k] *= d_f
3082
+ flu.ri[k] *= d_f
3083
+ sta.suz[k] = 0.0
3084
+ else:
3085
+ sta.suz[k] = 0.0
3086
+ flu.rs[k] = 0.0
3087
+ flu.ri[k] = 0.0
3088
+
3089
+
3090
+ class Calc_LZ_V1(modeltools.Method):
3091
+ r"""Add percolation from the upper zone layera and lake precipitation to the lower
3092
+ zone storage.
3093
+
3094
+ Basic equation:
3095
+ .. math::
3096
+ \frac{dLZ}{dt} = \frac{RelUpperZoneArea}{RelLowerZoneArea} \cdot Perc +
3097
+ \sum_{k=1}^{NmbZones} \frac{RelZoneAreas_k}{RelLowerZoneArea} \cdot
3098
+ \begin{cases}
3099
+ Pc_k &|\ ZoneType_k = ILAKE
3100
+ \\
3101
+ 0 &|\ ZoneType_k \neq ILAKE
3102
+ \end{cases}
3103
+
3104
+ Examples:
3105
+
3106
+ We define a subbasin with five zones of different land-use types and sizes:
3107
+
3108
+ >>> from hydpy.models.hland import *
3109
+ >>> simulationstep("12h")
3110
+ >>> parameterstep("1d")
3111
+ >>> nmbzones(5)
3112
+ >>> zonetype(FIELD, FOREST, GLACIER, ILAKE, SEALED)
3113
+ >>> area(100.0)
3114
+ >>> zonearea(10.0, 20.0, 30.0, 15.0, 25.0)
3115
+ >>> psi(1.0)
3116
+
3117
+ To ensure the consistency of the values of the relevant derived parameters, we
3118
+ apply their |Parameter.update| methods:
3119
+
3120
+ >>> derived.relzoneareas.update()
3121
+ >>> derived.relupperzonearea.update()
3122
+ >>> derived.rellowerzonearea.update()
3123
+
3124
+ First, we set the precipitation intensity (|PC|) to 30 mm and the percolation
3125
+ intensity (|PERC|) to zero. Only the internal lake zone passes its value for
3126
+ |PC| directly to the lower zone layer. The fraction between its size (15 km²)
3127
+ and the extent of the lower zone layer (75 km²) is 1/5. Hence, the single
3128
+ zone's input of 30 mm increases the lower zone layer's water content by 6 mm:
3129
+
3130
+ >>> fluxes.pc = 30.0
3131
+ >>> fluxes.perc = 0.0
3132
+ >>> states.lz = 10.0
3133
+ >>> model.calc_lz_v1()
3134
+ >>> states.lz
3135
+ lz(16.0)
3136
+
3137
+ Second, we set |PC| to zero and the percolation intensity to 5 mm. The
3138
+ fraction between the extents of the upper zone layer (60 km²) and the lower
3139
+ zone layer (75 km³) is 4/5. Hence, percolation released by the upper zone layer
3140
+ increases the content of the lower zone layer by 4 mm:
3141
+
3142
+ >>> fluxes.pc = 0.0
3143
+ >>> fluxes.perc = 5.0
3144
+ >>> model.calc_lz_v1()
3145
+ >>> states.lz
3146
+ lz(20.0)
3147
+
3148
+ In case the extent of the lower zone area is zero (which is possible for
3149
+ completely sealed subbasins only) method |Calc_LZ_V1| sets |LZ| to zero:
3150
+
3151
+ >>> derived.rellowerzonearea(0.0)
3152
+ >>> model.calc_lz_v1()
3153
+ >>> states.lz
3154
+ lz(0.0)
3155
+ """
3156
+
3157
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
3158
+ DERIVEDPARAMETERS = (
3159
+ hland_derived.RelUpperZoneArea,
3160
+ hland_derived.RelLowerZoneArea,
3161
+ hland_derived.RelZoneAreas,
3162
+ )
3163
+ REQUIREDSEQUENCES = (hland_fluxes.Perc, hland_fluxes.PC)
3164
+ UPDATEDSEQUENCES = (hland_states.LZ,)
3165
+
3166
+ @staticmethod
3167
+ def __call__(model: modeltools.Model) -> None:
3168
+ con = model.parameters.control.fastaccess
3169
+ der = model.parameters.derived.fastaccess
3170
+ flu = model.sequences.fluxes.fastaccess
3171
+ sta = model.sequences.states.fastaccess
3172
+ if der.rellowerzonearea > 0.0:
3173
+ sta.lz += der.relupperzonearea / der.rellowerzonearea * flu.perc
3174
+ for k in range(con.nmbzones):
3175
+ if con.zonetype[k] == ILAKE:
3176
+ sta.lz += der.relzoneareas[k] / der.rellowerzonearea * flu.pc[k]
3177
+ else:
3178
+ sta.lz = 0.0
3179
+
3180
+
3181
+ class Calc_LZ_V2(modeltools.Method):
3182
+ r"""Add percolation from the interflow reservoir and lake precipitation to the
3183
+ lower zone storage.
3184
+
3185
+ Basic equation:
3186
+ .. math::
3187
+ \frac{dLZ}{dt} =
3188
+ \sum_{k=1}^{NmbZones} \frac{RelZoneAreas_k}{RelLowerZoneArea} \cdot
3189
+ \begin{cases}
3190
+ QVs2_k &|\ ZoneType_k \in \{ FIELD, FOREST, GLACIER \}
3191
+ \\
3192
+ Pc_k &|\ ZoneType_k = ILAKE
3193
+ \\
3194
+ 0 &|\ ZoneType_k = SEALED
3195
+ \end{cases}
3196
+
3197
+ Example:
3198
+
3199
+ The first three zones of type |FIELD|, |FOREST|, and |GLACIER| contribute via
3200
+ deep percolation to the lower zone reservoir. For the fourth zone of type
3201
+ |ILAKE|, precipitation contributes directly to the lower zone storage. The
3202
+ fifth zone of type |SEALED| does not contribute to the lower zone storage at
3203
+ all:
3204
+
3205
+ >>> from hydpy.models.hland import *
3206
+ >>> simulationstep("12h")
3207
+ >>> parameterstep("1d")
3208
+ >>> nmbzones(5)
3209
+ >>> zonetype(FIELD, FOREST, GLACIER, ILAKE, SEALED)
3210
+ >>> derived.relzoneareas = 0.24, 0.18, 0.12, 0.06, 0.4
3211
+ >>> derived.rellowerzonearea = 0.6
3212
+ >>> fluxes.qvs2 = 1.0, 2.0, 3.0, nan, nan
3213
+ >>> fluxes.pc = nan, nan, nan, 14.0, nan
3214
+ >>> states.lz = 5.0
3215
+ >>> model.calc_lz_v2()
3216
+ >>> states.lz
3217
+ lz(8.0)
3218
+ """
3219
+
3220
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
3221
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelLowerZoneArea)
3222
+ REQUIREDSEQUENCES = (hland_fluxes.QVs2, hland_fluxes.PC)
3223
+ UPDATEDSEQUENCES = (hland_states.LZ,)
3224
+
3225
+ @staticmethod
3226
+ def __call__(model: modeltools.Model) -> None:
3227
+ con = model.parameters.control.fastaccess
3228
+ der = model.parameters.derived.fastaccess
3229
+ flu = model.sequences.fluxes.fastaccess
3230
+ sta = model.sequences.states.fastaccess
3231
+ for k in range(con.nmbzones):
3232
+ if con.zonetype[k] == ILAKE:
3233
+ sta.lz += der.relzoneareas[k] / der.rellowerzonearea * flu.pc[k]
3234
+ elif con.zonetype[k] != SEALED:
3235
+ sta.lz += der.relzoneareas[k] / der.rellowerzonearea * flu.qvs2[k]
3236
+
3237
+
3238
+ class Calc_GR1_V1(modeltools.Method):
3239
+ r"""Calculate the recharge to the fast response groundwater reservoir.
3240
+
3241
+ Basic equation:
3242
+ :math:`GR1 = min \left(DP, \frac{SG1Max - SG1}{K2} \right)`
3243
+
3244
+ Examples:
3245
+
3246
+ For internal lakes and sealed areas, method |Calc_GR1_V1| always sets the values
3247
+ of |GR1| and |SG1| to zero:
3248
+
3249
+ >>> from hydpy.models.hland import *
3250
+ >>> simulationstep("1h")
3251
+ >>> parameterstep("1d")
3252
+ >>> nmbzones(9)
3253
+ >>> zonetype(FIELD, FIELD, FIELD, FIELD, FIELD, FOREST, GLACIER, ILAKE, SEALED)
3254
+ >>> sg1max(10.0)
3255
+ >>> k2(10.0/24.0)
3256
+ >>> from hydpy import round_
3257
+ >>> round_(k2.values[0])
3258
+ 10.0
3259
+ >>> fluxes.dp = 0.5
3260
+ >>> states.sg1 = 0.0, 5.0, 9.0, 9.9, 10.0, 5.0, 5.0, 5.0, 5.0
3261
+ >>> model.calc_gr1_v1()
3262
+ >>> fluxes.gr1
3263
+ gr1(0.5, 0.5, 0.1, 0.01, 0.0, 0.5, 0.5, 0.0, 0.0)
3264
+
3265
+ For unreasonably low values of parameter |K2|, the sum of |SG1| and |GR1| could
3266
+ theoretically become larger than |SG1Max|. We let method |Calc_GR1_V1| reduce
3267
+ |GR1| when necessary to ensure this does not happen:
3268
+
3269
+ >>> k2.values = 0.5
3270
+ >>> states.sg1 = 0.0, 5.0, 9.0, 9.9, 10.0, 5.0, 5.0, 5.0, 5.0
3271
+ >>> model.calc_gr1_v1()
3272
+ >>> fluxes.gr1
3273
+ gr1(0.5, 0.5, 0.5, 0.1, 0.0, 0.5, 0.5, 0.0, 0.0)
3274
+ """
3275
+
3276
+ CONTROLPARAMETERS = (
3277
+ hland_control.NmbZones,
3278
+ hland_control.ZoneType,
3279
+ hland_control.SG1Max,
3280
+ hland_control.K2,
3281
+ )
3282
+ REQUIREDSEQUENCES = (hland_fluxes.DP,)
3283
+ UPDATEDSEQUENCES = (hland_states.SG1,)
3284
+ RESULTSEQUENCES = (hland_fluxes.GR1,)
3285
+
3286
+ @staticmethod
3287
+ def __call__(model: modeltools.Model) -> None:
3288
+ con = model.parameters.control.fastaccess
3289
+ flu = model.sequences.fluxes.fastaccess
3290
+ sta = model.sequences.states.fastaccess
3291
+ for k in range(con.nmbzones):
3292
+ if con.zonetype[k] in (FIELD, FOREST, GLACIER):
3293
+ flu.gr1[k] = min(flu.dp[k], (con.sg1max[k] - sta.sg1[k]) / con.k2[k])
3294
+ flu.gr1[k] -= max(sta.sg1[k] + flu.gr1[k] - con.sg1max[k], 0.0)
3295
+ else:
3296
+ sta.sg1[k] = 0.0
3297
+ flu.gr1[k] = 0.0
3298
+
3299
+
3300
+ class Calc_RG1_SG1_V1(modeltools.Method):
3301
+ r"""Calculate the discharge from the fast response groundwater reservoir and
3302
+ subtract it.
3303
+
3304
+ Basic equation:
3305
+ :math:`SG1_{new} = W2 \cdot SG1_{old} + (1 - W2) \cdot K2 \cdot GR1`
3306
+
3307
+ :math:`RG1 = SG1_{old} + GR1 - SG1_{new}`
3308
+
3309
+ Example:
3310
+
3311
+ For internal lakes and sealed areas, method |Calc_RG1_SG1_V1| always sets the
3312
+ values of |GR1| and |SG1| to zero:
3313
+
3314
+ >>> from hydpy.models.hland import *
3315
+ >>> simulationstep("1h")
3316
+ >>> parameterstep("1d")
3317
+ >>> nmbzones(7)
3318
+ >>> zonetype(FIELD, FIELD, FIELD, FOREST, GLACIER, ILAKE, SEALED)
3319
+ >>> k2(1.0/24, 10.0/24, 100.0/24, 100.0/24, 100.0/24, 100.0/24, 100.0/24)
3320
+ >>> from hydpy import round_
3321
+ >>> round_(k2.values)
3322
+ 1.442695, 10.0, 100.0, 100.0, 100.0, 100.0, 100.0
3323
+ >>> derived.w2.update()
3324
+ >>> fluxes.gr1 = 2.0
3325
+ >>> states.sg1 = 5.0
3326
+ >>> model.calc_rg1_sg1_v1()
3327
+ >>> fluxes.rg1
3328
+ rg1(3.057305, 0.572561, 0.059718, 0.059718, 0.059718, 0.0, 0.0)
3329
+ >>> states.sg1
3330
+ sg1(3.942695, 6.427439, 6.940282, 6.940282, 6.940282, 0.0, 0.0)
3331
+ """
3332
+
3333
+ CONTROLPARAMETERS = (
3334
+ hland_control.NmbZones,
3335
+ hland_control.ZoneType,
3336
+ hland_control.K2,
3337
+ )
3338
+ DERIVEDPARAMETERS = (hland_derived.W2,)
3339
+ REQUIREDSEQUENCES = (hland_fluxes.GR1,)
3340
+ UPDATEDSEQUENCES = (hland_states.SG1,)
3341
+ RESULTSEQUENCES = (hland_fluxes.RG1,)
3342
+
3343
+ @staticmethod
3344
+ def __call__(model: modeltools.Model) -> None:
3345
+ con = model.parameters.control.fastaccess
3346
+ der = model.parameters.derived.fastaccess
3347
+ flu = model.sequences.fluxes.fastaccess
3348
+ sta = model.sequences.states.fastaccess
3349
+ for k in range(con.nmbzones):
3350
+ if con.zonetype[k] in (FIELD, FOREST, GLACIER):
3351
+ d_sg1 = sta.sg1[k]
3352
+ sta.sg1[k] = (
3353
+ der.w2[k] * d_sg1 + (1.0 - der.w2[k]) * con.k2[k] * flu.gr1[k]
3354
+ )
3355
+ flu.rg1[k] = d_sg1 + flu.gr1[k] - sta.sg1[k]
3356
+ else:
3357
+ sta.sg1[k] = 0.0
3358
+ flu.rg1[k] = 0.0
3359
+
3360
+
3361
+ class Calc_GR2_GR3_V1(modeltools.Method):
3362
+ r"""Calculate the recharge of the first-order and the second-order slow response
3363
+ groundwater reservoir.
3364
+
3365
+ Basic equations:
3366
+ .. math::
3367
+ GRT =
3368
+ \sum_{k=1}^{NmbZones} \frac{RelZoneAreas_k}{RelLowerZoneArea} \cdot
3369
+ \begin{cases}
3370
+ DP_k - GR1_k &|\ ZoneType_k \in \{ FIELD, FOREST, GLACIER \}
3371
+ \\
3372
+ Pc_k &|\ ZoneType_k = ILAKE
3373
+ \\
3374
+ 0 &|\ ZoneType_k = SEALED
3375
+ \end{cases}
3376
+
3377
+ :math:`GR2 = FSG \cdot GRT`
3378
+
3379
+ :math:`GR3 = (1 - FSG) \cdot GRT`
3380
+
3381
+ Example:
3382
+
3383
+ Method |Calc_GR2_GR3_V1| aggregates the given input (term "GRT" in the given
3384
+ basic equations) divides it between |GR2| and |GR3|:
3385
+
3386
+ >>> from hydpy.models.hland import *
3387
+ >>> simulationstep("12h")
3388
+ >>> parameterstep("1d")
3389
+ >>> nmbzones(5)
3390
+ >>> zonetype(FIELD, FOREST, GLACIER, ILAKE, SEALED)
3391
+ >>> derived.relzoneareas(0.24, 0.18, 0.12, 0.06, 0.4)
3392
+ >>> derived.rellowerzonearea(0.6)
3393
+ >>> fluxes.gr1 = 1.0, 2.0, 3.0, nan, nan
3394
+ >>> fluxes.dp = 4.0, 6.0, 8.0, nan, nan
3395
+ >>> fluxes.pc = nan, nan, nan, 11.0, nan
3396
+ >>> model.calc_gr2_gr3_v1()
3397
+ >>> fluxes.gr2
3398
+ gr2(4.0)
3399
+ >>> fluxes.gr3
3400
+ gr3(0.5)
3401
+ """
3402
+
3403
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
3404
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelLowerZoneArea)
3405
+ FIXEDPARAMETERS = (hland_fixed.FSG,)
3406
+ REQUIREDSEQUENCES = (hland_fluxes.PC, hland_fluxes.DP, hland_fluxes.GR1)
3407
+ RESULTSEQUENCES = (hland_fluxes.GR2, hland_fluxes.GR3)
3408
+
3409
+ @staticmethod
3410
+ def __call__(model: modeltools.Model) -> None:
3411
+ con = model.parameters.control.fastaccess
3412
+ der = model.parameters.derived.fastaccess
3413
+ fix = model.parameters.fixed.fastaccess
3414
+ flu = model.sequences.fluxes.fastaccess
3415
+ flu.gr2 = 0.0
3416
+ flu.gr3 = 0.0
3417
+ for k in range(con.nmbzones):
3418
+ if con.zonetype[k] == SEALED:
3419
+ continue
3420
+ d_weight = der.relzoneareas[k] / der.rellowerzonearea
3421
+ if con.zonetype[k] == ILAKE:
3422
+ d_total = d_weight * flu.pc[k]
3423
+ else:
3424
+ d_total = d_weight * (flu.dp[k] - flu.gr1[k])
3425
+ flu.gr2 += fix.fsg * d_total
3426
+ flu.gr3 += (1.0 - fix.fsg) * d_total
3427
+
3428
+
3429
+ class Calc_EL_SG2_SG3_AETModel_V1(modeltools.Method):
3430
+ r"""Let a submodel that follows the |AETModel_V1| submodel interface calculate
3431
+ lake evaporation and adjust the slow response groundwater reservoirs.
3432
+
3433
+ Basic equations:
3434
+ :math:`\frac{dSG2_i}{dt} =
3435
+ -FSG \cdot \frac{RelZoneAreas_i}{RelLowerZoneArea} \cdot EL_i`
3436
+
3437
+ :math:`\frac{dSG3_i}{dt} =
3438
+ -(1 - FSG) \cdot \frac{RelZoneAreas_i}{RelLowerZoneArea} \cdot EL_i`
3439
+
3440
+ Examples:
3441
+
3442
+ We build an example based on |evap_aet_hbv96| for calculating lake evaporation:
3443
+
3444
+ >>> from hydpy.models.hland_96p import *
3445
+ >>> parameterstep("1h")
3446
+ >>> nmbzones(5)
3447
+ >>> zonetype(GLACIER, SEALED, FIELD, FOREST, ILAKE)
3448
+ >>> area(0.9)
3449
+ >>> zonearea(0.2, 0.1, 0.1, 0.1, 0.4)
3450
+ >>> psi(1.0)
3451
+ >>> zonez(5.0)
3452
+ >>> fc(50.0)
3453
+ >>> derived.relzoneareas.update()
3454
+ >>> derived.rellowerzonearea.update()
3455
+ >>> factors.tc = 10.0
3456
+ >>> with model.add_aetmodel_v1("evap_aet_hbv96"):
3457
+ ... temperaturethresholdice(0.0)
3458
+
3459
+ |Calc_EL_SG2_SG3_AETModel_V1| uses the flux returned by the submodel to adjust
3460
+ |SG2| and |SG3|, considering the total extent of the groundwater-affected
3461
+ subarea and the fraction between the spatial extents of the first-order and the
3462
+ second-order slow response groundwater reservoir:
3463
+
3464
+ >>> model.aetmodel.sequences.fluxes.potentialwaterevaporation = 2.25
3465
+ >>> states.sg2 = 3.0
3466
+ >>> states.sg3 = 0.3
3467
+ >>> model.calc_el_sg2_sg3_v1()
3468
+ >>> fluxes.el
3469
+ el(0.0, 0.0, 0.0, 0.0, 2.25)
3470
+ >>> states.sg2
3471
+ sg2(2.0)
3472
+ >>> states.sg3
3473
+ sg3(0.175)
3474
+
3475
+ Zones of type |ILAKE| are assumed to have an open water surface, so evaporation
3476
+ is always possible. Therefore, applying |Calc_EL_SG2_SG3_AETModel_V1| can
3477
+ result in negative |SG2| and |SG3| values:
3478
+
3479
+ >>> model.aetmodel.sequences.fluxes.potentialwaterevaporation = 4.5
3480
+ >>> states.sg2 = 1.0
3481
+ >>> states.sg3 = 0.1
3482
+ >>> model.calc_el_sg2_sg3_v1()
3483
+ >>> fluxes.el
3484
+ el(0.0, 0.0, 0.0, 0.0, 4.5)
3485
+ >>> states.sg2
3486
+ sg2(-1.0)
3487
+ >>> states.sg3
3488
+ sg3(-0.15)
3489
+ """
3490
+
3491
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
3492
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelLowerZoneArea)
3493
+ FIXEDPARAMETERS = (hland_fixed.FSG,)
3494
+ UPDATEDSEQUENCES = (hland_states.SG2, hland_states.SG3)
3495
+ RESULTSEQUENCES = (hland_fluxes.EL,)
3496
+
3497
+ @staticmethod
3498
+ def __call__(model: modeltools.Model, submodel: aetinterfaces.AETModel_V1) -> None:
3499
+ con = model.parameters.control.fastaccess
3500
+ der = model.parameters.derived.fastaccess
3501
+ fix = model.parameters.fixed.fastaccess
3502
+ flu = model.sequences.fluxes.fastaccess
3503
+ sta = model.sequences.states.fastaccess
3504
+ submodel.determine_waterevaporation()
3505
+ for k in range(con.nmbzones):
3506
+ if con.zonetype[k] == ILAKE:
3507
+ flu.el[k] = submodel.get_waterevaporation(k)
3508
+ weight: float = der.relzoneareas[k] / der.rellowerzonearea
3509
+ sta.sg2 -= fix.fsg * weight * flu.el[k]
3510
+ sta.sg3 -= (1.0 - fix.fsg) * weight * flu.el[k]
3511
+ else:
3512
+ flu.el[k] = 0.0
3513
+
3514
+
3515
+ class Calc_EL_SG2_SG3_V1(modeltools.Method):
3516
+ """Let a submodel that follows the |AETModel_V1| submodel interface calculate
3517
+ interception evaporation, soil evapotranspiration, and open water evaporation, and
3518
+ adjust the related interception, soil water, and slow response groundwater storages
3519
+ accordingly."""
3520
+
3521
+ SUBMODELINTERFACES = (aetinterfaces.AETModel_V1,)
3522
+ SUBMETHODS = (Calc_EL_SG2_SG3_AETModel_V1,)
3523
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
3524
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelLowerZoneArea)
3525
+ FIXEDPARAMETERS = (hland_fixed.FSG,)
3526
+ UPDATEDSEQUENCES = (hland_states.SG2, hland_states.SG3)
3527
+ RESULTSEQUENCES = (hland_fluxes.EL,)
3528
+
3529
+ @staticmethod
3530
+ def __call__(model: modeltools.Model) -> None:
3531
+ if model.aetmodel_typeid == 1:
3532
+ model.calc_el_sg2_sg3_aetmodel_v1(
3533
+ cast(aetinterfaces.AETModel_V1, model.aetmodel)
3534
+ )
3535
+ # ToDo:
3536
+ # else:
3537
+ # assert_never(model.petmodel)
3538
+
3539
+
3540
+ class Calc_RG2_SG2_V1(modeltools.Method):
3541
+ r"""Calculate the discharge from the first-order slow response groundwater
3542
+ reservoir and subtract it.
3543
+
3544
+ Basic equation:
3545
+ :math:`SG2_{new} = W3 \cdot SG2_{old} + (1 - W3) \cdot K3 \cdot GR2`
3546
+
3547
+ :math:`RG2 = SG2_{old} + GR2 - SG2_{new}`
3548
+
3549
+ Examples:
3550
+
3551
+ >>> from hydpy.models.hland import *
3552
+ >>> simulationstep("1h")
3553
+ >>> parameterstep("1d")
3554
+ >>> k3(2.0/24)
3555
+ >>> from hydpy import round_
3556
+ >>> round_(k3.values)
3557
+ 2.0
3558
+ >>> derived.w3.update()
3559
+ >>> fluxes.gr2 = 2.0
3560
+
3561
+ For non-negative |SG2| values, method |Calc_RG2_SG2_V1| strictly follows the
3562
+ given base equation:
3563
+
3564
+ >>> states.sg2 = 5.0
3565
+ >>> model.calc_rg2_sg2_v1()
3566
+ >>> fluxes.rg2
3567
+ rg2(2.393469)
3568
+ >>> states.sg2
3569
+ sg2(4.606531)
3570
+
3571
+ For negative |SG2| values, it uses |RG2| to fill the groundwater storage
3572
+ so that no discharge occurs:
3573
+
3574
+ >>> states.sg2 = -3.0
3575
+ >>> model.calc_rg2_sg2_v1()
3576
+ >>> fluxes.rg2
3577
+ rg2(0.0)
3578
+ >>> states.sg2
3579
+ sg2(-1.0)
3580
+
3581
+ >>> states.sg2 = -2.0
3582
+ >>> model.calc_rg2_sg2_v1()
3583
+ >>> fluxes.rg2
3584
+ rg2(0.0)
3585
+ >>> states.sg2
3586
+ sg2(0.0)
3587
+
3588
+ If the sum of |SG2| and |RG2| is positive, recharge first fills the deficit.
3589
+ In the remaining time, |Calc_RG2_SG2_V1| handles the remaining recharge as
3590
+ implied by the basic equations (with parameters |K3| and |W3| adapted to the
3591
+ remaining time interval):
3592
+
3593
+ >>> states.sg2 = -1.0
3594
+ >>> model.calc_rg2_sg2_v1()
3595
+ >>> fluxes.rg2
3596
+ rg2(0.115203)
3597
+ >>> states.sg2
3598
+ sg2(0.884797)
3599
+ """
3600
+
3601
+ CONTROLPARAMETERS = (hland_control.K3,)
3602
+ DERIVEDPARAMETERS = (hland_derived.W3,)
3603
+ REQUIREDSEQUENCES = (hland_fluxes.GR2,)
3604
+ UPDATEDSEQUENCES = (hland_states.SG2,)
3605
+ RESULTSEQUENCES = (hland_fluxes.RG2,)
3606
+
3607
+ @staticmethod
3608
+ def __call__(model: modeltools.Model) -> None:
3609
+ con = model.parameters.control.fastaccess
3610
+ der = model.parameters.derived.fastaccess
3611
+ flu = model.sequences.fluxes.fastaccess
3612
+ sta = model.sequences.states.fastaccess
3613
+ d_sg2 = sta.sg2
3614
+ d_gr2 = flu.gr2
3615
+ d_k3 = con.k3
3616
+ d_w3 = der.w3
3617
+ if d_sg2 < 0.0 < d_gr2:
3618
+ d_add = min(-sta.sg2, d_gr2)
3619
+ d_k3 *= d_gr2 / d_add
3620
+ d_w3 = modelutils.exp(-1.0 / d_k3)
3621
+ d_sg2 += d_add
3622
+ d_gr2 -= d_add
3623
+ if d_sg2 >= 0.0:
3624
+ sta.sg2 = d_w3 * d_sg2 + (1.0 - d_w3) * d_k3 * d_gr2
3625
+ flu.rg2 = d_sg2 + d_gr2 - sta.sg2
3626
+ else:
3627
+ sta.sg2 = d_sg2
3628
+ flu.rg2 = 0.0
3629
+
3630
+
3631
+ class Calc_RG3_SG3_V1(modeltools.Method):
3632
+ r"""Calculate the discharge from the second-order slow response groundwater
3633
+ reservoir and subtract it.
3634
+
3635
+ Basic equation:
3636
+ :math:`SG3_{new} = W4 \cdot SG3_{old} + (1 - W4) \cdot K4 \cdot GR3`
3637
+
3638
+ :math:`RG3 = SG3_{old} + GR3 - SG3_{new}`
3639
+
3640
+ Examples:
3641
+
3642
+ >>> from hydpy.models.hland import *
3643
+ >>> simulationstep("1h")
3644
+ >>> parameterstep("1d")
3645
+ >>> derived.k4(1.0/24)
3646
+ >>> from hydpy import round_
3647
+ >>> round_(derived.k4.values)
3648
+ 1.0
3649
+ >>> derived.w4.update()
3650
+ >>> fluxes.gr3 = 2.0
3651
+
3652
+ For non-negative |SG3| values, method |Calc_RG3_SG3_V1| strictly follows the
3653
+ given base equation:
3654
+
3655
+ >>> states.sg3 = 5.0
3656
+ >>> model.calc_rg3_sg3_v1()
3657
+ >>> fluxes.rg3
3658
+ rg3(3.896362)
3659
+ >>> states.sg3
3660
+ sg3(3.103638)
3661
+
3662
+ For negative |SG3| values, it uses |RG3| to fill the groundwater storage
3663
+ so that no discharge occurs:
3664
+
3665
+ >>> states.sg3 = -3.0
3666
+ >>> model.calc_rg3_sg3_v1()
3667
+ >>> fluxes.rg3
3668
+ rg3(0.0)
3669
+ >>> states.sg3
3670
+ sg3(-1.0)
3671
+
3672
+ >>> states.sg3 = -2.0
3673
+ >>> model.calc_rg3_sg3_v1()
3674
+ >>> fluxes.rg3
3675
+ rg3(0.0)
3676
+ >>> states.sg3
3677
+ sg3(0.0)
3678
+
3679
+ If the sum of |SG3| and |RG3| is positive, recharge first fills the deficit.
3680
+ In the remaining time, |Calc_RG3_SG3_V1| handles the remaining recharge as
3681
+ implied by the basic equations (with parameters |hland_derived.K4| and |W4|
3682
+ adapted to the remaining time interval):
3683
+
3684
+ >>> states.sg3 = -1.0
3685
+ >>> model.calc_rg3_sg3_v1()
3686
+ >>> fluxes.rg3
3687
+ rg3(0.213061)
3688
+ >>> states.sg3
3689
+ sg3(0.786939)
3690
+ """
3691
+
3692
+ DERIVEDPARAMETERS = (hland_derived.K4, hland_derived.W4)
3693
+ REQUIREDSEQUENCES = (hland_fluxes.GR3,)
3694
+ UPDATEDSEQUENCES = (hland_states.SG3,)
3695
+ RESULTSEQUENCES = (hland_fluxes.RG3,)
3696
+
3697
+ @staticmethod
3698
+ def __call__(model: modeltools.Model) -> None:
3699
+ der = model.parameters.derived.fastaccess
3700
+ flu = model.sequences.fluxes.fastaccess
3701
+ sta = model.sequences.states.fastaccess
3702
+ d_sg3 = sta.sg3
3703
+ d_gr3 = flu.gr3
3704
+ d_k4 = der.k4
3705
+ d_w4 = der.w4
3706
+ if d_sg3 < 0.0 < d_gr3:
3707
+ d_add = min(-sta.sg3, d_gr3)
3708
+ d_k4 *= d_gr3 / d_add
3709
+ d_w4 = modelutils.exp(-1.0 / d_k4)
3710
+ d_sg3 += d_add
3711
+ d_gr3 -= d_add
3712
+ if d_sg3 >= 0.0:
3713
+ sta.sg3 = d_w4 * d_sg3 + (1.0 - d_w4) * d_k4 * d_gr3
3714
+ flu.rg3 = d_sg3 + d_gr3 - sta.sg3
3715
+ else:
3716
+ sta.sg3 = d_sg3
3717
+ flu.rg3 = 0.0
3718
+
3719
+
3720
+ class Calc_EL_LZ_AETModel_V1(modeltools.Method):
3721
+ r"""Let a submodel that follows the |AETModel_V1| submodel interface calculate
3722
+ lake evaporation and adjust the lower zone's water content.
3723
+
3724
+ Basic equation:
3725
+ :math:`\frac{dLZ_i}{dt} = -\frac{RelZoneAreas_i}{RelLowerZoneArea} \cdot EL_i`
3726
+
3727
+ Examples:
3728
+
3729
+ We build an example based on |evap_aet_hbv96| for calculating lake evaporation:
3730
+
3731
+ >>> from hydpy.models.hland_96 import *
3732
+ >>> parameterstep("1h")
3733
+ >>> nmbzones(5)
3734
+ >>> zonetype(GLACIER, SEALED, FIELD, FOREST, ILAKE)
3735
+ >>> area(0.9)
3736
+ >>> zonearea(0.2, 0.1, 0.1, 0.1, 0.4)
3737
+ >>> psi(1.0)
3738
+ >>> zonez(5.0)
3739
+ >>> fc(50.0)
3740
+ >>> derived.relzoneareas.update()
3741
+ >>> derived.rellowerzonearea.update()
3742
+ >>> factors.tc = 10.0
3743
+ >>> with model.add_aetmodel_v1("evap_aet_hbv96"):
3744
+ ... temperaturethresholdice(0.0)
3745
+
3746
+ |Calc_EL_LZ_AETModel_V1| uses the flux returned by the submodel to adjust |LZ|,
3747
+ considering the extent of the groundwater-affected subarea:
3748
+
3749
+ >>> model.aetmodel.sequences.fluxes.potentialwaterevaporation = 2.0
3750
+ >>> states.lz = 3.0
3751
+ >>> model.calc_el_lz_v1()
3752
+ >>> fluxes.el
3753
+ el(0.0, 0.0, 0.0, 0.0, 2.0)
3754
+ >>> states.lz
3755
+ lz(2.0)
3756
+
3757
+ Zones of type |ILAKE| are assumed to have an open water surface, so evaporation
3758
+ is always possible. Therefore, applying |Calc_EL_LZ_AETModel_V1| can result in
3759
+ negative |LZ| values:
3760
+
3761
+ >>> model.aetmodel.sequences.fluxes.potentialwaterevaporation = 6.0
3762
+ >>> states.lz = 1.0
3763
+ >>> model.calc_el_lz_v1()
3764
+ >>> fluxes.el
3765
+ el(0.0, 0.0, 0.0, 0.0, 6.0)
3766
+ >>> states.lz
3767
+ lz(-2.0)
3768
+ """
3769
+
3770
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
3771
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelLowerZoneArea)
3772
+ UPDATEDSEQUENCES = (hland_states.LZ,)
3773
+ RESULTSEQUENCES = (hland_fluxes.EL,)
3774
+
3775
+ @staticmethod
3776
+ def __call__(model: modeltools.Model, submodel: aetinterfaces.AETModel_V1) -> None:
3777
+ con = model.parameters.control.fastaccess
3778
+ der = model.parameters.derived.fastaccess
3779
+ flu = model.sequences.fluxes.fastaccess
3780
+ sta = model.sequences.states.fastaccess
3781
+ submodel.determine_waterevaporation()
3782
+ for k in range(con.nmbzones):
3783
+ if con.zonetype[k] == ILAKE:
3784
+ flu.el[k] = submodel.get_waterevaporation(k)
3785
+ sta.lz -= der.relzoneareas[k] / der.rellowerzonearea * flu.el[k]
3786
+ else:
3787
+ flu.el[k] = 0.0
3788
+
3789
+
3790
+ class Calc_EL_LZ_V1(modeltools.Method):
3791
+ """Let a submodel that follows the |AETModel_V1| submodel interface calculate lake
3792
+ evaporation and adjust the lower zone's water content."""
3793
+
3794
+ SUBMODELINTERFACES = (aetinterfaces.AETModel_V1,)
3795
+ SUBMETHODS = (Calc_EL_LZ_AETModel_V1,)
3796
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
3797
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelLowerZoneArea)
3798
+ UPDATEDSEQUENCES = (hland_states.LZ,)
3799
+ RESULTSEQUENCES = (hland_fluxes.EL,)
3800
+
3801
+ @staticmethod
3802
+ def __call__(model: modeltools.Model) -> None:
3803
+ if model.aetmodel_typeid == 1:
3804
+ model.calc_el_lz_aetmodel_v1(
3805
+ cast(aetinterfaces.AETModel_V1, model.aetmodel)
3806
+ )
3807
+ # ToDo:
3808
+ # else:
3809
+ # assert_never(model.petmodel)
3810
+
3811
+
3812
+ class Calc_Q1_LZ_V1(modeltools.Method):
3813
+ r"""Calculate the slow response of the lower zone layer.
3814
+
3815
+ Basic equations:
3816
+ .. math::
3817
+ Q1 =
3818
+ \begin{cases}
3819
+ K4 \cdot LZ^{1 + Gamma} &|\ LZ > 0
3820
+ \\
3821
+ 0 &|\ LZ \leq 0
3822
+ \end{cases}
3823
+
3824
+ :math:`\frac{dLZ}{dt} = -Q1`
3825
+
3826
+ Examples:
3827
+
3828
+ As long as the lower zone storage is negative or zero, there is no slow
3829
+ discharge response:
3830
+
3831
+ >>> from hydpy.models.hland import *
3832
+ >>> simulationstep("12h")
3833
+ >>> parameterstep("1d")
3834
+ >>> k4(0.2)
3835
+ >>> gamma(0.0)
3836
+ >>> states.lz = -2.0
3837
+ >>> model.calc_q1_lz_v1()
3838
+ >>> fluxes.q1
3839
+ q1(0.0)
3840
+ >>> states.lz
3841
+ lz(-2.0)
3842
+
3843
+ >>> states.lz = 0.0
3844
+ >>> model.calc_q1_lz_v1()
3845
+ >>> fluxes.q1
3846
+ q1(0.0)
3847
+ >>> states.lz
3848
+ lz(0.0)
3849
+
3850
+ For storage values above zero the linear or nonlinear storage routing equation
3851
+ applies:
3852
+
3853
+ >>> states.lz = 2.0
3854
+ >>> model.calc_q1_lz_v1()
3855
+ >>> fluxes.q1
3856
+ q1(0.2)
3857
+ >>> states.lz
3858
+ lz(1.8)
3859
+
3860
+ >>> gamma(1.0)
3861
+ >>> states.lz = 2.0
3862
+ >>> model.calc_q1_lz_v1()
3863
+ >>> fluxes.q1
3864
+ q1(0.4)
3865
+ >>> states.lz
3866
+ lz(1.6)
3867
+
3868
+ Note that the assumed length of the simulation step is half a day. Hence the
3869
+ effective value of the storage coefficient is not 0.2 but 0.1:
3870
+
3871
+ >>> k4
3872
+ k4(0.2)
3873
+ >>> k4.value
3874
+ 0.1
3875
+ """
3876
+
3877
+ CONTROLPARAMETERS = (hland_control.K4, hland_control.Gamma)
3878
+ UPDATEDSEQUENCES = (hland_states.LZ,)
3879
+ RESULTSEQUENCES = (hland_fluxes.Q1,)
3880
+
3881
+ @staticmethod
3882
+ def __call__(model: modeltools.Model) -> None:
3883
+ con = model.parameters.control.fastaccess
3884
+ flu = model.sequences.fluxes.fastaccess
3885
+ sta = model.sequences.states.fastaccess
3886
+ if sta.lz > 0.0:
3887
+ flu.q1 = con.k4 * sta.lz ** (1.0 + con.gamma)
3888
+ else:
3889
+ flu.q1 = 0.0
3890
+ sta.lz -= flu.q1
3891
+
3892
+
3893
+ class Calc_InRC_V1(modeltools.Method):
3894
+ r"""Calculate the input of the runoff concentration submodel.
3895
+
3896
+ Basic equation:
3897
+ .. math::
3898
+ InRC = A_U \cdot Q0 + A_L \cdot Q1 +
3899
+ \sum_{k=1}^{N} A_Z^k \cdot \begin{cases}
3900
+ R &|\ T_Z^k = S
3901
+ \\
3902
+ 0 &|\ T_Z^k \neq S
3903
+ \end{cases}
3904
+ \\ \\
3905
+ N = NmbZones \\
3906
+ A_U = RelUpperZoneArea \\
3907
+ A_L = RelLowerZoneArea \\
3908
+ A_Z = RelZoneAreas \\
3909
+ T_Z = ZoneType \\
3910
+ S = SEALED
3911
+
3912
+ Example:
3913
+
3914
+ We define a subbasin with five zones of different land-use types and sizes:
3915
+
3916
+ >>> from hydpy.models.hland import *
3917
+ >>> simulationstep("12h")
3918
+ >>> parameterstep("1d")
3919
+ >>> nmbzones(5)
3920
+ >>> zonetype(FIELD, FOREST, GLACIER, ILAKE, SEALED)
3921
+ >>> area(100.0)
3922
+ >>> zonearea(10.0, 20.0, 30.0, 15.0, 25.0)
3923
+ >>> psi(1.0)
3924
+
3925
+ To ensure the consistency of the values of the relevant derived parameters, we
3926
+ apply their |Parameter.update| methods:
3927
+
3928
+ >>> derived.relzoneareas.update()
3929
+ >>> derived.relupperzonearea.update()
3930
+ >>> derived.rellowerzonearea.update()
3931
+
3932
+ The runoff concentration submodel receives freshly generated runoff (|R|)
3933
+ directly from the sealed zone (0.5 mm), direct runoff (|Q0|) indirectly from
3934
+ the field, forest, and glacier zones (0.6 mm) and base flow (|Q1|) indirectly
3935
+ from the field, forest, glacier and internal lake zones (3.0 mm):
3936
+
3937
+ >>> fluxes.r = 2.0
3938
+ >>> fluxes.q0 = 1.0
3939
+ >>> fluxes.q1 = 4.0
3940
+ >>> model.calc_inrc_v1()
3941
+ >>> fluxes.inrc
3942
+ inrc(4.1)
3943
+ """
3944
+
3945
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
3946
+ DERIVEDPARAMETERS = (
3947
+ hland_derived.RelZoneAreas,
3948
+ hland_derived.RelUpperZoneArea,
3949
+ hland_derived.RelLowerZoneArea,
3950
+ )
3951
+ REQUIREDSEQUENCES = (hland_fluxes.R, hland_fluxes.Q0, hland_fluxes.Q1)
3952
+ RESULTSEQUENCES = (hland_fluxes.InRC,)
3953
+
3954
+ @staticmethod
3955
+ def __call__(model: modeltools.Model) -> None:
3956
+ con = model.parameters.control.fastaccess
3957
+ der = model.parameters.derived.fastaccess
3958
+ flu = model.sequences.fluxes.fastaccess
3959
+ flu.inrc = der.relupperzonearea * flu.q0 + der.rellowerzonearea * flu.q1
3960
+ for k in range(con.nmbzones):
3961
+ if con.zonetype[k] == SEALED:
3962
+ flu.inrc += der.relzoneareas[k] * flu.r[k]
3963
+
3964
+
3965
+ class Calc_InRC_V2(modeltools.Method):
3966
+ r"""Calculate the input of the runoff concentration submodel.
3967
+
3968
+ Basic equation:
3969
+ .. math::
3970
+ InRC = A_L \cdot (RG2 + RG3) +
3971
+ \sum_{k=1}^{N}
3972
+ \begin{cases}
3973
+ RS + RI + RG1 &|\ T_Z^k \in \{FI, FO, G \}
3974
+ \\
3975
+ R &|\ T_Z^k = S
3976
+ \\
3977
+ 0 &|\ T_Z^k = L
3978
+ \end{cases}
3979
+ \\ \\
3980
+ N = NmbZones \\
3981
+ A_L = RelLowerZoneArea \\
3982
+ Z_T = ZoneType \\
3983
+ FI = FIELD \\
3984
+ FO = FOREST \\
3985
+ G = GLACIER \\
3986
+ S = SEALED \\
3987
+ L = ILAKE
3988
+
3989
+ Example:
3990
+
3991
+ Besides adding all components, method |Calc_InRC_V2| needs to aggregate the HRU
3992
+ level values of |RS|, |RI|, |RG1|, and |R| to the subbasin level:
3993
+
3994
+ >>> from hydpy.models.hland import *
3995
+ >>> simulationstep("12h")
3996
+ >>> parameterstep("1d")
3997
+ >>> nmbzones(5)
3998
+ >>> zonetype(FIELD, FOREST, GLACIER, ILAKE, SEALED)
3999
+ >>> derived.relzoneareas(0.35, 0.25, 0.15, 0.05, 0.2)
4000
+ >>> derived.rellowerzonearea(0.8)
4001
+ >>> fluxes.rs = 0.1, 0.2, 0.3, nan, nan
4002
+ >>> fluxes.ri = 0.4, 0.6, 0.8, nan, nan
4003
+ >>> fluxes.rg1 = 1.1, 1.4, 1.7, nan, nan
4004
+ >>> fluxes.r = nan, nan, nan, nan, 2.0
4005
+ >>> fluxes.rg2 = 3.0
4006
+ >>> fluxes.rg3 = 4.0
4007
+ >>> model.calc_inrc_v2()
4008
+ >>> fluxes.inrc
4009
+ inrc(7.53)
4010
+ """
4011
+
4012
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
4013
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelLowerZoneArea)
4014
+ REQUIREDSEQUENCES = (
4015
+ hland_fluxes.R,
4016
+ hland_fluxes.RS,
4017
+ hland_fluxes.RI,
4018
+ hland_fluxes.RG1,
4019
+ hland_fluxes.RG2,
4020
+ hland_fluxes.RG3,
4021
+ )
4022
+ RESULTSEQUENCES = (hland_fluxes.InRC,)
4023
+
4024
+ @staticmethod
4025
+ def __call__(model: modeltools.Model) -> None:
4026
+ con = model.parameters.control.fastaccess
4027
+ der = model.parameters.derived.fastaccess
4028
+ flu = model.sequences.fluxes.fastaccess
4029
+ flu.inrc = der.rellowerzonearea * (flu.rg2 + flu.rg3)
4030
+ for k in range(con.nmbzones):
4031
+ if con.zonetype[k] in (FIELD, FOREST, GLACIER):
4032
+ flu.inrc += der.relzoneareas[k] * (flu.rs[k] + flu.ri[k] + flu.rg1[k])
4033
+ elif con.zonetype[k] == SEALED:
4034
+ flu.inrc += der.relzoneareas[k] * flu.r[k]
4035
+
4036
+
4037
+ class Calc_InRC_V3(modeltools.Method):
4038
+ r"""Calculate the input of the runoff concentration submodel.
4039
+
4040
+ Basic equation:
4041
+ .. math::
4042
+ InRC = \sum_{k=1}^{N} \frac{A_Z^k}{A_L} \cdot
4043
+ \begin{cases}
4044
+ QAb1 + QAb2 &|\ T_Z^k \in \{FI, FO, G \}
4045
+ \\
4046
+ R &|\ T_Z^k = S
4047
+ \\
4048
+ 0 &|\ T_Z^k = L
4049
+ \end{cases}
4050
+ \\ \\
4051
+ N = NmbZones \\
4052
+ A_Z = RelZoneAreas \\
4053
+ A_L = RelLandArea \\
4054
+ T_Z = ZoneType \\
4055
+ FI = FIELD \\
4056
+ FO = FOREST \\
4057
+ G = GLACIER \\
4058
+ S = SEALED \\
4059
+ L = ILAKE
4060
+
4061
+ Example:
4062
+
4063
+ The runoff concentration submodel receives surface flow (|QAb1| and |QAb2|)
4064
+ from the first three zones of type |FIELD|, |FOREST|, and |GLACIER|, receives
4065
+ directly generated runoff from the fifth zone of type |SEALED|, and receives
4066
+ nothing from the fourth zone of type |ILAKE|:
4067
+
4068
+ >>> from hydpy.models.hland import *
4069
+ >>> simulationstep("12h")
4070
+ >>> parameterstep("1d")
4071
+ >>> nmbzones(5)
4072
+ >>> zonetype(FIELD, FOREST, GLACIER, ILAKE, SEALED)
4073
+ >>> derived.relzoneareas = 0.35, 0.25, 0.15, 0.2, 0.05
4074
+ >>> derived.rellandarea(0.8)
4075
+ >>> fluxes.qab1 = 1.0, 2.0, 3.0, nan, nan
4076
+ >>> fluxes.qab2 = 3.0, 6.0, 9.0, nan, nan
4077
+ >>> fluxes.r = nan, nan, nan, nan, 8.0
4078
+ >>> model.calc_inrc_v3()
4079
+ >>> fluxes.inrc
4080
+ inrc(7.0)
4081
+ """
4082
+
4083
+ CONTROLPARAMETERS = (hland_control.NmbZones, hland_control.ZoneType)
4084
+ DERIVEDPARAMETERS = (hland_derived.RelZoneAreas, hland_derived.RelLandArea)
4085
+ REQUIREDSEQUENCES = (hland_fluxes.R, hland_fluxes.QAb1, hland_fluxes.QAb2)
4086
+ RESULTSEQUENCES = (hland_fluxes.InRC,)
4087
+
4088
+ @staticmethod
4089
+ def __call__(model: modeltools.Model) -> None:
4090
+ con = model.parameters.control.fastaccess
4091
+ der = model.parameters.derived.fastaccess
4092
+ flu = model.sequences.fluxes.fastaccess
4093
+ flu.inrc = 0.0
4094
+ for k in range(con.nmbzones):
4095
+ if con.zonetype[k] == ILAKE:
4096
+ continue
4097
+ d_weight = der.relzoneareas[k] / der.rellandarea
4098
+ if con.zonetype[k] == SEALED:
4099
+ flu.inrc += d_weight * flu.r[k]
4100
+ else:
4101
+ flu.inrc += d_weight * (flu.qab1[k] + flu.qab2[k])
4102
+
4103
+
4104
+ class Calc_OutRC_RConcModel_V1(modeltools.Method):
4105
+ """Let a submodel that follows the |RConcModel_V1| submodel interface calculate
4106
+ runoff concentration."""
4107
+
4108
+ REQUIREDSEQUENCES = (hland_fluxes.InRC,)
4109
+ RESULTSEQUENCES = (hland_fluxes.OutRC,)
4110
+
4111
+ @staticmethod
4112
+ def __call__(
4113
+ model: modeltools.Model, submodel: rconcinterfaces.RConcModel_V1
4114
+ ) -> None:
4115
+ flu = model.sequences.fluxes.fastaccess
4116
+ submodel.set_inflow(flu.inrc)
4117
+ submodel.determine_outflow()
4118
+ flu.outrc = submodel.get_outflow()
4119
+
4120
+
4121
+ class Calc_OutRC_V1(modeltools.Method):
4122
+ """If the model has a submodel that follows the |RConcModel_V1| submodel interface,
4123
+ calculate runoff concentration. If not, set the output equal to the input.
4124
+
4125
+ Examples:
4126
+
4127
+ A model without a submodel for runoff concentration directs the input directly
4128
+ to the output:
4129
+
4130
+ >>> from hydpy.models.hland_96 import *
4131
+ >>> simulationstep("1h")
4132
+ >>> parameterstep("1d")
4133
+ >>> fluxes.inrc = 1.0
4134
+ >>> model.calc_outrc_v1()
4135
+ >>> fluxes.outrc
4136
+ outrc(1.0)
4137
+
4138
+ If a submodel for runoff concentration is added (in this case, a unit
4139
+ hydrograph with three ordinates), the output for the first time step
4140
+ corresponds to the portion of the input specified by the first ordinate (since
4141
+ the initial conditions of the logging sequence |rconc_logs.QUH| were set to
4142
+ zero, and thus no additional runoff portions from previous time steps are
4143
+ included):
4144
+
4145
+ >>> with model.add_rconcmodel_v1("rconc_uh"):
4146
+ ... uh([0.3,0.4,0.3])
4147
+ ... logs.quh = 0.0, 0.0, 0.0
4148
+ >>> model.calc_outrc_v1()
4149
+ >>> fluxes.outrc
4150
+ outrc(0.3)
4151
+ """
4152
+
4153
+ SUBMODELINTERFACES = (rconcinterfaces.RConcModel_V1,)
4154
+ SUBMETHODS = (Calc_OutRC_RConcModel_V1,)
4155
+ REQUIREDSEQUENCES = (hland_fluxes.InRC,)
4156
+ RESULTSEQUENCES = (hland_fluxes.OutRC,)
4157
+
4158
+ @staticmethod
4159
+ def __call__(model: modeltools.Model) -> None:
4160
+ flu = model.sequences.fluxes.fastaccess
4161
+ if model.rconcmodel is None:
4162
+ flu.outrc = flu.inrc
4163
+ elif model.rconcmodel_typeid == 1:
4164
+ model.calc_outrc_rconcmodel_v1(
4165
+ cast(rconcinterfaces.RConcModel_V1, model.rconcmodel)
4166
+ )
4167
+
4168
+
4169
+ class Calc_RT_V1(modeltools.Method):
4170
+ r"""Calculate the total discharge in mm.
4171
+
4172
+ Basic equation:
4173
+ :math:`RT = OutRC`
4174
+
4175
+ Examples:
4176
+
4177
+ >>> from hydpy.models.hland import *
4178
+ >>> parameterstep()
4179
+ >>> fluxes.outrc = 3.0
4180
+ >>> model.calc_rt_v1()
4181
+ >>> fluxes.rt
4182
+ rt(3.0)
4183
+ """
4184
+
4185
+ REQUIREDSEQUENCES = (hland_fluxes.OutRC,)
4186
+ RESULTSEQUENCES = (hland_fluxes.RT,)
4187
+
4188
+ @staticmethod
4189
+ def __call__(model: modeltools.Model) -> None:
4190
+ flu = model.sequences.fluxes.fastaccess
4191
+ flu.rt = flu.outrc
4192
+
4193
+
4194
+ class Calc_RT_V2(modeltools.Method):
4195
+ r"""Calculate the total discharge in mm.
4196
+
4197
+ Basic equation:
4198
+ :math:`RT = RelUpperZoneArea \cdot OutRC + RelLowerZoneArea \cdot Q1`
4199
+
4200
+ Example:
4201
+
4202
+ >>> from hydpy.models.hland import *
4203
+ >>> parameterstep()
4204
+ >>> derived.rellandarea(0.8)
4205
+ >>> derived.rellowerzonearea(0.6)
4206
+ >>> fluxes.outrc = 2.5
4207
+ >>> fluxes.q1 = 1.0
4208
+ >>> model.calc_rt_v2()
4209
+ >>> fluxes.rt
4210
+ rt(2.6)
4211
+ """
4212
+
4213
+ DERIVEDPARAMETERS = (hland_derived.RelLandArea, hland_derived.RelLowerZoneArea)
4214
+ REQUIREDSEQUENCES = (hland_fluxes.OutRC, hland_fluxes.Q1)
4215
+ RESULTSEQUENCES = (hland_fluxes.RT,)
4216
+
4217
+ @staticmethod
4218
+ def __call__(model: modeltools.Model) -> None:
4219
+ der = model.parameters.derived.fastaccess
4220
+ flu = model.sequences.fluxes.fastaccess
4221
+ flu.rt = der.rellandarea * flu.outrc + der.rellowerzonearea * flu.q1
4222
+
4223
+
4224
+ class Calc_QT_V1(modeltools.Method):
4225
+ r"""Calculate the total discharge in m³/s.
4226
+
4227
+ Basic equation:
4228
+ :math:`QT = QFactor \cdot RT`
4229
+
4230
+ Example:
4231
+
4232
+ >>> from hydpy.models.hland import *
4233
+ >>> simulationstep("12h")
4234
+ >>> parameterstep("1d")
4235
+ >>> derived.qfactor(0.5)
4236
+ >>> fluxes.rt = 2.0
4237
+ >>> model.calc_qt_v1()
4238
+ >>> fluxes.qt
4239
+ qt(1.0)
4240
+ """
4241
+
4242
+ DERIVEDPARAMETERS = (hland_derived.QFactor,)
4243
+ REQUIREDSEQUENCES = (hland_fluxes.RT,)
4244
+ RESULTSEQUENCES = (hland_fluxes.QT,)
4245
+
4246
+ @staticmethod
4247
+ def __call__(model: modeltools.Model) -> None:
4248
+ der = model.parameters.derived.fastaccess
4249
+ flu = model.sequences.fluxes.fastaccess
4250
+ flu.qt = der.qfactor * flu.rt
4251
+
4252
+
4253
+ class Pass_Q_V1(modeltools.Method):
4254
+ r"""Update the outlet link sequence."""
4255
+
4256
+ REQUIREDSEQUENCES = (hland_fluxes.QT,)
4257
+ RESULTSEQUENCES = (hland_outlets.Q,)
4258
+
4259
+ @staticmethod
4260
+ def __call__(model: modeltools.Model) -> None:
4261
+ flu = model.sequences.fluxes.fastaccess
4262
+ out = model.sequences.outlets.fastaccess
4263
+ out.q[0] += flu.qt
4264
+
4265
+
4266
+ class Get_Temperature_V1(modeltools.Method):
4267
+ """Get the selected zone's current temperature.
4268
+
4269
+ Example:
4270
+
4271
+ >>> from hydpy.models.hland import *
4272
+ >>> parameterstep()
4273
+ >>> nmbzones(2)
4274
+ >>> factors.tc = 2.0, 4.0
4275
+ >>> from hydpy import round_
4276
+ >>> round_(model.get_temperature_v1(0))
4277
+ 2.0
4278
+ >>> round_(model.get_temperature_v1(1))
4279
+ 4.0
4280
+ """
4281
+
4282
+ REQUIREDSEQUENCES = (hland_factors.TC,)
4283
+
4284
+ @staticmethod
4285
+ def __call__(model: modeltools.Model, s: int) -> float:
4286
+ fac = model.sequences.factors.fastaccess
4287
+
4288
+ return fac.tc[s]
4289
+
4290
+
4291
+ class Get_MeanTemperature_V1(modeltools.Method):
4292
+ """Get the basin's current mean temperature.
4293
+
4294
+ Example:
4295
+
4296
+ >>> from hydpy.models.hland import *
4297
+ >>> parameterstep()
4298
+ >>> inputs.t = 2.0
4299
+ >>> from hydpy import round_
4300
+ >>> round_(model.get_meantemperature_v1())
4301
+ 2.0
4302
+ """
4303
+
4304
+ REQUIREDSEQUENCES = (hland_inputs.T,)
4305
+
4306
+ @staticmethod
4307
+ def __call__(model: modeltools.Model) -> float:
4308
+ inp = model.sequences.inputs.fastaccess
4309
+
4310
+ return inp.t
4311
+
4312
+
4313
+ class Get_Precipitation_V1(modeltools.Method):
4314
+ """Get the current precipitation from the selected zone.
4315
+
4316
+ Example:
4317
+
4318
+ >>> from hydpy.models.hland import *
4319
+ >>> parameterstep()
4320
+ >>> nmbzones(2)
4321
+ >>> fluxes.pc = 2.0, 4.0
4322
+ >>> from hydpy import round_
4323
+ >>> round_(model.get_precipitation_v1(0))
4324
+ 2.0
4325
+ >>> round_(model.get_precipitation_v1(1))
4326
+ 4.0
4327
+ """
4328
+
4329
+ REQUIREDSEQUENCES = (hland_fluxes.PC,)
4330
+
4331
+ @staticmethod
4332
+ def __call__(model: modeltools.Model, s: int) -> float:
4333
+ flu = model.sequences.fluxes.fastaccess
4334
+
4335
+ return flu.pc[s]
4336
+
4337
+
4338
+ class Get_InterceptedWater_V1(modeltools.Method):
4339
+ """Get the selected zone's current amount of intercepted water.
4340
+
4341
+ Example:
4342
+
4343
+ >>> from hydpy.models.hland import *
4344
+ >>> parameterstep()
4345
+ >>> nmbzones(2)
4346
+ >>> states.ic = 2.0, 4.0
4347
+ >>> from hydpy import round_
4348
+ >>> round_(model.get_interceptedwater_v1(0))
4349
+ 2.0
4350
+ >>> round_(model.get_interceptedwater_v1(1))
4351
+ 4.0
4352
+ """
4353
+
4354
+ REQUIREDSEQUENCES = (hland_states.Ic,)
4355
+
4356
+ @staticmethod
4357
+ def __call__(model: modeltools.Model, k: int) -> float:
4358
+ sta = model.sequences.states.fastaccess
4359
+
4360
+ return sta.ic[k]
4361
+
4362
+
4363
+ class Get_SoilWater_V1(modeltools.Method):
4364
+ """Get the selected zone's current soil water content.
4365
+
4366
+ Example:
4367
+
4368
+ >>> from hydpy.models.hland import *
4369
+ >>> parameterstep()
4370
+ >>> nmbzones(2)
4371
+ >>> states.sm = 2.0, 4.0
4372
+ >>> from hydpy import round_
4373
+ >>> round_(model.get_soilwater_v1(0))
4374
+ 2.0
4375
+ >>> round_(model.get_soilwater_v1(1))
4376
+ 4.0
4377
+ """
4378
+
4379
+ REQUIREDSEQUENCES = (hland_states.SM,)
4380
+
4381
+ @staticmethod
4382
+ def __call__(model: modeltools.Model, k: int) -> float:
4383
+ sta = model.sequences.states.fastaccess
4384
+
4385
+ return sta.sm[k]
4386
+
4387
+
4388
+ class Get_SnowCover_V1(modeltools.Method):
4389
+ """Get the selected zone's current snow cover degree.
4390
+
4391
+ Example:
4392
+
4393
+ Each snow class with a non-zero amount of snow counts as completely covered:
4394
+
4395
+ >>> from hydpy.models.hland import *
4396
+ >>> parameterstep()
4397
+ >>> nmbzones(3)
4398
+ >>> sclass(2)
4399
+ >>> states.sp = [[0.0, 0.0, 1.0], [0.0, 1.0, 1.0]]
4400
+ >>> from hydpy import round_
4401
+ >>> round_(model.get_snowcover_v1(0))
4402
+ 0.0
4403
+ >>> round_(model.get_snowcover_v1(1))
4404
+ 0.5
4405
+ >>> round_(model.get_snowcover_v1(2))
4406
+ 1.0
4407
+ """
4408
+
4409
+ CONTROLPARAMETERS = (hland_control.SClass,)
4410
+ REQUIREDSEQUENCES = (hland_states.SP,)
4411
+
4412
+ @staticmethod
4413
+ def __call__(model: modeltools.Model, k: int) -> float:
4414
+ con = model.parameters.control.fastaccess
4415
+ sta = model.sequences.states.fastaccess
4416
+
4417
+ snowcovered: float = 0.0
4418
+ for c in range(con.sclass):
4419
+ snowcovered += sta.sp[c, k] > 0.0
4420
+ return snowcovered / con.sclass
4421
+
4422
+
4423
+ class Model(modeltools.AdHocModel):
4424
+ """|hland.DOCNAME.complete|."""
4425
+
4426
+ DOCNAME = modeltools.DocName(short="H")
4427
+ __HYDPY_ROOTMODEL__ = None
4428
+
4429
+ INLET_METHODS = ()
4430
+ RECEIVER_METHODS = ()
4431
+ RUN_METHODS = (
4432
+ Calc_TC_V1,
4433
+ Calc_FracRain_V1,
4434
+ Calc_RFC_SFC_V1,
4435
+ Calc_PC_V1,
4436
+ Calc_TF_Ic_V1,
4437
+ Calc_EI_Ic_V1,
4438
+ Calc_SP_WC_V1,
4439
+ Calc_SPL_WCL_SP_WC_V1,
4440
+ Calc_SPG_WCG_SP_WC_V1,
4441
+ Calc_CFAct_V1,
4442
+ Calc_Melt_SP_WC_V1,
4443
+ Calc_Refr_SP_WC_V1,
4444
+ Calc_In_WC_V1,
4445
+ Calc_SWE_V1,
4446
+ Calc_SR_V1,
4447
+ Calc_GAct_V1,
4448
+ Calc_GlMelt_In_V1,
4449
+ Calc_R_SM_V1,
4450
+ Calc_CF_SM_V1,
4451
+ Calc_EA_SM_V1,
4452
+ Calc_InUZ_V1,
4453
+ Calc_SUZ_V1,
4454
+ Calc_ContriArea_V1,
4455
+ Calc_Q0_Perc_UZ_V1,
4456
+ Calc_DP_SUZ_V1,
4457
+ Calc_QAb1_QVs1_BW1_V1,
4458
+ Calc_QAb2_QVs2_BW2_V1,
4459
+ Calc_RS_RI_SUZ_V1,
4460
+ Calc_LZ_V1,
4461
+ Calc_LZ_V2,
4462
+ Calc_GR1_V1,
4463
+ Calc_RG1_SG1_V1,
4464
+ Calc_GR2_GR3_V1,
4465
+ Calc_RG2_SG2_V1,
4466
+ Calc_RG3_SG3_V1,
4467
+ Calc_EL_SG2_SG3_V1,
4468
+ Calc_EL_LZ_V1,
4469
+ Calc_Q1_LZ_V1,
4470
+ Calc_InRC_V1,
4471
+ Calc_InRC_V3,
4472
+ Calc_OutRC_V1,
4473
+ Calc_InRC_V2,
4474
+ Calc_RT_V1,
4475
+ Calc_RT_V2,
4476
+ Calc_QT_V1,
4477
+ )
4478
+ INTERFACE_METHODS = (
4479
+ Get_Temperature_V1,
4480
+ Get_MeanTemperature_V1,
4481
+ Get_Precipitation_V1,
4482
+ Get_InterceptedWater_V1,
4483
+ Get_SoilWater_V1,
4484
+ Get_SnowCover_V1,
4485
+ )
4486
+ ADD_METHODS = (
4487
+ Calc_EI_Ic_AETModel_V1,
4488
+ Calc_EA_SM_AETModel_V1,
4489
+ Calc_EL_LZ_AETModel_V1,
4490
+ Calc_EL_SG2_SG3_AETModel_V1,
4491
+ Calc_QAb_QVs_BW_V1,
4492
+ Calc_OutRC_RConcModel_V1,
4493
+ )
4494
+ OUTLET_METHODS = (Pass_Q_V1,)
4495
+ SENDER_METHODS = ()
4496
+ SUBMODELINTERFACES = (aetinterfaces.AETModel_V1, rconcinterfaces.RConcModel_V1)
4497
+ SUBMODELS = ()
4498
+
4499
+ aetmodel = modeltools.SubmodelProperty(aetinterfaces.AETModel_V1)
4500
+ aetmodel_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
4501
+ aetmodel_typeid = modeltools.SubmodelTypeIDProperty()
4502
+
4503
+ rconcmodel = modeltools.SubmodelProperty(rconcinterfaces.RConcModel_V1)
4504
+ rconcmodel_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
4505
+ rconcmodel_typeid = modeltools.SubmodelTypeIDProperty()
4506
+
4507
+
4508
+ class Main_AETModel_V1(modeltools.AdHocModel):
4509
+ """Base class for |hland.DOCNAME.long| models that use submodels that comply with
4510
+ the |AETModel_V1| interface."""
4511
+
4512
+ aetmodel: modeltools.SubmodelProperty
4513
+ aetmodel_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
4514
+ aetmodel_typeid = modeltools.SubmodelTypeIDProperty()
4515
+
4516
+ @importtools.prepare_submodel(
4517
+ "aetmodel",
4518
+ aetinterfaces.AETModel_V1,
4519
+ aetinterfaces.AETModel_V1.prepare_nmbzones,
4520
+ aetinterfaces.AETModel_V1.prepare_subareas,
4521
+ aetinterfaces.AETModel_V1.prepare_elevations,
4522
+ aetinterfaces.AETModel_V1.prepare_maxsoilwater,
4523
+ aetinterfaces.AETModel_V1.prepare_water,
4524
+ aetinterfaces.AETModel_V1.prepare_interception,
4525
+ aetinterfaces.AETModel_V1.prepare_soil,
4526
+ aetinterfaces.AETModel_V1.prepare_plant,
4527
+ landtype_constants=hland_constants.CONSTANTS,
4528
+ landtype_refindices=hland_control.ZoneType,
4529
+ refweights=hland_control.ZoneArea,
4530
+ )
4531
+ def add_aetmodel_v1(
4532
+ self,
4533
+ aetmodel: aetinterfaces.AETModel_V1,
4534
+ /,
4535
+ *,
4536
+ refresh: bool, # pylint: disable=unused-argument
4537
+ ) -> None:
4538
+ """Initialise the given submodel that follows the |AETModel_V1| interface and
4539
+ is responsible for calculating the different kinds of actual
4540
+ evapotranspiration.
4541
+
4542
+ >>> from hydpy.models.hland_96 import *
4543
+ >>> parameterstep()
4544
+ >>> nmbzones(5)
4545
+ >>> area(10.0)
4546
+ >>> zonetype(FIELD, FOREST, ILAKE, GLACIER, SEALED)
4547
+ >>> zonearea(2.0)
4548
+ >>> zonez(3.0)
4549
+ >>> fc(200.0)
4550
+ >>> with model.add_aetmodel_v1("evap_aet_hbv96"):
4551
+ ... nmbhru
4552
+ ... water
4553
+ ... interception
4554
+ ... soil
4555
+ ... excessreduction(field=1.0, forest=0.5, default=nan)
4556
+ ... for method, arguments in model.preparemethod2arguments.items():
4557
+ ... print(method, arguments[0][0], sep=": ")
4558
+ nmbhru(5)
4559
+ water(field=False, forest=False, glacier=False, ilake=True,
4560
+ sealed=False)
4561
+ interception(field=True, forest=True, glacier=False, ilake=False,
4562
+ sealed=True)
4563
+ soil(field=True, forest=True, glacier=False, ilake=False, sealed=False)
4564
+ prepare_nmbzones: 5
4565
+ prepare_zonetypes: [1 2 4 3 5]
4566
+ prepare_subareas: [2. 2. 2. 2. 2.]
4567
+ prepare_elevations: [300. 300. 300. 300. 300.]
4568
+ prepare_maxsoilwater: [200. 200. 200. 200. 200.]
4569
+ prepare_water: [False False True False False]
4570
+ prepare_interception: [ True True False False True]
4571
+ prepare_plant: [ True True False False False]
4572
+ prepare_soil: [ True True False False False]
4573
+
4574
+ >>> ered = model.aetmodel.parameters.control.excessreduction
4575
+ >>> ered
4576
+ excessreduction(field=1.0, forest=0.5)
4577
+ >>> zonetype(FOREST, FIELD, ILAKE, GLACIER, SEALED)
4578
+ >>> ered
4579
+ excessreduction(field=0.5, forest=1.0)
4580
+ >>> from hydpy import round_
4581
+ >>> round_(ered.average_values())
4582
+ 0.75
4583
+ """
4584
+ control = self.parameters.control
4585
+ nmbzones = control.nmbzones.value
4586
+ zonetype = control.zonetype.values
4587
+
4588
+ aetmodel.prepare_nmbzones(nmbzones)
4589
+ aetmodel.prepare_zonetypes(zonetype)
4590
+ aetmodel.prepare_subareas(control.zonearea.value)
4591
+ aetmodel.prepare_elevations(100.0 * control.zonez.values)
4592
+ aetmodel.prepare_maxsoilwater(control.fc.values)
4593
+ sel = numpy.full(nmbzones, False, dtype=config.NP_BOOL)
4594
+ sel[zonetype == ILAKE] = True
4595
+ aetmodel.prepare_water(sel)
4596
+ sel = ~sel
4597
+ sel[zonetype == GLACIER] = False
4598
+ aetmodel.prepare_interception(sel)
4599
+ sel[zonetype == SEALED] = False
4600
+ aetmodel.prepare_plant(sel)
4601
+ aetmodel.prepare_soil(sel)
4602
+
4603
+
4604
+ class Main_RConcModel_V1(modeltools.AdHocModel):
4605
+ """Base class for |hland.DOCNAME.long| models that use submodels that comply with
4606
+ the |RConcModel_V1| interface."""
4607
+
4608
+ rconcmodel: modeltools.SubmodelProperty
4609
+ rconcmodel_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
4610
+ rconcmodel_typeid = modeltools.SubmodelTypeIDProperty()
4611
+
4612
+ @importtools.prepare_submodel("rconcmodel", rconcinterfaces.RConcModel_V1)
4613
+ def add_rconcmodel_v1(
4614
+ self, rconcmodel: rconcinterfaces.RConcModel_V1, /, *, refresh: bool
4615
+ ) -> None:
4616
+ """Initialise the given submodel that follows the |RConcModel_V1| interface and
4617
+ is responsible for calculating the runoff concentration.
4618
+
4619
+ >>> from hydpy.models.hland_96 import *
4620
+ >>> simulationstep("12h")
4621
+ >>> parameterstep("1d")
4622
+ >>> with model.add_rconcmodel_v1("rconc_uh"):
4623
+ ... uh([0.3, 0.5, 0.2])
4624
+ ... logs.quh.shape = 3
4625
+ ... logs.quh = 1.0, 3.0, 0.0
4626
+ >>> model.sequences.fluxes.inrc = 0.0
4627
+ >>> model.calc_outrc_v1()
4628
+ >>> fluxes.outrc
4629
+ outrc(1.0)
4630
+ """
4631
+
4632
+ def _get_rconcmodel_waterbalance(
4633
+ self, initial_conditions: ConditionsModel
4634
+ ) -> float:
4635
+ r"""Get the water balance of the rconc submodel if used."""
4636
+ if self.rconcmodel:
4637
+ rconcmodel_conditions = initial_conditions["model.rconcmodel"]
4638
+ return self.rconcmodel.get_waterbalance(rconcmodel_conditions)
4639
+ return 0.0
4640
+
4641
+
4642
+ class Sub_TempModel_V1(modeltools.AdHocModel, tempinterfaces.TempModel_V1):
4643
+ """Base class for |hland.DOCNAME.long| models that comply with the |TempModel_V1|
4644
+ submodel interface."""
4645
+
4646
+
4647
+ class Sub_PrecipModel_V1(modeltools.AdHocModel, precipinterfaces.PrecipModel_V1):
4648
+ """Base class for |hland.DOCNAME.long| models that comply with the |PrecipModel_V1|
4649
+ submodel interface."""
4650
+
4651
+
4652
+ class Sub_IntercModel_V1(modeltools.AdHocModel, stateinterfaces.IntercModel_V1):
4653
+ """Base class for |hland.DOCNAME.long| models that comply with the |IntercModel_V1|
4654
+ submodel interface."""
4655
+
4656
+
4657
+ class Sub_SoilWaterModel_V1(modeltools.AdHocModel, stateinterfaces.SoilWaterModel_V1):
4658
+ """Base class for |hland.DOCNAME.long| models that comply with the
4659
+ |SoilWaterModel_V1| submodel interface."""
4660
+
4661
+
4662
+ class Sub_SnowCoverModel_V1(modeltools.AdHocModel, stateinterfaces.SnowCoverModel_V1):
4663
+ """Base class for |hland.DOCNAME.long| models that comply with the
4664
+ |SnowCoverModel_V1| submodel interface."""