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,2615 @@
1
+ """This module implements general features for defining and working with model
2
+ parameters and sequences.
3
+
4
+ Features more specific to either parameters or sequences are implemented in modules
5
+ |parametertools| and |sequencetools|, respectively.
6
+ """
7
+
8
+ # import...
9
+ # ...from standard library
10
+ from __future__ import annotations
11
+ import abc
12
+ import contextlib
13
+ import copy
14
+ import functools
15
+ import inspect
16
+ import warnings
17
+
18
+ # ...from site-packages
19
+ import numpy
20
+
21
+ # ...from HydPy
22
+ import hydpy
23
+ from hydpy import config
24
+ from hydpy.core import exceptiontools
25
+ from hydpy.core import masktools
26
+ from hydpy.core import objecttools
27
+ from hydpy.core import propertytools
28
+ from hydpy.core.typingtools import *
29
+
30
+ if TYPE_CHECKING:
31
+ from hydpy.core import devicetools
32
+ from hydpy.core import parametertools
33
+ from hydpy.core import sequencetools
34
+ from hydpy.cythons import pointerutils
35
+ from hydpy.cythons import sequenceutils
36
+
37
+
38
+ TypeGroup_co = TypeVar(
39
+ "TypeGroup_co",
40
+ "parametertools.Parameters",
41
+ "sequencetools.Sequences",
42
+ "devicetools.Node",
43
+ covariant=True,
44
+ )
45
+ TypeVariable = TypeVar("TypeVariable", bound="Variable")
46
+ TypeVariable_co = TypeVar("TypeVariable_co", bound="Variable", covariant=True)
47
+ TypeFastAccess_co = TypeVar("TypeFastAccess_co", bound="FastAccess", covariant=True)
48
+
49
+ INT_NAN: int = -999999
50
+ """Surrogate for `nan`, which is available for floating-point values but not for
51
+ integer values."""
52
+
53
+ TYPE2MISSINGVALUE = {float: numpy.nan, int: INT_NAN, bool: False}
54
+
55
+
56
+ def trim(self: Variable, lower=None, upper=None) -> bool:
57
+ """Trim the value(s) of a |Variable| instance.
58
+
59
+ The returned boolean indicates whether at least one value has been trimmed.
60
+
61
+ Usually, users do not need to apply the |trim| function directly. Instead, some
62
+ |Variable| subclasses implement their own `trim` methods relying on function |trim|.
63
+ Model developers should implement individual `trim` methods for their |Parameter|
64
+ or |Sequence_| subclasses when their boundary values depend on the actual project
65
+ configuration (one example is soil moisture; its lowest possible value should
66
+ possibly be zero in all cases, but its highest possible value could depend on
67
+ another parameter defining the maximum storage capacity).
68
+
69
+ For the following examples, we prepare a simple (not fully functional) |Variable|
70
+ subclass, making use of function |trim| without any modifications. Function |trim|
71
+ works slightly different for variables handling |float|, |int|, and |bool| values.
72
+ We start with the most common content type, |float|:
73
+
74
+ >>> from hydpy.core.variabletools import trim, Variable
75
+ >>> class Var(Variable):
76
+ ... NDIM = 0
77
+ ... TYPE = float
78
+ ... SPAN = 1.0, 3.0
79
+ ... trim = trim
80
+ ... initinfo = 2.0, False
81
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
82
+
83
+ First, we enable the printing of warning messages raised by function |trim|:
84
+
85
+ >>> from hydpy import pub
86
+ >>> pub.options.warntrim = True
87
+
88
+ When not passing boundary values, function |trim| extracts them from class
89
+ attribute `SPAN` of the given |Variable| instance, if available:
90
+
91
+ >>> var = Var(None)
92
+ >>> var.value = 2.0
93
+ >>> assert var.trim() is False
94
+ >>> var
95
+ var(2.0)
96
+
97
+ >>> var.value = 0.0
98
+ >>> from hydpy.core.testtools import warn_later
99
+ >>> with warn_later():
100
+ ... assert var.trim() is True
101
+ UserWarning: For variable `var` at least one value needed to be trimmed. The old \
102
+ and the new value(s) are `0.0` and `1.0`, respectively.
103
+ >>> var
104
+ var(1.0)
105
+
106
+ >>> var.value = 4.0
107
+ >>> with warn_later():
108
+ ... assert var.trim() is True
109
+ UserWarning: For variable `var` at least one value needed to be trimmed. The old \
110
+ and the new value(s) are `4.0` and `3.0`, respectively.
111
+ >>> var
112
+ var(3.0)
113
+
114
+ In the examples above, outlier values are set to the respective boundary value,
115
+ accompanied by suitable warning messages. For minimal deviations (defined by
116
+ function |get_tolerance|), which might be due to precision problems only, outliers
117
+ are trimmed but not reported:
118
+
119
+ >>> var.value = 1.0 - 1e-15
120
+ >>> var == 1.0
121
+ False
122
+ >>> assert trim(var) is False
123
+ >>> var == 1.0
124
+ True
125
+
126
+ >>> var.value = 3.0 + 1e-15
127
+ >>> var == 3.0
128
+ False
129
+ >>> assert var.trim() is False
130
+ >>> var == 3.0
131
+ True
132
+
133
+ Use arguments `lower` and `upper` to override the (eventually) available `SPAN`
134
+ entries:
135
+
136
+ >>> with warn_later():
137
+ ... assert var.trim(lower=4.0) is True
138
+ UserWarning: For variable `var` at least one value needed to be trimmed. The old \
139
+ and the new value(s) are `3.0` and `4.0`, respectively.
140
+
141
+ >>> with warn_later():
142
+ ... assert var.trim(lower=3.0) is True
143
+ UserWarning: For variable `var` at least one value needed to be trimmed. The old \
144
+ and the new value(s) are `4.0` and `3.0`, respectively.
145
+
146
+ Function |trim| interprets both |None| and |numpy.nan| values as if no boundary
147
+ value exists:
148
+
149
+ >>> import numpy
150
+ >>> var.value = 0.0
151
+ >>> assert var.trim(lower=numpy.nan) is False
152
+ >>> var.value = 5.0
153
+ >>> assert var.trim(upper=numpy.nan) is False
154
+
155
+ You can disable function |trim| via option |Options.trimvariables|:
156
+
157
+ >>> with pub.options.trimvariables(False):
158
+ ... var.value = 5.0
159
+ ... assert var.trim() is False
160
+ >>> var
161
+ var(5.0)
162
+
163
+ Alternatively, you can omit the warning messages only without modifying the return
164
+ value:
165
+
166
+ >>> with pub.options.warntrim(False):
167
+ ... var.value = 5.0
168
+ ... assert var.trim() is True
169
+ >>> var
170
+ var(3.0)
171
+
172
+ If a |Variable| subclass does not have (fixed) boundaries, give it either no `SPAN`
173
+ attribute or a |tuple| containing |None| values:
174
+
175
+ >>> del Var.SPAN
176
+ >>> var.value = 5.0
177
+ >>> assert var.trim() is False
178
+ >>> var
179
+ var(5.0)
180
+
181
+ >>> Var.SPAN = (None, None)
182
+ >>> assert var.trim() is False
183
+ >>> var
184
+ var(5.0)
185
+
186
+ The above examples deal with a 0-dimensional |Variable| subclass. The following
187
+ examples repeat the most relevant examples for a 2-dimensional subclass:
188
+
189
+ >>> Var.SPAN = 1.0, 3.0
190
+ >>> Var.NDIM = 2
191
+ >>> var.shape = 1, 3
192
+ >>> var.values = 2.0
193
+ >>> assert var.trim() is False
194
+
195
+ >>> var.values = 0.0, 1.0, 2.0
196
+ >>> with warn_later():
197
+ ... assert var.trim() is True
198
+ UserWarning: For variable `var` at least one value needed to be trimmed. The old \
199
+ and the new value(s) are `0.0, 1.0, 2.0` and `1.0, 1.0, 2.0`, respectively.
200
+ >>> var
201
+ var(1.0, 1.0, 2.0)
202
+
203
+ >>> var.values = 2.0, 3.0, 4.0
204
+ >>> with warn_later():
205
+ ... assert var.trim() is True
206
+ UserWarning: For variable `var` at least one value needed to be trimmed. The old \
207
+ and the new value(s) are `2.0, 3.0, 4.0` and `2.0, 3.0, 3.0`, respectively.
208
+ >>> var
209
+ var(2.0, 3.0, 3.0)
210
+
211
+ >>> from hydpy import print_matrix
212
+ >>> var.values = 1.0-1e-15, 2.0, 3.0+1e-15
213
+ >>> print_matrix(var.values == (1.0, 2.0, 3.0))
214
+ | False, True, False |
215
+ >>> assert var.trim() is False
216
+ >>> print_matrix(var.values == (1.0, 2.0, 3.0))
217
+ | True, True, True |
218
+
219
+ >>> var.values = 0.0, 2.0, 4.0
220
+ >>> assert var.trim(lower=numpy.nan, upper=numpy.nan) is False
221
+ >>> var
222
+ var(0.0, 2.0, 4.0)
223
+
224
+ >>> with warn_later():
225
+ ... assert var.trim(lower=[numpy.nan, 3.0, 3.0]) is True
226
+ UserWarning: For variable `var` at least one value needed to be trimmed. The old \
227
+ and the new value(s) are `0.0, 2.0, 4.0` and `0.0, 3.0, 3.0`, respectively.
228
+
229
+ >>> var.values = 0.0, 2.0, 4.0
230
+ >>> with warn_later():
231
+ ... assert var.trim(upper=[numpy.nan, 1.0, numpy.nan]) is True
232
+ UserWarning: For variable `var` at least one value needed to be trimmed. The old \
233
+ and the new value(s) are `0.0, 2.0, 4.0` and `1.0, 1.0, 4.0`, respectively.
234
+
235
+ For |Variable| subclasses handling |float| values, setting outliers to the
236
+ respective boundary value might often be an acceptable approach. However, this is
237
+ often not the case for subclasses handling |int| values, which often serve as
238
+ option flags (e.g. to enable/disable a certain hydrological process for different
239
+ land-use types). Hence, function |trim| raises an exception instead of a warning
240
+ and does not modify the wrong |int| value:
241
+
242
+ >>> Var.TYPE = int
243
+ >>> Var.NDIM = 0
244
+ >>> Var.SPAN = 1, 3
245
+
246
+ >>> var.value = 2
247
+ >>> assert var.trim() is False
248
+ >>> var
249
+ var(2)
250
+
251
+ >>> var.value = 0
252
+ >>> var.trim()
253
+ Traceback (most recent call last):
254
+ ...
255
+ ValueError: The value `0` of parameter `var` of element `?` is not valid.
256
+ >>> var
257
+ var(0)
258
+ >>> var.value = 4
259
+ >>> var.trim()
260
+ Traceback (most recent call last):
261
+ ...
262
+ ValueError: The value `4` of parameter `var` of element `?` is not valid.
263
+ >>> var
264
+ var(4)
265
+
266
+ >>> from hydpy import INT_NAN
267
+ >>> var.value = 0
268
+ >>> assert var.trim(lower=0) is False
269
+ >>> assert var.trim(lower=INT_NAN) is False
270
+
271
+ >>> var.value = 4
272
+ >>> assert var.trim(upper=4) is False
273
+ >>> assert var.trim(upper=INT_NAN) is False
274
+
275
+ >>> Var.SPAN = 1, None
276
+ >>> var.value = 0
277
+ >>> var.trim()
278
+ Traceback (most recent call last):
279
+ ...
280
+ ValueError: The value `0` of parameter `var` of element `?` is not valid.
281
+ >>> var
282
+ var(0)
283
+
284
+ >>> Var.SPAN = None, 3
285
+ >>> var.value = 0
286
+ >>> assert var.trim() is False
287
+ >>> var.value = 4
288
+ >>> var.trim()
289
+ Traceback (most recent call last):
290
+ ...
291
+ ValueError: The value `4` of parameter `var` of element `?` is not valid.
292
+
293
+ >>> del Var.SPAN
294
+ >>> var.value = 0
295
+ >>> assert var.trim() is False
296
+ >>> var.value = 4
297
+ >>> assert var.trim() is False
298
+
299
+ >>> Var.SPAN = 1, 3
300
+ >>> Var.NDIM = 2
301
+ >>> var.shape = (1, 3)
302
+ >>> var.values = 2
303
+ >>> assert var.trim() is False
304
+
305
+ >>> var.values = 0, 1, 2
306
+ >>> var.trim()
307
+ Traceback (most recent call last):
308
+ ...
309
+ ValueError: At least one value of parameter `var` of element `?` is not valid.
310
+ >>> var
311
+ var(0, 1, 2)
312
+ >>> var.values = 2, 3, 4
313
+ >>> var.trim()
314
+ Traceback (most recent call last):
315
+ ...
316
+ ValueError: At least one value of parameter `var` of element `?` is not valid.
317
+ >>> var
318
+ var(2, 3, 4)
319
+
320
+
321
+ >>> var.values = 0, 0, 2
322
+ >>> assert var.trim(lower=[0, INT_NAN, 2]) is False
323
+
324
+ >>> var.values = 2, 4, 4
325
+ >>> assert var.trim(upper=[2, INT_NAN, 4]) is False
326
+
327
+ For |bool| values, defining outliers does not make much sense, which is why
328
+ function |trim| does nothing when applied to variables handling |bool| values:
329
+
330
+ >>> Var.TYPE = bool
331
+ >>> assert var.trim() is False
332
+
333
+ If function |trim| encounters an unmanageable type, it raises an exception like the
334
+ following:
335
+
336
+ >>> Var.TYPE = str
337
+ >>> var.trim()
338
+ Traceback (most recent call last):
339
+ ...
340
+ NotImplementedError: Method `trim` can only be applied on parameters handling \
341
+ floating-point, integer, or boolean values, but the "value type" of parameter `var` \
342
+ is `str`.
343
+
344
+ >>> pub.options.warntrim = False
345
+ """
346
+ if hydpy.pub.options.trimvariables:
347
+ if lower is None:
348
+ lower = self.SPAN[0]
349
+ if upper is None:
350
+ upper = self.SPAN[1]
351
+ type_ = getattr(self, "TYPE", float)
352
+ if type_ is float:
353
+ if self.NDIM == 0:
354
+ return _trim_float_0d(self, lower, upper)
355
+ return _trim_float_nd(self, lower, upper)
356
+ if type_ is int:
357
+ if self.NDIM == 0:
358
+ return _trim_int_0d(self, lower, upper)
359
+ return _trim_int_nd(self, lower, upper)
360
+ if type_ is bool:
361
+ return False
362
+ raise NotImplementedError(
363
+ f"Method `trim` can only be applied on parameters handling "
364
+ f'floating-point, integer, or boolean values, but the "value type" of '
365
+ f"parameter `{self.name}` is `{self.TYPE.__name__}`."
366
+ )
367
+ return False
368
+
369
+
370
+ def _trim_float_0d(self, lower, upper) -> bool:
371
+ if numpy.isnan(self.value):
372
+ return False
373
+ if (lower is None) or numpy.isnan(lower):
374
+ lower = -numpy.inf
375
+ if (upper is None) or numpy.isnan(upper):
376
+ upper = numpy.inf
377
+ if self < lower:
378
+ old = self.value
379
+ self.value = lower
380
+ if (old + get_tolerance(old)) < (lower - get_tolerance(lower)):
381
+ _warn_trim(self, oldvalue=old, newvalue=lower)
382
+ return True
383
+ elif self > upper:
384
+ old = self.value
385
+ self.value = upper
386
+ if (old - get_tolerance(old)) > (upper + get_tolerance(upper)):
387
+ _warn_trim(self, oldvalue=old, newvalue=upper)
388
+ return True
389
+ return False
390
+
391
+
392
+ def _trim_float_nd(self, lower, upper) -> bool:
393
+ values = self.values
394
+ shape = values.shape
395
+ if lower is None:
396
+ lower = -numpy.inf
397
+ lower = numpy.full(shape, lower, dtype=config.NP_FLOAT)
398
+ lower[numpy.where(numpy.isnan(lower))] = -numpy.inf
399
+ if upper is None:
400
+ upper = numpy.inf
401
+ upper = numpy.full(shape, upper, dtype=config.NP_FLOAT)
402
+ upper[numpy.where(numpy.isnan(upper))] = numpy.inf
403
+ idxs = numpy.isnan(values)
404
+ try:
405
+ values[idxs] = lower[idxs]
406
+ if numpy.any(values < lower) or numpy.any(values > upper):
407
+ old = values.copy()
408
+ trimmed = numpy.clip(values, lower, upper)
409
+ values[:] = trimmed
410
+ if numpy.any(
411
+ (old + get_tolerance(old)) < (lower - get_tolerance(lower))
412
+ ) or numpy.any((old - get_tolerance(old)) > (upper + get_tolerance(upper))):
413
+ _warn_trim(self, oldvalue=old, newvalue=trimmed)
414
+ return True
415
+ return False
416
+ finally:
417
+ values[idxs] = numpy.nan
418
+
419
+
420
+ def _trim_int_0d(self, lower, upper) -> bool:
421
+ if lower is None:
422
+ lower = INT_NAN
423
+ if (upper is None) or (upper == INT_NAN):
424
+ upper = -INT_NAN
425
+ if (self != INT_NAN) and ((self < lower) or (self > upper)):
426
+ raise ValueError(
427
+ f"The value `{self.value}` of parameter "
428
+ f"{objecttools.elementphrase(self)} is not valid."
429
+ )
430
+ return False
431
+
432
+
433
+ def _trim_int_nd(self, lower, upper) -> bool:
434
+ if lower is None:
435
+ lower = INT_NAN
436
+ lower = numpy.full(self.shape, lower, dtype=config.NP_INT)
437
+ if upper is None:
438
+ upper = -INT_NAN
439
+ upper = numpy.full(self.shape, upper, dtype=config.NP_INT)
440
+ upper[upper == INT_NAN] = -INT_NAN
441
+ idxs = numpy.where(self.values == INT_NAN)
442
+ try:
443
+ self[idxs] = lower[idxs]
444
+ if numpy.any(self.values < lower) or numpy.any(self.values > upper):
445
+ raise ValueError(
446
+ f"At least one value of parameter {objecttools.elementphrase(self)} "
447
+ f"is not valid."
448
+ )
449
+ return False
450
+ finally:
451
+ self[idxs] = INT_NAN
452
+
453
+
454
+ def get_tolerance(values):
455
+ """Return some "numerical accuracy" to be expected for the given floating-point
456
+ value(s).
457
+
458
+ The documentation on function |trim| explains also function |get_tolerance|.
459
+ However, note the special case of infinite input values, for which function
460
+ |get_tolerance| returns zero:
461
+
462
+ >>> from hydpy.core.variabletools import get_tolerance
463
+ >>> import numpy
464
+ >>> get_tolerance(numpy.inf)
465
+ 0.0
466
+ >>> from hydpy import round_
467
+ >>> round_(get_tolerance(
468
+ ... numpy.array([1.0, numpy.inf, 2.0, -numpy.inf])), 16)
469
+ 0.000000000000001, 0.0, 0.000000000000002, 0.0
470
+ """
471
+ tolerance = numpy.abs(values * 1e-15)
472
+ if hasattr(tolerance, "__setitem__"):
473
+ tolerance[numpy.isinf(tolerance)] = 0.0
474
+ elif numpy.isinf(tolerance):
475
+ tolerance = 0.0
476
+ return tolerance
477
+
478
+
479
+ def _warn_trim(self, oldvalue, newvalue):
480
+ if hydpy.pub.options.warntrim:
481
+ warnings.warn(
482
+ f"For variable {objecttools.devicephrase(self)} at least one value "
483
+ f"needed to be trimmed. The old and the new value(s) are "
484
+ f"`{objecttools.repr_numbers(oldvalue)}` and "
485
+ f"`{objecttools.repr_numbers(newvalue)}`, respectively."
486
+ )
487
+
488
+
489
+ def combine_arrays_to_lower_or_upper_bound(
490
+ *arrays: NDArrayFloat | None, lower: bool
491
+ ) -> NDArrayFloat | None:
492
+ """Helper function for parameter-specific trimming functions that collects all
493
+ available lower or upper bound values.
494
+
495
+ See function |sw1d_control.BottomLowWaterThreshold.trim| of class
496
+ |sw1d_control.BottomLowWaterThreshold| for an example.
497
+ """
498
+ result: NDArrayFloat | None = None
499
+ for array in arrays:
500
+ if (array is not None) and (array.ndim > 0):
501
+ if result is None:
502
+ result = array
503
+ elif lower:
504
+ result = numpy.maximum(result, array)
505
+ else:
506
+ result = numpy.minimum(result, array)
507
+ return result
508
+
509
+
510
+ class FastAccess:
511
+ """Used as a surrogate for typed Cython classes handling parameters or sequences
512
+ when working in pure Python mode."""
513
+
514
+ def _get_attribute(self, name, suffix, default=None):
515
+ return getattr(self, f"_{name}_{suffix}", default)
516
+
517
+ def _set_attribute(self, name, suffix, value):
518
+ return setattr(self, f"_{name}_{suffix}", value)
519
+
520
+ def __iter__(self):
521
+ """Iterate over all sequence names."""
522
+ for key in vars(self).keys():
523
+ if not key.startswith("_"):
524
+ yield key
525
+
526
+ # ToDo: Replace this hack with a Mypy plugin?
527
+ def __getattr__(self, item: str) -> Any:
528
+ assert False
529
+
530
+ del __getattr__
531
+
532
+ def __setattr__(self, key: str, value: Any) -> None:
533
+ assert False
534
+
535
+ del __setattr__
536
+
537
+
538
+ class Variable:
539
+ """Base class for |Parameter| and |Sequence_|.
540
+
541
+ The subclasses are required to provide the class attributes `NDIM`
542
+ and `TYPE`, defining the dimensionality and the type of the values
543
+ to be handled by the subclass, respectively. Class attribute `INIT`
544
+ is optional and should provide a suitable default value.
545
+
546
+ Class |Variable| implements methods for arithmetic calculations,
547
+ comparisons and type conversions. See the following examples on
548
+ how to do math with HydPys |Parameter| and |Sequence_| objects.
549
+
550
+ We start with demonstrating the supported mathematical operations
551
+ on 0-dimensional |Variable| objects handling |float| values:
552
+
553
+ >>> import numpy
554
+ >>> from hydpy.core.variabletools import FastAccess, Variable
555
+ >>> class Var(Variable):
556
+ ... NDIM = 0
557
+ ... TYPE = float
558
+ ... initinfo = 0.0, False
559
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
560
+ >>> var = Var(None)
561
+
562
+ You can perform additions both with other |Variable| objects and
563
+ with ordinary number objects:
564
+
565
+ >>> var.value = 2.0
566
+ >>> var + var
567
+ 4.0
568
+ >>> var + 3.0
569
+ 5.0
570
+ >>> 4.0 + var
571
+ 6.0
572
+ >>> var += 1
573
+ >>> var
574
+ var(3.0)
575
+ >>> var += -1.0
576
+ >>> var
577
+ var(2.0)
578
+
579
+ If something goes wrong, all math operations return errors like the following:
580
+
581
+ >>> var = Var(None)
582
+ >>> var + 1.0
583
+ Traceback (most recent call last):
584
+ ...
585
+ hydpy.core.exceptiontools.AttributeNotReady: While trying to add \
586
+ variable `var` and `float` instance `1.0`, the following error occurred: \
587
+ For variable `var`, no value has been defined so far.
588
+
589
+ In general, the examples above are valid for the following binary
590
+ operations:
591
+
592
+ >>> var.value = 3.0
593
+ >>> var - 1
594
+ 2.0
595
+ >>> 7.0 - var
596
+ 4.0
597
+ >>> var -= 2.0
598
+ >>> var
599
+ var(1.0)
600
+
601
+ >>> var.value = 2.0
602
+ >>> var * 3
603
+ 6.0
604
+ >>> 4.0 * var
605
+ 8.0
606
+ >>> var *= 0.5
607
+ >>> var
608
+ var(1.0)
609
+
610
+ >>> var.value = 3.0
611
+ >>> var / 2
612
+ 1.5
613
+ >>> 7.5 / var
614
+ 2.5
615
+ >>> var /= 6.0
616
+ >>> var
617
+ var(0.5)
618
+
619
+ >>> var.value = 3.0
620
+ >>> var // 2
621
+ 1.0
622
+ >>> 7.5 // var
623
+ 2.0
624
+ >>> var //= 0.9
625
+ >>> var
626
+ var(3.0)
627
+
628
+ >>> var.value = 5.0
629
+ >>> var % 2
630
+ 1.0
631
+ >>> 7.5 % var
632
+ 2.5
633
+ >>> var %= 3.0
634
+ >>> var
635
+ var(2.0)
636
+
637
+ >>> var.value = 2.0
638
+ >>> var**3
639
+ 8.0
640
+ >>> 3.0**var
641
+ 9.0
642
+ >>> var **= 4.0
643
+ >>> var
644
+ var(16.0)
645
+
646
+ >>> var.value = 5.0
647
+ >>> divmod(var, 3)
648
+ (1.0, 2.0)
649
+ >>> divmod(13.0, var)
650
+ (2.0, 3.0)
651
+
652
+ Additionally, we support the following unary operations:
653
+
654
+ >>> var.values = -5.0
655
+ >>> +var
656
+ -5.0
657
+ >>> -var
658
+ 5.0
659
+ >>> abs(var)
660
+ 5.0
661
+ >>> ~var
662
+ -0.2
663
+ >>> var.value = 2.5
664
+ >>> import math
665
+ >>> math.floor(var)
666
+ 2
667
+ >>> math.ceil(var)
668
+ 3
669
+ >>> bool(var)
670
+ True
671
+ >>> int(var)
672
+ 2
673
+ >>> float(var)
674
+ 2.5
675
+ >>> var.value = 1.67
676
+ >>> from hydpy import round_
677
+ >>> round_(var.value, 1)
678
+ 1.7
679
+
680
+ You can apply all the operations discussed above (except |float| and
681
+ |int|) on |Variable| objects of arbitrary dimensionality:
682
+
683
+ >>> from hydpy import print_matrix, print_vector
684
+ >>> Var.NDIM = 1
685
+ >>> Var.TYPE = float
686
+ >>> var.shape = (2,)
687
+ >>> var.values = 2.0
688
+ >>> print_vector(var + var)
689
+ 4.0, 4.0
690
+ >>> print_vector(var + 3.0)
691
+ 5.0, 5.0
692
+ >>> print_vector([4.0, 0.0] + var)
693
+ 6.0, 2.0
694
+ >>> var += 1
695
+ >>> var
696
+ var(3.0, 3.0)
697
+
698
+ >>> var.values = 3.0
699
+ >>> print_vector(var - [1.0, 0.0])
700
+ 2.0, 3.0
701
+ >>> print_vector([7.0, 0.0] - var)
702
+ 4.0, -3.0
703
+ >>> var -= [2.0, 0.0]
704
+ >>> var
705
+ var(1.0, 3.0)
706
+
707
+ >>> var.values = 2.0
708
+ >>> print_vector(var * [3.0, 1.0])
709
+ 6.0, 2.0
710
+ >>> print_vector([4.0, 1.0] * var)
711
+ 8.0, 2.0
712
+ >>> var *= [0.5, 1.0]
713
+ >>> var
714
+ var(1.0, 2.0)
715
+
716
+ >>> var.values = 3.0
717
+ >>> print_vector(var / [2.0, 1.0])
718
+ 1.5, 3.0
719
+ >>> print_vector([7.5, 3.0] / var)
720
+ 2.5, 1.0
721
+ >>> var /= [6.0, 1.]
722
+ >>> var
723
+ var(0.5, 3.0)
724
+
725
+ >>> var.values = 3.0
726
+ >>> print_vector(var // [2.0, 1.0])
727
+ 1.0, 3.0
728
+ >>> print_vector([7.5, 3.0] // var)
729
+ 2.0, 1.0
730
+ >>> var //= [0.9, 1.0]
731
+ >>> var
732
+ var(3.0, 3.0)
733
+
734
+ >>> var.values = 5.0
735
+ >>> print_vector(var % [2.0, 5.0])
736
+ 1.0, 0.0
737
+ >>> print_vector([7.5, 5.0] % var)
738
+ 2.5, 0.0
739
+ >>> var %= [3.0, 5.0]
740
+ >>> var
741
+ var(2.0, 0.0)
742
+
743
+ >>> var.values = 2.0
744
+ >>> print_vector(var**[3.0, 1.0])
745
+ 8.0, 2.0
746
+ >>> print_vector([3.0, 1.0]**var)
747
+ 9.0, 1.0
748
+ >>> var **= [4.0, 1.0]
749
+ >>> var
750
+ var(16.0, 2.0)
751
+
752
+ >>> var.value = 5.0
753
+ >>> print_matrix(divmod(var, [3.0, 5.0]))
754
+ | 1.0, 1.0 |
755
+ | 2.0, 0.0 |
756
+ >>> print_matrix(divmod([13.0, 5.0], var))
757
+ | 2.0, 1.0 |
758
+ | 3.0, 0.0 |
759
+
760
+ >>> var.values = -5.0
761
+ >>> print_vector(+var)
762
+ -5.0, -5.0
763
+ >>> print_vector(-var)
764
+ 5.0, 5.0
765
+ >>> print_vector(abs(var))
766
+ 5.0, 5.0
767
+ >>> print_vector(~var)
768
+ -0.2, -0.2
769
+ >>> var.value = 2.5
770
+ >>> import math
771
+ >>> print_vector(math.floor(var))
772
+ 2, 2
773
+ >>> print_vector(math.ceil(var))
774
+ 3, 3
775
+ >>> var.values = 1.67
776
+ >>> print_vector(round(var, 1))
777
+ 1.7, 1.7
778
+ >>> bool(var)
779
+ True
780
+ >>> int(var)
781
+ Traceback (most recent call last):
782
+ ...
783
+ TypeError: The variable `var` is 1-dimensional and thus cannot be \
784
+ converted to a scalar int value.
785
+ >>> float(var)
786
+ Traceback (most recent call last):
787
+ ...
788
+ TypeError: The variable `var` is 1-dimensional and thus cannot be \
789
+ converted to a scalar float value.
790
+
791
+ Indexing is supported (for consistency reasons, even for
792
+ 0-dimensional variables):
793
+
794
+ >>> Var.NDIM = 0
795
+ >>> var.value = 5.0
796
+ >>> var[0] += var[0]
797
+ >>> var[:]
798
+ 10.0
799
+ >>> var[1]
800
+ Traceback (most recent call last):
801
+ ...
802
+ IndexError: While trying to access the value(s) of variable `var` \
803
+ with key `1`, the following error occurred: The only allowed keys for \
804
+ 0-dimensional variables are `0` and `:`.
805
+
806
+ >>> Var.NDIM = 1
807
+ >>> var = Var(None)
808
+ >>> var.shape = (5,)
809
+ >>> var.value = 2.0, 4.0, 6.0, 8.0, 10.0
810
+ >>> round_(var[0])
811
+ 2.0
812
+ >>> round_(var[-1])
813
+ 10.0
814
+ >>> var[1:-1:2] = 2.0 * var[1:-1:2]
815
+ >>> var
816
+ var(2.0, 8.0, 6.0, 16.0, 10.0)
817
+ >>> var[:] = "test"
818
+ Traceback (most recent call last):
819
+ ...
820
+ ValueError: While trying to set the value(s) of variable `var` \
821
+ with key `slice(None, None, None)`, the following error occurred: \
822
+ could not convert string to float: 'test'
823
+
824
+ Comparisons with |Variable| objects containing multiple values return a single
825
+ boolean value. Two objects are equal if all of their value pairs are equal, and
826
+ they are unequal if at least one of their value pairs is unequal:
827
+
828
+ >>> var.shape = (2,)
829
+ >>> var.values = 1.0, 3.0
830
+ >>> var == [0.0, 2.0], var == [1.0, 2.0], var == [1.0, 3.0]
831
+ (False, False, True)
832
+ >>> var != [0.0, 2.0], var != [1.0, 2.0], var != [1.0, 3.0]
833
+ (True, True, False)
834
+
835
+ While either the `==` or the `!=` operator returns `True` (but not both),
836
+ this must not be the case for the operator pairs `<`and `>=` as well as
837
+ `>` and `<=`:
838
+
839
+ >>> var < 2.0, var < 3.0, var < 4.0
840
+ (False, False, True)
841
+ >>> var <= 2.0, var <= 3.0, var <= 4.0
842
+ (False, True, True)
843
+ >>> var >= 0.0, var >= 1.0, var >= 2.0
844
+ (True, True, False)
845
+ >>> var > 0.0, var > 1.0, var > 2.0
846
+ (True, False, False)
847
+
848
+ Comparing wrongly shaped values does work for `==` and `!=` but
849
+ results in errors for the other operations:
850
+
851
+ >>> var.values = 2.0
852
+ >>> var == [2.0], var != [2.0]
853
+ (True, False)
854
+ >>> var == [2.0, 2.0, 2.0], var != [2.0, 2.0, 2.0]
855
+ (False, True)
856
+ >>> var < [2.0], var <= [2.0], var >= [2.0], var > [2.0]
857
+ (False, True, True, False)
858
+ >>> var < [2.0, 2.0, 2.0] # doctest: +ELLIPSIS
859
+ Traceback (most recent call last):
860
+ ...
861
+ ValueError: While trying to compare variable `var` of element `?` \
862
+ with object `[2.0, 2.0, 2.0]` of type `list`, the following error occurred: \
863
+ operands could not be broadcast together with shapes (2,) (3,)...
864
+
865
+ You can compare different |Variable| objects directly with each other:
866
+
867
+ >>> from copy import deepcopy
868
+ >>> var < var, var < deepcopy(var)
869
+ (False, False)
870
+ >>> var <= var, var <= deepcopy(var)
871
+ (True, True)
872
+ >>> var == var, var == deepcopy(var)
873
+ (True, True)
874
+ >>> var != var, var != deepcopy(var)
875
+ (False, False)
876
+ >>> var >= var, var >= deepcopy(var)
877
+ (True, True)
878
+ >>> var > var, var > deepcopy(var)
879
+ (False, False)
880
+
881
+ When asking for impossible comparisons, |trim| raises error
882
+ like the following:
883
+
884
+ >>> var < "text"
885
+ Traceback (most recent call last):
886
+ ...
887
+ TypeError: While trying to compare variable `var` of element `?` with \
888
+ object `text` of type `str`, the following error occurred: ufunc 'isnan' \
889
+ not supported for the input types, and the inputs could not be safely \
890
+ coerced to any supported types according to the casting rule ''safe''
891
+
892
+ Note that, in contrast to the usual |numpy| array comparison, we ignore
893
+ all single comparison results between two |numpy.nan| values:
894
+
895
+ >>> from numpy import nan
896
+ >>> var.shape = (3,)
897
+ >>> var.values = 1.0, 2.0, nan
898
+ >>> var < [2.0, 3.0, nan], var < [1.0, 2.0, nan], var < [2.0, nan, nan], \
899
+ var < [2.0, 3.0, 4.0]
900
+ (True, False, False, False)
901
+ >>> var <= [1.0, 3.0, nan], var <= [1.0, 1.0, nan], var <= [1.0, nan, nan], \
902
+ var <= [1.0, 3.0, 5.0]
903
+ (True, False, False, False)
904
+ >>> var == [1.0, 2.0, nan], var == [1.0, 1.0, nan], var == [1.0, nan, nan], \
905
+ var == [1.0, 2.0, 3.0]
906
+ (True, False, False, False)
907
+ >>> var != [1.0, 1.0, nan], var != [1.0, 2.0, nan], var != [1.0, nan, nan], \
908
+ var != [1.0, 2.0, 3.0]
909
+ (True, False, True, True)
910
+ >>> var >= [1.0, 1.0, nan], var >= [1.0, 3.0, nan], var <= [1.0, nan, nan], \
911
+ var <= [1.0, 3.0, 5.0]
912
+ (True, False, False, False)
913
+ >>> var > [0.0, 1.0, nan], var > [0.0, 2.0, nan], var < [0.0, nan, nan], \
914
+ var < [0.0, 1.0, 2.0]
915
+ (True, False, False, False)
916
+
917
+ Hence, when all entries of two compared objects are |numpy.nan|, we
918
+ consider these objects equal:
919
+
920
+ >>> var.values = nan
921
+ >>> var < [nan, nan, nan], var <= [nan, nan, nan], var == [nan, nan, nan], \
922
+ var != [nan, nan, nan], var >= [nan, nan, nan], var > [nan, nan, nan]
923
+ (False, True, True, False, True, False)
924
+ >>> Var.NDIM = 0
925
+ >>> var = Var(None)
926
+ >>> var.shape = ()
927
+ >>> var.value = nan
928
+ >>> var < nan, var <= nan, var == nan, var != nan, var >= nan, var > nan
929
+ (False, True, True, False, True, False)
930
+
931
+ The |len| operator does not work for 0-dimensional variables:
932
+
933
+ >>> Var.NDIM = 0
934
+ >>> var = Var(None)
935
+ >>> var.shape = ()
936
+ >>> len(var)
937
+ Traceback (most recent call last):
938
+ ...
939
+ TypeError: The `len` operator was applied on `var`, but this variable is \
940
+ 0-dimensional and thus unsized. Consider using the `numberofvalues` property instead.
941
+
942
+ For higher-dimensional variables, `len` always returns the length of the first
943
+ dimension:
944
+
945
+ >>> Var.NDIM = 1
946
+ >>> var = Var(None)
947
+ >>> var.shape = (5,)
948
+ >>> len(var)
949
+ 5
950
+ >>> Var.NDIM = 3
951
+ >>> var = Var(None)
952
+ >>> var.shape = (2, 1, 4)
953
+ >>> len(var)
954
+ 2
955
+
956
+ |Variable| objects are hashable based on their |id| value to avoid avoiding
957
+ confusion when adding different but equal objects into one |set| or |dict| object.
958
+ The following examples show this behaviour by making deep copies of existing
959
+ |Variable| objects:
960
+
961
+ >>> Var.NDIM = 0
962
+ >>> var1 = Var(None)
963
+ >>> var1.value = 5.0
964
+ >>> varset = set([var1])
965
+ >>> var1 in varset
966
+ True
967
+ >>> var1.value = 7.0
968
+ >>> var1 in varset
969
+ True
970
+ >>> var2 = deepcopy(var1)
971
+ >>> var1 == var2
972
+ True
973
+ >>> var2 in varset
974
+ False
975
+
976
+ >>> Var.NDIM = 1
977
+ >>> var1 = Var(None)
978
+ >>> var1.shape = (2,)
979
+ >>> var1.value = 3.0, 5.0
980
+ >>> varset = set([var1])
981
+ >>> var1 in varset
982
+ True
983
+ >>> var1[1] = 7.0
984
+ >>> var1 in varset
985
+ True
986
+ >>> var2 = deepcopy(var1)
987
+ >>> var1 == var2
988
+ True
989
+ >>> var2 in varset
990
+ False
991
+
992
+ During initialisation, each |Variable| subclass tries to extract its
993
+ unit from its docstring:
994
+
995
+ >>> type("Var", (Variable,), {"__doc__": "Discharge [m³/s]."}).unit
996
+ 'm³/s'
997
+
998
+ For missing or poorly written docstrings, we set `unit` to "?":
999
+
1000
+ >>> type("Var", (Variable,), {}).unit
1001
+ '?'
1002
+ >>> type("Var", (Variable,), {"__doc__": "Discharge ]m³/s[."}).unit
1003
+ '?'
1004
+ >>> type("Var", (Variable,), {"__doc__": "Discharge m³/s]."}).unit
1005
+ '?'
1006
+ """
1007
+
1008
+ # Subclasses need to define...
1009
+ NDIM: int
1010
+ TYPE: type[float | int | bool] # ToDo: is still `str` in some cases
1011
+ # ...and optionally...
1012
+ SPAN: tuple[int | float | bool | None, int | float | bool | None] = (None, None)
1013
+ INIT: int | float | bool | None = None
1014
+
1015
+ _NOT_DEEPCOPYABLE_MEMBERS: Final[frozenset[str]] = frozenset(
1016
+ (
1017
+ "subvars",
1018
+ "subpars",
1019
+ "subseqs",
1020
+ "fastaccess",
1021
+ "fastaccess_old",
1022
+ "fastaccess_new",
1023
+ )
1024
+ )
1025
+ _CLS_FASTACCESS_PYTHON: ClassVar[type[FastAccess]]
1026
+
1027
+ strict_valuehandling: bool = True
1028
+
1029
+ __hydpy__subclasscounter__ = 1
1030
+
1031
+ name: str
1032
+ """Name of the variable in lowercase letters."""
1033
+ unit: str
1034
+ """Unit of the variable."""
1035
+ fastaccess: FastAccess
1036
+ """Object for accessing the variable's data with little overhead."""
1037
+ subvars: SubVariables
1038
+ """The subgroup to which the variable belongs."""
1039
+
1040
+ _refweights: parametertools.Parameter | VectorFloat | None = None
1041
+
1042
+ mask = masktools.DefaultMask(
1043
+ doc="The standard mask used by all variables (if not overwritten)."
1044
+ )
1045
+
1046
+ @classmethod
1047
+ @contextlib.contextmanager
1048
+ def modify_refweights(
1049
+ cls, refweights: parametertools.Parameter | None
1050
+ ) -> Generator[None, None, None]:
1051
+ """Eventually, set or modify the reference to a parameter defining the
1052
+ weighting coefficients required for aggregating values.
1053
+
1054
+ The following example demonstrates that changes affect the relevant class only
1055
+ temporarily, but its objects initialised within the "with" block persistently:
1056
+
1057
+ >>> from hydpy.core.variabletools import FastAccess, Variable
1058
+ >>> class Var1(Variable):
1059
+ ... initinfo = 0.0, True
1060
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
1061
+ >>> class Var2(Variable):
1062
+ ... NDIM = 1
1063
+ ... TYPE = float
1064
+ ... initinfo = 0.0, True
1065
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
1066
+ >>> var2 = Var2(None)
1067
+ >>> var2.shape = 3
1068
+ >>> with Var1.modify_refweights(var2):
1069
+ ... Var1._refweights
1070
+ ... var1 = Var1(None)
1071
+ ... var1.refweights
1072
+ var2(0.0, 0.0, 0.0)
1073
+ var2(0.0, 0.0, 0.0)
1074
+ >>> Var1._refweights
1075
+ >>> var1.refweights
1076
+ var2(0.0, 0.0, 0.0)
1077
+
1078
+ Passing |None| does not overwrite previously set references:
1079
+
1080
+ >>> Var1._refweights = var2
1081
+ >>> with Var1.modify_refweights(None):
1082
+ ... Var1._refweights
1083
+ ... var1 = Var1(None)
1084
+ ... var1.refweights
1085
+ var2(0.0, 0.0, 0.0)
1086
+ var2(0.0, 0.0, 0.0)
1087
+ >>> Var1._refweights
1088
+ var2(0.0, 0.0, 0.0)
1089
+ >>> var1.refweights
1090
+ var2(0.0, 0.0, 0.0)
1091
+ """
1092
+ if refweights is None:
1093
+ yield
1094
+ else:
1095
+ old = cls._refweights
1096
+ try:
1097
+ cls._refweights = refweights
1098
+ yield
1099
+ finally:
1100
+ cls._refweights = old
1101
+
1102
+ def __init__(self, subvars: SubVariables) -> None:
1103
+ self.subvars = subvars
1104
+ self.fastaccess = self._CLS_FASTACCESS_PYTHON()
1105
+ self._valueready = False
1106
+ self.__shapeready = False
1107
+ self._refweights = type(self)._refweights
1108
+
1109
+ def __init_subclass__(cls) -> None:
1110
+ super().__init_subclass__()
1111
+ cls.name = cls.__name__.lower()
1112
+ cls.unit = cls._get_unit()
1113
+ subclasscounter = Variable.__hydpy__subclasscounter__ + 1
1114
+ Variable.__hydpy__subclasscounter__ = subclasscounter
1115
+ cls.__hydpy__subclasscounter__ = subclasscounter
1116
+
1117
+ @classmethod
1118
+ def _get_unit(cls) -> str:
1119
+ descr = objecttools.description(cls)
1120
+ idx1 = descr.find("[") + 1
1121
+ idx2 = descr.find("]")
1122
+ if 0 < idx1 < idx2:
1123
+ return descr[idx1:idx2]
1124
+ return "?"
1125
+
1126
+ def __hydpy__connect_variable2subgroup__(self) -> None:
1127
+ """To be called by the |SubVariables| object when preparing a
1128
+ new |Variable| object."""
1129
+ self.fastaccess = self.subvars.fastaccess
1130
+ self._finalise_connections()
1131
+
1132
+ def _finalise_connections(self) -> None:
1133
+ """A hook method, called at the end of method
1134
+ `__hydpy__connect_variable2subgroup__` for initialising
1135
+ values and some related attributes."""
1136
+
1137
+ @property
1138
+ @abc.abstractmethod
1139
+ def initinfo(self) -> tuple[float | int | bool | pointerutils.Double, bool]:
1140
+ """To be overridden."""
1141
+
1142
+ def __call__(self, *args) -> None:
1143
+ if len(args) == 1:
1144
+ args = args[0]
1145
+ self.values = args
1146
+
1147
+ def _get_value(self):
1148
+ """The actual parameter or sequence value(s).
1149
+
1150
+ First, we prepare a simple (not fully functional) |Variable| subclass:
1151
+
1152
+ >>> from hydpy.core.variabletools import Variable
1153
+ >>> class Var(Variable):
1154
+ ... NDIM = 0
1155
+ ... TYPE = float
1156
+ ... initinfo = 3.0, True
1157
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
1158
+
1159
+ Without making use of default values (see below), trying to
1160
+ query the actual value of a freshly initialised |Variable|
1161
+ object results in the following error:
1162
+
1163
+ >>> var = Var(None)
1164
+ >>> var.value
1165
+ Traceback (most recent call last):
1166
+ ...
1167
+ hydpy.core.exceptiontools.AttributeNotReady: For variable `var`, \
1168
+ no value has been defined so far.
1169
+
1170
+ Property |Variable.value| tries to normalise assigned values and
1171
+ raises an error, if not possible:
1172
+
1173
+ >>> var.value = 3
1174
+ >>> var.value
1175
+ 3.0
1176
+
1177
+ >>> var.value = ["2.0"]
1178
+ >>> var.value
1179
+ 2.0
1180
+
1181
+ >>> var.value = 1.0, 1.0
1182
+ Traceback (most recent call last):
1183
+ ...
1184
+ ValueError: While trying to set the value(s) of variable `var`, the \
1185
+ following error occurred: 2 values are assigned to the scalar variable `var`.
1186
+ >>> var.value
1187
+ 2.0
1188
+
1189
+ >>> var.value = "O"
1190
+ Traceback (most recent call last):
1191
+ ...
1192
+ TypeError: While trying to set the value(s) of variable `var`, \
1193
+ the following error occurred: The given value `O` cannot be converted \
1194
+ to type `float`.
1195
+ >>> var.value
1196
+ 2.0
1197
+
1198
+ The above examples deal with a 0-dimensional variable handling
1199
+ |float| values. The following examples focus on a 2-dimensional
1200
+ variable handling |int| values:
1201
+
1202
+ >>> from hydpy import INT_NAN
1203
+ >>> Var.NDIM = 2
1204
+ >>> Var.TYPE = int
1205
+ >>> Var.initinfo = INT_NAN, False
1206
+
1207
+ For multidimensional objects, assigning new values required
1208
+ defining their |Variable.shape| first:
1209
+
1210
+ >>> var = Var(None)
1211
+ >>> var.value
1212
+ Traceback (most recent call last):
1213
+ ...
1214
+ hydpy.core.exceptiontools.AttributeNotReady: Shape information for \
1215
+ variable `var` can only be retrieved after it has been defined.
1216
+
1217
+ >>> var.value = 2
1218
+ Traceback (most recent call last):
1219
+ ...
1220
+ hydpy.core.exceptiontools.AttributeNotReady: While trying to set the \
1221
+ value(s) of variable `var`, the following error occurred: Shape information \
1222
+ for variable `var` can only be retrieved after it has been defined.
1223
+
1224
+ >>> var.shape = (2, 3)
1225
+ >>> var.value
1226
+ Traceback (most recent call last):
1227
+ ...
1228
+ hydpy.core.exceptiontools.AttributeNotReady: For variable `var`, \
1229
+ no values have been defined so far.
1230
+
1231
+ >>> from hydpy import print_matrix
1232
+ >>> var.value = 2
1233
+ >>> print_matrix(var.value)
1234
+ | 2, 2, 2 |
1235
+ | 2, 2, 2 |
1236
+
1237
+ >>> var.value = 1, 2
1238
+ Traceback (most recent call last):
1239
+ ...
1240
+ ValueError: While trying to set the value(s) of variable `var`, \
1241
+ the following error occurred: While trying to convert the value(s) `(1, 2)` \
1242
+ to a numpy ndarray with shape `(2, 3)` and type `int`, the following error \
1243
+ occurred: could not broadcast input array from shape (2,) into shape (2,3)
1244
+ >>> print_matrix(var.value)
1245
+ | 2, 2, 2 |
1246
+ | 2, 2, 2 |
1247
+
1248
+ >>> var.shape = (0, 0)
1249
+ >>> var.shape
1250
+ (0, 0)
1251
+ >>> var.value # doctest: +ELLIPSIS
1252
+ array([], shape=(0, 0), dtype=...)
1253
+ """
1254
+ if (self.NDIM > 0) and not self.__shapeready:
1255
+ self._get_shape() # raise the proper error
1256
+ value = self._prepare_getvalue(
1257
+ self._valueready or not self.strict_valuehandling,
1258
+ getattr(self.fastaccess, self.name, None),
1259
+ )
1260
+ if value is None:
1261
+ substring = "values have" if self.NDIM else "value has"
1262
+ raise exceptiontools.AttributeNotReady(
1263
+ f"For variable {objecttools.devicephrase(self)}, no {substring} been "
1264
+ f"defined so far."
1265
+ )
1266
+ return value
1267
+
1268
+ def _set_value(self, value) -> None:
1269
+ try:
1270
+ value = self._prepare_setvalue(value)
1271
+ setattr(self.fastaccess, self.name, value)
1272
+ self._valueready = True
1273
+ except BaseException:
1274
+ objecttools.augment_excmessage(
1275
+ f"While trying to set the value(s) of variable "
1276
+ f"{objecttools.devicephrase(self)}"
1277
+ )
1278
+
1279
+ def _prepare_getvalue(self, readyflag: bool, value):
1280
+ if readyflag:
1281
+ if self.NDIM:
1282
+ return numpy.asarray(value)
1283
+ return self.TYPE(value)
1284
+ if self.NDIM and not sum(self.shape):
1285
+ return numpy.asarray(value)
1286
+ return None
1287
+
1288
+ def _prepare_setvalue(self, value):
1289
+ if self.NDIM:
1290
+ value = getattr(value, "value", value)
1291
+ try:
1292
+ value = numpy.full(
1293
+ self.shape, value, dtype=config.TYPES_PY2NP[self.TYPE]
1294
+ )
1295
+ except BaseException:
1296
+ objecttools.augment_excmessage(
1297
+ f"While trying to convert the value(s) `{value}` to a numpy "
1298
+ f"ndarray with shape `{self.shape}` and type `{self.TYPE.__name__}`"
1299
+ )
1300
+ else:
1301
+ if isinstance(value, Sequence):
1302
+ if len(value) > 1:
1303
+ raise ValueError(
1304
+ f"{len(value)} values are assigned to the scalar variable "
1305
+ f"{objecttools.devicephrase(self)}."
1306
+ )
1307
+ value = value[0]
1308
+ try:
1309
+ value = self.TYPE(value)
1310
+ except BaseException:
1311
+ raise TypeError(
1312
+ f"The given value `{value}` cannot be converted to type "
1313
+ f"`{self.TYPE.__name__}`."
1314
+ ) from None
1315
+ return value
1316
+
1317
+ value = property(fget=_get_value, fset=_set_value)
1318
+
1319
+ @property
1320
+ def values(self):
1321
+ """Alias for |Variable.value|."""
1322
+ return self._get_value()
1323
+
1324
+ @values.setter
1325
+ def values(self, values):
1326
+ self._set_value(values)
1327
+
1328
+ def _get_shape(self) -> tuple[int, ...]:
1329
+ """A tuple containing the actual lengths of all dimensions.
1330
+
1331
+ Note that setting a new |Variable.shape| results in a loss of
1332
+ the actual |Variable.values| of the respective |Variable| object.
1333
+
1334
+ First, we prepare a simple (not fully functional) |Variable| subclass:
1335
+
1336
+ >>> from hydpy.core.variabletools import Variable
1337
+ >>> class Var(Variable):
1338
+ ... NDIM = 1
1339
+ ... TYPE = float
1340
+ ... initinfo = 3.0, True
1341
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
1342
+
1343
+ Initially, the shape of a new |Variable| object is unknown:
1344
+
1345
+ >>> var = Var(None)
1346
+ >>> var.shape
1347
+ Traceback (most recent call last):
1348
+ ...
1349
+ hydpy.core.exceptiontools.AttributeNotReady: Shape information for \
1350
+ variable `var` can only be retrieved after it has been defined.
1351
+
1352
+ For multidimensional objects, assigning shape information (as a
1353
+ |tuple| of |int| values) prepares the required array automatically.
1354
+ Due to the |Variable.initinfo| surrogate of our test class,
1355
+ the entries of this array are `3.0`:
1356
+
1357
+ >>> from hydpy import print_vector
1358
+ >>> var.shape = (3,)
1359
+ >>> var.shape
1360
+ (3,)
1361
+ >>> print_vector(var.values)
1362
+ 3.0, 3.0, 3.0
1363
+
1364
+ For the |Variable.initinfo| flag (second |tuple| entry) being
1365
+ |False|, the array is still prepared but not directly accessible
1366
+ to the user:
1367
+
1368
+ >>> import numpy
1369
+ >>> Var.initinfo = numpy.nan, False
1370
+ >>> var = Var(None)
1371
+
1372
+ >>> var.shape = (3,)
1373
+ >>> var.shape
1374
+ (3,)
1375
+ >>> var.values
1376
+ Traceback (most recent call last):
1377
+ ...
1378
+ hydpy.core.exceptiontools.AttributeNotReady: For variable `var`, no \
1379
+ values have been defined so far.
1380
+
1381
+ >>> print_vector(var.fastaccess.var)
1382
+ nan, nan, nan
1383
+
1384
+ Property |Variable.shape| tries to normalise assigned values and
1385
+ raises errors like the following, if not possible:
1386
+
1387
+ >>> var.shape = "x"
1388
+ Traceback (most recent call last):
1389
+ ...
1390
+ TypeError: While trying create a new numpy ndarray for \
1391
+ variable `var`, the following error occurred: 'str' object cannot \
1392
+ be interpreted as an integer
1393
+ >>> from hydpy import attrready
1394
+ >>> attrready(var, "shape")
1395
+ False
1396
+ >>> var.fastaccess.var
1397
+
1398
+ >>> var.shape = (1,)
1399
+ >>> attrready(var, "shape")
1400
+ True
1401
+
1402
+ >>> var.shape = (2, 3)
1403
+ Traceback (most recent call last):
1404
+ ...
1405
+ ValueError: Variable `var` is 1-dimensional, but the given \
1406
+ shape indicates `2` dimensions.
1407
+ >>> attrready(var, "shape")
1408
+ False
1409
+ >>> var.fastaccess.var
1410
+
1411
+
1412
+ 0-dimensional |Variable| objects inform the user about their shape
1413
+ but do not allow to change it for obvious reasons:
1414
+
1415
+ >>> class Var(Variable):
1416
+ ... NDIM = 0
1417
+ ... TYPE = int
1418
+ ... initinfo = 3, True
1419
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
1420
+
1421
+ >>> var = Var(None)
1422
+ >>> var.shape
1423
+ ()
1424
+ >>> var.value
1425
+ Traceback (most recent call last):
1426
+ ...
1427
+ hydpy.core.exceptiontools.AttributeNotReady: For variable `var`, \
1428
+ no value has been defined so far.
1429
+
1430
+ >>> var.shape = ()
1431
+ >>> var.shape
1432
+ ()
1433
+ >>> var.value
1434
+ 3
1435
+ >>> var.shape = (2,)
1436
+ Traceback (most recent call last):
1437
+ ...
1438
+ ValueError: The shape information of 0-dimensional variables \
1439
+ as `var` can only be `()`, but `(2,)` is given.
1440
+
1441
+ With a |False| |Variable.initinfo| flag, the default value is
1442
+ still readily prepared after initialisation but not directly
1443
+ accessible to the user:
1444
+
1445
+ >>> from hydpy import INT_NAN
1446
+ >>> Var.initinfo = INT_NAN, False
1447
+ >>> var = Var(None)
1448
+ >>> var.shape
1449
+ ()
1450
+ >>> var.shape = ()
1451
+ >>> attrready(var, "value")
1452
+ False
1453
+ >>> var.fastaccess.var
1454
+ -999999
1455
+
1456
+ >>> var.value = 6
1457
+ >>> var.value
1458
+ 6
1459
+
1460
+ >>> var.shape = ()
1461
+ >>> var.fastaccess.var
1462
+ -999999
1463
+ """
1464
+ if self.NDIM:
1465
+ if self.__shapeready:
1466
+ shape = getattr(self.fastaccess, self.name).shape
1467
+ return tuple(int(x) for x in shape)
1468
+ raise exceptiontools.AttributeNotReady(
1469
+ f"Shape information for variable {objecttools.devicephrase(self)} can "
1470
+ f"only be retrieved after it has been defined."
1471
+ )
1472
+ return ()
1473
+
1474
+ def _set_shape(self, shape: int | tuple[int, ...]) -> None:
1475
+ self._valueready = False
1476
+ self.__shapeready = False
1477
+ initvalue, initflag = self.initinfo
1478
+ if self.NDIM:
1479
+ try:
1480
+ array = numpy.full(
1481
+ shape, initvalue, dtype=config.TYPES_PY2NP[self.TYPE]
1482
+ )
1483
+ except BaseException:
1484
+ setattr(self.fastaccess, self.name, None)
1485
+ objecttools.augment_excmessage(
1486
+ f"While trying create a new numpy ndarray for variable "
1487
+ f"{objecttools.devicephrase(self)}"
1488
+ )
1489
+ if array.ndim != self.NDIM:
1490
+ setattr(self.fastaccess, self.name, None)
1491
+ raise ValueError(
1492
+ f"Variable {objecttools.devicephrase(self)} is "
1493
+ f"{self.NDIM}-dimensional, but the given "
1494
+ f"shape indicates `{array.ndim}` dimensions."
1495
+ )
1496
+ setattr(self.fastaccess, self.name, array)
1497
+ self.__shapeready = True
1498
+ else:
1499
+ if shape:
1500
+ setattr(self.fastaccess, self.name, TYPE2MISSINGVALUE[self.TYPE])
1501
+ self._raise_wrongshape(shape)
1502
+ setattr(self.fastaccess, self.name, initvalue)
1503
+ if initflag:
1504
+ self._valueready = True
1505
+
1506
+ shape = propertytools.Property(fget=_get_shape, fset=_set_shape)
1507
+
1508
+ def _raise_wrongshape(self, shape):
1509
+ raise ValueError(
1510
+ f"The shape information of 0-dimensional variables "
1511
+ f"as {objecttools.devicephrase(self)} can only be `()`, "
1512
+ f"but `{shape}` is given."
1513
+ )
1514
+
1515
+ @property
1516
+ def numberofvalues(self) -> int:
1517
+ """The total number of values handled by the variable according to the current
1518
+ shape.
1519
+
1520
+ We create an incomplete |Variable| subclass for testing:
1521
+
1522
+ >>> from hydpy.core.variabletools import FastAccess, Variable
1523
+ >>> class Var(Variable):
1524
+ ... TYPE = float
1525
+ ... initinfo = 0.0, False
1526
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
1527
+ >>> var = Var(None)
1528
+
1529
+ 0-dimensional variables always handle precisely one value:
1530
+
1531
+ >>> Var.NDIM = 0
1532
+ >>> var = Var(None)
1533
+ >>> var.shape = ()
1534
+ >>> var.numberofvalues
1535
+ 1
1536
+
1537
+ For higher-dimensional variables, |Variable.numberofvalues| is the cumulative
1538
+ product of the individual dimensons lengths:
1539
+
1540
+ >>> Var.NDIM = 1
1541
+ >>> var = Var(None)
1542
+ >>> var.shape = (5,)
1543
+ >>> var.numberofvalues
1544
+ 5
1545
+ >>> Var.NDIM = 3
1546
+ >>> var = Var(None)
1547
+ >>> var.shape = (2, 1, 4)
1548
+ >>> var.numberofvalues
1549
+ 8
1550
+
1551
+ As long as the shape of a higher-dimensional variable is undefined,
1552
+ |Variable.numberofvalues| is zero:
1553
+
1554
+ >>> var = Var(None)
1555
+ >>> var.numberofvalues
1556
+ 0
1557
+ """
1558
+ if self.NDIM == 0:
1559
+ return 1
1560
+ if (shape := exceptiontools.getattr_(self, "shape", None)) is None:
1561
+ return 0
1562
+ return int(numpy.cumprod(shape)[-1])
1563
+
1564
+ def verify(self) -> None:
1565
+ """Raise a |RuntimeError| if at least one of the required values of a |Variable|
1566
+ object is |None| or |numpy.nan|.
1567
+
1568
+ The descriptor |Variable.mask| defines which values are considered necessary.
1569
+ For |Variable| subclasses defining |numpy.nan| as their |Variable.INIT| value,
1570
+ method |Variable.verify| assumes that |numpy.nan| are not problematic.
1571
+
1572
+ Examples on a 0-dimensional |Variable|:
1573
+
1574
+ >>> from hydpy.core.variabletools import Variable
1575
+ >>> class Var(Variable):
1576
+ ... NDIM = 0
1577
+ ... TYPE = float
1578
+ ... initinfo = 0.0, False
1579
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
1580
+ >>> var = Var(None)
1581
+ >>> import numpy
1582
+ >>> var.shape = ()
1583
+ >>> var.value = 1.0
1584
+ >>> var.verify()
1585
+ >>> var.value = numpy.nan
1586
+ >>> var.verify()
1587
+ Traceback (most recent call last):
1588
+ ...
1589
+ RuntimeError: For variable `var`, 1 required value has not been set yet: \
1590
+ var(nan).
1591
+
1592
+ >>> var.INIT = numpy.nan
1593
+ >>> var.verify()
1594
+
1595
+ Examples on a 2-dimensional |Variable|:
1596
+
1597
+ >>> Var.NDIM = 2
1598
+ >>> var = Var(None)
1599
+ >>> var.shape = (2, 3)
1600
+ >>> var.value = numpy.ones((2,3))
1601
+ >>> var.value[:, 1] = numpy.nan
1602
+ >>> var.verify()
1603
+ Traceback (most recent call last):
1604
+ ...
1605
+ RuntimeError: For variable `var`, 2 required values have not been set yet: \
1606
+ var([[1.0, nan, 1.0], [1.0, nan, 1.0]]).
1607
+
1608
+ >>> Var.mask = var.mask
1609
+ >>> Var.mask[0, 1] = False
1610
+ >>> var.verify()
1611
+ Traceback (most recent call last):
1612
+ ...
1613
+ RuntimeError: For variable `var`, 1 required value has not been set yet: \
1614
+ var([[1.0, nan, 1.0], [1.0, nan, 1.0]]).
1615
+
1616
+ >>> Var.mask[1, 1] = False
1617
+ >>> var.verify()
1618
+ """
1619
+ valueready = self._valueready
1620
+ try:
1621
+ self._valueready = True
1622
+ nmbnan: int = numpy.sum(numpy.isnan(numpy.array(self.value)[self.mask]))
1623
+ finally:
1624
+ self._valueready = valueready
1625
+ if nmbnan and ((self.INIT is None) or ~numpy.isnan(self.INIT)):
1626
+ text = "value has" if nmbnan == 1 else "values have"
1627
+ raise RuntimeError(
1628
+ f"For variable {objecttools.devicephrase(self)}, {nmbnan} required "
1629
+ f"{text} not been set yet: {objecttools.flatten_repr(self)}."
1630
+ )
1631
+
1632
+ @property
1633
+ def valuevector(self) -> Vector:
1634
+ """The values of the actual |Variable| object, arranged in a 1-dimensional
1635
+ vector.
1636
+
1637
+ For a 1-dimensional variable object, property |Variable.valuevector| returns
1638
+ the original values without any modification:
1639
+
1640
+ >>> from hydpy.models.hland import *
1641
+ >>> simulationstep("1d")
1642
+ >>> parameterstep("1d")
1643
+ >>> nmbzones(3)
1644
+ >>> sclass(2)
1645
+ >>> states.sm.values = 1.0, 2.0, 3.0
1646
+ >>> from hydpy import print_vector
1647
+ >>> print_vector(states.sm.valuevector)
1648
+ 1.0, 2.0, 3.0
1649
+
1650
+ For all other variables, |Variable.valuevector| raises the following error by
1651
+ default:
1652
+
1653
+ >>> states.uz.valuevector
1654
+ Traceback (most recent call last):
1655
+ ...
1656
+ NotImplementedError: Variable `uz` does not implement a method for converting \
1657
+ its values to a 1-dimensional vector.
1658
+
1659
+ If considered appropriate, model developers should override
1660
+ |Variable.valuevector| for individual multidimensional variables, to support
1661
+ methods like |Variable.average_values|, which rely on 1-dimensional data. One
1662
+ example is the state sequence |hland_states.SP| of base model |hland|, which
1663
+ handles values for individual zones (second axis) and snow classes (first axis).
1664
+ Here we decided to let |hland_sequences.State2DSequence.valuevector| return the
1665
+ sums of all snow classes for each zone so that the content of the returned
1666
+ vector agrees with the contents of most 1-dimensional sequences of |hland|:
1667
+
1668
+ >>> states.sp = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
1669
+ >>> print_vector(states.sp.valuevector)
1670
+ 2.5, 3.5, 4.5
1671
+ """
1672
+ if self.NDIM == 1:
1673
+ return self.value
1674
+ raise NotImplementedError(
1675
+ f"Variable {objecttools.devicephrase(self)} does not implement a method "
1676
+ f"for converting its values to a 1-dimensional vector."
1677
+ )
1678
+
1679
+ @property
1680
+ def refweights(self) -> parametertools.Parameter | VectorFloat:
1681
+ """Reference to a |Parameter| object or a simple vector that defines weighting
1682
+ coefficients (e.g. fractional areas) for applying function
1683
+ |Variable.average_values|.
1684
+
1685
+ Must be overwritten by subclasses when required."""
1686
+ if (refweights := self._refweights) is not None:
1687
+ return refweights
1688
+ raise AttributeError(
1689
+ f"Variable {objecttools.devicephrase(self)} does not define any weighting "
1690
+ f"coefficients."
1691
+ )
1692
+
1693
+ def average_values(self, *args, **kwargs) -> float:
1694
+ """Average the actual values of the |Variable| object.
1695
+
1696
+ For 0-dimensional |Variable| objects, the result of method
1697
+ |Variable.average_values| equals |Variable.value|. The following example shows
1698
+ this for the poorly defined class `SoilMoisture`:
1699
+
1700
+ >>> from hydpy.core.variabletools import Variable
1701
+ >>> class SoilMoisture(Variable):
1702
+ ... NDIM = 0
1703
+ ... TYPE = float
1704
+ ... refweigths = None
1705
+ ... availablemasks = None
1706
+ ... initinfo = None
1707
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
1708
+ ... value = 200.0
1709
+ >>> sm = SoilMoisture(None)
1710
+ >>> sm.average_values()
1711
+ 200.0
1712
+
1713
+ When the dimensionality of this class is increased to one, applying method
1714
+ |Variable.average_values| results in the following error:
1715
+
1716
+ >>> SoilMoisture.NDIM = 1
1717
+ >>> import numpy
1718
+ >>> SoilMoisture.shape = (3,)
1719
+ >>> SoilMoisture.value = numpy.array([200.0, 400.0, 500.0])
1720
+ >>> sm.average_values()
1721
+ Traceback (most recent call last):
1722
+ ...
1723
+ AttributeError: While trying to calculate the mean value of variable \
1724
+ `soilmoisture`, the following error occurred: Variable `soilmoisture` does not define \
1725
+ any weighting coefficients.
1726
+
1727
+ So model developers have to define another (in this case 1-dimensional)
1728
+ |Variable| subclass (usually a |Parameter| subclass) and make the relevant
1729
+ object available via property |Variable.refweights|:
1730
+
1731
+ >>> class Area(Variable):
1732
+ ... NDIM = 1
1733
+ ... shape = (3,)
1734
+ ... value = numpy.array([1.0, 1.0, 2.0])
1735
+ ... initinfo = None
1736
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
1737
+ >>> area = Area(None)
1738
+ >>> SoilMoisture.refweights = property(lambda self: area)
1739
+ >>> sm.average_values()
1740
+ 400.0
1741
+
1742
+ In the examples above, all single entries of `values` are relevant, which is
1743
+ the default case. However, subclasses of |Variable| can define an alternative
1744
+ mask, allowing to make some entries irrelevant. Assume, for example, that our
1745
+ `SoilMoisture` object contains three single values, each one associated with a
1746
+ specific hydrological response unit (hru). To indicate that soil moisture is
1747
+ undefined for the third unit (maybe because it is a water area), we set the
1748
+ third entry of the verification mask to |False|:
1749
+
1750
+ >>> from hydpy.core.masktools import DefaultMask
1751
+ >>> class Soil(DefaultMask):
1752
+ ... @classmethod
1753
+ ... def new(cls, variable, **kwargs):
1754
+ ... return cls.array2mask([True, True, False])
1755
+ >>> SoilMoisture.mask = Soil()
1756
+ >>> sm.average_values()
1757
+ 300.0
1758
+
1759
+ Alternatively, method |Variable.average_values| accepts additional masking
1760
+ information as positional or keyword arguments. Therefore, the corresponding
1761
+ model must implement some alternative masks, which are provided by property
1762
+ |Variable.availablemasks|. We mock this property with a new |Masks| object,
1763
+ handling one mask for flat soils (only the first hru), one mask for deep soils
1764
+ (only the second hru), and one mask for water areas (only the third hru):
1765
+
1766
+ >>> class FlatSoil(DefaultMask):
1767
+ ... @classmethod
1768
+ ... def new(cls, variable, **kwargs):
1769
+ ... return cls.array2mask([True, False, False])
1770
+ >>> class DeepSoil(DefaultMask):
1771
+ ... @classmethod
1772
+ ... def new(cls, variable, **kwargs):
1773
+ ... return cls.array2mask([False, True, False])
1774
+ >>> class Water(DefaultMask):
1775
+ ... @classmethod
1776
+ ... def new(cls, variable, **kwargs):
1777
+ ... return cls.array2mask([False, False, True])
1778
+ >>> from hydpy.core import masktools
1779
+ >>> class Masks(masktools.Masks):
1780
+ ... CLASSES = (FlatSoil,
1781
+ ... DeepSoil,
1782
+ ... Water)
1783
+ >>> SoilMoisture.availablemasks = Masks()
1784
+
1785
+ One can pass either the mask classes themselves or their names:
1786
+
1787
+ >>> sm.average_values(sm.availablemasks.flatsoil)
1788
+ 200.0
1789
+ >>> sm.average_values("deepsoil")
1790
+ 400.0
1791
+
1792
+ Both variants can be combined:
1793
+
1794
+ >>> sm.average_values(sm.availablemasks.deepsoil, "flatsoil")
1795
+ 300.0
1796
+
1797
+ The following error happens if the general mask of the variable
1798
+ does not contain the given masks:
1799
+
1800
+ >>> sm.average_values("flatsoil", "water")
1801
+ Traceback (most recent call last):
1802
+ ...
1803
+ ValueError: While trying to calculate the mean value of variable \
1804
+ `soilmoisture`, the following error occurred: Based on the arguments \
1805
+ `('flatsoil', 'water')` and `{}` the mask `CustomMask([ True, False, True])` \
1806
+ has been determined, which is not a submask of `Soil([ True, True, False])`.
1807
+
1808
+ Applying masks with custom options is also supported. One can change the
1809
+ behaviour of the following mask via the argument `complete`:
1810
+
1811
+ >>> class AllOrNothing(DefaultMask):
1812
+ ... @classmethod
1813
+ ... def new(cls, variable, complete):
1814
+ ... if complete:
1815
+ ... bools = [True, True, True]
1816
+ ... else:
1817
+ ... bools = [False, False, False]
1818
+ ... return cls.array2mask(bools)
1819
+ >>> class Masks(Masks):
1820
+ ... CLASSES = (FlatSoil,
1821
+ ... DeepSoil,
1822
+ ... Water,
1823
+ ... AllOrNothing)
1824
+ >>> SoilMoisture.availablemasks = Masks()
1825
+
1826
+ Again, one can apply the mask class directly (but note that one has to pass the
1827
+ relevant variable as the first argument):
1828
+
1829
+ >>> sm.average_values( # doctest: +ELLIPSIS
1830
+ ... sm.availablemasks.allornothing(sm, complete=True))
1831
+ Traceback (most recent call last):
1832
+ ...
1833
+ ValueError: While trying to...
1834
+
1835
+ Alternatively, one can pass the mask name as a keyword and pack the mask's
1836
+ options into a |dict| object:
1837
+
1838
+ >>> sm.average_values(allornothing={"complete": False})
1839
+ nan
1840
+
1841
+ You can combine all variants explained above:
1842
+
1843
+ >>> sm.average_values("deepsoil", flatsoil={}, allornothing={"complete": False})
1844
+ 300.0
1845
+ """
1846
+ try:
1847
+ if self.NDIM == 0:
1848
+ return self.value
1849
+ mask = self.get_submask(*args, **kwargs)
1850
+ if numpy.any(mask):
1851
+ weights = self.refweights[mask]
1852
+ values = self.valuevector[mask]
1853
+ return float(numpy.sum(weights * values) / numpy.sum(weights))
1854
+ return numpy.nan
1855
+ except BaseException:
1856
+ objecttools.augment_excmessage(
1857
+ f"While trying to calculate the mean value of variable "
1858
+ f"{objecttools.devicephrase(self)}"
1859
+ )
1860
+
1861
+ @property
1862
+ def availablemasks(self) -> masktools.Masks:
1863
+ """For |ModelSequence| objects, a |Masks| object provided by the corresponding
1864
+ |Model| object; for |NodeSequence| object, a suitable |DefaultMask|.
1865
+
1866
+ >>> from hydpy.core.testtools import prepare_full_example_2
1867
+ >>> hp, pub, TestIO = prepare_full_example_2()
1868
+
1869
+ >>> hp.elements["land_dill_assl"].model.parameters.control.fc.availablemasks
1870
+ complete of module hydpy.models.hland.hland_masks
1871
+ land of module hydpy.models.hland.hland_masks
1872
+ upperzone of module hydpy.models.hland.hland_masks
1873
+ snow of module hydpy.models.hland.hland_masks
1874
+ soil of module hydpy.models.hland.hland_masks
1875
+ field of module hydpy.models.hland.hland_masks
1876
+ forest of module hydpy.models.hland.hland_masks
1877
+ ilake of module hydpy.models.hland.hland_masks
1878
+ glacier of module hydpy.models.hland.hland_masks
1879
+ sealed of module hydpy.models.hland.hland_masks
1880
+ noglacier of module hydpy.models.hland.hland_masks
1881
+
1882
+ >>> hp.nodes.dill_assl.sequences.sim.availablemasks
1883
+ defaultmask of module hydpy.core.masktools
1884
+ """
1885
+ model = getattr(self.subvars.vars, "model", None)
1886
+ if model:
1887
+ return model.masks
1888
+ return self.subvars.vars.masks
1889
+
1890
+ def get_submask(
1891
+ self, *args, **kwargs
1892
+ ) -> masktools.CustomMask | masktools.DefaultMask:
1893
+ """Get a sub-mask of the mask handled by the actual |Variable| object based on
1894
+ the given arguments.
1895
+
1896
+ See the documentation on method |Variable.average_values| for further
1897
+ information.
1898
+ """
1899
+ if args or kwargs:
1900
+ masks = self.availablemasks
1901
+ mask = masktools.CustomMask(numpy.full(self.shape, False))
1902
+ for arg in args:
1903
+ mask = mask + self._prepare_mask(arg, masks)
1904
+ for key, value in kwargs.items():
1905
+ mask = mask + self._prepare_mask(key, masks, **value)
1906
+ if mask not in self.mask:
1907
+ raise ValueError(
1908
+ f"Based on the arguments `{args}` and `{kwargs}` the mask "
1909
+ f"`{repr(mask)}` has been determined, which is not a submask of "
1910
+ f"`{repr(self.mask)}`."
1911
+ )
1912
+ return mask
1913
+ return self.mask
1914
+
1915
+ def _prepare_mask(self, mask, masks, **kwargs):
1916
+ mask = masks[mask]
1917
+ if inspect.isclass(mask):
1918
+ return mask(self, **kwargs)
1919
+ return mask
1920
+
1921
+ def __deepcopy__(self, memo):
1922
+ new = type(self)(None)
1923
+ for key, value in vars(self).items():
1924
+ if key not in self._NOT_DEEPCOPYABLE_MEMBERS:
1925
+ setattr(new, key, copy.deepcopy(value, memo))
1926
+ if self.NDIM:
1927
+ new.shape = self.shape
1928
+ new.value = self.value
1929
+ return new
1930
+
1931
+ def __getitem__(self, key):
1932
+ try:
1933
+ if self.NDIM:
1934
+ return self.value[key]
1935
+ self._check_key(key)
1936
+ return self.value
1937
+ except BaseException:
1938
+ objecttools.augment_excmessage(
1939
+ f"While trying to access the value(s) of variable "
1940
+ f"{objecttools.devicephrase(self)} with key `{key}`"
1941
+ )
1942
+
1943
+ def __setitem__(self, key, value):
1944
+ try:
1945
+ if self.NDIM:
1946
+ self.value[key] = value
1947
+ else:
1948
+ self._check_key(key)
1949
+ self.value = value
1950
+ except BaseException:
1951
+ objecttools.augment_excmessage(
1952
+ f"While trying to set the value(s) of variable "
1953
+ f"{objecttools.devicephrase(self)} with key `{key}`"
1954
+ )
1955
+
1956
+ @staticmethod
1957
+ def _check_key(key):
1958
+ if key not in (0, slice(None, None, None)):
1959
+ raise IndexError(
1960
+ "The only allowed keys for 0-dimensional variables are `0` and `:`."
1961
+ )
1962
+
1963
+ def __len__(self) -> int:
1964
+ if self.NDIM == 0:
1965
+ raise TypeError(
1966
+ f"The `len` operator was applied on {objecttools.devicephrase(self)}, "
1967
+ f"but this variable is 0-dimensional and thus unsized. Consider "
1968
+ f"using the `numberofvalues` property instead."
1969
+ )
1970
+ return self._get_shape()[0]
1971
+
1972
+ def _do_math(self, other, methodname, description):
1973
+ try:
1974
+ if hasattr(type(other), "_get_value"):
1975
+ value = other.value
1976
+ else:
1977
+ value = other
1978
+ result = getattr(self.value, methodname)(value)
1979
+ if (result is NotImplemented) and (not self.NDIM) and (self.TYPE is int):
1980
+ result = getattr(float(self.value), methodname)(value)
1981
+ return result
1982
+ except BaseException:
1983
+ objecttools.augment_excmessage(
1984
+ f"While trying to {description} variable "
1985
+ f"{objecttools.devicephrase(self)} and `{type(other).__name__}` "
1986
+ f"instance `{objecttools.repr_(other)}`"
1987
+ )
1988
+
1989
+ def __add__(self, other):
1990
+ return self._do_math(other, "__add__", "add")
1991
+
1992
+ def __radd__(self, other):
1993
+ return self._do_math(other, "__radd__", "add")
1994
+
1995
+ def __iadd__(self, other):
1996
+ self.value = self._do_math(other, "__add__", "add")
1997
+ return self
1998
+
1999
+ def __sub__(self, other):
2000
+ return self._do_math(other, "__sub__", "subtract")
2001
+
2002
+ def __rsub__(self, other):
2003
+ return self._do_math(other, "__rsub__", "subtract")
2004
+
2005
+ def __isub__(self, other):
2006
+ self.value = self._do_math(other, "__sub__", "subtract")
2007
+ return self
2008
+
2009
+ def __mul__(self, other):
2010
+ return self._do_math(other, "__mul__", "multiply")
2011
+
2012
+ def __rmul__(self, other):
2013
+ return self._do_math(other, "__rmul__", "multiply")
2014
+
2015
+ def __imul__(self, other):
2016
+ self.value = self._do_math(other, "__mul__", "multiply")
2017
+ return self
2018
+
2019
+ def __truediv__(self, other):
2020
+ return self._do_math(other, "__truediv__", "divide")
2021
+
2022
+ def __rtruediv__(self, other):
2023
+ return self._do_math(other, "__rtruediv__", "divide")
2024
+
2025
+ def __itruediv__(self, other):
2026
+ self.value = self._do_math(other, "__truediv__", "divide")
2027
+ return self
2028
+
2029
+ def __floordiv__(self, other):
2030
+ return self._do_math(other, "__floordiv__", "floor divide")
2031
+
2032
+ def __rfloordiv__(self, other):
2033
+ return self._do_math(other, "__rfloordiv__", "floor divide")
2034
+
2035
+ def __ifloordiv__(self, other):
2036
+ self.value = self._do_math(other, "__floordiv__", "floor divide")
2037
+ return self
2038
+
2039
+ def __mod__(self, other):
2040
+ return self._do_math(other, "__mod__", "mod divide")
2041
+
2042
+ def __rmod__(self, other):
2043
+ return self._do_math(other, "__rmod__", "mod divide")
2044
+
2045
+ def __imod__(self, other):
2046
+ self.value = self._do_math(other, "__mod__", "mod divide")
2047
+ return self
2048
+
2049
+ def __divmod__(self, other):
2050
+ return self.__floordiv__(other), self.__mod__(other)
2051
+
2052
+ def __rdivmod__(self, other):
2053
+ return self.__rfloordiv__(other), self.__rmod__(other)
2054
+
2055
+ def __pow__(self, other):
2056
+ return self._do_math(other, "__pow__", "exponentiate")
2057
+
2058
+ def __rpow__(self, other):
2059
+ return self._do_math(other, "__rpow__", "exponentiate (reflectively)")
2060
+
2061
+ def __ipow__(self, other):
2062
+ self.value = self._do_math(other, "__pow__", "exponentiate")
2063
+ return self
2064
+
2065
+ def __pos__(self):
2066
+ return +self.value
2067
+
2068
+ def __neg__(self):
2069
+ return -self.value
2070
+
2071
+ def __abs__(self):
2072
+ return abs(self.value)
2073
+
2074
+ def __invert__(self):
2075
+ return 1.0 / self.value
2076
+
2077
+ def __floor__(self):
2078
+ result = self.value // 1.0
2079
+ try:
2080
+ return int(result)
2081
+ except TypeError:
2082
+ return numpy.array(result, dtype=config.NP_INT)
2083
+
2084
+ def __ceil__(self):
2085
+ result = numpy.ceil(self.value)
2086
+ try:
2087
+ return int(result)
2088
+ except TypeError:
2089
+ return numpy.array(result, dtype=config.NP_INT)
2090
+
2091
+ def _compare(
2092
+ self,
2093
+ other: object,
2094
+ comparefunc: Callable,
2095
+ callingfunc: Literal["lt", "le", "eq", "ne", "ge", "gt"],
2096
+ ) -> bool:
2097
+ try:
2098
+ vs1 = self._get_value()
2099
+ if isinstance(other, Variable):
2100
+ vs2 = other._get_value() # pylint: disable=protected-access
2101
+ else:
2102
+ vs2 = numpy.asarray(other)
2103
+ if self.NDIM == 0:
2104
+ if numpy.isnan(vs1) and bool(numpy.isnan(vs2)):
2105
+ if callingfunc in ("le", "eq", "ge"):
2106
+ return True
2107
+ return False
2108
+ return comparefunc(vs1, vs2)
2109
+ try:
2110
+ idxs = ~(numpy.isnan(vs1) * numpy.isnan(vs2))
2111
+ except BaseException as exc:
2112
+ if callingfunc == "eq":
2113
+ return False
2114
+ if callingfunc == "ne":
2115
+ return True
2116
+ raise exc
2117
+ if numpy.sum(idxs) == 0:
2118
+ if callingfunc in ("le", "eq", "ge"):
2119
+ return True
2120
+ return False
2121
+ return comparefunc(vs1, vs2)[idxs]
2122
+ except BaseException:
2123
+ objecttools.augment_excmessage(
2124
+ f"While trying to compare variable {objecttools.elementphrase(self)} "
2125
+ f"with object `{other}` of type `{type(other).__name__}`"
2126
+ )
2127
+
2128
+ def __lt__(self, other: Variable | float) -> bool:
2129
+ return bool(
2130
+ numpy.all(
2131
+ self._compare(
2132
+ other=other,
2133
+ comparefunc=lambda vs1, vs2: vs1 < vs2,
2134
+ callingfunc="lt",
2135
+ )
2136
+ )
2137
+ )
2138
+
2139
+ def __le__(self, other: Variable | float) -> bool:
2140
+ return bool(
2141
+ numpy.all(
2142
+ self._compare(
2143
+ other=other,
2144
+ comparefunc=lambda vs1, vs2: vs1 <= vs2,
2145
+ callingfunc="le",
2146
+ )
2147
+ )
2148
+ )
2149
+
2150
+ def __eq__(self, other: object) -> bool:
2151
+ if self is other:
2152
+ return True
2153
+ return bool(
2154
+ numpy.all(
2155
+ self._compare(
2156
+ other=other,
2157
+ comparefunc=lambda vs1, vs2: vs1 == vs2,
2158
+ callingfunc="eq",
2159
+ )
2160
+ )
2161
+ )
2162
+
2163
+ def __ne__(self, other: object) -> bool:
2164
+ return bool(
2165
+ numpy.any(
2166
+ self._compare(
2167
+ other=other,
2168
+ comparefunc=lambda vs1, vs2: vs1 != vs2,
2169
+ callingfunc="ne",
2170
+ )
2171
+ )
2172
+ )
2173
+
2174
+ def __ge__(self, other: Variable | float) -> bool:
2175
+ return bool(
2176
+ numpy.all(
2177
+ self._compare(
2178
+ other=other,
2179
+ comparefunc=lambda vs1, vs2: vs1 >= vs2,
2180
+ callingfunc="ge",
2181
+ )
2182
+ )
2183
+ )
2184
+
2185
+ def __gt__(self, other: Variable | float) -> bool:
2186
+ return bool(
2187
+ numpy.all(
2188
+ self._compare(
2189
+ other=other,
2190
+ comparefunc=lambda vs1, vs2: vs1 > vs2,
2191
+ callingfunc="gt",
2192
+ )
2193
+ )
2194
+ )
2195
+
2196
+ def _typeconversion(self, type_):
2197
+ if self.NDIM:
2198
+ raise TypeError(
2199
+ f"The variable {objecttools.devicephrase(self)} is "
2200
+ f"{self.NDIM}-dimensional and thus cannot be converted "
2201
+ f"to a scalar {type_.__name__} value."
2202
+ )
2203
+ return type_(self.value)
2204
+
2205
+ def __bool__(self) -> bool:
2206
+ if self.NDIM == 0:
2207
+ return bool(self.value)
2208
+ return self.numberofvalues > 0
2209
+
2210
+ def __float__(self) -> float:
2211
+ return self._typeconversion(float)
2212
+
2213
+ def __int__(self) -> int:
2214
+ return self._typeconversion(int)
2215
+
2216
+ def __round__(self, ndigits: int = 0):
2217
+ return numpy.round(self.value, ndigits)
2218
+
2219
+ def __hash__(self) -> int:
2220
+ return id(self)
2221
+
2222
+ def __repr__(self) -> str:
2223
+ brackets = (self.NDIM == 2) and (self.shape[0] != 1)
2224
+ return to_repr(self, self.value, brackets)
2225
+
2226
+
2227
+ class MixinFixedShape:
2228
+ """Mixin class for defining variables with a fixed shape."""
2229
+
2230
+ SHAPE: tuple[int, ...]
2231
+ name: str
2232
+
2233
+ def _finalise_connections(self) -> None:
2234
+ super()._finalise_connections() # type: ignore[misc]
2235
+ self.shape = self.SHAPE
2236
+
2237
+ def _get_shape(self) -> tuple[int, ...]:
2238
+ """Variables that mix in |MixinFixedShape| are generally initialised with a
2239
+ fixed shape.
2240
+
2241
+ We take parameter |kinw_control.BV| of base model |kinw| and sequence
2242
+ |exch_factors.WaterLevels| of base model |exch| as examples:
2243
+
2244
+ >>> from hydpy import prepare_model
2245
+ >>> prepare_model("kinw").parameters.control.bv.shape
2246
+ (2,)
2247
+ >>> waterlevels = prepare_model("exch").sequences.factors.waterlevels
2248
+ >>> waterlevels.shape
2249
+ (2,)
2250
+
2251
+ If we try to set a new shape, |MixinFixedShape| responds with the following
2252
+ exceptions:
2253
+
2254
+ >>> waterlevels.shape = 2
2255
+ Traceback (most recent call last):
2256
+ ...
2257
+ AttributeError: The shape of variable `waterlevels` cannot be changed but \
2258
+ this was attempted for element `?`.
2259
+
2260
+ See the documentation on property |Variable.shape| of class |Variable| for
2261
+ further information.
2262
+ """
2263
+ return super()._get_shape() # type: ignore[misc]
2264
+
2265
+ def _set_shape(self, shape: int | tuple[int, ...]) -> None:
2266
+ oldshape = exceptiontools.getattr_(self, "shape", None)
2267
+ if oldshape is None:
2268
+ super()._set_shape(shape) # type: ignore[misc]
2269
+ elif shape != oldshape:
2270
+ raise AttributeError(
2271
+ f"The shape of variable `{self.name}` cannot be changed but this was "
2272
+ f"attempted for element `{objecttools.devicename(self)}`."
2273
+ )
2274
+
2275
+ shape = propertytools.Property(fget=_get_shape, fset=_set_shape)
2276
+
2277
+
2278
+ @overload
2279
+ def sort_variables(
2280
+ values: Iterable[type[TypeVariable_co]],
2281
+ ) -> tuple[type[TypeVariable_co], ...]: ...
2282
+
2283
+
2284
+ @overload
2285
+ def sort_variables(
2286
+ values: Iterable[tuple[type[TypeVariable_co], T]],
2287
+ ) -> tuple[tuple[type[TypeVariable_co], T], ...]: ...
2288
+
2289
+
2290
+ def sort_variables(
2291
+ values: Iterable[type[TypeVariable] | tuple[type[TypeVariable], T]],
2292
+ ) -> tuple[type[TypeVariable] | tuple[type[TypeVariable], T], ...]:
2293
+ """Sort the given |Variable| subclasses by their initialisation order.
2294
+
2295
+ When defined in one module, the initialisation order corresponds to the order
2296
+ within the file:
2297
+
2298
+ >>> from hydpy import classname, sort_variables
2299
+ >>> from hydpy.models.hland.hland_control import Area, NmbZones, ZoneType
2300
+ >>> from hydpy import classname
2301
+ >>> for var in sort_variables([NmbZones, ZoneType, Area]):
2302
+ ... print(classname(var))
2303
+ Area
2304
+ NmbZones
2305
+ ZoneType
2306
+
2307
+ When defined in multiple modules, alphabetical sorting of the modules' filepaths
2308
+ takes priority:
2309
+
2310
+ >>> from hydpy.models.evap.evap_control import NmbHRU, ExcessReduction
2311
+ >>> for var in sort_variables([NmbZones, ZoneType, Area, NmbHRU, ExcessReduction]):
2312
+ ... print(classname(var))
2313
+ NmbHRU
2314
+ ExcessReduction
2315
+ Area
2316
+ NmbZones
2317
+ ZoneType
2318
+
2319
+ Function |sort_variables| also supports sorting tuples. Each first entry must be
2320
+ a |Variable| subclass:
2321
+
2322
+ >>> for var, i in sort_variables([(NmbZones, 1), (ZoneType, 2), (Area, 3)]):
2323
+ ... print(classname(var), i)
2324
+ Area 3
2325
+ NmbZones 1
2326
+ ZoneType 2
2327
+
2328
+ >>> for var, i in sort_variables([(NmbZones, 1), (ZoneType, 2), (Area, 3)]):
2329
+ ... print(classname(var), i)
2330
+ Area 3
2331
+ NmbZones 1
2332
+ ZoneType 2
2333
+
2334
+ |sort_variables| does not remove duplicates:
2335
+
2336
+ >>> for var, i in sort_variables([(Area, 3), (ZoneType, 2), (Area, 1), (Area, 3)]):
2337
+ ... print(classname(var), i)
2338
+ Area 1
2339
+ Area 3
2340
+ Area 3
2341
+ ZoneType 2
2342
+ """
2343
+ modulepath_position_value = []
2344
+ for value in values:
2345
+ variable = value[0] if isinstance(value, tuple) else value
2346
+ modulepath = variable.__module__
2347
+ position = variable.__hydpy__subclasscounter__
2348
+ modulepath_position_value.append((modulepath, position, value))
2349
+ return tuple(value for _, _, value in sorted(modulepath_position_value))
2350
+
2351
+
2352
+ class SubVariables(Generic[TypeGroup_co, TypeVariable_co, TypeFastAccess_co]):
2353
+ """Base class for |SubParameters| and |SubSequences|.
2354
+
2355
+ Each subclass of class |SubVariables| is thought for handling a certain group of
2356
+ |Parameter| or |Sequence_| objects. One specific example is subclass
2357
+ |sequencetools.InputSequences|, collecting all |InputSequence| objects of a
2358
+ specific hydrological model.
2359
+
2360
+ For the following examples, we first prepare a (not fully functional) |Variable|
2361
+ subclass:
2362
+
2363
+ >>> from hydpy.core.variabletools import FastAccess, SubVariables, Variable
2364
+ >>> class TestVar(Variable):
2365
+ ... NDIM = 0
2366
+ ... TYPE = float
2367
+ ... initinfo = 0.0, False
2368
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
2369
+
2370
+ Out test |SubVariables| subclass is thought to handle only this
2371
+ single |Variable| subclass, indicated by putting it into the
2372
+ |tuple| class attribute `CLASSES`:
2373
+
2374
+ >>> class SubVars(SubVariables):
2375
+ ... CLASSES = (TestVar,)
2376
+ ... name = "subvars"
2377
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
2378
+
2379
+
2380
+ After initialisation, |SubVariables| objects reference their master object (either
2381
+ a |Parameters| or a |Sequences| object), passed to their constructor. However, in
2382
+ our simple test example, we just passed a string instead:
2383
+
2384
+ >>> subvars = SubVars("test")
2385
+ >>> subvars.vars
2386
+ 'test'
2387
+
2388
+ The string representation lists all available variables and uses question marks to
2389
+ indicate cases where their values are not readily available:
2390
+
2391
+ >>> subvars
2392
+ testvar(?)
2393
+
2394
+ Class |SubVariables| provides attribute access to the handled |Variable| objects
2395
+ and protects |Variable| objects from accidental overwriting:
2396
+
2397
+ >>> subvars.testvar = 3.0
2398
+ >>> subvars.testvar
2399
+ testvar(3.0)
2400
+
2401
+ Trying to query not available |Variable| objects (or other attributes) results in
2402
+ the following error message:
2403
+
2404
+ >>> subvars.wrong
2405
+ Traceback (most recent call last):
2406
+ ...
2407
+ AttributeError: Collection object `subvars` does neither handle a \
2408
+ variable nor another attribute named wrong.
2409
+
2410
+ Class |SubVariables| protects only the handled |Variable| objects from overwriting
2411
+ with unplausible data:
2412
+
2413
+ >>> subvars.vars = "wrong"
2414
+ >>> subvars.vars
2415
+ 'wrong'
2416
+
2417
+ >>> subvars.testvar = "wrong"
2418
+ Traceback (most recent call last):
2419
+ ...
2420
+ ValueError: While trying to set the value(s) of variable `testvar`, the following \
2421
+ error occurred: 5 values are assigned to the scalar variable `testvar`.
2422
+
2423
+ Alternatively, you can item-access a variable:
2424
+
2425
+ >>> subvars["testvar"]
2426
+ testvar(3.0)
2427
+
2428
+ >>> subvars["wrong"]
2429
+ Traceback (most recent call last):
2430
+ ...
2431
+ AttributeError: Collection object `subvars` does not handle a variable named \
2432
+ `wrong`.
2433
+
2434
+ Class |SubVariables| supporte iteration and the application of the |len| operator:
2435
+
2436
+ >>> for variable in subvars:
2437
+ ... print(variable.name)
2438
+ testvar
2439
+ >>> len(subvars)
2440
+ 1
2441
+ """
2442
+
2443
+ CLASSES: tuple[type[TypeVariable_co], ...]
2444
+ vars: TypeGroup_co
2445
+ _name2variable: dict[str, TypeVariable_co] = {}
2446
+ fastaccess: TypeFastAccess_co
2447
+ _cls_fastaccess: type[TypeFastAccess_co] | None = None
2448
+ _CLS_FASTACCESS_PYTHON: ClassVar[type[TypeFastAccess_co]] # type: ignore[misc]
2449
+
2450
+ def __init__(
2451
+ self,
2452
+ master: TypeGroup_co,
2453
+ cls_fastaccess: type[TypeFastAccess_co] | None = None,
2454
+ ):
2455
+ self.vars = master
2456
+ if cls_fastaccess:
2457
+ self._cls_fastaccess = cls_fastaccess
2458
+ self._init_fastaccess()
2459
+ self._name2variable = {}
2460
+ for cls in self.CLASSES:
2461
+ variable = cls(self)
2462
+ self._name2variable[variable.name] = variable
2463
+ variable.__hydpy__connect_variable2subgroup__()
2464
+
2465
+ @property
2466
+ @abc.abstractmethod
2467
+ def name(self) -> str:
2468
+ """To be overridden."""
2469
+
2470
+ @functools.cached_property
2471
+ def names(self) -> frozenset:
2472
+ """The names of all handled variables."""
2473
+ return frozenset(self._name2variable)
2474
+
2475
+ def _init_fastaccess(self) -> None:
2476
+ """Create a `fastaccess` attribute and build the required connections to the
2477
+ related cythonized model eventually."""
2478
+ if (self._cls_fastaccess is None) or (self._cymodel is None):
2479
+ self.fastaccess = self._CLS_FASTACCESS_PYTHON()
2480
+ else:
2481
+ self.fastaccess = self._cls_fastaccess()
2482
+
2483
+ def __getitem__(self, item) -> TypeVariable_co:
2484
+ try:
2485
+ return self._name2variable[item]
2486
+ except KeyError:
2487
+ raise AttributeError(
2488
+ f"Collection object {objecttools.devicephrase(self)} does not handle "
2489
+ f"a variable named `{item}`."
2490
+ ) from None
2491
+
2492
+ def __getattr__(self, name) -> TypeVariable_co:
2493
+ try:
2494
+ return self._name2variable[name]
2495
+ except KeyError:
2496
+ raise AttributeError(
2497
+ f"Collection object {objecttools.devicephrase(self)} does neither "
2498
+ f"handle a variable nor another attribute named {name}."
2499
+ ) from None
2500
+
2501
+ def __setattr__(self, name, value):
2502
+ variable = self._name2variable.get(name)
2503
+ if variable is None:
2504
+ super().__setattr__(name, value)
2505
+ else:
2506
+ variable._set_value(value)
2507
+
2508
+ def __iter__(self) -> Iterator[TypeVariable_co]:
2509
+ yield from self._name2variable.values()
2510
+
2511
+ def __len__(self) -> int:
2512
+ return len(self.CLASSES)
2513
+
2514
+ def __bool__(self) -> bool:
2515
+ return bool(self.CLASSES)
2516
+
2517
+ def __repr__(self) -> str:
2518
+ lines = []
2519
+ for variable in self:
2520
+ try:
2521
+ lines.append(repr(variable))
2522
+ except BaseException:
2523
+ lines.append(f"{variable.name}(?)")
2524
+ return "\n".join(lines)
2525
+
2526
+ def __dir__(self) -> list[str]:
2527
+ """
2528
+ >>> from hydpy.core.variabletools import SubVariables, Variable
2529
+ >>> class TestVar(Variable):
2530
+ ... NDIM = 0
2531
+ ... TYPE = float
2532
+ ... initinfo = 0.0, False
2533
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
2534
+ >>> class TestSubVars(SubVariables):
2535
+ ... CLASSES = (TestVar,)
2536
+ ... name = None
2537
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
2538
+ >>> testsubvars = TestSubVars(None)
2539
+ >>> sorted(set(dir(testsubvars)) - set(object.__dir__(testsubvars)))
2540
+ ['testvar']
2541
+ """
2542
+ return cast(list[str], super().__dir__()) + list(self._name2variable.keys())
2543
+
2544
+
2545
+ def to_repr(self: Variable, values, brackets: bool = False) -> str:
2546
+ """Return a valid string representation for the given |Variable| object.
2547
+
2548
+ Function |to_repr| is thought for internal purposes only, more specifically for
2549
+ defining string representations of subclasses of class |Variable| like the
2550
+ following:
2551
+
2552
+ >>> from hydpy.core.variabletools import to_repr, Variable
2553
+ >>> class Var(Variable):
2554
+ ... NDIM = 0
2555
+ ... TYPE = int
2556
+ ... initinfo = 1.0, False
2557
+ ... _CLS_FASTACCESS_PYTHON = FastAccess
2558
+ >>> var = Var(None)
2559
+ >>> var.value = 2
2560
+ >>> var
2561
+ var(2)
2562
+
2563
+ The following examples demonstrate all covered cases. Note that option `brackets`
2564
+ allows choosing between a "vararg" and an "iterable" string representation for
2565
+ multidimensional variables:
2566
+
2567
+ >>> print(to_repr(var, 2))
2568
+ var(2)
2569
+
2570
+ >>> Var.NDIM = 1
2571
+ >>> var = Var(None)
2572
+ >>> var.shape = 3
2573
+ >>> print(to_repr(var, range(3)))
2574
+ var(0, 1, 2)
2575
+ >>> print(to_repr(var, range(3), True))
2576
+ var([0, 1, 2])
2577
+ >>> print(to_repr(var, range(30)))
2578
+ var(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
2579
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29)
2580
+ >>> print(to_repr(var, range(30), True))
2581
+ var([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
2582
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
2583
+
2584
+ >>> Var.NDIM = 2
2585
+ >>> var = Var(None)
2586
+ >>> var.shape = (2, 3)
2587
+ >>> print(to_repr(var, [range(3), range(3, 6)]))
2588
+ var(0, 1, 2,
2589
+ 3, 4, 5)
2590
+ >>> print(to_repr(var, [range(3), range(3, 6)], True))
2591
+ var([[0, 1, 2],
2592
+ [3, 4, 5]])
2593
+ >>> print(to_repr(var, [range(30), range(30, 60)], True))
2594
+ var([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
2595
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
2596
+ [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
2597
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]])
2598
+ >>> print(to_repr(var, [range(30), range(30, 60)]))
2599
+ var(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
2600
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
2601
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
2602
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59)
2603
+ """
2604
+ prefix = f"{self.name}("
2605
+ if isinstance(values, str):
2606
+ return f"{self.name}({values})"
2607
+ if self.NDIM == 0:
2608
+ return f"{self.name}({objecttools.repr_(values)})"
2609
+ if self.NDIM == 1:
2610
+ if brackets:
2611
+ return objecttools.assignrepr_list(values, prefix, 72) + ")"
2612
+ return objecttools.assignrepr_values(values, prefix, 72) + ")"
2613
+ if brackets:
2614
+ return objecttools.assignrepr_list2(values, prefix, 72) + ")"
2615
+ return objecttools.assignrepr_values2(values, prefix, 72) + ")"