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.
- hydpy/__init__.py +275 -0
- hydpy/aliases.py +2554 -0
- hydpy/auxs/__init__.py +0 -0
- hydpy/auxs/anntools.py +1305 -0
- hydpy/auxs/armatools.py +883 -0
- hydpy/auxs/calibtools.py +3337 -0
- hydpy/auxs/interptools.py +1094 -0
- hydpy/auxs/iuhtools.py +543 -0
- hydpy/auxs/networktools.py +597 -0
- hydpy/auxs/ppolytools.py +809 -0
- hydpy/auxs/quadtools.py +61 -0
- hydpy/auxs/roottools.py +228 -0
- hydpy/auxs/smoothtools.py +273 -0
- hydpy/auxs/statstools.py +2125 -0
- hydpy/auxs/validtools.py +81 -0
- hydpy/conf/HydPyConfigBase.xsd +68637 -0
- hydpy/conf/HydPyConfigBase.xsdt +358 -0
- hydpy/conf/HydPyConfigMultipleRuns.xsd +25 -0
- hydpy/conf/HydPyConfigSingleRun.xsd +24 -0
- hydpy/conf/__init__.py +0 -0
- hydpy/conf/a_coefficients_explicit_lobatto_sequence.npy +0 -0
- hydpy/conf/support_points_for_smoothpar_logistic2.npy +0 -0
- hydpy/config.py +42 -0
- hydpy/core/__init__.py +0 -0
- hydpy/core/aliastools.py +214 -0
- hydpy/core/autodoctools.py +1947 -0
- hydpy/core/auxfiletools.py +1169 -0
- hydpy/core/devicetools.py +3810 -0
- hydpy/core/exceptiontools.py +269 -0
- hydpy/core/filetools.py +1985 -0
- hydpy/core/hydpytools.py +3089 -0
- hydpy/core/importtools.py +1398 -0
- hydpy/core/indextools.py +345 -0
- hydpy/core/itemtools.py +1849 -0
- hydpy/core/masktools.py +460 -0
- hydpy/core/modeltools.py +4868 -0
- hydpy/core/netcdftools.py +2683 -0
- hydpy/core/objecttools.py +2023 -0
- hydpy/core/optiontools.py +1045 -0
- hydpy/core/parametertools.py +4674 -0
- hydpy/core/printtools.py +222 -0
- hydpy/core/propertytools.py +643 -0
- hydpy/core/pubtools.py +254 -0
- hydpy/core/selectiontools.py +1571 -0
- hydpy/core/sequencetools.py +4476 -0
- hydpy/core/seriestools.py +339 -0
- hydpy/core/testtools.py +2483 -0
- hydpy/core/timetools.py +3567 -0
- hydpy/core/typingtools.py +333 -0
- hydpy/core/variabletools.py +2615 -0
- hydpy/cythons/__init__.py +24 -0
- hydpy/cythons/annutils.pxd +33 -0
- hydpy/cythons/annutils.pyi +25 -0
- hydpy/cythons/annutils.pyx +120 -0
- hydpy/cythons/autogen/__init__.py +0 -0
- hydpy/cythons/autogen/annutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/annutils.pxd +42 -0
- hydpy/cythons/autogen/annutils.pyx +129 -0
- hydpy/cythons/autogen/c_arma.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_arma.pxd +179 -0
- hydpy/cythons/autogen/c_arma.pyx +356 -0
- hydpy/cythons/autogen/c_arma_rimorido.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_arma_rimorido.pxd +179 -0
- hydpy/cythons/autogen/c_arma_rimorido.pyx +356 -0
- hydpy/cythons/autogen/c_conv.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_conv.pxd +198 -0
- hydpy/cythons/autogen/c_conv.pyx +491 -0
- hydpy/cythons/autogen/c_conv_idw.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_conv_idw.pxd +124 -0
- hydpy/cythons/autogen/c_conv_idw.pyx +264 -0
- hydpy/cythons/autogen/c_conv_idw_ed.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_conv_idw_ed.pxd +197 -0
- hydpy/cythons/autogen/c_conv_idw_ed.pyx +481 -0
- hydpy/cythons/autogen/c_conv_nn.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_conv_nn.pxd +120 -0
- hydpy/cythons/autogen/c_conv_nn.pyx +224 -0
- hydpy/cythons/autogen/c_dam.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam.pxd +805 -0
- hydpy/cythons/autogen/c_dam.pyx +1477 -0
- hydpy/cythons/autogen/c_dam_llake.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_llake.pxd +364 -0
- hydpy/cythons/autogen/c_dam_llake.pyx +705 -0
- hydpy/cythons/autogen/c_dam_lreservoir.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_lreservoir.pxd +365 -0
- hydpy/cythons/autogen/c_dam_lreservoir.pyx +708 -0
- hydpy/cythons/autogen/c_dam_lretention.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_lretention.pxd +340 -0
- hydpy/cythons/autogen/c_dam_lretention.pyx +625 -0
- hydpy/cythons/autogen/c_dam_pump.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_pump.pxd +402 -0
- hydpy/cythons/autogen/c_dam_pump.pyx +724 -0
- hydpy/cythons/autogen/c_dam_pump_sluice.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_pump_sluice.pxd +452 -0
- hydpy/cythons/autogen/c_dam_pump_sluice.pyx +829 -0
- hydpy/cythons/autogen/c_dam_sluice.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_sluice.pxd +404 -0
- hydpy/cythons/autogen/c_dam_sluice.pyx +726 -0
- hydpy/cythons/autogen/c_dam_v001.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v001.pxd +452 -0
- hydpy/cythons/autogen/c_dam_v001.pyx +816 -0
- hydpy/cythons/autogen/c_dam_v002.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v002.pxd +394 -0
- hydpy/cythons/autogen/c_dam_v002.pyx +703 -0
- hydpy/cythons/autogen/c_dam_v003.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v003.pxd +417 -0
- hydpy/cythons/autogen/c_dam_v003.pyx +744 -0
- hydpy/cythons/autogen/c_dam_v004.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v004.pxd +486 -0
- hydpy/cythons/autogen/c_dam_v004.pyx +891 -0
- hydpy/cythons/autogen/c_dam_v005.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v005.pxd +524 -0
- hydpy/cythons/autogen/c_dam_v005.pyx +928 -0
- hydpy/cythons/autogen/c_dummy.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy.pxd +151 -0
- hydpy/cythons/autogen/c_dummy.pyx +263 -0
- hydpy/cythons/autogen/c_dummy_interceptedwater.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_interceptedwater.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_interceptedwater.pyx +104 -0
- hydpy/cythons/autogen/c_dummy_node2node.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_node2node.pxd +89 -0
- hydpy/cythons/autogen/c_dummy_node2node.pyx +148 -0
- hydpy/cythons/autogen/c_dummy_snowalbedo.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_snowalbedo.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_snowalbedo.pyx +104 -0
- hydpy/cythons/autogen/c_dummy_snowcover.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_snowcover.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_snowcover.pyx +104 -0
- hydpy/cythons/autogen/c_dummy_snowycanopy.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_snowycanopy.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_snowycanopy.pyx +104 -0
- hydpy/cythons/autogen/c_dummy_soilwater.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_soilwater.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_soilwater.pyx +104 -0
- hydpy/cythons/autogen/c_evap.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap.pxd +1029 -0
- hydpy/cythons/autogen/c_evap.pyx +2601 -0
- hydpy/cythons/autogen/c_evap_aet_hbv96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_aet_hbv96.pxd +227 -0
- hydpy/cythons/autogen/c_evap_aet_hbv96.pyx +584 -0
- hydpy/cythons/autogen/c_evap_aet_minhas.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_aet_minhas.pxd +193 -0
- hydpy/cythons/autogen/c_evap_aet_minhas.pyx +478 -0
- hydpy/cythons/autogen/c_evap_aet_morsim.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_aet_morsim.pxd +681 -0
- hydpy/cythons/autogen/c_evap_aet_morsim.pyx +1642 -0
- hydpy/cythons/autogen/c_evap_pet_ambav1.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_pet_ambav1.pxd +532 -0
- hydpy/cythons/autogen/c_evap_pet_ambav1.pyx +1296 -0
- hydpy/cythons/autogen/c_evap_pet_hbv96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_pet_hbv96.pxd +179 -0
- hydpy/cythons/autogen/c_evap_pet_hbv96.pyx +328 -0
- hydpy/cythons/autogen/c_evap_pet_m.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_pet_m.pxd +124 -0
- hydpy/cythons/autogen/c_evap_pet_m.pyx +214 -0
- hydpy/cythons/autogen/c_evap_pet_mlc.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_pet_mlc.pxd +126 -0
- hydpy/cythons/autogen/c_evap_pet_mlc.pyx +214 -0
- hydpy/cythons/autogen/c_evap_ret_fao56.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_ret_fao56.pxd +305 -0
- hydpy/cythons/autogen/c_evap_ret_fao56.pyx +624 -0
- hydpy/cythons/autogen/c_evap_ret_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_ret_io.pxd +112 -0
- hydpy/cythons/autogen/c_evap_ret_io.pyx +176 -0
- hydpy/cythons/autogen/c_evap_ret_tw2002.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_ret_tw2002.pxd +139 -0
- hydpy/cythons/autogen/c_evap_ret_tw2002.pyx +273 -0
- hydpy/cythons/autogen/c_exch.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_exch.pxd +230 -0
- hydpy/cythons/autogen/c_exch.pyx +462 -0
- hydpy/cythons/autogen/c_exch_branch_hbv96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_exch_branch_hbv96.pxd +134 -0
- hydpy/cythons/autogen/c_exch_branch_hbv96.pyx +255 -0
- hydpy/cythons/autogen/c_exch_waterlevel.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_exch_waterlevel.pxd +54 -0
- hydpy/cythons/autogen/c_exch_waterlevel.pyx +78 -0
- hydpy/cythons/autogen/c_exch_weir_hbv96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_exch_weir_hbv96.pxd +156 -0
- hydpy/cythons/autogen/c_exch_weir_hbv96.pyx +282 -0
- hydpy/cythons/autogen/c_ga.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_ga.pxd +353 -0
- hydpy/cythons/autogen/c_ga.pyx +1204 -0
- hydpy/cythons/autogen/c_ga_garto.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_ga_garto.pxd +330 -0
- hydpy/cythons/autogen/c_ga_garto.pyx +1105 -0
- hydpy/cythons/autogen/c_ga_garto_submodel1.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_ga_garto_submodel1.pxd +236 -0
- hydpy/cythons/autogen/c_ga_garto_submodel1.pyx +944 -0
- hydpy/cythons/autogen/c_gland.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_gland.pxd +437 -0
- hydpy/cythons/autogen/c_gland.pyx +726 -0
- hydpy/cythons/autogen/c_gland_gr4.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_gland_gr4.pxd +382 -0
- hydpy/cythons/autogen/c_gland_gr4.pyx +605 -0
- hydpy/cythons/autogen/c_gland_gr5.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_gland_gr5.pxd +368 -0
- hydpy/cythons/autogen/c_gland_gr5.pyx +568 -0
- hydpy/cythons/autogen/c_gland_gr6.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_gland_gr6.pxd +420 -0
- hydpy/cythons/autogen/c_gland_gr6.pyx +673 -0
- hydpy/cythons/autogen/c_hland.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_hland.pxd +855 -0
- hydpy/cythons/autogen/c_hland.pyx +2486 -0
- hydpy/cythons/autogen/c_hland_96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_hland_96.pxd +631 -0
- hydpy/cythons/autogen/c_hland_96.pyx +1724 -0
- hydpy/cythons/autogen/c_hland_96c.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_hland_96c.pxd +621 -0
- hydpy/cythons/autogen/c_hland_96c.pyx +1822 -0
- hydpy/cythons/autogen/c_hland_96p.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_hland_96p.pxd +683 -0
- hydpy/cythons/autogen/c_hland_96p.pyx +1911 -0
- hydpy/cythons/autogen/c_kinw.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_kinw.pxd +509 -0
- hydpy/cythons/autogen/c_kinw.pyx +965 -0
- hydpy/cythons/autogen/c_kinw_williams.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_kinw_williams.pxd +409 -0
- hydpy/cythons/autogen/c_kinw_williams.pyx +763 -0
- hydpy/cythons/autogen/c_kinw_williams_ext.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_kinw_williams_ext.pxd +220 -0
- hydpy/cythons/autogen/c_kinw_williams_ext.pyx +440 -0
- hydpy/cythons/autogen/c_lland.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_lland.pxd +1386 -0
- hydpy/cythons/autogen/c_lland.pyx +3679 -0
- hydpy/cythons/autogen/c_lland_dd.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_lland_dd.pxd +679 -0
- hydpy/cythons/autogen/c_lland_dd.pyx +1719 -0
- hydpy/cythons/autogen/c_lland_knauf.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_lland_knauf.pxd +1096 -0
- hydpy/cythons/autogen/c_lland_knauf.pyx +2784 -0
- hydpy/cythons/autogen/c_lland_knauf_ic.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_lland_knauf_ic.pxd +1369 -0
- hydpy/cythons/autogen/c_lland_knauf_ic.pyx +3625 -0
- hydpy/cythons/autogen/c_meteo.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo.pxd +469 -0
- hydpy/cythons/autogen/c_meteo.pyx +879 -0
- hydpy/cythons/autogen/c_meteo_clear_glob_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_clear_glob_io.pxd +75 -0
- hydpy/cythons/autogen/c_meteo_clear_glob_io.pyx +107 -0
- hydpy/cythons/autogen/c_meteo_glob_fao56.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_glob_fao56.pxd +209 -0
- hydpy/cythons/autogen/c_meteo_glob_fao56.pyx +339 -0
- hydpy/cythons/autogen/c_meteo_glob_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_glob_io.pxd +63 -0
- hydpy/cythons/autogen/c_meteo_glob_io.pyx +91 -0
- hydpy/cythons/autogen/c_meteo_glob_morsim.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_glob_morsim.pxd +289 -0
- hydpy/cythons/autogen/c_meteo_glob_morsim.pyx +527 -0
- hydpy/cythons/autogen/c_meteo_precip_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_precip_io.pxd +112 -0
- hydpy/cythons/autogen/c_meteo_precip_io.pyx +176 -0
- hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.pxd +87 -0
- hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.pyx +123 -0
- hydpy/cythons/autogen/c_meteo_sun_fao56.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_sun_fao56.pxd +209 -0
- hydpy/cythons/autogen/c_meteo_sun_fao56.pyx +343 -0
- hydpy/cythons/autogen/c_meteo_sun_morsim.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_sun_morsim.pxd +286 -0
- hydpy/cythons/autogen/c_meteo_sun_morsim.pyx +519 -0
- hydpy/cythons/autogen/c_meteo_temp_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_temp_io.pxd +112 -0
- hydpy/cythons/autogen/c_meteo_temp_io.pyx +176 -0
- hydpy/cythons/autogen/c_musk.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_musk.pxd +282 -0
- hydpy/cythons/autogen/c_musk.pyx +605 -0
- hydpy/cythons/autogen/c_musk_classic.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_musk_classic.pxd +138 -0
- hydpy/cythons/autogen/c_musk_classic.pyx +226 -0
- hydpy/cythons/autogen/c_musk_mct.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_musk_mct.pxd +282 -0
- hydpy/cythons/autogen/c_musk_mct.pyx +609 -0
- hydpy/cythons/autogen/c_rconc.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_rconc.pxd +119 -0
- hydpy/cythons/autogen/c_rconc.pyx +174 -0
- hydpy/cythons/autogen/c_rconc_nash.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_rconc_nash.pxd +111 -0
- hydpy/cythons/autogen/c_rconc_nash.pyx +185 -0
- hydpy/cythons/autogen/c_rconc_uh.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_rconc_uh.pxd +92 -0
- hydpy/cythons/autogen/c_rconc_uh.pyx +125 -0
- hydpy/cythons/autogen/c_sw1d.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d.pxd +511 -0
- hydpy/cythons/autogen/c_sw1d.pyx +1263 -0
- hydpy/cythons/autogen/c_sw1d_channel.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_channel.pxd +119 -0
- hydpy/cythons/autogen/c_sw1d_channel.pyx +300 -0
- hydpy/cythons/autogen/c_sw1d_gate_out.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_gate_out.pxd +240 -0
- hydpy/cythons/autogen/c_sw1d_gate_out.pyx +476 -0
- hydpy/cythons/autogen/c_sw1d_lias.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_lias.pxd +320 -0
- hydpy/cythons/autogen/c_sw1d_lias.pyx +619 -0
- hydpy/cythons/autogen/c_sw1d_lias_sluice.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_lias_sluice.pxd +325 -0
- hydpy/cythons/autogen/c_sw1d_lias_sluice.pyx +644 -0
- hydpy/cythons/autogen/c_sw1d_network.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_network.pxd +90 -0
- hydpy/cythons/autogen/c_sw1d_network.pyx +246 -0
- hydpy/cythons/autogen/c_sw1d_pump.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_pump.pxd +256 -0
- hydpy/cythons/autogen/c_sw1d_pump.pyx +502 -0
- hydpy/cythons/autogen/c_sw1d_q_in.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_q_in.pxd +224 -0
- hydpy/cythons/autogen/c_sw1d_q_in.pyx +383 -0
- hydpy/cythons/autogen/c_sw1d_q_out.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_q_out.pxd +224 -0
- hydpy/cythons/autogen/c_sw1d_q_out.pyx +383 -0
- hydpy/cythons/autogen/c_sw1d_storage.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_storage.pxd +193 -0
- hydpy/cythons/autogen/c_sw1d_storage.pyx +349 -0
- hydpy/cythons/autogen/c_sw1d_weir_out.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_weir_out.pxd +212 -0
- hydpy/cythons/autogen/c_sw1d_weir_out.pyx +404 -0
- hydpy/cythons/autogen/c_test.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_test.pxd +175 -0
- hydpy/cythons/autogen/c_test.pyx +348 -0
- hydpy/cythons/autogen/c_test_discontinous.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_test_discontinous.pxd +146 -0
- hydpy/cythons/autogen/c_test_discontinous.pyx +256 -0
- hydpy/cythons/autogen/c_test_stiff0d.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_test_stiff0d.pxd +146 -0
- hydpy/cythons/autogen/c_test_stiff0d.pyx +250 -0
- hydpy/cythons/autogen/c_test_stiff1d.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_test_stiff1d.pxd +145 -0
- hydpy/cythons/autogen/c_test_stiff1d.pyx +294 -0
- hydpy/cythons/autogen/c_whmod.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_whmod.pxd +482 -0
- hydpy/cythons/autogen/c_whmod.pyx +1156 -0
- hydpy/cythons/autogen/c_whmod_rural.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_whmod_rural.pxd +411 -0
- hydpy/cythons/autogen/c_whmod_rural.pyx +982 -0
- hydpy/cythons/autogen/c_whmod_urban.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_whmod_urban.pxd +482 -0
- hydpy/cythons/autogen/c_whmod_urban.pyx +1155 -0
- hydpy/cythons/autogen/c_wland.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wland.pxd +842 -0
- hydpy/cythons/autogen/c_wland.pyx +1890 -0
- hydpy/cythons/autogen/c_wland_gd.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wland_gd.pxd +829 -0
- hydpy/cythons/autogen/c_wland_gd.pyx +1847 -0
- hydpy/cythons/autogen/c_wland_wag.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wland_wag.pxd +810 -0
- hydpy/cythons/autogen/c_wland_wag.pyx +1780 -0
- hydpy/cythons/autogen/c_wq.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wq.pxd +275 -0
- hydpy/cythons/autogen/c_wq.pyx +652 -0
- hydpy/cythons/autogen/c_wq_trapeze.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wq_trapeze.pxd +170 -0
- hydpy/cythons/autogen/c_wq_trapeze.pyx +400 -0
- hydpy/cythons/autogen/c_wq_trapeze_strickler.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wq_trapeze_strickler.pxd +243 -0
- hydpy/cythons/autogen/c_wq_trapeze_strickler.pyx +578 -0
- hydpy/cythons/autogen/c_wq_walrus.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wq_walrus.pxd +61 -0
- hydpy/cythons/autogen/c_wq_walrus.pyx +82 -0
- hydpy/cythons/autogen/configutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/configutils.pxd +17 -0
- hydpy/cythons/autogen/configutils.pyx +119 -0
- hydpy/cythons/autogen/interfaceutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/interfaceutils.pxd +31 -0
- hydpy/cythons/autogen/interfaceutils.pyx +82 -0
- hydpy/cythons/autogen/interputils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/interputils.pxd +42 -0
- hydpy/cythons/autogen/interputils.pyx +118 -0
- hydpy/cythons/autogen/masterinterface.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/masterinterface.pxd +153 -0
- hydpy/cythons/autogen/masterinterface.pyx +222 -0
- hydpy/cythons/autogen/pointerutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/pointerutils.pxd +31 -0
- hydpy/cythons/autogen/pointerutils.pyx +650 -0
- hydpy/cythons/autogen/ppolyutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/ppolyutils.pxd +35 -0
- hydpy/cythons/autogen/ppolyutils.pyx +59 -0
- hydpy/cythons/autogen/quadutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/quadutils.pxd +26 -0
- hydpy/cythons/autogen/quadutils.pyx +973 -0
- hydpy/cythons/autogen/rootutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/rootutils.pxd +28 -0
- hydpy/cythons/autogen/rootutils.pyx +109 -0
- hydpy/cythons/autogen/sequenceutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/sequenceutils.pxd +45 -0
- hydpy/cythons/autogen/sequenceutils.pyx +101 -0
- hydpy/cythons/autogen/smoothutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/smoothutils.pxd +29 -0
- hydpy/cythons/autogen/smoothutils.pyx +833 -0
- hydpy/cythons/configutils.pxd +8 -0
- hydpy/cythons/configutils.pyi +5 -0
- hydpy/cythons/configutils.pyx +110 -0
- hydpy/cythons/interfaceutils.pxd +22 -0
- hydpy/cythons/interfaceutils.pyi +15 -0
- hydpy/cythons/interfaceutils.pyx +73 -0
- hydpy/cythons/interputils.pxd +33 -0
- hydpy/cythons/interputils.pyi +32 -0
- hydpy/cythons/interputils.pyx +109 -0
- hydpy/cythons/modelutils.py +2990 -0
- hydpy/cythons/pointerutils.pxd +22 -0
- hydpy/cythons/pointerutils.pyi +89 -0
- hydpy/cythons/pointerutils.pyx +641 -0
- hydpy/cythons/ppolyutils.pxd +26 -0
- hydpy/cythons/ppolyutils.pyi +21 -0
- hydpy/cythons/ppolyutils.pyx +50 -0
- hydpy/cythons/quadutils.pxd +17 -0
- hydpy/cythons/quadutils.pyi +13 -0
- hydpy/cythons/quadutils.pyx +964 -0
- hydpy/cythons/rootutils.pxd +19 -0
- hydpy/cythons/rootutils.pyi +21 -0
- hydpy/cythons/rootutils.pyx +100 -0
- hydpy/cythons/sequenceutils.pxd +36 -0
- hydpy/cythons/sequenceutils.pyi +7 -0
- hydpy/cythons/sequenceutils.pyx +92 -0
- hydpy/cythons/smoothutils.pxd +20 -0
- hydpy/cythons/smoothutils.pyi +15 -0
- hydpy/cythons/smoothutils.pyx +824 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_dill_assl.py +13 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_kalk.py +13 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_leun.py +14 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_marb.py +13 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_dill_assl_lahn_leun.py +5 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_lahn_leun_lahn_kalk.py +5 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_lahn_marb_lahn_leun.py +5 -0
- hydpy/data/HydPy-H-Lahn/control/default/land.py +9 -0
- hydpy/data/HydPy-H-Lahn/control/default/land_dill_assl.py +57 -0
- hydpy/data/HydPy-H-Lahn/control/default/land_lahn_kalk.py +57 -0
- hydpy/data/HydPy-H-Lahn/control/default/land_lahn_leun.py +56 -0
- hydpy/data/HydPy-H-Lahn/control/default/land_lahn_marb.py +57 -0
- hydpy/data/HydPy-H-Lahn/control/default/stream_dill_assl_lahn_leun.py +7 -0
- hydpy/data/HydPy-H-Lahn/control/default/stream_lahn_leun_lahn_kalk.py +7 -0
- hydpy/data/HydPy-H-Lahn/control/default/stream_lahn_marb_lahn_leun.py +7 -0
- hydpy/data/HydPy-H-Lahn/multiple_runs.xml +309 -0
- hydpy/data/HydPy-H-Lahn/multiple_runs_alpha.xml +71 -0
- hydpy/data/HydPy-H-Lahn/network/default/headwaters.py +11 -0
- hydpy/data/HydPy-H-Lahn/network/default/nonheadwaters.py +11 -0
- hydpy/data/HydPy-H-Lahn/network/default/streams.py +8 -0
- hydpy/data/HydPy-H-Lahn/series/default/dill_assl_obs_q.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/evap_pet_hbv96_input_normalairtemperature.nc +0 -0
- hydpy/data/HydPy-H-Lahn/series/default/evap_pet_hbv96_input_normalevapotranspiration.nc +0 -0
- hydpy/data/HydPy-H-Lahn/series/default/hland_96_input_p.nc +0 -0
- hydpy/data/HydPy-H-Lahn/series/default/hland_96_input_t.nc +0 -0
- hydpy/data/HydPy-H-Lahn/series/default/lahn_kalk_obs_q.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/lahn_leun_obs_q.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/lahn_marb_obs_q.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_hland_96_input_p.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_hland_96_input_t.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_hland_96_input_p.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_hland_96_input_t.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_hland_96_input_p.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_hland_96_input_t.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_hland_96_input_p.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_hland_96_input_t.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/obs_q.nc +0 -0
- hydpy/data/HydPy-H-Lahn/single_run.xml +152 -0
- hydpy/data/HydPy-H-Lahn/single_run.xmlt +143 -0
- hydpy/data/__init__.py +17 -0
- hydpy/docs/__init__.py +0 -0
- hydpy/docs/autofigs/__init__.py +0 -0
- hydpy/docs/bib/__init__.py +0 -0
- hydpy/docs/bib/refs.bib +566 -0
- hydpy/docs/combine_docversions.py +133 -0
- hydpy/docs/draw_model_sketches.py +1301 -0
- hydpy/docs/enable_autodoc.py +7 -0
- hydpy/docs/figs/HydPy-G-GR4.png +0 -0
- hydpy/docs/figs/HydPy-G-GR5.png +0 -0
- hydpy/docs/figs/HydPy-G-GR6.png +0 -0
- hydpy/docs/figs/HydPy-H-HBV96-COSERO.png +0 -0
- hydpy/docs/figs/HydPy-H-HBV96-PREVAH.png +0 -0
- hydpy/docs/figs/HydPy-H-HBV96.png +0 -0
- hydpy/docs/figs/HydPy-H-Lahn.png +0 -0
- hydpy/docs/figs/HydPy-KinW-Williams.png +0 -0
- hydpy/docs/figs/HydPy-L-DD.png +0 -0
- hydpy/docs/figs/HydPy-W-Wag.png +0 -0
- hydpy/docs/figs/HydPy_Logo.png +0 -0
- hydpy/docs/figs/HydPy_Logo_Text.png +0 -0
- hydpy/docs/figs/IDLE-editor.png +0 -0
- hydpy/docs/figs/IDLE-shell.png +0 -0
- hydpy/docs/figs/LAWA_river-basin-bumbers.png +0 -0
- hydpy/docs/figs/__init__.py +0 -0
- hydpy/docs/html_/__init__.py +0 -0
- hydpy/docs/polish_html.py +57 -0
- hydpy/docs/prepare.py +224 -0
- hydpy/docs/publish_docs.py +53 -0
- hydpy/docs/rst/HydPy-ARMA.rst +27 -0
- hydpy/docs/rst/HydPy-Conv.rst +22 -0
- hydpy/docs/rst/HydPy-Dam.rst +79 -0
- hydpy/docs/rst/HydPy-Dummy.rst +21 -0
- hydpy/docs/rst/HydPy-Evap.rst +26 -0
- hydpy/docs/rst/HydPy-Exch.rst +36 -0
- hydpy/docs/rst/HydPy-G.rst +40 -0
- hydpy/docs/rst/HydPy-GA.rst +34 -0
- hydpy/docs/rst/HydPy-H.rst +24 -0
- hydpy/docs/rst/HydPy-KinW.rst +32 -0
- hydpy/docs/rst/HydPy-L.rst +42 -0
- hydpy/docs/rst/HydPy-Meteo.rst +28 -0
- hydpy/docs/rst/HydPy-Musk.rst +21 -0
- hydpy/docs/rst/HydPy-Rconc.rst +17 -0
- hydpy/docs/rst/HydPy-SW1D.rst +49 -0
- hydpy/docs/rst/HydPy-Test.rst +19 -0
- hydpy/docs/rst/HydPy-W.rst +20 -0
- hydpy/docs/rst/HydPy-WHMod.rst +19 -0
- hydpy/docs/rst/HydPy-WQ.rst +20 -0
- hydpy/docs/rst/__init__.py +0 -0
- hydpy/docs/rst/additional_repositories.rst +40 -0
- hydpy/docs/rst/auxiliaries.rst +31 -0
- hydpy/docs/rst/continuous_integration.rst +75 -0
- hydpy/docs/rst/core.rst +75 -0
- hydpy/docs/rst/cythons.rst +47 -0
- hydpy/docs/rst/definitions.rst +506 -0
- hydpy/docs/rst/developer_guide.rst +54 -0
- hydpy/docs/rst/example_projects.rst +40 -0
- hydpy/docs/rst/execution.rst +22 -0
- hydpy/docs/rst/framework_tools.rst +56 -0
- hydpy/docs/rst/how_to_read_the_reference_manual.rst +156 -0
- hydpy/docs/rst/hydpydependencies.rst +55 -0
- hydpy/docs/rst/index.rst +125 -0
- hydpy/docs/rst/installation.rst +155 -0
- hydpy/docs/rst/model_families.rst +79 -0
- hydpy/docs/rst/model_overview.rst +291 -0
- hydpy/docs/rst/modelimports.rst +10 -0
- hydpy/docs/rst/options.rst +119 -0
- hydpy/docs/rst/programming_style.rst +572 -0
- hydpy/docs/rst/project_structure.rst +520 -0
- hydpy/docs/rst/quickstart.rst +304 -0
- hydpy/docs/rst/reference_manual.rst +29 -0
- hydpy/docs/rst/required_tools.rst +50 -0
- hydpy/docs/rst/simulation.rst +514 -0
- hydpy/docs/rst/submodel_interfaces.rst +32 -0
- hydpy/docs/rst/tests_and_documentation.rst +85 -0
- hydpy/docs/rst/user_guide.rst +38 -0
- hydpy/docs/rst/version_control.rst +116 -0
- hydpy/docs/rst/zbibliography.rst +8 -0
- hydpy/docs/sphinx/__init__.py +0 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/changes/frameset.html +11 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/changes/rstsource.html +15 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/changes/versionchanges.html +33 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/defindex.html +35 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/domainindex.html +56 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/genindex-single.html +63 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/genindex-split.html +41 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/genindex.html +76 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/globaltoc.html +11 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/layout.html +221 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/localtoc.html +15 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/opensearch.xml +13 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/page.html +13 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/relations.html +23 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/search.html +65 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/searchbox.html +21 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/searchfield.html +23 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/sourcelink.html +18 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/basic.css_t +925 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/doctools.js +156 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/documentation_options.js_t +13 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/file.png +0 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/language_data.js_t +26 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/minus.png +0 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/plus.png +0 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/searchtools.js +574 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/sphinx_highlight.js +154 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/theme.conf +16 -0
- hydpy/docs/sphinx/_themes/classic_hydpy/layout.html +23 -0
- hydpy/docs/sphinx/_themes/classic_hydpy/static/classic.css_t +358 -0
- hydpy/docs/sphinx/_themes/classic_hydpy/static/sidebar.js_t +72 -0
- hydpy/docs/sphinx/_themes/classic_hydpy/theme.conf +32 -0
- hydpy/docs/sphinx/conf.py +398 -0
- hydpy/docs/sphinx/defaultlinks_extension.py +36 -0
- hydpy/docs/sphinx/integrationtest_extension.py +104 -0
- hydpy/docs/sphinx/projectstructure_extension.py +58 -0
- hydpy/docs/sphinx/submodelgraph_extension.py +53 -0
- hydpy/exe/__init__.py +0 -0
- hydpy/exe/commandtools.py +651 -0
- hydpy/exe/hyd.py +277 -0
- hydpy/exe/modelimports.py +41 -0
- hydpy/exe/replacetools.py +216 -0
- hydpy/exe/servertools.py +2348 -0
- hydpy/exe/xmltools.py +3280 -0
- hydpy/interfaces/__init__.py +0 -0
- hydpy/interfaces/aetinterfaces.py +94 -0
- hydpy/interfaces/dischargeinterfaces.py +45 -0
- hydpy/interfaces/petinterfaces.py +117 -0
- hydpy/interfaces/precipinterfaces.py +42 -0
- hydpy/interfaces/radiationinterfaces.py +79 -0
- hydpy/interfaces/rconcinterfaces.py +30 -0
- hydpy/interfaces/routinginterfaces.py +324 -0
- hydpy/interfaces/soilinterfaces.py +96 -0
- hydpy/interfaces/stateinterfaces.py +98 -0
- hydpy/interfaces/tempinterfaces.py +46 -0
- hydpy/models/__init__.py +0 -0
- hydpy/models/arma/__init__.py +14 -0
- hydpy/models/arma/arma_control.py +383 -0
- hydpy/models/arma/arma_derived.py +204 -0
- hydpy/models/arma/arma_fluxes.py +41 -0
- hydpy/models/arma/arma_inlets.py +11 -0
- hydpy/models/arma/arma_logs.py +19 -0
- hydpy/models/arma/arma_model.py +461 -0
- hydpy/models/arma/arma_outlets.py +11 -0
- hydpy/models/arma_rimorido.py +381 -0
- hydpy/models/conv/__init__.py +12 -0
- hydpy/models/conv/conv_control.py +303 -0
- hydpy/models/conv/conv_derived.py +271 -0
- hydpy/models/conv/conv_fluxes.py +54 -0
- hydpy/models/conv/conv_inlets.py +11 -0
- hydpy/models/conv/conv_model.py +687 -0
- hydpy/models/conv/conv_outlets.py +11 -0
- hydpy/models/conv_idw.py +120 -0
- hydpy/models/conv_idw_ed.py +184 -0
- hydpy/models/conv_nn.py +112 -0
- hydpy/models/dam/__init__.py +16 -0
- hydpy/models/dam/dam_aides.py +17 -0
- hydpy/models/dam/dam_control.py +346 -0
- hydpy/models/dam/dam_derived.py +559 -0
- hydpy/models/dam/dam_factors.py +46 -0
- hydpy/models/dam/dam_fluxes.py +179 -0
- hydpy/models/dam/dam_inlets.py +29 -0
- hydpy/models/dam/dam_logs.py +52 -0
- hydpy/models/dam/dam_model.py +5011 -0
- hydpy/models/dam/dam_outlets.py +23 -0
- hydpy/models/dam/dam_receivers.py +41 -0
- hydpy/models/dam/dam_senders.py +23 -0
- hydpy/models/dam/dam_solver.py +75 -0
- hydpy/models/dam/dam_states.py +11 -0
- hydpy/models/dam_llake.py +499 -0
- hydpy/models/dam_lreservoir.py +548 -0
- hydpy/models/dam_lretention.py +343 -0
- hydpy/models/dam_pump.py +278 -0
- hydpy/models/dam_pump_sluice.py +339 -0
- hydpy/models/dam_sluice.py +319 -0
- hydpy/models/dam_v001.py +1127 -0
- hydpy/models/dam_v002.py +381 -0
- hydpy/models/dam_v003.py +422 -0
- hydpy/models/dam_v004.py +665 -0
- hydpy/models/dam_v005.py +479 -0
- hydpy/models/dummy/__init__.py +15 -0
- hydpy/models/dummy/dummy_control.py +22 -0
- hydpy/models/dummy/dummy_fluxes.py +11 -0
- hydpy/models/dummy/dummy_inlets.py +11 -0
- hydpy/models/dummy/dummy_inputs.py +41 -0
- hydpy/models/dummy/dummy_model.py +196 -0
- hydpy/models/dummy/dummy_outlets.py +11 -0
- hydpy/models/dummy_interceptedwater.py +85 -0
- hydpy/models/dummy_node2node.py +83 -0
- hydpy/models/dummy_snowalbedo.py +84 -0
- hydpy/models/dummy_snowcover.py +84 -0
- hydpy/models/dummy_snowycanopy.py +86 -0
- hydpy/models/dummy_soilwater.py +85 -0
- hydpy/models/evap/__init__.py +13 -0
- hydpy/models/evap/evap_control.py +354 -0
- hydpy/models/evap/evap_derived.py +236 -0
- hydpy/models/evap/evap_factors.py +188 -0
- hydpy/models/evap/evap_fixed.py +68 -0
- hydpy/models/evap/evap_fluxes.py +150 -0
- hydpy/models/evap/evap_inputs.py +54 -0
- hydpy/models/evap/evap_logs.py +91 -0
- hydpy/models/evap/evap_masks.py +48 -0
- hydpy/models/evap/evap_model.py +9170 -0
- hydpy/models/evap/evap_parameters.py +149 -0
- hydpy/models/evap/evap_sequences.py +32 -0
- hydpy/models/evap/evap_states.py +18 -0
- hydpy/models/evap_aet_hbv96.py +372 -0
- hydpy/models/evap_aet_minhas.py +331 -0
- hydpy/models/evap_aet_morsim.py +627 -0
- hydpy/models/evap_pet_ambav1.py +483 -0
- hydpy/models/evap_pet_hbv96.py +147 -0
- hydpy/models/evap_pet_m.py +94 -0
- hydpy/models/evap_pet_mlc.py +107 -0
- hydpy/models/evap_ret_fao56.py +265 -0
- hydpy/models/evap_ret_io.py +74 -0
- hydpy/models/evap_ret_tw2002.py +165 -0
- hydpy/models/exch/__init__.py +14 -0
- hydpy/models/exch/exch_control.py +262 -0
- hydpy/models/exch/exch_derived.py +36 -0
- hydpy/models/exch/exch_factors.py +26 -0
- hydpy/models/exch/exch_fluxes.py +48 -0
- hydpy/models/exch/exch_inlets.py +11 -0
- hydpy/models/exch/exch_logs.py +12 -0
- hydpy/models/exch/exch_model.py +451 -0
- hydpy/models/exch/exch_outlets.py +17 -0
- hydpy/models/exch/exch_receivers.py +17 -0
- hydpy/models/exch_branch_hbv96.py +186 -0
- hydpy/models/exch_waterlevel.py +73 -0
- hydpy/models/exch_weir_hbv96.py +609 -0
- hydpy/models/ga/__init__.py +14 -0
- hydpy/models/ga/ga_aides.py +17 -0
- hydpy/models/ga/ga_control.py +208 -0
- hydpy/models/ga/ga_derived.py +77 -0
- hydpy/models/ga/ga_fluxes.py +83 -0
- hydpy/models/ga/ga_inputs.py +26 -0
- hydpy/models/ga/ga_logs.py +17 -0
- hydpy/models/ga/ga_model.py +2952 -0
- hydpy/models/ga/ga_states.py +87 -0
- hydpy/models/ga_garto.py +1001 -0
- hydpy/models/ga_garto_submodel1.py +79 -0
- hydpy/models/gland/__init__.py +14 -0
- hydpy/models/gland/gland_control.py +90 -0
- hydpy/models/gland/gland_derived.py +113 -0
- hydpy/models/gland/gland_fluxes.py +137 -0
- hydpy/models/gland/gland_inputs.py +12 -0
- hydpy/models/gland/gland_model.py +1439 -0
- hydpy/models/gland/gland_outlets.py +11 -0
- hydpy/models/gland/gland_states.py +90 -0
- hydpy/models/gland_gr4.py +501 -0
- hydpy/models/gland_gr5.py +463 -0
- hydpy/models/gland_gr6.py +487 -0
- hydpy/models/hland/__init__.py +20 -0
- hydpy/models/hland/hland_aides.py +19 -0
- hydpy/models/hland/hland_constants.py +37 -0
- hydpy/models/hland/hland_control.py +1530 -0
- hydpy/models/hland/hland_derived.py +683 -0
- hydpy/models/hland/hland_factors.py +57 -0
- hydpy/models/hland/hland_fixed.py +42 -0
- hydpy/models/hland/hland_fluxes.py +279 -0
- hydpy/models/hland/hland_inputs.py +19 -0
- hydpy/models/hland/hland_masks.py +107 -0
- hydpy/models/hland/hland_model.py +4664 -0
- hydpy/models/hland/hland_outlets.py +11 -0
- hydpy/models/hland/hland_parameters.py +227 -0
- hydpy/models/hland/hland_sequences.py +382 -0
- hydpy/models/hland/hland_states.py +236 -0
- hydpy/models/hland_96.py +1812 -0
- hydpy/models/hland_96c.py +1196 -0
- hydpy/models/hland_96p.py +1204 -0
- hydpy/models/kinw/__init__.py +18 -0
- hydpy/models/kinw/kinw_aides.py +306 -0
- hydpy/models/kinw/kinw_control.py +270 -0
- hydpy/models/kinw/kinw_derived.py +197 -0
- hydpy/models/kinw/kinw_fixed.py +33 -0
- hydpy/models/kinw/kinw_fluxes.py +37 -0
- hydpy/models/kinw/kinw_inlets.py +11 -0
- hydpy/models/kinw/kinw_model.py +3026 -0
- hydpy/models/kinw/kinw_outlets.py +11 -0
- hydpy/models/kinw/kinw_solver.py +45 -0
- hydpy/models/kinw/kinw_states.py +17 -0
- hydpy/models/kinw_williams.py +1299 -0
- hydpy/models/kinw_williams_ext.py +768 -0
- hydpy/models/lland/__init__.py +42 -0
- hydpy/models/lland/lland_aides.py +38 -0
- hydpy/models/lland/lland_constants.py +88 -0
- hydpy/models/lland/lland_control.py +1329 -0
- hydpy/models/lland/lland_derived.py +380 -0
- hydpy/models/lland/lland_factors.py +18 -0
- hydpy/models/lland/lland_fixed.py +128 -0
- hydpy/models/lland/lland_fluxes.py +626 -0
- hydpy/models/lland/lland_inlets.py +12 -0
- hydpy/models/lland/lland_inputs.py +33 -0
- hydpy/models/lland/lland_logs.py +17 -0
- hydpy/models/lland/lland_masks.py +212 -0
- hydpy/models/lland/lland_model.py +7690 -0
- hydpy/models/lland/lland_outlets.py +12 -0
- hydpy/models/lland/lland_parameters.py +195 -0
- hydpy/models/lland/lland_sequences.py +67 -0
- hydpy/models/lland/lland_states.py +280 -0
- hydpy/models/lland_dd.py +2270 -0
- hydpy/models/lland_knauf.py +2156 -0
- hydpy/models/lland_knauf_ic.py +1920 -0
- hydpy/models/meteo/__init__.py +12 -0
- hydpy/models/meteo/meteo_control.py +154 -0
- hydpy/models/meteo/meteo_derived.py +159 -0
- hydpy/models/meteo/meteo_factors.py +88 -0
- hydpy/models/meteo/meteo_fixed.py +19 -0
- hydpy/models/meteo/meteo_fluxes.py +46 -0
- hydpy/models/meteo/meteo_inputs.py +47 -0
- hydpy/models/meteo/meteo_logs.py +30 -0
- hydpy/models/meteo/meteo_model.py +2904 -0
- hydpy/models/meteo/meteo_parameters.py +14 -0
- hydpy/models/meteo/meteo_sequences.py +22 -0
- hydpy/models/meteo_clear_glob_io.py +77 -0
- hydpy/models/meteo_glob_fao56.py +217 -0
- hydpy/models/meteo_glob_io.py +68 -0
- hydpy/models/meteo_glob_morsim.py +444 -0
- hydpy/models/meteo_precip_io.py +76 -0
- hydpy/models/meteo_psun_sun_glob_io.py +83 -0
- hydpy/models/meteo_sun_fao56.py +188 -0
- hydpy/models/meteo_sun_morsim.py +466 -0
- hydpy/models/meteo_temp_io.py +76 -0
- hydpy/models/musk/__init__.py +15 -0
- hydpy/models/musk/musk_control.py +328 -0
- hydpy/models/musk/musk_derived.py +32 -0
- hydpy/models/musk/musk_factors.py +53 -0
- hydpy/models/musk/musk_fluxes.py +24 -0
- hydpy/models/musk/musk_inlets.py +11 -0
- hydpy/models/musk/musk_masks.py +15 -0
- hydpy/models/musk/musk_model.py +838 -0
- hydpy/models/musk/musk_outlets.py +11 -0
- hydpy/models/musk/musk_sequences.py +88 -0
- hydpy/models/musk/musk_solver.py +68 -0
- hydpy/models/musk/musk_states.py +64 -0
- hydpy/models/musk_classic.py +228 -0
- hydpy/models/musk_mct.py +1247 -0
- hydpy/models/rconc/__init__.py +12 -0
- hydpy/models/rconc/rconc_control.py +473 -0
- hydpy/models/rconc/rconc_derived.py +76 -0
- hydpy/models/rconc/rconc_fluxes.py +19 -0
- hydpy/models/rconc/rconc_logs.py +74 -0
- hydpy/models/rconc/rconc_model.py +260 -0
- hydpy/models/rconc/rconc_states.py +11 -0
- hydpy/models/rconc_nash.py +48 -0
- hydpy/models/rconc_uh.py +53 -0
- hydpy/models/sw1d/__init__.py +17 -0
- hydpy/models/sw1d/sw1d_control.py +356 -0
- hydpy/models/sw1d/sw1d_derived.py +85 -0
- hydpy/models/sw1d/sw1d_factors.py +78 -0
- hydpy/models/sw1d/sw1d_fixed.py +12 -0
- hydpy/models/sw1d/sw1d_fluxes.py +55 -0
- hydpy/models/sw1d/sw1d_inlets.py +17 -0
- hydpy/models/sw1d/sw1d_model.py +3385 -0
- hydpy/models/sw1d/sw1d_outlets.py +11 -0
- hydpy/models/sw1d/sw1d_receivers.py +11 -0
- hydpy/models/sw1d/sw1d_senders.py +11 -0
- hydpy/models/sw1d/sw1d_states.py +23 -0
- hydpy/models/sw1d_channel.py +2051 -0
- hydpy/models/sw1d_gate_out.py +599 -0
- hydpy/models/sw1d_lias.py +105 -0
- hydpy/models/sw1d_lias_sluice.py +531 -0
- hydpy/models/sw1d_network.py +1219 -0
- hydpy/models/sw1d_pump.py +448 -0
- hydpy/models/sw1d_q_in.py +79 -0
- hydpy/models/sw1d_q_out.py +81 -0
- hydpy/models/sw1d_storage.py +78 -0
- hydpy/models/sw1d_weir_out.py +75 -0
- hydpy/models/test/__init__.py +14 -0
- hydpy/models/test/test_control.py +28 -0
- hydpy/models/test/test_fluxes.py +17 -0
- hydpy/models/test/test_model.py +201 -0
- hydpy/models/test/test_solver.py +48 -0
- hydpy/models/test/test_states.py +17 -0
- hydpy/models/test_discontinous.py +46 -0
- hydpy/models/test_stiff0d.py +47 -0
- hydpy/models/test_stiff1d.py +42 -0
- hydpy/models/whmod/__init__.py +21 -0
- hydpy/models/whmod/whmod_constants.py +77 -0
- hydpy/models/whmod/whmod_control.py +333 -0
- hydpy/models/whmod/whmod_derived.py +210 -0
- hydpy/models/whmod/whmod_factors.py +9 -0
- hydpy/models/whmod/whmod_fluxes.py +105 -0
- hydpy/models/whmod/whmod_inputs.py +15 -0
- hydpy/models/whmod/whmod_masks.py +178 -0
- hydpy/models/whmod/whmod_model.py +2091 -0
- hydpy/models/whmod/whmod_parameters.py +155 -0
- hydpy/models/whmod/whmod_sequences.py +193 -0
- hydpy/models/whmod/whmod_states.py +73 -0
- hydpy/models/whmod_rural.py +794 -0
- hydpy/models/whmod_urban.py +1011 -0
- hydpy/models/wland/__init__.py +43 -0
- hydpy/models/wland/wland_aides.py +55 -0
- hydpy/models/wland/wland_constants.py +103 -0
- hydpy/models/wland/wland_control.py +508 -0
- hydpy/models/wland/wland_derived.py +330 -0
- hydpy/models/wland/wland_factors.py +11 -0
- hydpy/models/wland/wland_fixed.py +12 -0
- hydpy/models/wland/wland_fluxes.py +166 -0
- hydpy/models/wland/wland_inputs.py +33 -0
- hydpy/models/wland/wland_masks.py +54 -0
- hydpy/models/wland/wland_model.py +3755 -0
- hydpy/models/wland/wland_outlets.py +11 -0
- hydpy/models/wland/wland_parameters.py +214 -0
- hydpy/models/wland/wland_sequences.py +108 -0
- hydpy/models/wland/wland_solver.py +45 -0
- hydpy/models/wland/wland_states.py +56 -0
- hydpy/models/wland_gd.py +888 -0
- hydpy/models/wland_wag.py +1244 -0
- hydpy/models/wq/__init__.py +14 -0
- hydpy/models/wq/wq_control.py +117 -0
- hydpy/models/wq/wq_derived.py +182 -0
- hydpy/models/wq/wq_factors.py +79 -0
- hydpy/models/wq/wq_fluxes.py +17 -0
- hydpy/models/wq/wq_model.py +1889 -0
- hydpy/models/wq_trapeze.py +168 -0
- hydpy/models/wq_trapeze_strickler.py +101 -0
- hydpy/models/wq_walrus.py +57 -0
- hydpy/py.typed +0 -0
- hydpy/tests/.coveragerc +22 -0
- hydpy/tests/__init__.py +0 -0
- hydpy/tests/check_consistency.py +32 -0
- hydpy/tests/hydpydoctestcustomize.pth +1 -0
- hydpy/tests/hydpydoctestcustomize.py +15 -0
- hydpy/tests/iotesting/__init__.py +0 -0
- hydpy/tests/run_doctests.py +233 -0
- hydpy-6.2.dev1.data/scripts/hyd.py +277 -0
- hydpy-6.2.dev1.dist-info/LICENSE +165 -0
- hydpy-6.2.dev1.dist-info/METADATA +163 -0
- hydpy-6.2.dev1.dist-info/RECORD +890 -0
- hydpy-6.2.dev1.dist-info/WHEEL +5 -0
- hydpy-6.2.dev1.dist-info/licenses_hydpy_installer.txt +42 -0
- hydpy-6.2.dev1.dist-info/top_level.txt +1 -0
hydpy/core/hydpytools.py
ADDED
|
@@ -0,0 +1,3089 @@
|
|
|
1
|
+
"""This module implements the main features for managing *HydPy* projects.
|
|
2
|
+
|
|
3
|
+
.. _`NetCDF Climate and Forecast (CF) Metadata Conventions`: http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/cf-conventions.html # pylint: disable=line-too-long
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# import...
|
|
7
|
+
# ...from standard library
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
import collections
|
|
10
|
+
import contextlib
|
|
11
|
+
import itertools
|
|
12
|
+
import warnings
|
|
13
|
+
|
|
14
|
+
# ...from site-packages
|
|
15
|
+
import networkx
|
|
16
|
+
|
|
17
|
+
# ...from HydPy
|
|
18
|
+
import hydpy
|
|
19
|
+
from hydpy.core import devicetools
|
|
20
|
+
from hydpy.core import exceptiontools
|
|
21
|
+
from hydpy.core import filetools
|
|
22
|
+
from hydpy.core import modeltools
|
|
23
|
+
from hydpy.core import objecttools
|
|
24
|
+
from hydpy.core import printtools
|
|
25
|
+
from hydpy.core import propertytools
|
|
26
|
+
from hydpy.core import selectiontools
|
|
27
|
+
from hydpy.core import sequencetools
|
|
28
|
+
from hydpy.core import timetools
|
|
29
|
+
from hydpy.core.typingtools import *
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from hydpy.core import auxfiletools
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class HydPy:
|
|
36
|
+
"""The main class for managing *HydPy* projects.
|
|
37
|
+
|
|
38
|
+
In typical *HydPy* projects, one prepares a single instance of class |HydPy|. This
|
|
39
|
+
instance, which we name "hp" throughout this documentation instead of "hydpy" to
|
|
40
|
+
avoid a naming collision with the `hydpy` site package, provides many convenient
|
|
41
|
+
methods to perform tasks like reading time series data or starting simulation runs.
|
|
42
|
+
Additionally, it serves as a root to access most details of a *HydPy* project,
|
|
43
|
+
allowing for more granular control over the framework features.
|
|
44
|
+
|
|
45
|
+
We elaborate on these short explanations by using the :ref:`HydPy-H-Lahn` example
|
|
46
|
+
project. Calling function |prepare_full_example_1| copies the complete example
|
|
47
|
+
project :ref:`HydPy-H-Lahn` into the `iotesting` directory of the *HydPy* site
|
|
48
|
+
package (alternatively, you can copy the `HydPy-H-Lahn` example project, which can
|
|
49
|
+
be found in subpackage `data`, into a working directory of your choice):
|
|
50
|
+
|
|
51
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
52
|
+
>>> prepare_full_example_1()
|
|
53
|
+
|
|
54
|
+
At first, the |HydPy| instance needs to know the name of the relevant project,
|
|
55
|
+
which is identical to the name of the project's root directory. Pass
|
|
56
|
+
`HydPy-H-Lahn` to the constructor of class |HydPy|:
|
|
57
|
+
|
|
58
|
+
>>> from hydpy import HydPy
|
|
59
|
+
>>> hp = HydPy("HydPy-H-Lahn")
|
|
60
|
+
|
|
61
|
+
So far, our |HydPy| instance does not know any project configurations except its
|
|
62
|
+
name. Most of this information would be available via properties |HydPy.nodes| and
|
|
63
|
+
|HydPy.elements|, but we get the following error responses if we try to access them:
|
|
64
|
+
|
|
65
|
+
>>> hp.nodes
|
|
66
|
+
Traceback (most recent call last):
|
|
67
|
+
...
|
|
68
|
+
hydpy.core.exceptiontools.AttributeNotReady: The actual HydPy instance does not \
|
|
69
|
+
handle any nodes at the moment.
|
|
70
|
+
|
|
71
|
+
>>> hp.elements
|
|
72
|
+
Traceback (most recent call last):
|
|
73
|
+
...
|
|
74
|
+
hydpy.core.exceptiontools.AttributeNotReady: The actual HydPy instance does not \
|
|
75
|
+
handle any elements at the moment.
|
|
76
|
+
|
|
77
|
+
One could continue rather quickly by calling the method |HydPy.prepare_everything|,
|
|
78
|
+
which would make our |HydPy| instance ready for its first simulation run in one go.
|
|
79
|
+
However, we prefer to continue step by step by calling the more specific
|
|
80
|
+
preparation methods, which offers more flexibility.
|
|
81
|
+
|
|
82
|
+
First, the |HydPy| instance needs to know the relevant |Node| and |Element| objects.
|
|
83
|
+
Method |HydPy.prepare_network| reads this information from so-called "network
|
|
84
|
+
files". Then, the |Node| and |Element| objects connect automatically and thereby
|
|
85
|
+
define the topology or the network structure of the project (see the documentation
|
|
86
|
+
on class |NetworkManager| and module |devicetools| for more detailed explanations):
|
|
87
|
+
|
|
88
|
+
>>> from hydpy import TestIO
|
|
89
|
+
>>> with TestIO():
|
|
90
|
+
... hp.prepare_network()
|
|
91
|
+
|
|
92
|
+
(Using the "with" statement in combination with class |TestIO| makes sure we are
|
|
93
|
+
reading the network files from a subdirectory of the `iotesting` directory. Here
|
|
94
|
+
and in the following, you must omit such "with blocks" in case you copied the
|
|
95
|
+
:ref:`HydPy-H-Lahn` example project into your current working directory.)
|
|
96
|
+
|
|
97
|
+
Now, our |HydPy| instance offers access to all |Node| objects defined within the
|
|
98
|
+
:ref:`HydPy-H-Lahn` example project, which are grouped by a |Nodes| object:
|
|
99
|
+
|
|
100
|
+
>>> hp.nodes
|
|
101
|
+
Nodes("dill_assl", "lahn_kalk", "lahn_leun", "lahn_marb")
|
|
102
|
+
|
|
103
|
+
Taking the node `dill_assl` as an example, we can dive into the details and, for
|
|
104
|
+
example, search for those elements to which node `dill_assl` is connected (it
|
|
105
|
+
receives water from element `land_dill_assl` and passes it to element
|
|
106
|
+
`stream_dill_assl_lahn_leun`), or inspect its simulated discharge value handled by
|
|
107
|
+
a |Sim| sequence object (so far, zero):
|
|
108
|
+
|
|
109
|
+
>>> hp.nodes.dill_assl.entries
|
|
110
|
+
Elements("land_dill_assl")
|
|
111
|
+
|
|
112
|
+
>>> hp.nodes.dill_assl.exits
|
|
113
|
+
Elements("stream_dill_assl_lahn_leun")
|
|
114
|
+
|
|
115
|
+
>>> hp.nodes.dill_assl.sequences.sim
|
|
116
|
+
sim(0.0)
|
|
117
|
+
|
|
118
|
+
All |Node| objects are ready to be used. The same is only partly true for the
|
|
119
|
+
|Element| objects, which are also accessible (via a |Elements| instance) and
|
|
120
|
+
properly connected to the |Node| objects but do not handle workable |Model| objects,
|
|
121
|
+
which is required to perform any simulation run:
|
|
122
|
+
|
|
123
|
+
>>> hp.elements
|
|
124
|
+
Elements("land_dill_assl", "land_lahn_kalk", "land_lahn_leun",
|
|
125
|
+
"land_lahn_marb", "stream_dill_assl_lahn_leun",
|
|
126
|
+
"stream_lahn_leun_lahn_kalk", "stream_lahn_marb_lahn_leun")
|
|
127
|
+
|
|
128
|
+
>>> hp.elements.stream_dill_assl_lahn_leun
|
|
129
|
+
Element("stream_dill_assl_lahn_leun",
|
|
130
|
+
inlets="dill_assl",
|
|
131
|
+
outlets="lahn_leun",
|
|
132
|
+
keywords="river")
|
|
133
|
+
|
|
134
|
+
>>> hp.elements.land_dill_assl.model
|
|
135
|
+
Traceback (most recent call last):
|
|
136
|
+
...
|
|
137
|
+
hydpy.core.exceptiontools.AttributeNotReady: The model object of element \
|
|
138
|
+
`land_dill_assl` has been requested but not been prepared so far.
|
|
139
|
+
|
|
140
|
+
Hence, we need to call method |HydPy.prepare_models|, which instructs all |Element|
|
|
141
|
+
objects to read the relevant parameter control files and prepare their |Model|
|
|
142
|
+
objects. Note that the individual |Element| object does not know the relevant
|
|
143
|
+
model type beforehand; both the information on the model type and the parameter
|
|
144
|
+
settings is encoded in individual control files, making it easy to exchange
|
|
145
|
+
individual models later (the documentation on method |Elements.prepare_models| of
|
|
146
|
+
class |Elements| is a good starting point for a deeper understanding on configuring
|
|
147
|
+
*HydPy* projects via control files):
|
|
148
|
+
|
|
149
|
+
>>> with TestIO():
|
|
150
|
+
... hp.prepare_models()
|
|
151
|
+
Traceback (most recent call last):
|
|
152
|
+
...
|
|
153
|
+
hydpy.core.exceptiontools.AttributeNotReady: While trying to initialise the model \
|
|
154
|
+
object of element `land_dill_assl`, the following error occurred: The initialisation \
|
|
155
|
+
period has not been defined via attribute `timegrids` of module `pub` yet but might be \
|
|
156
|
+
required to prepare the model properly.
|
|
157
|
+
|
|
158
|
+
Oops, something went wrong. We forgot to define the simulation period, which might
|
|
159
|
+
be relevant for some time-dependent configurations. We discuss some examples of
|
|
160
|
+
such configurations below but now use this little accident to discuss the typical
|
|
161
|
+
pattern of *HydPy* error messages. First, we usually try to add some additional
|
|
162
|
+
"spatial" information (in this case: the name of the related |Element| object).
|
|
163
|
+
Second, we try to explain in which program context an error occurs. This context
|
|
164
|
+
is already available in much more detail in the so-called "stack trace" (the middle
|
|
165
|
+
part of the printed error response we do not show). Stack trace descriptions are
|
|
166
|
+
great for programmers but hard to read for others, which is why we often add "While
|
|
167
|
+
trying to..." explanations to our error messages. In our example, one can see that
|
|
168
|
+
the error occurred while trying to initialise the |Model| object of element
|
|
169
|
+
`land_dill_assl`, which is quite evident in our example but could be less evident in
|
|
170
|
+
more complex *HydPy* applications.
|
|
171
|
+
|
|
172
|
+
The last sentence of the error message tells us that we need to define the
|
|
173
|
+
attribute `timegrids` of module `pub`. `pub` stands for "public", meaning module
|
|
174
|
+
`pub` handles all (or at least most of) the globally available configuration data.
|
|
175
|
+
One example is that module `pub` handles a |Timegrids| instance defining both the
|
|
176
|
+
initialisation and the simulation period, which can be done by the following
|
|
177
|
+
assignment (see the documentation on class |Timegrid| and on class |Timegrids| for
|
|
178
|
+
further information):
|
|
179
|
+
|
|
180
|
+
>>> from hydpy import pub
|
|
181
|
+
>>> pub.timegrids = "1996-01-01", "1996-01-05", "1d"
|
|
182
|
+
|
|
183
|
+
Now, method |HydPy.prepare_models| does not complain anymore and adds an instance
|
|
184
|
+
of the |hland_96| application model to element `land_dill_assl`, to which we set an
|
|
185
|
+
additional reference to shorten the following examples:
|
|
186
|
+
|
|
187
|
+
>>> with TestIO():
|
|
188
|
+
... hp.prepare_models()
|
|
189
|
+
|
|
190
|
+
>>> model = hp.elements.land_dill_assl.model
|
|
191
|
+
>>> model.name
|
|
192
|
+
'hland_96'
|
|
193
|
+
|
|
194
|
+
All control parameter values, defined in the corresponding control file, are
|
|
195
|
+
correctly set. As an example, we show the values of the control parameter
|
|
196
|
+
|hland_control.IcMax|, which in this case defines different values for hydrological
|
|
197
|
+
response units of type |hland_constants.FIELD| (1.0 mm) and of type
|
|
198
|
+
|hland_constants.FOREST| (1.5 mm):
|
|
199
|
+
|
|
200
|
+
>>> model.parameters.control.icmax
|
|
201
|
+
icmax(field=1.0, forest=1.5)
|
|
202
|
+
|
|
203
|
+
The appearance (or "string representation") of all parameters that have a unit with
|
|
204
|
+
a time reference (we call these parameters "time-dependent") like
|
|
205
|
+
|hland_control.PercMax| depends on the current setting of option
|
|
206
|
+
|Options.parameterstep|, which is one day by default (see the documentation on
|
|
207
|
+
class |Parameter| for more information on dealing with time-dependent parameters
|
|
208
|
+
subclasses):
|
|
209
|
+
|
|
210
|
+
>>> model.parameters.control.percmax
|
|
211
|
+
percmax(1.39636)
|
|
212
|
+
>>> pub.options.parameterstep("1h")
|
|
213
|
+
Period("1d")
|
|
214
|
+
|
|
215
|
+
The values of the derived parameters, which need to be calculated before starting a
|
|
216
|
+
simulation run based on the control parameters and eventually based on some other
|
|
217
|
+
settings (e.g. the initialisation period), are also ready. Here, we show the value
|
|
218
|
+
of the derived parameter |hland_derived.Z|, representing the average (reference)
|
|
219
|
+
subbasin elevation:
|
|
220
|
+
|
|
221
|
+
>>> model.parameters.derived.z
|
|
222
|
+
z(4.205345)
|
|
223
|
+
|
|
224
|
+
We define all class names in "CamelCase" letters (which is a Python convention) and,
|
|
225
|
+
whenever practical, name the related objects identically but in lowercase letters.
|
|
226
|
+
We hope that eases finding the relevant parts of the online documentation when in
|
|
227
|
+
trouble with a particular object. Three examples we already encountered are the
|
|
228
|
+
|Timegrids| instance `timegrids` of module `pub`, the |Nodes| instance `nodes` of
|
|
229
|
+
class `HydPy`, and the |hland_derived.Z| instance `z` of application model
|
|
230
|
+
|hland_96|:
|
|
231
|
+
|
|
232
|
+
>>> from hydpy import classname
|
|
233
|
+
>>> classname(pub.timegrids)
|
|
234
|
+
'Timegrids'
|
|
235
|
+
|
|
236
|
+
>>> classname(hp.nodes)
|
|
237
|
+
'Nodes'
|
|
238
|
+
|
|
239
|
+
>>> classname(model.parameters.derived.z)
|
|
240
|
+
'Z'
|
|
241
|
+
|
|
242
|
+
As shown above, all |Parameter| objects of the model of element `land_dill_assl` are
|
|
243
|
+
ready to be used. However, all sequences (which handle the time variable properties)
|
|
244
|
+
contain |numpy| |numpy.nan| values, which we use to indicate missing data. We show
|
|
245
|
+
this for the 0-dimensional input sequence |hland_inputs.T|, the 1-dimensional factor
|
|
246
|
+
sequence |hland_factors.TC|, the 1-dimensional state sequence |hland_states.SM|,
|
|
247
|
+
and the 0-dimensional flux sequence |hland_fluxes.QT|:
|
|
248
|
+
|
|
249
|
+
>>> model.sequences.inputs.t
|
|
250
|
+
t(nan)
|
|
251
|
+
|
|
252
|
+
>>> model.sequences.factors.tc
|
|
253
|
+
tc(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan)
|
|
254
|
+
|
|
255
|
+
>>> model.sequences.states.sm
|
|
256
|
+
sm(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan)
|
|
257
|
+
|
|
258
|
+
>>> model.sequences.fluxes.qt
|
|
259
|
+
qt(nan)
|
|
260
|
+
|
|
261
|
+
There are some other sequence types (see the documentation on module |sequencetools|
|
|
262
|
+
for more details) but |InputSequence|, |FactorSequence| |FluxSequence|, and
|
|
263
|
+
|StateSequence| are the most common ones (besides the |NodeSequence| subtypes
|
|
264
|
+
|Obs| and especially |Sim|).
|
|
265
|
+
|
|
266
|
+
|StateSequence| objects describe many aspects of the current state of a model (or,
|
|
267
|
+
e.g., of a catchment). Each simulation run requires proper initial states, which
|
|
268
|
+
we call initial conditions in the following (also covering memory aspects
|
|
269
|
+
represented by |LogSequence| objects). We load all necessary initial conditions by
|
|
270
|
+
calling the method |HydPy.load_conditions| (see the documentation on method
|
|
271
|
+
|HydPy.load_conditions| for further details):
|
|
272
|
+
|
|
273
|
+
>>> with TestIO():
|
|
274
|
+
... hp.load_conditions()
|
|
275
|
+
|
|
276
|
+
Now, the states of our model are also ready to be used. However, one should note
|
|
277
|
+
that state sequence |hland_states.SM| knows only the current soil moisture states
|
|
278
|
+
for the twelve hydrological response units of element `land_dill_assl` (more
|
|
279
|
+
specifically, we loaded the soil moisture values related to the start date of the
|
|
280
|
+
initialisation period, which is January 1 at zero o'clock). By default and for
|
|
281
|
+
reasons of memory storage efficiency, sequences generally handle the currently
|
|
282
|
+
relevant values only instead of complete time series:
|
|
283
|
+
|
|
284
|
+
>>> model.sequences.inputs.t
|
|
285
|
+
t(nan)
|
|
286
|
+
|
|
287
|
+
>>> model.sequences.factors.tc
|
|
288
|
+
tc(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan)
|
|
289
|
+
|
|
290
|
+
>>> model.sequences.states.sm
|
|
291
|
+
sm(185.13164, 181.18755, 199.80432, 196.55888, 212.04018, 209.48859,
|
|
292
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
293
|
+
|
|
294
|
+
>>> model.sequences.fluxes.qt
|
|
295
|
+
qt(nan)
|
|
296
|
+
|
|
297
|
+
For states like |hland_states.SM|, we need to know the values at the beginning of
|
|
298
|
+
the simulation period only. All following values are calculated subsequentially
|
|
299
|
+
during the simulation run. However, this is different for input sequences like
|
|
300
|
+
|hland_inputs.T|. Time variable properties like the air temperature are external
|
|
301
|
+
forcings. Hence, they must be available over the whole simulation period apriori.
|
|
302
|
+
Such complete time series can be made available via property |IOSequence.series| of
|
|
303
|
+
class |IOSequence|, which has not happened for any sequence so far:
|
|
304
|
+
|
|
305
|
+
>>> model.sequences.inputs.t.series
|
|
306
|
+
Traceback (most recent call last):
|
|
307
|
+
...
|
|
308
|
+
hydpy.core.exceptiontools.AttributeNotReady: Sequence `t` of element \
|
|
309
|
+
`land_dill_assl` is not requested to make any time series data available.
|
|
310
|
+
|
|
311
|
+
Before loading time series data, we need to reserve the required memory storage.
|
|
312
|
+
We do this for all sequences at once (not only the |ModelSequence| objects but also
|
|
313
|
+
the |NodeSequence| objects as the |Sim| instance handled by node `dill_assl`) by
|
|
314
|
+
calling the method |HydPy.prepare_allseries|:
|
|
315
|
+
|
|
316
|
+
>>> hp.prepare_allseries()
|
|
317
|
+
|
|
318
|
+
Now, property |IOSequence.series| returns an |InfoArray| object, which is a slight
|
|
319
|
+
modification of the widely applied |numpy| |numpy.ndarray|. The first axis (or the
|
|
320
|
+
only axis) corresponds to the number of days of the initialisation period (a
|
|
321
|
+
*HydPy* convention). For the 1-dimensional sequences |hland_factors.TC| and
|
|
322
|
+
|hland_states.SM|, the second axis corresponds to the number of hydrological
|
|
323
|
+
response units (a |hland| convention):
|
|
324
|
+
|
|
325
|
+
>>> model.sequences.inputs.t.series
|
|
326
|
+
InfoArray([nan, nan, nan, nan])
|
|
327
|
+
|
|
328
|
+
>>> model.sequences.factors.tc.series
|
|
329
|
+
InfoArray([[nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
|
|
330
|
+
[nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
|
|
331
|
+
[nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
|
|
332
|
+
[nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan]])
|
|
333
|
+
|
|
334
|
+
>>> model.sequences.states.sm.series
|
|
335
|
+
InfoArray([[nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
|
|
336
|
+
[nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
|
|
337
|
+
[nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
|
|
338
|
+
[nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan]])
|
|
339
|
+
|
|
340
|
+
>>> model.sequences.fluxes.qt.series
|
|
341
|
+
InfoArray([nan, nan, nan, nan])
|
|
342
|
+
|
|
343
|
+
>>> hp.nodes.dill_assl.sequences.sim.series
|
|
344
|
+
InfoArray([nan, nan, nan, nan])
|
|
345
|
+
|
|
346
|
+
So far, each time series array is empty. The :ref:`HydPy-H-Lahn` example project
|
|
347
|
+
provides time series files for the input sequences, which is the minimum
|
|
348
|
+
requirement for starting a simulation run. We use method |HydPy.load_inputseries|
|
|
349
|
+
to load this data:
|
|
350
|
+
|
|
351
|
+
>>> with TestIO():
|
|
352
|
+
... hp.load_inputseries()
|
|
353
|
+
|
|
354
|
+
>>> from hydpy import round_
|
|
355
|
+
>>> round_(model.sequences.inputs.t.series)
|
|
356
|
+
0.0, -0.5, -2.4, -6.8
|
|
357
|
+
|
|
358
|
+
Finally, we can perform the simulation run by calling the method |HydPy.simulate|:
|
|
359
|
+
|
|
360
|
+
>>> hp.simulate()
|
|
361
|
+
|
|
362
|
+
The time series arrays of all sequences now contain calculated values --- except
|
|
363
|
+
those of input sequence |hland_inputs.T|, of course (for the sequences
|
|
364
|
+
|hland_factors.TC| and |hland_states.SM|, we show the time series of the first
|
|
365
|
+
hydrological response unit only):
|
|
366
|
+
|
|
367
|
+
>>> round_(model.sequences.inputs.t.series)
|
|
368
|
+
0.0, -0.5, -2.4, -6.8
|
|
369
|
+
|
|
370
|
+
>>> round_(model.sequences.factors.tc.series[:, 0])
|
|
371
|
+
1.323207, 0.823207, -1.076793, -5.476793
|
|
372
|
+
|
|
373
|
+
>>> round_(model.sequences.states.sm.series[:, 0])
|
|
374
|
+
184.958475, 184.763638, 184.610776, 184.553224
|
|
375
|
+
|
|
376
|
+
>>> round_(model.sequences.fluxes.qt.series)
|
|
377
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
378
|
+
|
|
379
|
+
>>> round_(hp.nodes.dill_assl.sequences.sim.series)
|
|
380
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
381
|
+
|
|
382
|
+
By comparison, you see that the last calculated (or read) time series value is
|
|
383
|
+
the actual one for each |Sequence_| object. This mechanism allows, for example, to
|
|
384
|
+
write the final states of soil moisture sequence |hland_states.SM| and use them as
|
|
385
|
+
initial conditions later, even if its complete time series were not available:
|
|
386
|
+
|
|
387
|
+
>>> model.sequences.inputs.t
|
|
388
|
+
t(-6.8)
|
|
389
|
+
|
|
390
|
+
>>> model.sequences.states.sm
|
|
391
|
+
sm(184.553224, 180.623124, 199.181137, 195.947542, 212.04018, 209.48859,
|
|
392
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
393
|
+
|
|
394
|
+
>>> model.sequences.fluxes.qt
|
|
395
|
+
qt(5.994195)
|
|
396
|
+
|
|
397
|
+
>>> hp.nodes.dill_assl.sequences.sim
|
|
398
|
+
sim(5.994195)
|
|
399
|
+
|
|
400
|
+
In many applications, the simulated time series is the result we are interested in.
|
|
401
|
+
Hence, we close our explanations with some detailed examples on this topic that
|
|
402
|
+
also cover the potential problem of limited rapid access storage availability.
|
|
403
|
+
|
|
404
|
+
The *HydPy* framework does not overwrite already existing time series by default
|
|
405
|
+
files. However, you can change this and related settings via the |SequenceManager|
|
|
406
|
+
object available in module |pub| (module |pub| also handles |ControlManager| and
|
|
407
|
+
|ConditionManager| objects for settings related to reading and writing control
|
|
408
|
+
files and condition files). We change the default behaviour by setting the
|
|
409
|
+
|SequenceManager.overwrite| attribute to |True|:
|
|
410
|
+
|
|
411
|
+
>>> pub.sequencemanager.overwrite = True
|
|
412
|
+
|
|
413
|
+
Now, we can (over)write all possible time series:
|
|
414
|
+
|
|
415
|
+
>>> with TestIO():
|
|
416
|
+
... hp.save_inputseries()
|
|
417
|
+
... hp.save_factorseries()
|
|
418
|
+
... hp.save_fluxseries()
|
|
419
|
+
... hp.save_stateseries()
|
|
420
|
+
... hp.save_simseries()
|
|
421
|
+
... hp.save_obsseries()
|
|
422
|
+
|
|
423
|
+
Alternatively, apply |HydPy.save_modelseries| to write the series of all the
|
|
424
|
+
|InputSequence|, |FactorSequence|, |FluxSequence|, and |StateSequence| objects and
|
|
425
|
+
|HydPy.save_nodeseries| to write the series of all |Sim| and |Obs| objects in one
|
|
426
|
+
step:
|
|
427
|
+
|
|
428
|
+
>>> with TestIO():
|
|
429
|
+
... hp.save_modelseries()
|
|
430
|
+
... hp.save_nodeseries()
|
|
431
|
+
|
|
432
|
+
Even shorter, just apply the method |HydPy.save_allseries|:
|
|
433
|
+
|
|
434
|
+
>>> with TestIO():
|
|
435
|
+
... hp.save_allseries()
|
|
436
|
+
|
|
437
|
+
Next, we show how the reading of time series works. We first set the time series
|
|
438
|
+
values of all considered sequences to zero for this purpose:
|
|
439
|
+
|
|
440
|
+
>>> model.sequences.inputs.t.series = 0.0
|
|
441
|
+
>>> model.sequences.states.sm.series = 0.0
|
|
442
|
+
>>> model.sequences.inputs.t.series = 0.0
|
|
443
|
+
>>> hp.nodes.dill_assl.sequences.sim.series = 0.0
|
|
444
|
+
|
|
445
|
+
Now, we can reload the time series of all relevant sequences. However, doing so
|
|
446
|
+
would result in a warning due to incomplete data (for example, of the observation
|
|
447
|
+
data handled by the |Obs| sequence objects). To circumvent this problem, we turn
|
|
448
|
+
off the |Options.checkseries| option, which is one of the public options handled by
|
|
449
|
+
the instance of class |Options| available as another attribute of module |pub|. We
|
|
450
|
+
again use "with blocks", making sure the option (and the current working directory)
|
|
451
|
+
changes only temporarily while loading the time series:
|
|
452
|
+
|
|
453
|
+
>>> with TestIO(), pub.options.checkseries(False):
|
|
454
|
+
... hp.load_inputseries()
|
|
455
|
+
... hp.load_factorseries()
|
|
456
|
+
... hp.load_fluxseries()
|
|
457
|
+
... hp.load_stateseries()
|
|
458
|
+
... hp.load_simseries()
|
|
459
|
+
... hp.load_obsseries()
|
|
460
|
+
|
|
461
|
+
>>> with TestIO(), pub.options.checkseries(False):
|
|
462
|
+
... hp.load_modelseries()
|
|
463
|
+
... hp.load_nodeseries()
|
|
464
|
+
|
|
465
|
+
>>> with TestIO(), pub.options.checkseries(False):
|
|
466
|
+
... hp.load_allseries()
|
|
467
|
+
|
|
468
|
+
The read time series data equals the previously written one:
|
|
469
|
+
|
|
470
|
+
>>> round_(model.sequences.inputs.t.series)
|
|
471
|
+
0.0, -0.5, -2.4, -6.8
|
|
472
|
+
|
|
473
|
+
>>> round_(model.sequences.factors.tc.series[:, 0])
|
|
474
|
+
1.323207, 0.823207, -1.076793, -5.476793
|
|
475
|
+
|
|
476
|
+
>>> round_(model.sequences.states.sm.series[:, 0])
|
|
477
|
+
184.958475, 184.763638, 184.610776, 184.553224
|
|
478
|
+
|
|
479
|
+
>>> round_(model.sequences.fluxes.qt.series)
|
|
480
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
481
|
+
|
|
482
|
+
>>> round_(hp.nodes.dill_assl.sequences.sim.series)
|
|
483
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
484
|
+
|
|
485
|
+
We mentioned the possibility for more granular control of *HydPy* by using the
|
|
486
|
+
different objects handled by the |HydPy| object instead of using its convenience
|
|
487
|
+
methods. Here is an elaborate example showing how to (re)load the states of an
|
|
488
|
+
arbitrary simulation time step, which might be relevant for more complex workflows
|
|
489
|
+
implementing data assimilation techniques:
|
|
490
|
+
|
|
491
|
+
>>> model.sequences.states.load_data(1)
|
|
492
|
+
>>> model.sequences.states.sm
|
|
493
|
+
sm(184.763638, 180.829058, 199.40823, 196.170947, 212.04018, 209.48859,
|
|
494
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
495
|
+
|
|
496
|
+
Using the node sequence |Sim| as an example, we also show the inverse functionality
|
|
497
|
+
of changing time series values:
|
|
498
|
+
|
|
499
|
+
>>> hp.nodes.dill_assl.sequences.sim = 0.0
|
|
500
|
+
>>> hp.nodes.dill_assl.sequences.save_data(2)
|
|
501
|
+
>>> round_(hp.nodes.dill_assl.sequences.sim.series)
|
|
502
|
+
11.757526, 8.865079, 0.0, 5.994195
|
|
503
|
+
|
|
504
|
+
>>> hp.nodes.dill_assl.sequences.load_data(1)
|
|
505
|
+
>>> hp.nodes.dill_assl.sequences.sim
|
|
506
|
+
sim(8.865079)
|
|
507
|
+
|
|
508
|
+
In the examples above, we keep all data in rapid access memory, which can be
|
|
509
|
+
problematic when handling long time series in huge *HydPy* projects. When in
|
|
510
|
+
trouble, first try to prepare only those time series that are strictly required
|
|
511
|
+
(very often, it is sufficient to call |HydPy.prepare_inputseries|,
|
|
512
|
+
|HydPy.load_inputseries|, and |HydPy.prepare_simseries| only). If this does not
|
|
513
|
+
work in your project, you can read input data from and write output data to NetCDF
|
|
514
|
+
files during simulation. These follow the `NetCDF Climate and Forecast (CF)
|
|
515
|
+
Metadata Conventions`_. To benefit from this feature, assign |False| to the
|
|
516
|
+
`allocate_ram` argument of the individual "prepare series" methods (which disables
|
|
517
|
+
handling the time series in RAM) and assign |True| to the respective "jit"
|
|
518
|
+
arguments (which prepares the "just-in-time" file access). The methods
|
|
519
|
+
|HydPy.prepare_factorseries|, |HydPy.prepare_fluxseries|, and
|
|
520
|
+
|HydPy.prepare_stateseries| deal with "output sequences" for which read data would
|
|
521
|
+
be overwritten during the simulation and thus only support the `write_jit` argument.
|
|
522
|
+
The |HydPy.prepare_inputseries| method, on the other hand, supports both the
|
|
523
|
+
`read_jit` and the `write_jit` argument. However, in most cases, only reading
|
|
524
|
+
makes sense. The argument `write_jit` is thought for when other methods (for
|
|
525
|
+
example data assimilation approaches) modify the input data, and we need to keep
|
|
526
|
+
track of these modifications:
|
|
527
|
+
|
|
528
|
+
>>> hp.prepare_inputseries(allocate_ram=False, read_jit=True)
|
|
529
|
+
>>> hp.prepare_factorseries(allocate_ram=False, write_jit=True)
|
|
530
|
+
>>> hp.prepare_fluxseries(allocate_ram=False, write_jit=True)
|
|
531
|
+
>>> hp.prepare_stateseries(allocate_ram=False, write_jit=True)
|
|
532
|
+
>>> hp.prepare_simseries(allocate_ram=False, write_jit=True)
|
|
533
|
+
>>> hp.prepare_obsseries(allocate_ram=False, read_jit=True)
|
|
534
|
+
|
|
535
|
+
By doing so, you lose the previously available time series information. We use
|
|
536
|
+
function |attrready| to check this:
|
|
537
|
+
|
|
538
|
+
>>> from hydpy import attrready
|
|
539
|
+
>>> attrready(model.sequences.inputs.t, "series")
|
|
540
|
+
False
|
|
541
|
+
|
|
542
|
+
>>> attrready(model.sequences.factors.tc, "series")
|
|
543
|
+
False
|
|
544
|
+
|
|
545
|
+
>>> attrready(model.sequences.states.sm, "series")
|
|
546
|
+
False
|
|
547
|
+
|
|
548
|
+
>>> attrready(model.sequences.fluxes.qt, "series")
|
|
549
|
+
False
|
|
550
|
+
|
|
551
|
+
>>> attrready(hp.nodes.dill_assl.sequences.sim, "series")
|
|
552
|
+
False
|
|
553
|
+
|
|
554
|
+
Reloading the initial conditions and starting a new simulation run leads to the
|
|
555
|
+
same results as the simulation run above:
|
|
556
|
+
|
|
557
|
+
>>> with TestIO(), pub.options.checkseries(False):
|
|
558
|
+
... hp.load_conditions()
|
|
559
|
+
... hp.simulate()
|
|
560
|
+
|
|
561
|
+
This time, reading input data from files happened during simulation. Likewise, the
|
|
562
|
+
calculated output data is not directly available in RAM but in different NetCDF
|
|
563
|
+
files. To check all results are identical to those shown above, we must load them
|
|
564
|
+
into RAM. Therefore, we first need to prepare the |IOSequence.series| objects
|
|
565
|
+
again:
|
|
566
|
+
|
|
567
|
+
>>> hp.prepare_allseries()
|
|
568
|
+
|
|
569
|
+
By default, *HydPy* handles time series data in simple text files ("asc" files):
|
|
570
|
+
|
|
571
|
+
>>> pub.sequencemanager.filetype
|
|
572
|
+
'asc'
|
|
573
|
+
|
|
574
|
+
One way to prepare to load the results from the available NetCDF files instead is
|
|
575
|
+
to set the |SequenceManager.filetype| attribute of the public |SequenceManager|
|
|
576
|
+
object to "nc":
|
|
577
|
+
|
|
578
|
+
>>> pub.sequencemanager.filetype = "nc"
|
|
579
|
+
|
|
580
|
+
We can load the previously written results into RAM (see the documentation on
|
|
581
|
+
module |netcdftools| for further information) and inspect the results:
|
|
582
|
+
|
|
583
|
+
>>> with TestIO():
|
|
584
|
+
... hp.load_modelseries()
|
|
585
|
+
... hp.load_simseries()
|
|
586
|
+
|
|
587
|
+
>>> round_(model.sequences.inputs.t.series)
|
|
588
|
+
0.0, -0.5, -2.4, -6.8
|
|
589
|
+
|
|
590
|
+
>>> round_(model.sequences.factors.tc.series[:, 0])
|
|
591
|
+
1.323207, 0.823207, -1.076793, -5.476793
|
|
592
|
+
|
|
593
|
+
>>> round_(model.sequences.states.sm.series[:, 0])
|
|
594
|
+
184.958475, 184.763638, 184.610776, 184.553224
|
|
595
|
+
|
|
596
|
+
>>> round_(model.sequences.fluxes.qt.series)
|
|
597
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
598
|
+
|
|
599
|
+
>>> round_(hp.nodes.dill_assl.sequences.sim.series)
|
|
600
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
601
|
+
|
|
602
|
+
You can handle time series in RAM and allow just-in-time NetCDF file access at the
|
|
603
|
+
same time. Before showing how this works, we first disable both functionalities
|
|
604
|
+
for all sequences and delete all previously written NetCDF files:
|
|
605
|
+
|
|
606
|
+
>>> hp.prepare_allseries(allocate_ram=False)
|
|
607
|
+
|
|
608
|
+
>>> attrready(model.sequences.inputs.t, "series")
|
|
609
|
+
False
|
|
610
|
+
|
|
611
|
+
>>> attrready(model.sequences.factors.tc, "series")
|
|
612
|
+
False
|
|
613
|
+
|
|
614
|
+
>>> attrready(model.sequences.states.sm, "series")
|
|
615
|
+
False
|
|
616
|
+
|
|
617
|
+
>>> attrready(model.sequences.fluxes.qt, "series")
|
|
618
|
+
False
|
|
619
|
+
|
|
620
|
+
>>> attrready(hp.nodes.dill_assl.sequences.sim, "series")
|
|
621
|
+
False
|
|
622
|
+
|
|
623
|
+
>>> import os
|
|
624
|
+
>>> with TestIO():
|
|
625
|
+
... for filename in os.listdir(f"HydPy-H-Lahn/series/default"):
|
|
626
|
+
... if "input" not in filename:
|
|
627
|
+
... os.remove(f"HydPy-H-Lahn/series/default/{filename}")
|
|
628
|
+
|
|
629
|
+
We again call method |HydPy.prepare_allseries|, but now, by assigning |True| to the
|
|
630
|
+
arguments `allocate_ram` and `jit`:
|
|
631
|
+
|
|
632
|
+
>>> hp.prepare_allseries(allocate_ram=True, jit=True)
|
|
633
|
+
|
|
634
|
+
After another simulation run, all input data (read during simulation) and output
|
|
635
|
+
data (calculated during simulation) are directly available:
|
|
636
|
+
|
|
637
|
+
>>> with TestIO(), pub.options.checkseries(False):
|
|
638
|
+
... hp.load_conditions()
|
|
639
|
+
... hp.simulate()
|
|
640
|
+
|
|
641
|
+
>>> round_(model.sequences.inputs.t.series)
|
|
642
|
+
0.0, -0.5, -2.4, -6.8
|
|
643
|
+
|
|
644
|
+
>>> round_(model.sequences.factors.tc.series[:, 0])
|
|
645
|
+
1.323207, 0.823207, -1.076793, -5.476793
|
|
646
|
+
|
|
647
|
+
>>> round_(model.sequences.states.sm.series[:, 0])
|
|
648
|
+
184.958475, 184.763638, 184.610776, 184.553224
|
|
649
|
+
|
|
650
|
+
>>> round_(model.sequences.fluxes.qt.series)
|
|
651
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
652
|
+
|
|
653
|
+
>>> round_(hp.nodes.dill_assl.sequences.sim.series)
|
|
654
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
655
|
+
|
|
656
|
+
After subsequent deallocation and allocation for refreshing RAM, reading the
|
|
657
|
+
previously written NetCDF files makes the same data available:
|
|
658
|
+
|
|
659
|
+
>>> hp.prepare_allseries(allocate_ram=False)
|
|
660
|
+
>>> hp.prepare_allseries(allocate_ram=True)
|
|
661
|
+
>>> with TestIO():
|
|
662
|
+
... hp.load_modelseries()
|
|
663
|
+
... hp.load_simseries()
|
|
664
|
+
|
|
665
|
+
>>> round_(model.sequences.inputs.t.series)
|
|
666
|
+
0.0, -0.5, -2.4, -6.8
|
|
667
|
+
|
|
668
|
+
>>> round_(model.sequences.factors.tc.series[:, 0])
|
|
669
|
+
1.323207, 0.823207, -1.076793, -5.476793
|
|
670
|
+
|
|
671
|
+
>>> round_(model.sequences.states.sm.series[:, 0])
|
|
672
|
+
184.958475, 184.763638, 184.610776, 184.553224
|
|
673
|
+
|
|
674
|
+
>>> round_(model.sequences.fluxes.qt.series)
|
|
675
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
676
|
+
|
|
677
|
+
>>> round_(hp.nodes.dill_assl.sequences.sim.series)
|
|
678
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
679
|
+
|
|
680
|
+
All filenames of meteorological input time series provided by the
|
|
681
|
+
:ref:`HydPy-H-Lahn` example follow a "model-specific" pattern. Each filename
|
|
682
|
+
contains not only the name of the corresponding |InputSequence| subclass (e.g.,
|
|
683
|
+
"t") in lowercase letters but also the sequence's group (e.g., "input") and the
|
|
684
|
+
responsible model's name (e.g., "hland_96"):
|
|
685
|
+
|
|
686
|
+
>>> old_model = hp.elements.land_dill_assl.model
|
|
687
|
+
>>> old_model.sequences.inputs.t.filename
|
|
688
|
+
'hland_96_input_t.nc'
|
|
689
|
+
|
|
690
|
+
For file types that store the time series of single sequence instances, file names
|
|
691
|
+
must also contain information about the location. Therefore, the relevant
|
|
692
|
+
element's name prefixes the pure model-specific pattern:
|
|
693
|
+
|
|
694
|
+
>>> pub.sequencemanager.filetype = "asc"
|
|
695
|
+
>>> old_model.sequences.inputs.t.filename
|
|
696
|
+
'land_dill_assl_hland_96_input_t.asc'
|
|
697
|
+
|
|
698
|
+
This naming pattern is exact but not always convenient. For example, assume we
|
|
699
|
+
want to simulate the `dill_assl` subcatchment with application model |hland_96p|
|
|
700
|
+
instead of |hland_96|:
|
|
701
|
+
|
|
702
|
+
>>> from hydpy import prepare_model
|
|
703
|
+
>>> hp.elements.land_dill_assl.model = new_model = prepare_model("hland_96p")
|
|
704
|
+
|
|
705
|
+
|hland_96p| requires the same meteorological input as |hland_96|, for example, the
|
|
706
|
+
air temperature:
|
|
707
|
+
|
|
708
|
+
>>> new_model.prepare_inputseries()
|
|
709
|
+
>>> round_(new_model.sequences.inputs.t.series)
|
|
710
|
+
nan, nan, nan, nan
|
|
711
|
+
|
|
712
|
+
Reading these data from the available files does not work because of the described
|
|
713
|
+
filename convention:
|
|
714
|
+
|
|
715
|
+
>>> with TestIO():
|
|
716
|
+
... hp.load_inputseries() # doctest: +ELLIPSIS
|
|
717
|
+
Traceback (most recent call last):
|
|
718
|
+
...
|
|
719
|
+
FileNotFoundError: While trying to load the time series data of sequence `p` of \
|
|
720
|
+
element `land_dill_assl`, the following error occurred: [Errno 2] No such file or \
|
|
721
|
+
directory: '...land_dill_assl_hland_96p_input_p.asc'
|
|
722
|
+
|
|
723
|
+
To circumvent this problem, one can use the standard "HydPy" convention instead of
|
|
724
|
+
the "model-specific" convention when reading or writing input sequences.
|
|
725
|
+
|
|
726
|
+
>>> pub.sequencemanager.convention = "HydPy"
|
|
727
|
+
|
|
728
|
+
Then, the standard names defined by the |StandardInputNames| enum replace the
|
|
729
|
+
model-specific filename parts. For example, the input sequence |hland_inputs.T|
|
|
730
|
+
selects |StandardInputNames.AIR_TEMPERATURE| as its standard name:
|
|
731
|
+
|
|
732
|
+
>>> with pub.sequencemanager.filetype("nc"):
|
|
733
|
+
... old_model.sequences.inputs.t.filename
|
|
734
|
+
'air_temperature.nc'
|
|
735
|
+
>>> old_model.sequences.inputs.t.filename
|
|
736
|
+
'land_dill_assl_air_temperature.asc'
|
|
737
|
+
|
|
738
|
+
If we use the |hland_96| instance to store the meteorological time series based on
|
|
739
|
+
the "HydPy" convention, the |hland_96p| instance can load them without further
|
|
740
|
+
effort:
|
|
741
|
+
|
|
742
|
+
>>> hp.elements.land_dill_assl.model = old_model
|
|
743
|
+
>>> with TestIO():
|
|
744
|
+
... hp.save_inputseries()
|
|
745
|
+
... hp.elements.land_dill_assl.model = new_model
|
|
746
|
+
... hp.load_inputseries()
|
|
747
|
+
>>> round_(old_model.sequences.inputs.t.series)
|
|
748
|
+
0.0, -0.5, -2.4, -6.8
|
|
749
|
+
>>> round_(new_model.sequences.inputs.t.series)
|
|
750
|
+
0.0, -0.5, -2.4, -6.8
|
|
751
|
+
|
|
752
|
+
The standard "HydPy" naming convention is compatible with reading data
|
|
753
|
+
"just-in-time" from NetCDF files, even if main models and submodels come with
|
|
754
|
+
different input sequences that require the same data. Before explaining this, we
|
|
755
|
+
restore the original |hland_96| submodel and write all input time series to NetCDF
|
|
756
|
+
files following the standard naming convention:
|
|
757
|
+
|
|
758
|
+
>>> with TestIO():
|
|
759
|
+
... hp.elements.land_dill_assl.prepare_model()
|
|
760
|
+
... hp.elements.land_dill_assl.model.load_conditions()
|
|
761
|
+
... hp.elements.land_dill_assl.prepare_inputseries()
|
|
762
|
+
... hp.elements.land_dill_assl.load_inputseries()
|
|
763
|
+
... with pub.sequencemanager.filetype("nc"):
|
|
764
|
+
... hp.save_inputseries()
|
|
765
|
+
|
|
766
|
+
Now, instead of letting the |evap_pet_hbv96| sub-submodel query the air temperature
|
|
767
|
+
from the |hland_96| main model, we add a |meteo_temp_io| sub-sub-submodel that
|
|
768
|
+
comes with an independent air temperature sequence
|
|
769
|
+
|
|
770
|
+
>>> hland = hp.elements.land_dill_assl.model
|
|
771
|
+
>>> with hland.aetmodel.petmodel.add_tempmodel_v2("meteo_temp_io"):
|
|
772
|
+
... temperatureaddend(0.0)
|
|
773
|
+
>>> hp.prepare_inputseries(allocate_ram=True, read_jit=True)
|
|
774
|
+
>>> round_(hland.aetmodel.petmodel.tempmodel.sequences.inputs.temperature.series)
|
|
775
|
+
nan, nan, nan, nan
|
|
776
|
+
|
|
777
|
+
Reading data "just-in-time" makes the same data of the "air_temperature.nc" file
|
|
778
|
+
available to both sequences (and leads to the same simulation results):
|
|
779
|
+
|
|
780
|
+
>>> hland.sequences.inputs.t.series = -777.0
|
|
781
|
+
>>> with TestIO():
|
|
782
|
+
... hp.prepare_fluxseries()
|
|
783
|
+
... hp.simulate()
|
|
784
|
+
>>> round_(hland.sequences.inputs.t.series)
|
|
785
|
+
0.0, -0.5, -2.4, -6.8
|
|
786
|
+
>>> round_(hland.aetmodel.petmodel.tempmodel.sequences.inputs.temperature.series)
|
|
787
|
+
0.0, -0.5, -2.4, -6.8
|
|
788
|
+
>>> round_(hland.sequences.fluxes.qt.series)
|
|
789
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
790
|
+
"""
|
|
791
|
+
|
|
792
|
+
_deviceorder: tuple[devicetools.Node | devicetools.Element, ...] | None
|
|
793
|
+
|
|
794
|
+
_nodes: devicetools.Nodes | None
|
|
795
|
+
_elements: devicetools.Elements | None
|
|
796
|
+
_collectives: devicetools.Elements | None
|
|
797
|
+
|
|
798
|
+
def __init__(self, projectname: str | None = None) -> None:
|
|
799
|
+
self._nodes = None
|
|
800
|
+
self._elements = None
|
|
801
|
+
self._collectives = None
|
|
802
|
+
self._deviceorder = None
|
|
803
|
+
if projectname is not None:
|
|
804
|
+
if hydpy.pub.options.checkprojectstructure:
|
|
805
|
+
filetools.check_projectstructure(projectname)
|
|
806
|
+
hydpy.pub.projectname = projectname
|
|
807
|
+
hydpy.pub.networkmanager = filetools.NetworkManager()
|
|
808
|
+
hydpy.pub.controlmanager = filetools.ControlManager()
|
|
809
|
+
hydpy.pub.sequencemanager = filetools.SequenceManager()
|
|
810
|
+
hydpy.pub.conditionmanager = filetools.ConditionManager()
|
|
811
|
+
|
|
812
|
+
nodes = propertytools.Property[devicetools.NodesConstrArg, devicetools.Nodes]()
|
|
813
|
+
|
|
814
|
+
@nodes.getter
|
|
815
|
+
def _get_nodes(self) -> devicetools.Nodes:
|
|
816
|
+
"""The currently handled |Node| objects.
|
|
817
|
+
|
|
818
|
+
You are allowed to get, set and delete the currently handled nodes:
|
|
819
|
+
|
|
820
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
821
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
822
|
+
>>> hp.nodes
|
|
823
|
+
Nodes("dill_assl", "lahn_kalk", "lahn_leun", "lahn_marb")
|
|
824
|
+
|
|
825
|
+
>>> del hp.nodes
|
|
826
|
+
>>> hp.nodes
|
|
827
|
+
Traceback (most recent call last):
|
|
828
|
+
...
|
|
829
|
+
hydpy.core.exceptiontools.AttributeNotReady: The actual HydPy instance does \
|
|
830
|
+
not handle any nodes at the moment.
|
|
831
|
+
|
|
832
|
+
>>> hp.nodes = "dill_assl", "lahn_marb"
|
|
833
|
+
>>> hp.nodes
|
|
834
|
+
Nodes("dill_assl", "lahn_marb")
|
|
835
|
+
|
|
836
|
+
However, note that doing so might result in erroneous networks and that you,
|
|
837
|
+
even in case of correctness, must most likely call method |HydPy.update_devices|
|
|
838
|
+
before performing the next simulation run.
|
|
839
|
+
"""
|
|
840
|
+
nodes = self._nodes
|
|
841
|
+
if nodes is None:
|
|
842
|
+
raise exceptiontools.AttributeNotReady(
|
|
843
|
+
"The actual HydPy instance does not handle any nodes at the moment."
|
|
844
|
+
)
|
|
845
|
+
return nodes
|
|
846
|
+
|
|
847
|
+
@nodes.setter
|
|
848
|
+
def _set_nodes(self, values: devicetools.NodesConstrArg) -> None:
|
|
849
|
+
self._nodes = devicetools.Nodes(values).copy()
|
|
850
|
+
|
|
851
|
+
@nodes.deleter
|
|
852
|
+
def _del_nodes(self) -> None:
|
|
853
|
+
self._nodes = None
|
|
854
|
+
|
|
855
|
+
elements = propertytools.Property[
|
|
856
|
+
devicetools.ElementsConstrArg, devicetools.Elements
|
|
857
|
+
]()
|
|
858
|
+
|
|
859
|
+
@elements.getter
|
|
860
|
+
def _get_elements(self) -> devicetools.Elements:
|
|
861
|
+
"""The currently handled |Element| objects.
|
|
862
|
+
|
|
863
|
+
You are allowed to get, set and delete the currently handled elements:
|
|
864
|
+
|
|
865
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
866
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
867
|
+
>>> hp.elements
|
|
868
|
+
Elements("land_dill_assl", "land_lahn_kalk", "land_lahn_leun",
|
|
869
|
+
"land_lahn_marb", "stream_dill_assl_lahn_leun",
|
|
870
|
+
"stream_lahn_leun_lahn_kalk", "stream_lahn_marb_lahn_leun")
|
|
871
|
+
|
|
872
|
+
>>> del hp.elements
|
|
873
|
+
>>> hp.elements
|
|
874
|
+
Traceback (most recent call last):
|
|
875
|
+
...
|
|
876
|
+
hydpy.core.exceptiontools.AttributeNotReady: The actual HydPy instance does \
|
|
877
|
+
not handle any elements at the moment.
|
|
878
|
+
|
|
879
|
+
>>> hp.elements = "land_dill_assl", "land_lahn_marb"
|
|
880
|
+
>>> hp.elements
|
|
881
|
+
Elements("land_dill_assl", "land_lahn_marb")
|
|
882
|
+
|
|
883
|
+
However, note that doing so might result in erroneous networks
|
|
884
|
+
and that you, even in case of correctness, must most likely call
|
|
885
|
+
method |HydPy.update_devices| before performing the next
|
|
886
|
+
simulation run.
|
|
887
|
+
"""
|
|
888
|
+
elements = self._elements
|
|
889
|
+
if elements is None:
|
|
890
|
+
raise exceptiontools.AttributeNotReady(
|
|
891
|
+
"The actual HydPy instance does not handle any elements at the moment."
|
|
892
|
+
)
|
|
893
|
+
return elements
|
|
894
|
+
|
|
895
|
+
@elements.setter
|
|
896
|
+
def _set_elements(self, values: devicetools.ElementsConstrArg) -> None:
|
|
897
|
+
self._elements = devicetools.Elements(values).copy()
|
|
898
|
+
|
|
899
|
+
@elements.deleter
|
|
900
|
+
def _del_elements(self) -> None:
|
|
901
|
+
self._elements = None
|
|
902
|
+
|
|
903
|
+
@property
|
|
904
|
+
def collectives(self) -> devicetools.Elements:
|
|
905
|
+
"""The elements relevant for simulation.
|
|
906
|
+
|
|
907
|
+
Usually, |HydPy.collectives| returns the "original" elements also available via
|
|
908
|
+
property |HydPy.elements|. However, if some of these elements belong to a
|
|
909
|
+
|Element.collective|, |HydPy.collectives| does not return them but
|
|
910
|
+
overarching elements suitable for simulation.
|
|
911
|
+
|
|
912
|
+
|HydPy.collectives| raises the following error if the overarching elements are
|
|
913
|
+
unavailable:
|
|
914
|
+
|
|
915
|
+
>>> from hydpy import HydPy
|
|
916
|
+
>>> HydPy().collectives
|
|
917
|
+
Traceback (most recent call last):
|
|
918
|
+
...
|
|
919
|
+
RuntimeError: The currently available elements have not been analysed and \
|
|
920
|
+
eventually combined regarding their collectives. Please call method `update_devices` \
|
|
921
|
+
first.
|
|
922
|
+
"""
|
|
923
|
+
if (collectives := self._collectives) is None:
|
|
924
|
+
raise RuntimeError(
|
|
925
|
+
"The currently available elements have not been analysed and "
|
|
926
|
+
"eventually combined regarding their collectives. Please call method "
|
|
927
|
+
"`update_devices` first."
|
|
928
|
+
)
|
|
929
|
+
return collectives
|
|
930
|
+
|
|
931
|
+
def prepare_everything(self) -> None:
|
|
932
|
+
"""Convenience method to make the actual |HydPy| instance runnable.
|
|
933
|
+
|
|
934
|
+
Method |HydPy.prepare_everything| is the fastest approach to get a runnable
|
|
935
|
+
|HydPy| object. You only need to import class |Hydpy|, initialise it with the
|
|
936
|
+
project name, define the simulation period via the |Timegrids| object of module
|
|
937
|
+
|pub|, and call method |HydPy.prepare_everything| (in this documentation, we
|
|
938
|
+
first need to prepare the example project via function |prepare_full_example_1|
|
|
939
|
+
and change the current working directory via class |TestIO|):
|
|
940
|
+
|
|
941
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
942
|
+
>>> prepare_full_example_1()
|
|
943
|
+
>>> from hydpy import HydPy, print_vector, pub, TestIO
|
|
944
|
+
>>> with TestIO():
|
|
945
|
+
... hp = HydPy("HydPy-H-Lahn")
|
|
946
|
+
... pub.timegrids = "1996-01-01", "1996-01-05", "1d"
|
|
947
|
+
... hp.prepare_everything()
|
|
948
|
+
|
|
949
|
+
Now, you can start a simulation run and inspect the calculated time series of
|
|
950
|
+
all relevant sequences. We take the discharge values of the flux sequence
|
|
951
|
+
|hland_fluxes.QT| of |Element| object `land_dill_assl` and of the node sequence
|
|
952
|
+
|Sim| of |Node| object `dill_assl` as examples, which provide the same
|
|
953
|
+
information:
|
|
954
|
+
|
|
955
|
+
>>> hp.simulate()
|
|
956
|
+
>>> print_vector(hp.elements.land_dill_assl.model.sequences.fluxes.qt.series)
|
|
957
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
958
|
+
>>> print_vector(hp.nodes.dill_assl.sequences.sim.series)
|
|
959
|
+
11.757526, 8.865079, 7.101815, 5.994195
|
|
960
|
+
|
|
961
|
+
The observed discharge values are also directly available via the node sequence
|
|
962
|
+
|Obs|:
|
|
963
|
+
|
|
964
|
+
>>> print_vector(hp.nodes.dill_assl.sequences.obs.series)
|
|
965
|
+
4.84, 5.19, 4.22, 3.65
|
|
966
|
+
"""
|
|
967
|
+
self.prepare_network()
|
|
968
|
+
self.prepare_models()
|
|
969
|
+
self.load_conditions()
|
|
970
|
+
self.prepare_nodeseries()
|
|
971
|
+
with hydpy.pub.options.warnmissingobsfile(False):
|
|
972
|
+
self.load_obsseries()
|
|
973
|
+
self.prepare_modelseries()
|
|
974
|
+
self.load_inputseries()
|
|
975
|
+
|
|
976
|
+
@printtools.print_progress
|
|
977
|
+
def prepare_network(self) -> None:
|
|
978
|
+
"""Load all network files as |Selections| (stored in module |pub|) and assign
|
|
979
|
+
the |Selections.complete| selection to the |HydPy| object.
|
|
980
|
+
|
|
981
|
+
.. testsetup::
|
|
982
|
+
|
|
983
|
+
>>> from hydpy import pub
|
|
984
|
+
>>> del pub.selections
|
|
985
|
+
|
|
986
|
+
First, we call function |prepare_full_example_1| to prepare the
|
|
987
|
+
:ref:`HydPy-H-Lahn` example project, including its network files
|
|
988
|
+
`headwaters.py`, `nonheadwaters.py`, and `streams.py`:
|
|
989
|
+
|
|
990
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
991
|
+
>>> prepare_full_example_1()
|
|
992
|
+
|
|
993
|
+
Directly after initialising class |HydPy|, neither the resulting object nor
|
|
994
|
+
module |pub| contains any information from the network files:
|
|
995
|
+
|
|
996
|
+
>>> from hydpy import HydPy, pub, TestIO
|
|
997
|
+
>>> hp = HydPy("HydPy-H-Lahn")
|
|
998
|
+
>>> pub.selections
|
|
999
|
+
Traceback (most recent call last):
|
|
1000
|
+
...
|
|
1001
|
+
hydpy.core.exceptiontools.AttributeNotReady: Attribute selections of module \
|
|
1002
|
+
`pub` is not defined at the moment.
|
|
1003
|
+
|
|
1004
|
+
By calling the method |HydPy.prepare_network|, one loads all three network
|
|
1005
|
+
files into separate |Selection| objects, all handled by the |Selections| object
|
|
1006
|
+
of module |pub|:
|
|
1007
|
+
|
|
1008
|
+
>>> with TestIO():
|
|
1009
|
+
... hp.prepare_network()
|
|
1010
|
+
>>> pub.selections
|
|
1011
|
+
Selections("headwaters", "nonheadwaters", "streams")
|
|
1012
|
+
|
|
1013
|
+
Additionally, a |Selection| object named "complete" that covers all |Node| and
|
|
1014
|
+
|Element| objects of the user-defined selections is automatically creatable
|
|
1015
|
+
by property |Selections.complete| of class |Selections|:
|
|
1016
|
+
|
|
1017
|
+
>>> whole = pub.selections.headwaters.copy("whole")
|
|
1018
|
+
>>> whole += pub.selections.nonheadwaters
|
|
1019
|
+
>>> whole += pub.selections.streams
|
|
1020
|
+
>>> whole == pub.selections.complete
|
|
1021
|
+
True
|
|
1022
|
+
|
|
1023
|
+
Initially, the |HydPy| object is aware of the complete set of |Node| and
|
|
1024
|
+
|Element| objects:
|
|
1025
|
+
|
|
1026
|
+
>>> hp.nodes == pub.selections.complete.nodes
|
|
1027
|
+
True
|
|
1028
|
+
>>> hp.elements == pub.selections.complete.elements
|
|
1029
|
+
True
|
|
1030
|
+
|
|
1031
|
+
See the documentation on method |HydPy.update_devices| on how to "activate|
|
|
1032
|
+
another selection in the safest manner.
|
|
1033
|
+
"""
|
|
1034
|
+
hydpy.pub.selections = selectiontools.Selections()
|
|
1035
|
+
hydpy.pub.selections.add_selections(*hydpy.pub.networkmanager.load_files())
|
|
1036
|
+
self.update_devices(selection=hydpy.pub.selections.complete, silent=True)
|
|
1037
|
+
|
|
1038
|
+
def prepare_models(self) -> None:
|
|
1039
|
+
"""Read all control files related to the current |Element| objects, initialise
|
|
1040
|
+
the defined models, and prepare their parameter values.
|
|
1041
|
+
|
|
1042
|
+
.. testsetup::
|
|
1043
|
+
|
|
1044
|
+
>>> from hydpy import pub
|
|
1045
|
+
>>> del pub.options.parameterstep
|
|
1046
|
+
|
|
1047
|
+
First, we call function |prepare_full_example_1| to prepare the
|
|
1048
|
+
:ref:`HydPy-H-Lahn` example project:
|
|
1049
|
+
|
|
1050
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
1051
|
+
>>> prepare_full_example_1()
|
|
1052
|
+
|
|
1053
|
+
Now, we can initialise a |HydPy| instance accordingly and call its methods
|
|
1054
|
+
|HydPy.prepare_network| and |HydPy.prepare_models|:
|
|
1055
|
+
|
|
1056
|
+
>>> from hydpy import HydPy, pub, round_, TestIO
|
|
1057
|
+
>>> with TestIO():
|
|
1058
|
+
... pub.timegrids = "1996-01-01", "1996-01-05", "1d"
|
|
1059
|
+
... hp = HydPy("HydPy-H-Lahn")
|
|
1060
|
+
... hp.prepare_network()
|
|
1061
|
+
... hp.prepare_models()
|
|
1062
|
+
|
|
1063
|
+
As a result, each |Element| object handles a model of the type and with the
|
|
1064
|
+
parameter values defined in the relevant control file:
|
|
1065
|
+
|
|
1066
|
+
>>> hp.elements.land_dill_assl.model.name
|
|
1067
|
+
'hland_96'
|
|
1068
|
+
>>> hp.elements.land_dill_assl.model.parameters.control.area
|
|
1069
|
+
area(692.3)
|
|
1070
|
+
>>> hp.elements.stream_lahn_marb_lahn_leun.model.name
|
|
1071
|
+
'musk_classic'
|
|
1072
|
+
>>> hp.elements.stream_lahn_marb_lahn_leun.model.parameters.control.nmbsegments
|
|
1073
|
+
nmbsegments(lag=0.583)
|
|
1074
|
+
|
|
1075
|
+
The :ref:`HydPy-H-Lahn` example project comes with one auxiliary file, named
|
|
1076
|
+
`land.py`. This file defines general parameter values, valid for all single
|
|
1077
|
+
parameter objects of the different model instances referencing this file via
|
|
1078
|
+
the `auxfile` keyword argument. The following examples use the `land_dill_assl`
|
|
1079
|
+
element to show that the affected parameters are also correctly prepared:
|
|
1080
|
+
|
|
1081
|
+
>>> control = hp.elements.land_dill_assl.model.parameters.control
|
|
1082
|
+
>>> control.alpha
|
|
1083
|
+
alpha(1.0)
|
|
1084
|
+
>>> control.pcorr
|
|
1085
|
+
pcorr(1.0)
|
|
1086
|
+
>>> control.resparea
|
|
1087
|
+
resparea(True)
|
|
1088
|
+
>>> control.icmax
|
|
1089
|
+
icmax(field=1.0, forest=1.5)
|
|
1090
|
+
|
|
1091
|
+
We show that the individual |hland_control.IcMax| values for two different
|
|
1092
|
+
elements are different to demonstrate that parameter values defined within a
|
|
1093
|
+
master control file (|hland_control.ZoneType|) can affect the actual values of
|
|
1094
|
+
parameters defined in auxiliary control files:
|
|
1095
|
+
|
|
1096
|
+
>>> from hydpy import round_
|
|
1097
|
+
>>> round_(control.icmax.values)
|
|
1098
|
+
1.0, 1.5, 1.0, 1.5, 1.0, 1.5, 1.0, 1.5, 1.0, 1.5, 1.0, 1.5
|
|
1099
|
+
>>> round_(
|
|
1100
|
+
... hp.elements.land_lahn_leun.model.parameters.control.icmax.values)
|
|
1101
|
+
1.0, 1.5, 1.0, 1.5, 1.0, 1.5, 1.0, 1.5, 1.0, 1.5
|
|
1102
|
+
|
|
1103
|
+
Missing parameter information in auxiliary files results in errors like the
|
|
1104
|
+
following:
|
|
1105
|
+
|
|
1106
|
+
>>> filepath = "HydPy-H-Lahn/control/default/land.py"
|
|
1107
|
+
>>> with TestIO():
|
|
1108
|
+
... with open(filepath) as infile:
|
|
1109
|
+
... text = infile.read().replace("alpha(1.0)", "")
|
|
1110
|
+
... with open(filepath, "w") as outfile:
|
|
1111
|
+
... outfile.write(text)
|
|
1112
|
+
... hp.prepare_models() # doctest: +ELLIPSIS
|
|
1113
|
+
Traceback (most recent call last):
|
|
1114
|
+
...
|
|
1115
|
+
RuntimeError: While trying to initialise the model object of element \
|
|
1116
|
+
`land_dill_assl`, the following error occurred: While trying to load the control file \
|
|
1117
|
+
`...land_dill_assl.py`, the following error occurred: While trying to extract \
|
|
1118
|
+
information for parameter `alpha` from file `land`, the following error occurred: The \
|
|
1119
|
+
selected auxiliary file does not define value(s) for parameter `alpha`.
|
|
1120
|
+
|
|
1121
|
+
Completely wrong control files result in the following error:
|
|
1122
|
+
|
|
1123
|
+
>>> with TestIO():
|
|
1124
|
+
... with open("HydPy-H-Lahn/control/default/land_dill_assl.py", "w"):
|
|
1125
|
+
... pass
|
|
1126
|
+
... hp.prepare_models() # doctest: +ELLIPSIS
|
|
1127
|
+
Traceback (most recent call last):
|
|
1128
|
+
...
|
|
1129
|
+
RuntimeError: While trying to initialise the model object of element \
|
|
1130
|
+
`land_dill_assl`, the following error occurred: Model parameters cannot be loaded from \
|
|
1131
|
+
control file `...land_dill_assl.py`. Please refer to the HydPy documentation on how \
|
|
1132
|
+
to prepare control files properly.
|
|
1133
|
+
"""
|
|
1134
|
+
self.elements.prepare_models()
|
|
1135
|
+
|
|
1136
|
+
def init_models(self) -> None:
|
|
1137
|
+
"""Deprecated! Use method |HydPy.prepare_models| instead.
|
|
1138
|
+
|
|
1139
|
+
>>> from hydpy import HydPy
|
|
1140
|
+
>>> from unittest import mock
|
|
1141
|
+
>>> from hydpy.core.testtools import warn_later
|
|
1142
|
+
>>> with warn_later(), mock.patch.object(HydPy, "prepare_models") as mocked:
|
|
1143
|
+
... hp = HydPy("test")
|
|
1144
|
+
... hp.init_models()
|
|
1145
|
+
HydPyDeprecationWarning: Method `init_models` of class `HydPy` is \
|
|
1146
|
+
deprecated. Use method `prepare_models` instead.
|
|
1147
|
+
>>> mocked.call_args_list
|
|
1148
|
+
[call()]
|
|
1149
|
+
"""
|
|
1150
|
+
self.prepare_models()
|
|
1151
|
+
warnings.warn(
|
|
1152
|
+
"Method `init_models` of class `HydPy` is deprecated. Use method "
|
|
1153
|
+
"`prepare_models` instead.",
|
|
1154
|
+
exceptiontools.HydPyDeprecationWarning,
|
|
1155
|
+
)
|
|
1156
|
+
|
|
1157
|
+
def save_controls(
|
|
1158
|
+
self,
|
|
1159
|
+
parameterstep: timetools.PeriodConstrArg | None = None,
|
|
1160
|
+
simulationstep: timetools.PeriodConstrArg | None = None,
|
|
1161
|
+
auxfiler: auxfiletools.Auxfiler | None = None,
|
|
1162
|
+
) -> None:
|
|
1163
|
+
"""Write the control files of all current |Element| objects.
|
|
1164
|
+
|
|
1165
|
+
.. testsetup::
|
|
1166
|
+
|
|
1167
|
+
>>> from hydpy import pub
|
|
1168
|
+
>>> del pub.options.parameterstep
|
|
1169
|
+
|
|
1170
|
+
We use the :ref:`HydPy-H-Lahn` example project to demonstrate how to write a
|
|
1171
|
+
complete set of parameter control files. For convenience, we let function
|
|
1172
|
+
|prepare_full_example_2| prepare a fully functional |HydPy| object, handling
|
|
1173
|
+
seven |Element| objects controlling four |hland_96| and three |musk_classic|
|
|
1174
|
+
application models:
|
|
1175
|
+
|
|
1176
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
1177
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
1178
|
+
|
|
1179
|
+
At first, there is only one control subfolder named "default", containing the
|
|
1180
|
+
seven master control files used in the step above:
|
|
1181
|
+
|
|
1182
|
+
>>> import os
|
|
1183
|
+
>>> with TestIO():
|
|
1184
|
+
... os.listdir("HydPy-H-Lahn/control")
|
|
1185
|
+
['default']
|
|
1186
|
+
|
|
1187
|
+
Next, we use the |ControlManager| to create a new directory and write analogue
|
|
1188
|
+
control files into it:
|
|
1189
|
+
|
|
1190
|
+
>>> with TestIO():
|
|
1191
|
+
... pub.controlmanager.currentdir = "newdir"
|
|
1192
|
+
... hp.save_controls()
|
|
1193
|
+
... sorted(os.listdir("HydPy-H-Lahn/control"))
|
|
1194
|
+
['default', 'newdir']
|
|
1195
|
+
|
|
1196
|
+
First, we focus our examples on the (shorter) control files of the application
|
|
1197
|
+
model |musk_classic|. These control files define the values of the parameters
|
|
1198
|
+
|musk_control.NmbSegments| and |musk_control.Coefficients| via the keyword
|
|
1199
|
+
arguments `lag` and `damp`. For the river channel connecting the outlets of
|
|
1200
|
+
subcatchment `lahn_marb` and `lahn_leun`, the `lag` value is 0.583 days, and the
|
|
1201
|
+
`damp` value is zero:
|
|
1202
|
+
|
|
1203
|
+
>>> model = hp.elements.stream_lahn_marb_lahn_leun.model
|
|
1204
|
+
>>> model.parameters.control
|
|
1205
|
+
nmbsegments(lag=0.583)
|
|
1206
|
+
coefficients(damp=0.0)
|
|
1207
|
+
|
|
1208
|
+
Its control file's name equals the element's name:
|
|
1209
|
+
|
|
1210
|
+
>>> dir_ = "HydPy-H-Lahn/control/newdir/"
|
|
1211
|
+
>>> with TestIO():
|
|
1212
|
+
... with open(dir_ + "stream_lahn_marb_lahn_leun.py") as controlfile:
|
|
1213
|
+
... print(controlfile.read())
|
|
1214
|
+
from hydpy.models.musk_classic import *
|
|
1215
|
+
<BLANKLINE>
|
|
1216
|
+
simulationstep("1d")
|
|
1217
|
+
parameterstep("1d")
|
|
1218
|
+
<BLANKLINE>
|
|
1219
|
+
nmbsegments(lag=0.583)
|
|
1220
|
+
coefficients(damp=0.0)
|
|
1221
|
+
<BLANKLINE>
|
|
1222
|
+
|
|
1223
|
+
The time step information stems from the |Timegrid| object available via |pub|:
|
|
1224
|
+
|
|
1225
|
+
>>> pub.timegrids.stepsize
|
|
1226
|
+
Period("1d")
|
|
1227
|
+
|
|
1228
|
+
Use the |Auxfiler| class to avoid redefining the same parameter values in
|
|
1229
|
+
multiple control files. We prepare an |Auxfiler| object that handles the
|
|
1230
|
+
model's two parameters discussed above:
|
|
1231
|
+
|
|
1232
|
+
>>> from hydpy import Auxfiler
|
|
1233
|
+
>>> auxfiler = Auxfiler("musk_classic")
|
|
1234
|
+
>>> auxfiler.musk_classic.add_parameter(
|
|
1235
|
+
... model.parameters.control.nmbsegments, filename="stream")
|
|
1236
|
+
>>> auxfiler.musk_classic.add_parameter(
|
|
1237
|
+
... model.parameters.control.coefficients, filename="stream")
|
|
1238
|
+
|
|
1239
|
+
When passing the |Auxfiler| object to the method |HydPy.save_controls|, the
|
|
1240
|
+
control file of element `stream_lahn_marb_lahn_leun` does not define the values
|
|
1241
|
+
of both parameters on its own but references the auxiliary file `stream.py`
|
|
1242
|
+
instead:
|
|
1243
|
+
|
|
1244
|
+
>>> with TestIO():
|
|
1245
|
+
... pub.controlmanager.currentdir = "newdir"
|
|
1246
|
+
... hp.save_controls(auxfiler=auxfiler)
|
|
1247
|
+
... with open(dir_ + "stream_lahn_marb_lahn_leun.py") as controlfile:
|
|
1248
|
+
... print(controlfile.read())
|
|
1249
|
+
from hydpy.models.musk_classic import *
|
|
1250
|
+
<BLANKLINE>
|
|
1251
|
+
simulationstep("1d")
|
|
1252
|
+
parameterstep("1d")
|
|
1253
|
+
<BLANKLINE>
|
|
1254
|
+
nmbsegments(auxfile="stream")
|
|
1255
|
+
coefficients(auxfile="stream")
|
|
1256
|
+
<BLANKLINE>
|
|
1257
|
+
|
|
1258
|
+
`stream.py` contains the actual value definitions:
|
|
1259
|
+
|
|
1260
|
+
>>> with TestIO():
|
|
1261
|
+
... with open(dir_ + "stream.py") as controlfile:
|
|
1262
|
+
... print(controlfile.read())
|
|
1263
|
+
from hydpy.models.musk_classic import *
|
|
1264
|
+
<BLANKLINE>
|
|
1265
|
+
simulationstep("1d")
|
|
1266
|
+
parameterstep("1d")
|
|
1267
|
+
<BLANKLINE>
|
|
1268
|
+
nmbsegments(lag=0.583)
|
|
1269
|
+
coefficients(damp=0.0)
|
|
1270
|
+
<BLANKLINE>
|
|
1271
|
+
|
|
1272
|
+
The |musk_classic| model of element `stream_lahn_leun_lahn_kalk` defines the
|
|
1273
|
+
same value for parameter |musk_control.Coefficients| but a different one for
|
|
1274
|
+
parameter |musk_control.NmbSegments|. Hence, only |musk_control.Coefficients|
|
|
1275
|
+
can reference the control file `stream.py`:
|
|
1276
|
+
|
|
1277
|
+
>>> with TestIO():
|
|
1278
|
+
... with open(dir_ + "stream_lahn_leun_lahn_kalk.py") as controlfile:
|
|
1279
|
+
... print(controlfile.read())
|
|
1280
|
+
from hydpy.models.musk_classic import *
|
|
1281
|
+
<BLANKLINE>
|
|
1282
|
+
simulationstep("1d")
|
|
1283
|
+
parameterstep("1d")
|
|
1284
|
+
<BLANKLINE>
|
|
1285
|
+
nmbsegments(lag=0.417)
|
|
1286
|
+
coefficients(auxfile="stream")
|
|
1287
|
+
<BLANKLINE>
|
|
1288
|
+
|
|
1289
|
+
Another option is to pass alternative step size information. The
|
|
1290
|
+
`simulationstep` information, which is no integral part of control files but
|
|
1291
|
+
helpful in testing them, has no impact on the written data. However, passing
|
|
1292
|
+
an alternative `parameterstep` information changes the written values of
|
|
1293
|
+
time-dependent parameters both in the primary and the auxiliary control files:
|
|
1294
|
+
|
|
1295
|
+
>>> with TestIO():
|
|
1296
|
+
... pub.controlmanager.currentdir = "newdir"
|
|
1297
|
+
... hp.save_controls(
|
|
1298
|
+
... auxfiler=auxfiler, parameterstep="2d", simulationstep="1h")
|
|
1299
|
+
... with open(dir_ + "stream_lahn_marb_lahn_leun.py") as controlfile:
|
|
1300
|
+
... print(controlfile.read())
|
|
1301
|
+
from hydpy.models.musk_classic import *
|
|
1302
|
+
<BLANKLINE>
|
|
1303
|
+
simulationstep("1h")
|
|
1304
|
+
parameterstep("2d")
|
|
1305
|
+
<BLANKLINE>
|
|
1306
|
+
nmbsegments(auxfile="stream")
|
|
1307
|
+
coefficients(auxfile="stream")
|
|
1308
|
+
<BLANKLINE>
|
|
1309
|
+
|
|
1310
|
+
>>> with TestIO():
|
|
1311
|
+
... with open(dir_ + "stream.py") as controlfile:
|
|
1312
|
+
... print(controlfile.read())
|
|
1313
|
+
from hydpy.models.musk_classic import *
|
|
1314
|
+
<BLANKLINE>
|
|
1315
|
+
simulationstep("1h")
|
|
1316
|
+
parameterstep("2d")
|
|
1317
|
+
<BLANKLINE>
|
|
1318
|
+
nmbsegments(lag=0.2915)
|
|
1319
|
+
coefficients(damp=0.0)
|
|
1320
|
+
<BLANKLINE>
|
|
1321
|
+
|
|
1322
|
+
>>> with TestIO():
|
|
1323
|
+
... with open(dir_ + "stream_lahn_leun_lahn_kalk.py") as controlfile:
|
|
1324
|
+
... print(controlfile.read())
|
|
1325
|
+
from hydpy.models.musk_classic import *
|
|
1326
|
+
<BLANKLINE>
|
|
1327
|
+
simulationstep("1h")
|
|
1328
|
+
parameterstep("2d")
|
|
1329
|
+
<BLANKLINE>
|
|
1330
|
+
nmbsegments(lag=0.2085)
|
|
1331
|
+
coefficients(auxfile="stream")
|
|
1332
|
+
<BLANKLINE>
|
|
1333
|
+
|
|
1334
|
+
In the :ref:`HydPy-H-Lahn` example project, all |hland_96| instances use an
|
|
1335
|
+
|evap_pet_hbv96| submodel for calculating potential evapotranspiration. The
|
|
1336
|
+
discussed writing mechanisms include such submodels automatically. The written
|
|
1337
|
+
files rely on the preferred "with" block syntax for adding submodels and
|
|
1338
|
+
defining their parameter values:
|
|
1339
|
+
|
|
1340
|
+
>>> with TestIO():
|
|
1341
|
+
... with open(dir_ + "land_dill_assl.py") as controlfile:
|
|
1342
|
+
... print(controlfile.read()) # doctest: +ELLIPSIS
|
|
1343
|
+
from hydpy.models.hland_96 import *
|
|
1344
|
+
from hydpy.models import evap_aet_hbv96
|
|
1345
|
+
from hydpy.models import evap_pet_hbv96
|
|
1346
|
+
from hydpy.models import rconc_uh
|
|
1347
|
+
<BLANKLINE>
|
|
1348
|
+
simulationstep("1h")
|
|
1349
|
+
parameterstep("2d")
|
|
1350
|
+
<BLANKLINE>
|
|
1351
|
+
area(692.3)
|
|
1352
|
+
...
|
|
1353
|
+
gamma(0.0)
|
|
1354
|
+
with model.add_aetmodel_v1(evap_aet_hbv96):
|
|
1355
|
+
temperaturethresholdice(nan)
|
|
1356
|
+
soilmoisturelimit(0.9)
|
|
1357
|
+
excessreduction(0.0)
|
|
1358
|
+
with model.add_petmodel_v1(evap_pet_hbv96):
|
|
1359
|
+
evapotranspirationfactor(1.0)
|
|
1360
|
+
altitudefactor(0.0)
|
|
1361
|
+
precipitationfactor(0.01)
|
|
1362
|
+
airtemperaturefactor(0.1)
|
|
1363
|
+
with model.add_rconcmodel_v1(rconc_uh):
|
|
1364
|
+
uh("triangle", tb=0.18364)
|
|
1365
|
+
<BLANKLINE>
|
|
1366
|
+
|
|
1367
|
+
When delegating parameter value definitions to auxiliary files, it makes no
|
|
1368
|
+
difference if these parameters are members of a main model or a submodel:
|
|
1369
|
+
|
|
1370
|
+
>>> auxfiler = Auxfiler("evap_pet_hbv96")
|
|
1371
|
+
>>> for element in hp.elements.search_keywords("catchment"):
|
|
1372
|
+
... control = element.model.aetmodel.petmodel.parameters.control
|
|
1373
|
+
... control.airtemperaturefactor(field=0.2, forest=0.1)
|
|
1374
|
+
>>> auxfiler.evap_pet_hbv96.add_parameter(
|
|
1375
|
+
... control.airtemperaturefactor, filename="evap",
|
|
1376
|
+
... keywordarguments=control.airtemperaturefactor.keywordarguments)
|
|
1377
|
+
>>> with TestIO():
|
|
1378
|
+
... hp.save_controls(
|
|
1379
|
+
... auxfiler=auxfiler, parameterstep="2d", simulationstep="1h")
|
|
1380
|
+
... with open(dir_ + "evap.py") as controlfile:
|
|
1381
|
+
... print(controlfile.read()) # doctest: +ELLIPSIS
|
|
1382
|
+
from hydpy.models.evap_pet_hbv96 import *
|
|
1383
|
+
<BLANKLINE>
|
|
1384
|
+
simulationstep("1h")
|
|
1385
|
+
parameterstep("2d")
|
|
1386
|
+
<BLANKLINE>
|
|
1387
|
+
airtemperaturefactor(field=0.2, forest=0.1)
|
|
1388
|
+
<BLANKLINE>
|
|
1389
|
+
>>> with TestIO():
|
|
1390
|
+
... with open(dir_ + "land_dill_assl.py") as controlfile:
|
|
1391
|
+
... print(controlfile.read()) # doctest: +ELLIPSIS
|
|
1392
|
+
from hydpy.models.hland_96 import *
|
|
1393
|
+
...
|
|
1394
|
+
gamma(0.0)
|
|
1395
|
+
with model.add_aetmodel_v1(evap_aet_hbv96):
|
|
1396
|
+
temperaturethresholdice(nan)
|
|
1397
|
+
soilmoisturelimit(0.9)
|
|
1398
|
+
excessreduction(0.0)
|
|
1399
|
+
with model.add_petmodel_v1(evap_pet_hbv96):
|
|
1400
|
+
evapotranspirationfactor(1.0)
|
|
1401
|
+
altitudefactor(0.0)
|
|
1402
|
+
precipitationfactor(0.01)
|
|
1403
|
+
airtemperaturefactor(auxfile="evap")
|
|
1404
|
+
with model.add_rconcmodel_v1(rconc_uh):
|
|
1405
|
+
uh("triangle", tb=0.18364)
|
|
1406
|
+
<BLANKLINE>
|
|
1407
|
+
|
|
1408
|
+
>>> with TestIO():
|
|
1409
|
+
... hp.prepare_models()
|
|
1410
|
+
>>> parameters = hp.elements.land_dill_assl.model.aetmodel.petmodel.parameters
|
|
1411
|
+
>>> control = parameters.control
|
|
1412
|
+
>>> control.airtemperaturefactor
|
|
1413
|
+
airtemperaturefactor(field=0.2, forest=0.1)
|
|
1414
|
+
|
|
1415
|
+
The :ref:`HydPy-H-Lahn` example project relies only upon "scalar" submodels
|
|
1416
|
+
(handled by |SubmodelProperty| instances) and not on "vectorial" submodels
|
|
1417
|
+
(handled by |SubmodelsProperty| instances). Therefore, we now prepare an
|
|
1418
|
+
instance of model |sw1d_channel| and add, for a start, two |sw1d_storage|
|
|
1419
|
+
models to it, assign it to a new |Element| object, and show how method
|
|
1420
|
+
|HydPy.save_controls| writes the further information into a control file:
|
|
1421
|
+
|
|
1422
|
+
>>> from hydpy import prepare_model
|
|
1423
|
+
>>> channel = prepare_model("sw1d_channel")
|
|
1424
|
+
>>> channel.parameters.control.nmbsegments(2)
|
|
1425
|
+
>>> with channel.add_storagemodel_v1("sw1d_storage", position=0) as storage:
|
|
1426
|
+
... length(1.0)
|
|
1427
|
+
... with storage.add_crosssection_v2("wq_trapeze"):
|
|
1428
|
+
... nmbtrapezes(1)
|
|
1429
|
+
... bottomlevels(5.0)
|
|
1430
|
+
... bottomwidths(10.0)
|
|
1431
|
+
... sideslopes(0.0)
|
|
1432
|
+
>>> with channel.add_storagemodel_v1("sw1d_storage", position=1) as storage:
|
|
1433
|
+
... length(2.0)
|
|
1434
|
+
... with storage.add_crosssection_v2("wq_trapeze"):
|
|
1435
|
+
... nmbtrapezes(1)
|
|
1436
|
+
... bottomlevels(5.0)
|
|
1437
|
+
... bottomwidths(10.0)
|
|
1438
|
+
... sideslopes(0.0)
|
|
1439
|
+
>>> from hydpy import Element
|
|
1440
|
+
>>> my_channel = Element("my_channel")
|
|
1441
|
+
>>> my_channel.model = channel
|
|
1442
|
+
>>> hp.update_devices(elements=my_channel)
|
|
1443
|
+
>>> with TestIO():
|
|
1444
|
+
... hp.save_controls()
|
|
1445
|
+
... with open(dir_ + "my_channel.py") as controlfile:
|
|
1446
|
+
... print(controlfile.read()) # doctest: +ELLIPSIS
|
|
1447
|
+
from hydpy.models.sw1d_channel import *
|
|
1448
|
+
from hydpy.models import sw1d_storage
|
|
1449
|
+
from hydpy.models import wq_trapeze
|
|
1450
|
+
<BLANKLINE>
|
|
1451
|
+
simulationstep("1d")
|
|
1452
|
+
parameterstep("1d")
|
|
1453
|
+
<BLANKLINE>
|
|
1454
|
+
nmbsegments(2)
|
|
1455
|
+
with model.add_storagemodel_v1(sw1d_storage, position=0):
|
|
1456
|
+
length(1.0)
|
|
1457
|
+
...
|
|
1458
|
+
with model.add_storagemodel_v1(sw1d_storage, position=1):
|
|
1459
|
+
length(2.0)
|
|
1460
|
+
...
|
|
1461
|
+
<BLANKLINE>
|
|
1462
|
+
|
|
1463
|
+
We now add one of three possible routing models in the second position to
|
|
1464
|
+
demonstrate the writing mechanism not only for completely missing (like in the
|
|
1465
|
+
last example) but also for incomplete submodel vectors:
|
|
1466
|
+
|
|
1467
|
+
>>> with channel.add_routingmodel_v2("sw1d_lias", position=1):
|
|
1468
|
+
... lengthupstream(1.0)
|
|
1469
|
+
... lengthdownstream(2.0)
|
|
1470
|
+
... stricklercoefficient(30.0)
|
|
1471
|
+
... timestepfactor(0.7)
|
|
1472
|
+
... diffusionfactor(0.2)
|
|
1473
|
+
... with storage.add_crosssection_v2("wq_trapeze"):
|
|
1474
|
+
... nmbtrapezes(1)
|
|
1475
|
+
... bottomlevels(5.0)
|
|
1476
|
+
... bottomwidths(10.0)
|
|
1477
|
+
... sideslopes(0.0)
|
|
1478
|
+
>>> with TestIO():
|
|
1479
|
+
... hp.save_controls()
|
|
1480
|
+
... with open(dir_ + "my_channel.py") as controlfile:
|
|
1481
|
+
... print(controlfile.read()) # doctest: +ELLIPSIS
|
|
1482
|
+
from hydpy.models.sw1d_channel import *
|
|
1483
|
+
from hydpy.models import sw1d_lias
|
|
1484
|
+
from hydpy.models import sw1d_storage
|
|
1485
|
+
from hydpy.models import wq_trapeze
|
|
1486
|
+
<BLANKLINE>
|
|
1487
|
+
simulationstep("1d")
|
|
1488
|
+
parameterstep("1d")
|
|
1489
|
+
<BLANKLINE>
|
|
1490
|
+
nmbsegments(2)
|
|
1491
|
+
with model.add_routingmodel_v2(sw1d_lias, position=1):
|
|
1492
|
+
lengthupstream(1.0)
|
|
1493
|
+
...
|
|
1494
|
+
with model.add_storagemodel_v1(sw1d_storage, position=0):
|
|
1495
|
+
length(1.0)
|
|
1496
|
+
...
|
|
1497
|
+
with model.add_storagemodel_v1(sw1d_storage, position=1):
|
|
1498
|
+
length(2.0)
|
|
1499
|
+
...
|
|
1500
|
+
<BLANKLINE>
|
|
1501
|
+
|
|
1502
|
+
Finally, we demonstrate the writing mechanism for the case of different
|
|
1503
|
+
submodel types within the same submodel vector:
|
|
1504
|
+
|
|
1505
|
+
>>> with channel.add_routingmodel_v1("sw1d_q_in", position=0):
|
|
1506
|
+
... lengthdownstream(1.0)
|
|
1507
|
+
>>> with channel.add_routingmodel_v3("sw1d_weir_out", position=2):
|
|
1508
|
+
... lengthupstream(2.0)
|
|
1509
|
+
>>> with TestIO():
|
|
1510
|
+
... hp.save_controls()
|
|
1511
|
+
... with open(dir_ + "my_channel.py") as controlfile:
|
|
1512
|
+
... print(controlfile.read()) # doctest: +ELLIPSIS
|
|
1513
|
+
from hydpy.models.sw1d_channel import *
|
|
1514
|
+
from hydpy.models import sw1d_lias
|
|
1515
|
+
from hydpy.models import sw1d_q_in
|
|
1516
|
+
from hydpy.models import sw1d_storage
|
|
1517
|
+
from hydpy.models import sw1d_weir_out
|
|
1518
|
+
from hydpy.models import wq_trapeze
|
|
1519
|
+
<BLANKLINE>
|
|
1520
|
+
simulationstep("1d")
|
|
1521
|
+
parameterstep("1d")
|
|
1522
|
+
<BLANKLINE>
|
|
1523
|
+
nmbsegments(2)
|
|
1524
|
+
with model.add_routingmodel_v1(sw1d_q_in, position=0):
|
|
1525
|
+
lengthdownstream(1.0)
|
|
1526
|
+
...
|
|
1527
|
+
with model.add_routingmodel_v2(sw1d_lias, position=1):
|
|
1528
|
+
lengthupstream(1.0)
|
|
1529
|
+
lengthdownstream(2.0)
|
|
1530
|
+
...
|
|
1531
|
+
with model.add_routingmodel_v3(sw1d_weir_out, position=2):
|
|
1532
|
+
lengthupstream(2.0)
|
|
1533
|
+
...
|
|
1534
|
+
with model.add_storagemodel_v1(sw1d_storage, position=0):
|
|
1535
|
+
length(1.0)
|
|
1536
|
+
...
|
|
1537
|
+
with model.add_storagemodel_v1(sw1d_storage, position=1):
|
|
1538
|
+
length(2.0)
|
|
1539
|
+
...
|
|
1540
|
+
<BLANKLINE>
|
|
1541
|
+
"""
|
|
1542
|
+
self.elements.save_controls(
|
|
1543
|
+
parameterstep=parameterstep,
|
|
1544
|
+
simulationstep=simulationstep,
|
|
1545
|
+
auxfiler=auxfiler,
|
|
1546
|
+
)
|
|
1547
|
+
|
|
1548
|
+
def update_parameters(self) -> None:
|
|
1549
|
+
"""Update the derived parameters of all models managed by the respective
|
|
1550
|
+
elements.
|
|
1551
|
+
|
|
1552
|
+
The following examples demonstrate method |HydPy.update_parameters| based on
|
|
1553
|
+
the :ref:`HydPy-H-Lahn` project:
|
|
1554
|
+
|
|
1555
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
1556
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
1557
|
+
|
|
1558
|
+
We focus on the Dill subcatchment represented by element `land_dill_assl` and
|
|
1559
|
+
an application model instance of type |hland_96|:
|
|
1560
|
+
|
|
1561
|
+
>>> parameters = hp.elements.land_dill_assl.model.parameters
|
|
1562
|
+
|
|
1563
|
+
|hland_96| has the parameter |hland_derived.QFactor|, which serves as a factor
|
|
1564
|
+
for converting runoff height (mm/T) to runoff volume (m³/s):
|
|
1565
|
+
|
|
1566
|
+
>>> parameters.derived.qfactor
|
|
1567
|
+
qfactor(8.012731)
|
|
1568
|
+
|
|
1569
|
+
Such a factor factor obviously depends on the subcatchment's area. Hence,
|
|
1570
|
+
|hland_derived.QFactor| is implemented as a derived parameter with an
|
|
1571
|
+
|hland_derived.QFactor.update| method that relies on the current value of the
|
|
1572
|
+
control parameter |hland_control.Area|:
|
|
1573
|
+
|
|
1574
|
+
>>> parameters.control.area
|
|
1575
|
+
area(692.3)
|
|
1576
|
+
|
|
1577
|
+
Assume we made an error when transferring the original subcatchment size to our
|
|
1578
|
+
:ref:`HydPy-H-Lahn` project and now want to fix it:
|
|
1579
|
+
|
|
1580
|
+
>>> parameters.control.area(329.6)
|
|
1581
|
+
|
|
1582
|
+
Despite fixing the value of |hland_control.Area|, the value of the
|
|
1583
|
+
|hland_derived.QFactor| instance stays the same:
|
|
1584
|
+
|
|
1585
|
+
>>> parameters.derived.qfactor
|
|
1586
|
+
qfactor(8.012731)
|
|
1587
|
+
|
|
1588
|
+
One now could call method |Model.update_parameters| of the |hland_96| instance
|
|
1589
|
+
to achieve an update of all its derived parameters. However, if one has
|
|
1590
|
+
changed the control parameter values of multiple models, one might find it more
|
|
1591
|
+
convenient to call the |HydPy.update_parameters| of the |HydPy| instance, which
|
|
1592
|
+
then invokes the |Model.update_parameters| of all handled models:
|
|
1593
|
+
|
|
1594
|
+
>>> hp.update_parameters()
|
|
1595
|
+
>>> parameters.derived.qfactor
|
|
1596
|
+
qfactor(3.814815)
|
|
1597
|
+
|
|
1598
|
+
.. warning::
|
|
1599
|
+
|
|
1600
|
+
Updating derived parameters sometimes requires further action to restore
|
|
1601
|
+
runnable models. For example, it might cause a reshaping of condition
|
|
1602
|
+
sequences, which makes defining new initial conditions necessary.
|
|
1603
|
+
"""
|
|
1604
|
+
self.elements.update_parameters()
|
|
1605
|
+
|
|
1606
|
+
def load_conditions(self) -> None:
|
|
1607
|
+
"""Load all currently relevant initial conditions.
|
|
1608
|
+
|
|
1609
|
+
.. testsetup::
|
|
1610
|
+
|
|
1611
|
+
>>> from hydpy import pub
|
|
1612
|
+
>>> del pub.options.parameterstep
|
|
1613
|
+
|
|
1614
|
+
The following examples demonstrate both the functionality of method
|
|
1615
|
+
|HydPy.load_conditions| and |HydPy.save_conditions| based on the
|
|
1616
|
+
:ref:`HydPy-H-Lahn` project, which we prepare via function
|
|
1617
|
+
|prepare_full_example_2|:
|
|
1618
|
+
|
|
1619
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
1620
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
1621
|
+
|
|
1622
|
+
Our |HydPy| instance `hp` is ready for the first simulation run, meaning the
|
|
1623
|
+
required initial conditions are available already. First, we start a
|
|
1624
|
+
simulation run covering the whole initialisation period and inspect the
|
|
1625
|
+
resulting soil moisture values of |Element| `land_dill_assl`, handled by a
|
|
1626
|
+
sequence object of type |hland_states.SM|:
|
|
1627
|
+
|
|
1628
|
+
>>> hp.simulate()
|
|
1629
|
+
>>> sm = hp.elements.land_dill_assl.model.sequences.states.sm
|
|
1630
|
+
>>> sm
|
|
1631
|
+
sm(184.553224, 180.623124, 199.181137, 195.947542, 212.04018, 209.48859,
|
|
1632
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1633
|
+
|
|
1634
|
+
By default, method |HydPy.load_conditions| always (re)loads the initial
|
|
1635
|
+
conditions from the directory with its name matching the start date of the
|
|
1636
|
+
simulation period, which we prove by also showing the related content of the
|
|
1637
|
+
respective condition file `land_dill_assl.py`:
|
|
1638
|
+
|
|
1639
|
+
>>> with TestIO():
|
|
1640
|
+
... hp.load_conditions()
|
|
1641
|
+
>>> sm
|
|
1642
|
+
sm(185.13164, 181.18755, 199.80432, 196.55888, 212.04018, 209.48859,
|
|
1643
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1644
|
+
|
|
1645
|
+
>>> path = "HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_dill_assl.py"
|
|
1646
|
+
>>> with TestIO():
|
|
1647
|
+
... with open(path, "r") as file_:
|
|
1648
|
+
... lines = file_.read().split("\\n")
|
|
1649
|
+
... print(lines[8])
|
|
1650
|
+
... print(lines[9])
|
|
1651
|
+
sm(185.13164, 181.18755, 199.80432, 196.55888, 212.04018, 209.48859,
|
|
1652
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1653
|
+
|
|
1654
|
+
Now, we perform two consecutive runs, covering the first and the second half of
|
|
1655
|
+
the initialisation period, respectively, and write, in both cases, the
|
|
1656
|
+
resulting final conditions to disk:
|
|
1657
|
+
|
|
1658
|
+
>>> pub.timegrids.sim.lastdate = "1996-01-03"
|
|
1659
|
+
>>> hp.simulate()
|
|
1660
|
+
>>> sm
|
|
1661
|
+
sm(184.763638, 180.829058, 199.40823, 196.170947, 212.04018, 209.48859,
|
|
1662
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1663
|
+
>>> with TestIO():
|
|
1664
|
+
... hp.save_conditions()
|
|
1665
|
+
|
|
1666
|
+
>>> pub.timegrids.sim.firstdate = "1996-01-03"
|
|
1667
|
+
>>> pub.timegrids.sim.lastdate = "1996-01-05"
|
|
1668
|
+
>>> hp.simulate()
|
|
1669
|
+
>>> with TestIO():
|
|
1670
|
+
... hp.save_conditions()
|
|
1671
|
+
>>> sm
|
|
1672
|
+
sm(184.553224, 180.623124, 199.181137, 195.947542, 212.04018, 209.48859,
|
|
1673
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1674
|
+
|
|
1675
|
+
Analogous to method |HydPy.load_conditions|, method |HydPy.save_conditions|
|
|
1676
|
+
writes the resulting conditions to a directory with its name matching the end
|
|
1677
|
+
date of the simulation period, which we prove by reloading the conditions
|
|
1678
|
+
related to the middle of the initialisation period and showing the relevant
|
|
1679
|
+
file content:
|
|
1680
|
+
|
|
1681
|
+
>>> with TestIO():
|
|
1682
|
+
... hp.load_conditions()
|
|
1683
|
+
>>> sm
|
|
1684
|
+
sm(184.763638, 180.829058, 199.40823, 196.170947, 212.04018, 209.48859,
|
|
1685
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1686
|
+
|
|
1687
|
+
>>> path = "HydPy-H-Lahn/conditions/init_1996_01_03_00_00_00/land_dill_assl.py"
|
|
1688
|
+
>>> with TestIO():
|
|
1689
|
+
... with open(path, "r") as file_:
|
|
1690
|
+
... lines = file_.read().split("\\n")
|
|
1691
|
+
... print(lines[10])
|
|
1692
|
+
... print(lines[11])
|
|
1693
|
+
sm(184.763638, 180.829058, 199.40823, 196.170947, 212.04018, 209.48859,
|
|
1694
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1695
|
+
|
|
1696
|
+
You can define another directory by assigning a different name to the attribute
|
|
1697
|
+
|FileManager.currentdir| of the actual |ConditionManager| instance:
|
|
1698
|
+
|
|
1699
|
+
>>> with TestIO():
|
|
1700
|
+
... pub.conditionmanager.currentdir = "test"
|
|
1701
|
+
... hp.save_conditions()
|
|
1702
|
+
|
|
1703
|
+
>>> path = "HydPy-H-Lahn/conditions/test/land_dill_assl.py"
|
|
1704
|
+
>>> with TestIO():
|
|
1705
|
+
... with open(path, "r") as file_:
|
|
1706
|
+
... lines = file_.read().split("\\n")
|
|
1707
|
+
... print(lines[10])
|
|
1708
|
+
... print(lines[11])
|
|
1709
|
+
sm(184.763638, 180.829058, 199.40823, 196.170947, 212.04018, 209.48859,
|
|
1710
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1711
|
+
|
|
1712
|
+
This change remains permanent until you undo it manually:
|
|
1713
|
+
|
|
1714
|
+
>>> sm(0.0)
|
|
1715
|
+
>>> pub.timegrids.sim.firstdate = "1996-01-01"
|
|
1716
|
+
>>> with TestIO():
|
|
1717
|
+
... hp.load_conditions()
|
|
1718
|
+
>>> sm
|
|
1719
|
+
sm(184.763638, 180.829058, 199.40823, 196.170947, 212.04018, 209.48859,
|
|
1720
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1721
|
+
|
|
1722
|
+
>>> with TestIO():
|
|
1723
|
+
... del pub.conditionmanager.currentdir
|
|
1724
|
+
... hp.load_conditions()
|
|
1725
|
+
>>> sm
|
|
1726
|
+
sm(185.13164, 181.18755, 199.80432, 196.55888, 212.04018, 209.48859,
|
|
1727
|
+
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
|
|
1728
|
+
|
|
1729
|
+
The :ref:`HydPy-H-Lahn` example project relies only upon "scalar" submodels
|
|
1730
|
+
(handled by |SubmodelProperty| instances) and not on "vectorial" submodels
|
|
1731
|
+
(handled by |SubmodelsProperty| instances). Therefore, we now prepare an
|
|
1732
|
+
instance of model |sw1d_channel| and add, for a start, two |sw1d_storage|
|
|
1733
|
+
models to it, assign it to a new |Element| object, and show how method
|
|
1734
|
+
|HydPy.save_conditions| writes their states into a condition file:
|
|
1735
|
+
|
|
1736
|
+
>>> from hydpy import Element, prepare_model
|
|
1737
|
+
>>> channel = prepare_model("sw1d_channel")
|
|
1738
|
+
>>> channel.parameters.control.nmbsegments(2)
|
|
1739
|
+
>>> with channel.add_storagemodel_v1("sw1d_storage", position=0):
|
|
1740
|
+
... states.watervolume = 10.0
|
|
1741
|
+
>>> with channel.add_storagemodel_v1("sw1d_storage", position=1):
|
|
1742
|
+
... states.watervolume = 20.0
|
|
1743
|
+
>>> my_channel = Element("my_channel")
|
|
1744
|
+
>>> my_channel.model = channel
|
|
1745
|
+
>>> hp.update_devices(elements=my_channel)
|
|
1746
|
+
>>> pub.timegrids.sim.lastdate = "1996-01-03"
|
|
1747
|
+
>>> path = "HydPy-H-Lahn/conditions/init_1996_01_03_00_00_00/my_channel.py"
|
|
1748
|
+
>>> with TestIO():
|
|
1749
|
+
... hp.save_conditions()
|
|
1750
|
+
... with open(path) as conditionfile:
|
|
1751
|
+
... print(conditionfile.read())
|
|
1752
|
+
from hydpy.models.sw1d_channel import *
|
|
1753
|
+
from hydpy.models import sw1d_storage
|
|
1754
|
+
<BLANKLINE>
|
|
1755
|
+
controlcheck(projectdir=r"HydPy-H-Lahn", controldir="default", stepsize="1d")
|
|
1756
|
+
<BLANKLINE>
|
|
1757
|
+
with model.storagemodels[0].define_conditions(sw1d_storage):
|
|
1758
|
+
watervolume(10.0)
|
|
1759
|
+
with model.storagemodels[1].define_conditions(sw1d_storage):
|
|
1760
|
+
watervolume(20.0)
|
|
1761
|
+
<BLANKLINE>
|
|
1762
|
+
|
|
1763
|
+
For testing, we set both submodels' water volume to zero:
|
|
1764
|
+
|
|
1765
|
+
>>> channel.storagemodels[0].sequences.states.watervolume = 0.0
|
|
1766
|
+
>>> channel.storagemodels[1].sequences.states.watervolume = 0.0
|
|
1767
|
+
|
|
1768
|
+
Loading the previously written condition file restores the original values:
|
|
1769
|
+
|
|
1770
|
+
>>> pub.timegrids.sim.firstdate = "1996-01-03"
|
|
1771
|
+
>>> with TestIO():
|
|
1772
|
+
... hp.load_conditions()
|
|
1773
|
+
>>> channel.storagemodels[0].sequences.states.watervolume
|
|
1774
|
+
watervolume(10.0)
|
|
1775
|
+
>>> channel.storagemodels[1].sequences.states.watervolume
|
|
1776
|
+
watervolume(20.0)
|
|
1777
|
+
|
|
1778
|
+
We now add one of three possible routing models in the second position to
|
|
1779
|
+
demonstrate the writing mechanism not only for completely missing (like in the
|
|
1780
|
+
last example) but also for incomplete submodel vectors:
|
|
1781
|
+
|
|
1782
|
+
>>> with channel.add_routingmodel_v2("sw1d_lias", position=1, update=False):
|
|
1783
|
+
... states.discharge(1.1)
|
|
1784
|
+
>>> with TestIO():
|
|
1785
|
+
... hp.save_conditions()
|
|
1786
|
+
... with open(path) as conditionfile:
|
|
1787
|
+
... print(conditionfile.read())
|
|
1788
|
+
from hydpy.models.sw1d_channel import *
|
|
1789
|
+
from hydpy.models import sw1d_lias
|
|
1790
|
+
from hydpy.models import sw1d_storage
|
|
1791
|
+
<BLANKLINE>
|
|
1792
|
+
controlcheck(projectdir=r"HydPy-H-Lahn", controldir="default", stepsize="1d")
|
|
1793
|
+
<BLANKLINE>
|
|
1794
|
+
with model.routingmodels[1].define_conditions(sw1d_lias):
|
|
1795
|
+
discharge(1.1)
|
|
1796
|
+
with model.storagemodels[0].define_conditions(sw1d_storage):
|
|
1797
|
+
watervolume(10.0)
|
|
1798
|
+
with model.storagemodels[1].define_conditions(sw1d_storage):
|
|
1799
|
+
watervolume(20.0)
|
|
1800
|
+
<BLANKLINE>
|
|
1801
|
+
>>> channel.storagemodels[0].sequences.states.watervolume = 0.0
|
|
1802
|
+
>>> channel.storagemodels[1].sequences.states.watervolume = 0.0
|
|
1803
|
+
>>> channel.routingmodels[1].sequences.states.discharge = 0.0
|
|
1804
|
+
>>> with TestIO():
|
|
1805
|
+
... hp.load_conditions()
|
|
1806
|
+
>>> channel.storagemodels[0].sequences.states.watervolume
|
|
1807
|
+
watervolume(10.0)
|
|
1808
|
+
>>> channel.storagemodels[1].sequences.states.watervolume
|
|
1809
|
+
watervolume(20.0)
|
|
1810
|
+
>>> channel.routingmodels[1].sequences.states.discharge
|
|
1811
|
+
discharge(1.1)
|
|
1812
|
+
|
|
1813
|
+
Finally, we demonstrate the writing mechanism for the case of different
|
|
1814
|
+
submodel types within the same submodel vector:
|
|
1815
|
+
|
|
1816
|
+
>>> with channel.add_routingmodel_v1("sw1d_q_in", position=0):
|
|
1817
|
+
... states.discharge = 1.0
|
|
1818
|
+
>>> with channel.add_routingmodel_v3("sw1d_weir_out", position=2):
|
|
1819
|
+
... states.discharge = 1.2
|
|
1820
|
+
>>> with TestIO():
|
|
1821
|
+
... hp.save_conditions()
|
|
1822
|
+
... with open(path) as conditionfile:
|
|
1823
|
+
... print(conditionfile.read())
|
|
1824
|
+
from hydpy.models.sw1d_channel import *
|
|
1825
|
+
from hydpy.models import sw1d_lias
|
|
1826
|
+
from hydpy.models import sw1d_q_in
|
|
1827
|
+
from hydpy.models import sw1d_storage
|
|
1828
|
+
from hydpy.models import sw1d_weir_out
|
|
1829
|
+
<BLANKLINE>
|
|
1830
|
+
controlcheck(projectdir=r"HydPy-H-Lahn", controldir="default", stepsize="1d")
|
|
1831
|
+
<BLANKLINE>
|
|
1832
|
+
with model.routingmodels[0].define_conditions(sw1d_q_in):
|
|
1833
|
+
discharge(1.0)
|
|
1834
|
+
with model.routingmodels[1].define_conditions(sw1d_lias):
|
|
1835
|
+
discharge(1.1)
|
|
1836
|
+
with model.routingmodels[2].define_conditions(sw1d_weir_out):
|
|
1837
|
+
discharge(1.2)
|
|
1838
|
+
with model.storagemodels[0].define_conditions(sw1d_storage):
|
|
1839
|
+
watervolume(10.0)
|
|
1840
|
+
with model.storagemodels[1].define_conditions(sw1d_storage):
|
|
1841
|
+
watervolume(20.0)
|
|
1842
|
+
<BLANKLINE>
|
|
1843
|
+
>>> channel.storagemodels[0].sequences.states.watervolume = 0.0
|
|
1844
|
+
>>> channel.storagemodels[1].sequences.states.watervolume = 0.0
|
|
1845
|
+
>>> channel.routingmodels[0].sequences.states.discharge = 0.0
|
|
1846
|
+
>>> channel.routingmodels[1].sequences.states.discharge = 0.0
|
|
1847
|
+
>>> channel.routingmodels[2].sequences.states.discharge = 0.0
|
|
1848
|
+
>>> with TestIO():
|
|
1849
|
+
... hp.load_conditions()
|
|
1850
|
+
>>> channel.storagemodels[0].sequences.states.watervolume
|
|
1851
|
+
watervolume(10.0)
|
|
1852
|
+
>>> channel.storagemodels[1].sequences.states.watervolume
|
|
1853
|
+
watervolume(20.0)
|
|
1854
|
+
>>> channel.routingmodels[0].sequences.states.discharge
|
|
1855
|
+
discharge(1.0)
|
|
1856
|
+
>>> channel.routingmodels[1].sequences.states.discharge
|
|
1857
|
+
discharge(1.1)
|
|
1858
|
+
>>> channel.routingmodels[2].sequences.states.discharge
|
|
1859
|
+
discharge(1.2)
|
|
1860
|
+
"""
|
|
1861
|
+
self.elements.load_conditions()
|
|
1862
|
+
|
|
1863
|
+
def save_conditions(self) -> None:
|
|
1864
|
+
"""Save all currently relevant final conditions.
|
|
1865
|
+
|
|
1866
|
+
See the documentation on method |HydPy.load_conditions| for further information.
|
|
1867
|
+
"""
|
|
1868
|
+
self.elements.save_conditions()
|
|
1869
|
+
|
|
1870
|
+
def trim_conditions(self) -> None:
|
|
1871
|
+
"""Check all values of the condition sequences (|StateSequence| and
|
|
1872
|
+
|LogSequence| objects) for boundary violations and fix them if necessary.
|
|
1873
|
+
|
|
1874
|
+
We use the :ref:`HydPy-H-Lahn` example project to explain the functionality of
|
|
1875
|
+
the method |HydPy.trim_conditions|, which gives no response when all conditions
|
|
1876
|
+
are correctly set:
|
|
1877
|
+
|
|
1878
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
1879
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
1880
|
+
>>> with pub.options.warntrim(True):
|
|
1881
|
+
... hp.trim_conditions()
|
|
1882
|
+
|
|
1883
|
+
If you try, for example, to set the snow layer's liquid water content
|
|
1884
|
+
(|hland_states.WC|) to a value larger than the allowed fraction of the snow
|
|
1885
|
+
layer's frozen water content (|hland_states.SP|), you get a direct
|
|
1886
|
+
response based on function |trim|:
|
|
1887
|
+
|
|
1888
|
+
>>> from hydpy.core.testtools import warn_later
|
|
1889
|
+
>>> with pub.options.warntrim(True), warn_later(): # doctest: +ELLIPSIS
|
|
1890
|
+
... hp.elements.land_dill_assl.model.sequences.states.wc(1.0)
|
|
1891
|
+
UserWarning: For variable `wc` of element `land_dill_assl` at least one value \
|
|
1892
|
+
needed to be trimmed. The old and the new value(s) are `1.0, ..., 1.0` and `0.0, \
|
|
1893
|
+
..., 0.0`, respectively.
|
|
1894
|
+
|
|
1895
|
+
However, changing the allowed fraction (|hland_control.WHC|) without adjusting
|
|
1896
|
+
the conditions cannot be detected automatically. Whenever in doubt, call
|
|
1897
|
+
method |HydPy.trim_conditions| explicitly:
|
|
1898
|
+
|
|
1899
|
+
>>> hp.elements.land_dill_assl.model.sequences.states.sp(10.0)
|
|
1900
|
+
>>> hp.elements.land_dill_assl.model.sequences.states.wc(1.0)
|
|
1901
|
+
>>> hp.elements.land_dill_assl.model.parameters.control.whc(0.0)
|
|
1902
|
+
>>> with pub.options.warntrim(True), warn_later():
|
|
1903
|
+
... hp.trim_conditions() # doctest: +ELLIPSIS
|
|
1904
|
+
UserWarning: For variable `wc` of element `land_dill_assl` at least one value \
|
|
1905
|
+
needed to be trimmed. The old and the new value(s) are `1.0, ..., 1.0` and `0.0, \
|
|
1906
|
+
..., 0.0`, respectively.
|
|
1907
|
+
"""
|
|
1908
|
+
self.elements.trim_conditions()
|
|
1909
|
+
|
|
1910
|
+
def reset_conditions(self) -> None:
|
|
1911
|
+
"""Reset all currently relevant condition sequences.
|
|
1912
|
+
|
|
1913
|
+
Method |HydPy.reset_conditions| is the most convenient way to perform
|
|
1914
|
+
simulations repeatedly for the same period, each time starting from the same
|
|
1915
|
+
initial conditions, e.g. for parameter calibration. Each |StateSequence| and
|
|
1916
|
+
|LogSequence| object remembers the last assigned values and can reactivate them
|
|
1917
|
+
for the mentioned purpose.
|
|
1918
|
+
|
|
1919
|
+
For demonstration, we perform a simulation for the :ref:`HydPy-H-Lahn` example
|
|
1920
|
+
project spanning four days:
|
|
1921
|
+
|
|
1922
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
1923
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
1924
|
+
>>> hp.simulate()
|
|
1925
|
+
>>> from hydpy import print_vector
|
|
1926
|
+
>>> print_vector(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
1927
|
+
54.019337, 37.257561, 31.865308, 28.359542
|
|
1928
|
+
|
|
1929
|
+
Just repeating the simulation gives different results due to applying the final
|
|
1930
|
+
states of the first simulation run as the initial states of the second run:
|
|
1931
|
+
|
|
1932
|
+
>>> hp.simulate()
|
|
1933
|
+
>>> print_vector(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
1934
|
+
26.196165, 25.047469, 24.227865, 23.307609
|
|
1935
|
+
|
|
1936
|
+
Calling |HydPy.reset_conditions| first allows repeating the first simulation
|
|
1937
|
+
run exactly multiple times:
|
|
1938
|
+
|
|
1939
|
+
>>> hp.reset_conditions()
|
|
1940
|
+
>>> hp.simulate()
|
|
1941
|
+
>>> print_vector(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
1942
|
+
54.019337, 37.257561, 31.865308, 28.359542
|
|
1943
|
+
>>> hp.reset_conditions()
|
|
1944
|
+
>>> hp.simulate()
|
|
1945
|
+
>>> print_vector(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
1946
|
+
54.019337, 37.257561, 31.865308, 28.359542
|
|
1947
|
+
"""
|
|
1948
|
+
self.elements.reset_conditions()
|
|
1949
|
+
|
|
1950
|
+
@property
|
|
1951
|
+
def conditions(self) -> Conditions:
|
|
1952
|
+
"""A nested dictionary that contains the values of all condition sequences of
|
|
1953
|
+
all currently handled models.
|
|
1954
|
+
|
|
1955
|
+
The primary purpose of property |HydPy.conditions| is, similar to method
|
|
1956
|
+
|HydPy.reset_conditions|, to allow repeated calculations starting from the same
|
|
1957
|
+
initial conditions. Nevertheless, |HydPy.conditions| is more flexible when
|
|
1958
|
+
handling multiple conditions, which can, for example, help apply ensemble-based
|
|
1959
|
+
assimilation algorithms.
|
|
1960
|
+
|
|
1961
|
+
For demonstration, we perform simulations for the :ref:`HydPy-H-Lahn` example
|
|
1962
|
+
project spanning the first three months of 1996. We begin with a preparation
|
|
1963
|
+
run beginning on January 1 and ending on February 20:
|
|
1964
|
+
|
|
1965
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
1966
|
+
>>> prepare_full_example_1()
|
|
1967
|
+
>>> from hydpy import HydPy, pub, TestIO, print_vector
|
|
1968
|
+
>>> with TestIO():
|
|
1969
|
+
... hp = HydPy("HydPy-H-Lahn")
|
|
1970
|
+
... pub.timegrids = "1996-01-01", "1996-04-01", "1d"
|
|
1971
|
+
... hp.prepare_everything()
|
|
1972
|
+
>>> pub.timegrids.sim.lastdate = "1996-02-20"
|
|
1973
|
+
>>> hp.simulate()
|
|
1974
|
+
>>> print_vector(hp.nodes.lahn_kalk.sequences.sim.series[48:52])
|
|
1975
|
+
74.80616, 97.932993, nan, nan
|
|
1976
|
+
|
|
1977
|
+
At the end of the preparation run, a snow layer is covering the Lahn catchment.
|
|
1978
|
+
In the `lahn_marb` subcatchment, this snow layer contains 13.7 mm of frozen
|
|
1979
|
+
water and 1.3 mm of liquid water:
|
|
1980
|
+
|
|
1981
|
+
>>> lahn1_states = hp.elements.land_lahn_marb.model.sequences.states
|
|
1982
|
+
>>> print_vector([lahn1_states.sp.average_values()])
|
|
1983
|
+
13.727031
|
|
1984
|
+
>>> print_vector([lahn1_states.wc.average_values()])
|
|
1985
|
+
1.250427
|
|
1986
|
+
|
|
1987
|
+
Now, we save the current conditions and perform the first simulation run from
|
|
1988
|
+
the 20th day of February until the end of March:
|
|
1989
|
+
|
|
1990
|
+
>>> conditions = hp.conditions
|
|
1991
|
+
>>> hp.nodes.lahn_kalk.sequences.sim.series = 0.0
|
|
1992
|
+
>>> pub.timegrids.sim.firstdate = "1996-02-20"
|
|
1993
|
+
>>> pub.timegrids.sim.lastdate = "1996-04-01"
|
|
1994
|
+
>>> hp.simulate()
|
|
1995
|
+
>>> first = hp.nodes.lahn_kalk.sequences.sim.series.copy()
|
|
1996
|
+
>>> print_vector(first[48:52])
|
|
1997
|
+
0.0, 0.0, 88.226976, 66.667346
|
|
1998
|
+
|
|
1999
|
+
To exactly repeat the last simulation run, we assign the memorised conditions
|
|
2000
|
+
to property |HydPy.conditions|:
|
|
2001
|
+
|
|
2002
|
+
>>> hp.conditions = conditions
|
|
2003
|
+
>>> print_vector([lahn1_states.sp.average_values()])
|
|
2004
|
+
13.727031
|
|
2005
|
+
>>> print_vector([lahn1_states.wc.average_values()])
|
|
2006
|
+
1.250427
|
|
2007
|
+
|
|
2008
|
+
All discharge values of the second simulation run are identical to the ones of
|
|
2009
|
+
the first simulation run:
|
|
2010
|
+
|
|
2011
|
+
>>> hp.nodes.lahn_kalk.sequences.sim.series = 0.0
|
|
2012
|
+
>>> pub.timegrids.sim.firstdate = "1996-02-20"
|
|
2013
|
+
>>> pub.timegrids.sim.lastdate = "1996-04-01"
|
|
2014
|
+
>>> hp.simulate()
|
|
2015
|
+
>>> second = hp.nodes.lahn_kalk.sequences.sim.series.copy()
|
|
2016
|
+
>>> print_vector(second[48:52])
|
|
2017
|
+
0.0, 0.0, 88.226976, 66.667346
|
|
2018
|
+
>>> from numpy import isclose
|
|
2019
|
+
>>> assert all(isclose(first, second, rtol=0.0, atol=1e-12))
|
|
2020
|
+
|
|
2021
|
+
We selected the snow period as an example due to potential problems with the
|
|
2022
|
+
limited water-holding capacity of the snow layer, which depends on the ice
|
|
2023
|
+
content of the snow layer (|hland_states.SP|) and the relative water-holding
|
|
2024
|
+
capacity (|hland_control.WHC|). Due to this restriction, problems can occur.
|
|
2025
|
+
To give an example, we set |hland_control.WHC| to zero temporarily, apply the
|
|
2026
|
+
memorised conditions, and finally reset the original values of |
|
|
2027
|
+
hland_control.WHC|:
|
|
2028
|
+
|
|
2029
|
+
>>> for element in hp.elements.catchment:
|
|
2030
|
+
... element.whc = element.model.parameters.control.whc.values
|
|
2031
|
+
... element.model.parameters.control.whc = 0.0
|
|
2032
|
+
>>> with pub.options.warntrim(False):
|
|
2033
|
+
... hp.conditions = conditions
|
|
2034
|
+
>>> for element in hp.elements.catchment:
|
|
2035
|
+
... element.model.parameters.control.whc = element.whc
|
|
2036
|
+
|
|
2037
|
+
Without any water-holding capacity of the snow layer, its water content is zero
|
|
2038
|
+
despite the actual memorised value of 1.1 mm:
|
|
2039
|
+
|
|
2040
|
+
>>> print_vector([lahn1_states.sp.average_values()])
|
|
2041
|
+
13.727031
|
|
2042
|
+
>>> print_vector([lahn1_states.wc.average_values()])
|
|
2043
|
+
0.0
|
|
2044
|
+
|
|
2045
|
+
What happens in such conflicts depends on the implementation of the respective
|
|
2046
|
+
application model. For safety, we suggest setting the option
|
|
2047
|
+
|Options.warntrim| to |True| before resetting conditions.
|
|
2048
|
+
"""
|
|
2049
|
+
return self.elements.conditions
|
|
2050
|
+
|
|
2051
|
+
@conditions.setter
|
|
2052
|
+
def conditions(self, conditions: Conditions) -> None:
|
|
2053
|
+
self.elements.conditions = conditions
|
|
2054
|
+
|
|
2055
|
+
@property
|
|
2056
|
+
def networkproperties(
|
|
2057
|
+
self,
|
|
2058
|
+
) -> dict[str, int | dict[str, int] | dict[devicetools.NodeVariableType, int]]:
|
|
2059
|
+
"""Some properties of the network defined by the currently relevant |Node| and
|
|
2060
|
+
|Element| objects.
|
|
2061
|
+
|
|
2062
|
+
See the documentation on method |HydPy.print_networkproperties| for further
|
|
2063
|
+
information.
|
|
2064
|
+
"""
|
|
2065
|
+
return {
|
|
2066
|
+
"Number of nodes": len(self.nodes),
|
|
2067
|
+
"Number of elements": len(self.elements),
|
|
2068
|
+
"Number of end nodes": len(self.endnodes),
|
|
2069
|
+
"Number of distinct networks": len(self.segregatednetworks),
|
|
2070
|
+
"Applied node variables": self.variables,
|
|
2071
|
+
"Applied model types": self.modeltypes,
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
def print_networkproperties(self) -> None:
|
|
2075
|
+
"""Print some properties of the network defined by the currently relevant
|
|
2076
|
+
|Node| and |Element| objects.
|
|
2077
|
+
|
|
2078
|
+
|HydPy.print_networkproperties| is for convenience to summarise specific
|
|
2079
|
+
network measures like |HydPy.segregatednetworks|.
|
|
2080
|
+
|
|
2081
|
+
The :ref:`HydPy-H-Lahn` example project defines a small, single network, with
|
|
2082
|
+
all catchments ultimately discharging to node `lahn_kalk`:
|
|
2083
|
+
|
|
2084
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
2085
|
+
>>> prepare_full_example_1()
|
|
2086
|
+
>>> from hydpy import HydPy, pub, TestIO
|
|
2087
|
+
>>> pub.timegrids = "1996-01-01", "1996-01-05", "1d"
|
|
2088
|
+
>>> with TestIO():
|
|
2089
|
+
... hp = HydPy("HydPy-H-Lahn")
|
|
2090
|
+
... hp.prepare_network()
|
|
2091
|
+
... hp.prepare_models()
|
|
2092
|
+
>>> hp.print_networkproperties()
|
|
2093
|
+
Number of nodes: 4
|
|
2094
|
+
Number of elements: 7
|
|
2095
|
+
Number of end nodes: 1
|
|
2096
|
+
Number of distinct networks: 1
|
|
2097
|
+
Applied node variables: Q (4)
|
|
2098
|
+
Applied model types: hland_96 (4) and musk_classic (3)
|
|
2099
|
+
"""
|
|
2100
|
+
value: str | int | dict[str, int] | dict[devicetools.NodeVariableType, int]
|
|
2101
|
+
for key, value in self.networkproperties.items():
|
|
2102
|
+
if isinstance(value, dict):
|
|
2103
|
+
value = objecttools.enumeration(
|
|
2104
|
+
f"{name} ({nmb})" for name, nmb in value.items()
|
|
2105
|
+
)
|
|
2106
|
+
print(f"{key}: {value}")
|
|
2107
|
+
|
|
2108
|
+
@property
|
|
2109
|
+
def endnodes(self) -> devicetools.Nodes:
|
|
2110
|
+
"""All currently relevant |Node| objects that define a downstream endpoint of
|
|
2111
|
+
the network.
|
|
2112
|
+
|
|
2113
|
+
The :ref:`HydPy-H-Lahn` example project defines a small, single network, with
|
|
2114
|
+
all catchments ultimately discharging to node `lahn_kalk`:
|
|
2115
|
+
|
|
2116
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
2117
|
+
>>> prepare_full_example_1()
|
|
2118
|
+
>>> from hydpy import HydPy, TestIO
|
|
2119
|
+
>>> with TestIO():
|
|
2120
|
+
... hp = HydPy("HydPy-H-Lahn")
|
|
2121
|
+
... hp.prepare_network()
|
|
2122
|
+
>>> hp.endnodes
|
|
2123
|
+
Nodes("lahn_kalk")
|
|
2124
|
+
|
|
2125
|
+
After breaking the connection between node `lahn_marb` and its downstream river
|
|
2126
|
+
channel element `stream_lahn_marb_lahn2`, `lahn_marb` also becomes an end node:
|
|
2127
|
+
|
|
2128
|
+
>>> hp.nodes.lahn_marb.exits.remove_device("stream_lahn_marb_lahn_leun",
|
|
2129
|
+
... force=True)
|
|
2130
|
+
>>> hp.elements.stream_lahn_marb_lahn_leun.inlets.remove_device("lahn_marb",
|
|
2131
|
+
... force=True)
|
|
2132
|
+
>>> hp.endnodes
|
|
2133
|
+
Nodes("lahn_kalk", "lahn_marb")
|
|
2134
|
+
|
|
2135
|
+
Even with a proper connection to a downstream element, a node counts as an end
|
|
2136
|
+
node as long as these elements are not part of the currently relevant network
|
|
2137
|
+
(meaning, currently handled by the |HydPy| object):
|
|
2138
|
+
|
|
2139
|
+
>>> del hp.elements.stream_dill_assl_lahn_leun
|
|
2140
|
+
>>> hp.nodes.dill_assl.exits
|
|
2141
|
+
Elements("stream_dill_assl_lahn_leun")
|
|
2142
|
+
>>> hp.endnodes
|
|
2143
|
+
Nodes("dill_assl", "lahn_kalk", "lahn_marb")
|
|
2144
|
+
|
|
2145
|
+
Connections with "remote" elements are considered irrelevant:
|
|
2146
|
+
|
|
2147
|
+
>>> stream = hp.elements.stream_lahn_leun_lahn_kalk
|
|
2148
|
+
>>> stream.receivers.add_device(stream.inlets.lahn_leun, force=True)
|
|
2149
|
+
>>> stream.inlets.remove_device("lahn_leun", force=True)
|
|
2150
|
+
>>> hp.endnodes
|
|
2151
|
+
Nodes("dill_assl", "lahn_kalk", "lahn_leun", "lahn_marb")
|
|
2152
|
+
"""
|
|
2153
|
+
endnodes = devicetools.Nodes()
|
|
2154
|
+
for node in self.nodes:
|
|
2155
|
+
for element in node.exits:
|
|
2156
|
+
if (element in self.elements) and (node not in element.receivers):
|
|
2157
|
+
break
|
|
2158
|
+
else:
|
|
2159
|
+
endnodes += node
|
|
2160
|
+
return endnodes
|
|
2161
|
+
|
|
2162
|
+
@property
|
|
2163
|
+
def segregatednetworks(self) -> selectiontools.Selections:
|
|
2164
|
+
"""The number of segregated networks, as defined by the currently relevant
|
|
2165
|
+
|Node| and |Element| objects.
|
|
2166
|
+
|
|
2167
|
+
Each end node (as defined by property |HydPy.endnodes|) eventually defines a
|
|
2168
|
+
single network, segregated from the networks of other end nodes. Due to the
|
|
2169
|
+
:ref:`HydPy-H-Lahn` example project defining only a single end node, there can
|
|
2170
|
+
be only one segregated network, accordingly:
|
|
2171
|
+
|
|
2172
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
2173
|
+
>>> prepare_full_example_1()
|
|
2174
|
+
>>> from hydpy import HydPy, TestIO
|
|
2175
|
+
>>> with TestIO():
|
|
2176
|
+
... hp = HydPy("HydPy-H-Lahn")
|
|
2177
|
+
... hp.prepare_network()
|
|
2178
|
+
>>> hp.segregatednetworks
|
|
2179
|
+
Selections("lahn_kalk")
|
|
2180
|
+
>>> hp.segregatednetworks.lahn_kalk
|
|
2181
|
+
Selection("lahn_kalk",
|
|
2182
|
+
nodes=("dill_assl", "lahn_kalk", "lahn_leun", "lahn_marb"),
|
|
2183
|
+
elements=("land_dill_assl", "land_lahn_kalk",
|
|
2184
|
+
"land_lahn_leun", "land_lahn_marb",
|
|
2185
|
+
"stream_dill_assl_lahn_leun",
|
|
2186
|
+
"stream_lahn_leun_lahn_kalk",
|
|
2187
|
+
"stream_lahn_marb_lahn_leun"))
|
|
2188
|
+
|
|
2189
|
+
Revisiting the examples of the documentation on property |HydPy.endnodes|, we
|
|
2190
|
+
get the similar results. Note that the segregated networks are always
|
|
2191
|
+
|Selection| objects that do not overlap each other (meaning, no |Node| or
|
|
2192
|
+
|Element| object occurs more than one time):
|
|
2193
|
+
|
|
2194
|
+
>>> hp.nodes.lahn_marb.exits.remove_device("stream_lahn_marb_lahn_leun",
|
|
2195
|
+
... force=True)
|
|
2196
|
+
>>> hp.elements.stream_lahn_marb_lahn_leun.inlets.remove_device("lahn_marb",
|
|
2197
|
+
... force=True)
|
|
2198
|
+
>>> hp.segregatednetworks
|
|
2199
|
+
Selections("lahn_kalk", "lahn_marb")
|
|
2200
|
+
>>> hp.segregatednetworks.lahn_marb
|
|
2201
|
+
Selection("lahn_marb",
|
|
2202
|
+
nodes="lahn_marb",
|
|
2203
|
+
elements="land_lahn_marb")
|
|
2204
|
+
>>> hp.segregatednetworks.lahn_kalk
|
|
2205
|
+
Selection("lahn_kalk",
|
|
2206
|
+
nodes=("dill_assl", "lahn_kalk", "lahn_leun"),
|
|
2207
|
+
elements=("land_dill_assl", "land_lahn_kalk",
|
|
2208
|
+
"land_lahn_leun", "stream_dill_assl_lahn_leun",
|
|
2209
|
+
"stream_lahn_leun_lahn_kalk",
|
|
2210
|
+
"stream_lahn_marb_lahn_leun"))
|
|
2211
|
+
|
|
2212
|
+
>>> del hp.elements.stream_dill_assl_lahn_leun
|
|
2213
|
+
>>> hp.nodes.dill_assl.exits
|
|
2214
|
+
Elements("stream_dill_assl_lahn_leun")
|
|
2215
|
+
>>> hp.segregatednetworks
|
|
2216
|
+
Selections("dill_assl", "lahn_kalk", "lahn_marb")
|
|
2217
|
+
>>> hp.segregatednetworks.dill_assl
|
|
2218
|
+
Selection("dill_assl",
|
|
2219
|
+
nodes="dill_assl",
|
|
2220
|
+
elements="land_dill_assl")
|
|
2221
|
+
>>> hp.segregatednetworks.lahn_marb
|
|
2222
|
+
Selection("lahn_marb",
|
|
2223
|
+
nodes="lahn_marb",
|
|
2224
|
+
elements="land_lahn_marb")
|
|
2225
|
+
>>> hp.segregatednetworks.lahn_kalk
|
|
2226
|
+
Selection("lahn_kalk",
|
|
2227
|
+
nodes=("lahn_kalk", "lahn_leun"),
|
|
2228
|
+
elements=("land_lahn_kalk", "land_lahn_leun",
|
|
2229
|
+
"stream_lahn_leun_lahn_kalk",
|
|
2230
|
+
"stream_lahn_marb_lahn_leun"))
|
|
2231
|
+
|
|
2232
|
+
|
|
2233
|
+
>>> stream = hp.elements.stream_lahn_leun_lahn_kalk
|
|
2234
|
+
>>> stream.receivers.add_device(stream.inlets.lahn_leun, force=True)
|
|
2235
|
+
>>> stream.inlets.remove_device("lahn_leun", force=True)
|
|
2236
|
+
>>> hp.segregatednetworks
|
|
2237
|
+
Selections("dill_assl", "lahn_kalk", "lahn_leun", "lahn_marb")
|
|
2238
|
+
>>> hp.segregatednetworks.dill_assl
|
|
2239
|
+
Selection("dill_assl",
|
|
2240
|
+
nodes="dill_assl",
|
|
2241
|
+
elements="land_dill_assl")
|
|
2242
|
+
>>> hp.segregatednetworks.lahn_marb
|
|
2243
|
+
Selection("lahn_marb",
|
|
2244
|
+
nodes="lahn_marb",
|
|
2245
|
+
elements="land_lahn_marb")
|
|
2246
|
+
>>> hp.segregatednetworks.lahn_leun
|
|
2247
|
+
Selection("lahn_leun",
|
|
2248
|
+
nodes="lahn_leun",
|
|
2249
|
+
elements=("land_lahn_leun", "stream_lahn_marb_lahn_leun"))
|
|
2250
|
+
>>> hp.segregatednetworks.lahn_kalk
|
|
2251
|
+
Selection("lahn_kalk",
|
|
2252
|
+
nodes="lahn_kalk",
|
|
2253
|
+
elements=("land_lahn_kalk", "stream_lahn_leun_lahn_kalk"))
|
|
2254
|
+
|
|
2255
|
+
In all the examples above, the number of the end nodes and the number of the
|
|
2256
|
+
segregated networks are identical, which is not the case when two or more
|
|
2257
|
+
networks share the same network. We restore our original network and add two
|
|
2258
|
+
additional end nodes, `nowhere` and `somewhere`, linking the first one with
|
|
2259
|
+
element `stream_lahn_leun_lahn_kalk` and the second one with the additional
|
|
2260
|
+
element `stream_lahn_marb_nowhere`, which we connect to node `lahn_marb`:
|
|
2261
|
+
|
|
2262
|
+
>>> prepare_full_example_1()
|
|
2263
|
+
>>> with TestIO():
|
|
2264
|
+
... hp = HydPy("HydPy-H-Lahn")
|
|
2265
|
+
... hp.prepare_network()
|
|
2266
|
+
>>> from hydpy import Element
|
|
2267
|
+
>>> _ = Element("stream_lahn_leun_lahn_kalk", outlets="nowhere")
|
|
2268
|
+
>>> hp.nodes += "nowhere"
|
|
2269
|
+
>>> hp.elements += Element("stream_lahn_marb_nowhere",
|
|
2270
|
+
... inlets="lahn_marb",
|
|
2271
|
+
... outlets="somewhere")
|
|
2272
|
+
>>> hp.nodes += "somewhere"
|
|
2273
|
+
|
|
2274
|
+
Now, there are three end nodes but only two segregated networks, as node
|
|
2275
|
+
`nowhere` does not reference any upstream devices, which is not also referenced
|
|
2276
|
+
by node `lahn_kalk`. The unique feature of the elements `lahn_kalk` and
|
|
2277
|
+
`stream_lahn_marb_nowhere` is that they drain to either node `lahn_kalk` or
|
|
2278
|
+
`somewhere` but not both, which is why they are the only members of selection
|
|
2279
|
+
`lahn_kalk` and `somewhere`, respectively:
|
|
2280
|
+
|
|
2281
|
+
>>> hp.endnodes
|
|
2282
|
+
Nodes("lahn_kalk", "nowhere", "somewhere")
|
|
2283
|
+
>>> hp.segregatednetworks
|
|
2284
|
+
Selections("lahn_kalk", "somewhere")
|
|
2285
|
+
>>> hp.segregatednetworks.lahn_kalk
|
|
2286
|
+
Selection("lahn_kalk",
|
|
2287
|
+
nodes="lahn_kalk",
|
|
2288
|
+
elements="land_lahn_kalk")
|
|
2289
|
+
>>> hp.segregatednetworks.somewhere
|
|
2290
|
+
Selection("somewhere",
|
|
2291
|
+
nodes="somewhere",
|
|
2292
|
+
elements="stream_lahn_marb_nowhere")
|
|
2293
|
+
"""
|
|
2294
|
+
sels1, sels2 = selectiontools.Selections(), selectiontools.Selections()
|
|
2295
|
+
whole = selectiontools.Selection("whole", self.nodes, self.elements)
|
|
2296
|
+
for node in self.endnodes:
|
|
2297
|
+
sel = whole.search_upstream(device=node, name=node.name, inclusive=False)
|
|
2298
|
+
sels1.add_selections(sel)
|
|
2299
|
+
sels2.add_selections(sel.copy(node.name))
|
|
2300
|
+
for sel1, sel2 in itertools.product(sels1, sels2):
|
|
2301
|
+
if sel1.name != sel2.name:
|
|
2302
|
+
sel1 -= sel2
|
|
2303
|
+
for name in tuple(sels1.names):
|
|
2304
|
+
if not sels1[name].elements:
|
|
2305
|
+
del sels1[name]
|
|
2306
|
+
return sels1
|
|
2307
|
+
|
|
2308
|
+
@property
|
|
2309
|
+
def variables(self) -> dict[devicetools.NodeVariableType, int]:
|
|
2310
|
+
"""Summary of all |Node.variable| properties of the currently relevant |Node|
|
|
2311
|
+
objects.
|
|
2312
|
+
|
|
2313
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
2314
|
+
>>> prepare_full_example_1()
|
|
2315
|
+
>>> from hydpy import HydPy, TestIO
|
|
2316
|
+
>>> with TestIO():
|
|
2317
|
+
... hp = HydPy("HydPy-H-Lahn")
|
|
2318
|
+
... hp.prepare_network()
|
|
2319
|
+
>>> hp.variables
|
|
2320
|
+
{'Q': 4}
|
|
2321
|
+
|
|
2322
|
+
>>> from hydpy import FusedVariable, Node
|
|
2323
|
+
>>> from hydpy.aliases import hland_inputs_T
|
|
2324
|
+
>>> hp.nodes += Node("test", variable=FusedVariable("T", hland_inputs_T))
|
|
2325
|
+
>>> hp.variables
|
|
2326
|
+
{'Q': 4, FusedVariable("T", hland_inputs_T): 1}
|
|
2327
|
+
"""
|
|
2328
|
+
variables: collections.defaultdict[
|
|
2329
|
+
(
|
|
2330
|
+
str
|
|
2331
|
+
| type[sequencetools.InputSequence]
|
|
2332
|
+
| type[sequencetools.InletSequence]
|
|
2333
|
+
| type[sequencetools.ReceiverSequence]
|
|
2334
|
+
| type[sequencetools.OutputSequence]
|
|
2335
|
+
| type[sequencetools.OutletSequence]
|
|
2336
|
+
| type[sequencetools.SenderSequence]
|
|
2337
|
+
| devicetools.FusedVariable
|
|
2338
|
+
),
|
|
2339
|
+
int,
|
|
2340
|
+
] = collections.defaultdict(int)
|
|
2341
|
+
for node in self.nodes:
|
|
2342
|
+
variables[node.variable] += 1
|
|
2343
|
+
return dict(
|
|
2344
|
+
sorted(
|
|
2345
|
+
variables.items(),
|
|
2346
|
+
key=lambda tuple_: f"{(tuple_[0])}{str(tuple_[1]).rjust(9)}",
|
|
2347
|
+
)
|
|
2348
|
+
)
|
|
2349
|
+
|
|
2350
|
+
@property
|
|
2351
|
+
def modeltypes(self) -> dict[str, int]:
|
|
2352
|
+
"""Summary of all |Model| subclasses of the currently relevant |Element|
|
|
2353
|
+
objects.
|
|
2354
|
+
|
|
2355
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
2356
|
+
>>> prepare_full_example_1()
|
|
2357
|
+
>>> from hydpy import HydPy, pub, TestIO
|
|
2358
|
+
>>> with TestIO():
|
|
2359
|
+
... hp = HydPy("HydPy-H-Lahn")
|
|
2360
|
+
... hp.prepare_network()
|
|
2361
|
+
>>> hp.modeltypes
|
|
2362
|
+
{'unprepared': 7}
|
|
2363
|
+
|
|
2364
|
+
>>> pub.timegrids = "1996-01-01", "1996-01-05", "1d"
|
|
2365
|
+
>>> with TestIO():
|
|
2366
|
+
... hp.prepare_models()
|
|
2367
|
+
>>> hp.modeltypes
|
|
2368
|
+
{'hland_96': 4, 'musk_classic': 3}
|
|
2369
|
+
"""
|
|
2370
|
+
modeltypes: collections.defaultdict[str, int]
|
|
2371
|
+
modeltypes = collections.defaultdict(int)
|
|
2372
|
+
for element in self.elements:
|
|
2373
|
+
model = exceptiontools.getattr_(
|
|
2374
|
+
element,
|
|
2375
|
+
"model",
|
|
2376
|
+
"unprepared",
|
|
2377
|
+
modeltools.Model, # type: ignore[type-abstract]
|
|
2378
|
+
)
|
|
2379
|
+
modeltypes[str(model)] += 1
|
|
2380
|
+
return dict(sorted(modeltypes.items()))
|
|
2381
|
+
|
|
2382
|
+
@overload
|
|
2383
|
+
def update_devices(
|
|
2384
|
+
self, *, selection: selectiontools.Selection, silent: bool = False
|
|
2385
|
+
) -> None: ...
|
|
2386
|
+
|
|
2387
|
+
@overload
|
|
2388
|
+
def update_devices(
|
|
2389
|
+
self,
|
|
2390
|
+
*,
|
|
2391
|
+
nodes: devicetools.NodesConstrArg | None = None,
|
|
2392
|
+
elements: devicetools.ElementsConstrArg | None = None,
|
|
2393
|
+
silent: bool = False,
|
|
2394
|
+
) -> None: ...
|
|
2395
|
+
|
|
2396
|
+
def update_devices(
|
|
2397
|
+
self,
|
|
2398
|
+
*,
|
|
2399
|
+
selection: selectiontools.Selection | None = None,
|
|
2400
|
+
nodes: devicetools.NodesConstrArg | None = None,
|
|
2401
|
+
elements: devicetools.ElementsConstrArg | None = None,
|
|
2402
|
+
silent: bool = False,
|
|
2403
|
+
) -> None:
|
|
2404
|
+
"""Determine the order in which method |HydPy.simulate| processes the currently
|
|
2405
|
+
relevant |Node| and |Element| objects.
|
|
2406
|
+
|
|
2407
|
+
Passed |Node| and |Element| objects (for example, contained within a
|
|
2408
|
+
|Selection| object) replace existing ones.
|
|
2409
|
+
|
|
2410
|
+
As described in the documentation on the method |HydPy.prepare_network|, a
|
|
2411
|
+
|HydPy| object usually starts with the complete network of the considered
|
|
2412
|
+
project:
|
|
2413
|
+
|
|
2414
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
2415
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
2416
|
+
|
|
2417
|
+
The safest approach to "activate" another selection is to use the method
|
|
2418
|
+
|HydPy.update_devices|. The first option is to pass a |Selection| object:
|
|
2419
|
+
|
|
2420
|
+
>>> pub.selections.headwaters
|
|
2421
|
+
Selection("headwaters",
|
|
2422
|
+
nodes=("dill_assl", "lahn_marb"),
|
|
2423
|
+
elements=("land_dill_assl", "land_lahn_marb"))
|
|
2424
|
+
|
|
2425
|
+
>>> hp.update_devices(selection=pub.selections.headwaters)
|
|
2426
|
+
>>> hp.nodes
|
|
2427
|
+
Nodes("dill_assl", "lahn_marb")
|
|
2428
|
+
>>> hp.elements
|
|
2429
|
+
Elements("land_dill_assl", "land_lahn_marb")
|
|
2430
|
+
|
|
2431
|
+
Method |HydPy.update_devices| automatically updates the `deviceorder`, assuring
|
|
2432
|
+
method |HydPy.simulate| processes "upstream" model instances before it
|
|
2433
|
+
processes their "downstream" neighbours:
|
|
2434
|
+
|
|
2435
|
+
>>> for device in hp.deviceorder:
|
|
2436
|
+
... print(device)
|
|
2437
|
+
land_dill_assl
|
|
2438
|
+
land_lahn_marb
|
|
2439
|
+
dill_assl
|
|
2440
|
+
lahn_marb
|
|
2441
|
+
|
|
2442
|
+
Second, you can pass some nodes only, which, by the way, removes the old
|
|
2443
|
+
elements:
|
|
2444
|
+
|
|
2445
|
+
>>> hp.update_devices(nodes="dill_assl")
|
|
2446
|
+
>>> hp.nodes
|
|
2447
|
+
Nodes("dill_assl")
|
|
2448
|
+
>>> hp.elements
|
|
2449
|
+
Elements()
|
|
2450
|
+
>>> for device in hp.deviceorder:
|
|
2451
|
+
... print(device)
|
|
2452
|
+
dill_assl
|
|
2453
|
+
|
|
2454
|
+
Third, you can pass some elements only, which, by the way, removes the old
|
|
2455
|
+
nodes:
|
|
2456
|
+
|
|
2457
|
+
>>> hp.update_devices(elements=["land_lahn_marb", "land_dill_assl"])
|
|
2458
|
+
>>> hp.nodes
|
|
2459
|
+
Nodes()
|
|
2460
|
+
>>> hp.elements
|
|
2461
|
+
Elements("land_dill_assl", "land_lahn_marb")
|
|
2462
|
+
>>> for device in hp.deviceorder:
|
|
2463
|
+
... print(device)
|
|
2464
|
+
land_dill_assl
|
|
2465
|
+
land_lahn_marb
|
|
2466
|
+
|
|
2467
|
+
Fourth, you can pass nodes and elements at the same time:
|
|
2468
|
+
|
|
2469
|
+
>>> hp.update_devices(nodes="dill_assl", elements=["land_lahn_marb",
|
|
2470
|
+
... "land_dill_assl"])
|
|
2471
|
+
>>> hp.nodes
|
|
2472
|
+
Nodes("dill_assl")
|
|
2473
|
+
>>> hp.elements
|
|
2474
|
+
Elements("land_dill_assl", "land_lahn_marb")
|
|
2475
|
+
>>> for device in hp.deviceorder:
|
|
2476
|
+
... print(device)
|
|
2477
|
+
land_dill_assl
|
|
2478
|
+
land_lahn_marb
|
|
2479
|
+
dill_assl
|
|
2480
|
+
|
|
2481
|
+
Fifth, you can pass no argument at all, which only updates the device order:
|
|
2482
|
+
|
|
2483
|
+
>>> del hp.nodes.dill_assl
|
|
2484
|
+
>>> for device in hp.deviceorder:
|
|
2485
|
+
... print(device)
|
|
2486
|
+
land_dill_assl
|
|
2487
|
+
land_lahn_marb
|
|
2488
|
+
dill_assl
|
|
2489
|
+
>>> hp.update_devices()
|
|
2490
|
+
>>> for device in hp.deviceorder:
|
|
2491
|
+
... print(device)
|
|
2492
|
+
land_dill_assl
|
|
2493
|
+
land_lahn_marb
|
|
2494
|
+
|
|
2495
|
+
Method |HydPy.update_devices| does not allow using the `selections` argument
|
|
2496
|
+
and the `nodes` or `elements` argument simultaneously:
|
|
2497
|
+
|
|
2498
|
+
>>> hp.update_devices(selection=pub.selections.headwaters, nodes="dill_assl")
|
|
2499
|
+
Traceback (most recent call last):
|
|
2500
|
+
...
|
|
2501
|
+
ValueError: Method `update_devices` of class `HydPy` does not allow to use \
|
|
2502
|
+
both the `selection` argument and the `nodes` or the `elements` argument at the same \
|
|
2503
|
+
time.
|
|
2504
|
+
|
|
2505
|
+
>>> hp.update_devices(selection=pub.selections.headwaters,
|
|
2506
|
+
... elements=["land_lahn_marb", "land_dill_assl"])
|
|
2507
|
+
Traceback (most recent call last):
|
|
2508
|
+
...
|
|
2509
|
+
ValueError: Method `update_devices` of class `HydPy` does not allow to use \
|
|
2510
|
+
both the `selection` argument and the `nodes` or the `elements` argument at the same \
|
|
2511
|
+
time.
|
|
2512
|
+
|
|
2513
|
+
Elements of the same |Element.collective| require special attention, as they
|
|
2514
|
+
and their models must be combined (at the latest before simulation). Method
|
|
2515
|
+
|HydPy.update_devices| raises the following error if any model is unavailable:
|
|
2516
|
+
|
|
2517
|
+
>>> from hydpy import Element, Node
|
|
2518
|
+
>>> junction = Node("junction")
|
|
2519
|
+
>>> reach1 = Element("reach1", collective="network", inlets=junction)
|
|
2520
|
+
>>> reach2 = Element("reach2", collective="network", outlets=junction)
|
|
2521
|
+
>>> hp.update_devices(elements=(reach1, reach2), nodes=junction)
|
|
2522
|
+
Traceback (most recent call last):
|
|
2523
|
+
...
|
|
2524
|
+
hydpy.core.exceptiontools.AttributeNotReady: While trying to unite the \
|
|
2525
|
+
elements belonging to collective `network`, the following error occurred: The model \
|
|
2526
|
+
object of element `reach1` has been requested but not been prepared so far.
|
|
2527
|
+
|
|
2528
|
+
After such an error, at least the passed devices are accessible:
|
|
2529
|
+
|
|
2530
|
+
>>> hp.nodes
|
|
2531
|
+
Nodes("junction")
|
|
2532
|
+
>>> hp.elements
|
|
2533
|
+
Elements("reach1", "reach2")
|
|
2534
|
+
|
|
2535
|
+
Use the `silent` argument if you are aware of the incompleteness of the current
|
|
2536
|
+
project configuration and want to avoid capturing the error:
|
|
2537
|
+
|
|
2538
|
+
>>> hp.update_devices(selection=pub.selections.headwaters)
|
|
2539
|
+
>>> hp.update_devices(elements=(reach1, reach2), nodes=junction, silent=True)
|
|
2540
|
+
>>> hp.nodes
|
|
2541
|
+
Nodes("junction")
|
|
2542
|
+
>>> hp.elements
|
|
2543
|
+
Elements("reach1", "reach2")
|
|
2544
|
+
|
|
2545
|
+
Of course, silencing the error still does not mean |HydPy.update_devices|
|
|
2546
|
+
can do the complete work, which one might realise later when trying to access
|
|
2547
|
+
one of the unprepared properties:
|
|
2548
|
+
|
|
2549
|
+
>>> hp.deviceorder
|
|
2550
|
+
Traceback (most recent call last):
|
|
2551
|
+
...
|
|
2552
|
+
hydpy.core.exceptiontools.AttributeNotReady: While trying to access the \
|
|
2553
|
+
simulation order of the currently relevant devices, the following error occurred: \
|
|
2554
|
+
While trying to unite the elements belonging to collective `network`, the following \
|
|
2555
|
+
error occurred: The model object of element `reach1` has been requested but not been \
|
|
2556
|
+
prepared so far.
|
|
2557
|
+
"""
|
|
2558
|
+
if (nodes is not None) or (elements is not None):
|
|
2559
|
+
if selection is not None:
|
|
2560
|
+
raise ValueError(
|
|
2561
|
+
"Method `update_devices` of class `HydPy` does not allow to use "
|
|
2562
|
+
"both the `selection` argument and the `nodes` or the `elements` "
|
|
2563
|
+
"argument at the same time."
|
|
2564
|
+
)
|
|
2565
|
+
del self.nodes
|
|
2566
|
+
if nodes is None:
|
|
2567
|
+
nodes = devicetools.Nodes()
|
|
2568
|
+
self.nodes = nodes
|
|
2569
|
+
del self.elements
|
|
2570
|
+
if elements is None:
|
|
2571
|
+
elements = devicetools.Elements()
|
|
2572
|
+
self.elements = elements
|
|
2573
|
+
if selection is not None:
|
|
2574
|
+
self.nodes = selection.nodes
|
|
2575
|
+
self.elements = selection.elements
|
|
2576
|
+
self._update_collectives_and_deviceorder(silent=silent)
|
|
2577
|
+
|
|
2578
|
+
def _update_collectives_and_deviceorder(self, silent: bool):
|
|
2579
|
+
try:
|
|
2580
|
+
self._collectives = self.elements.unite_collectives()
|
|
2581
|
+
except exceptiontools.AttributeNotReady as exc:
|
|
2582
|
+
self._collectives = None
|
|
2583
|
+
self._deviceorder = None
|
|
2584
|
+
if not silent:
|
|
2585
|
+
raise exc
|
|
2586
|
+
else:
|
|
2587
|
+
graph = create_directedgraph(self.nodes, self._collectives)
|
|
2588
|
+
devices = tuple(networkx.topological_sort(graph))
|
|
2589
|
+
names = set(self.nodes.names)
|
|
2590
|
+
names.update(self._collectives.names)
|
|
2591
|
+
self._deviceorder = tuple(d for d in devices if d.name in names)
|
|
2592
|
+
|
|
2593
|
+
@property
|
|
2594
|
+
def deviceorder(self) -> tuple[devicetools.Node | devicetools.Element, ...]:
|
|
2595
|
+
"""The simulation order of the currently selected devices.
|
|
2596
|
+
|
|
2597
|
+
|HydPy| needs to know the devices before determining their order:
|
|
2598
|
+
|
|
2599
|
+
>>> from hydpy import HydPy
|
|
2600
|
+
>>> HydPy().deviceorder
|
|
2601
|
+
Traceback (most recent call last):
|
|
2602
|
+
...
|
|
2603
|
+
hydpy.core.exceptiontools.AttributeNotReady: While trying to access the \
|
|
2604
|
+
simulation order of the currently relevant devices, the following error occurred: The \
|
|
2605
|
+
actual HydPy instance does not handle any elements at the moment.
|
|
2606
|
+
|
|
2607
|
+
Usually, |HydPy.deviceorder| is ready after calling |HydPy.prepare_network|.
|
|
2608
|
+
|HydPy.update_devices| updates the given devices' order, too.
|
|
2609
|
+
"""
|
|
2610
|
+
try:
|
|
2611
|
+
if self._deviceorder is None:
|
|
2612
|
+
self._update_collectives_and_deviceorder(silent=False)
|
|
2613
|
+
assert (deviceorder := self._deviceorder) is not None
|
|
2614
|
+
return deviceorder
|
|
2615
|
+
except BaseException:
|
|
2616
|
+
objecttools.augment_excmessage(
|
|
2617
|
+
"While trying to access the simulation order of the currently "
|
|
2618
|
+
"relevant devices"
|
|
2619
|
+
)
|
|
2620
|
+
|
|
2621
|
+
@property
|
|
2622
|
+
def methodorder(self) -> list[Callable[[int], None]]:
|
|
2623
|
+
"""All methods of the currently relevant |Node| and |Element| objects, which
|
|
2624
|
+
are to be processed by method |HydPy.simulate| during a simulation time step,
|
|
2625
|
+
in a working execution order.
|
|
2626
|
+
|
|
2627
|
+
Property |HydPy.methodorder| should be of interest to framework developers only.
|
|
2628
|
+
"""
|
|
2629
|
+
# due to https://github.com/python/mypy/issues/9718:
|
|
2630
|
+
# pylint: disable=consider-using-in
|
|
2631
|
+
|
|
2632
|
+
funcs: list[Callable[[int], None]] = []
|
|
2633
|
+
if exceptiontools.attrready(hydpy.pub, "sequencemanager"):
|
|
2634
|
+
funcs.append(hydpy.pub.sequencemanager.read_netcdfslices)
|
|
2635
|
+
for node in self.nodes:
|
|
2636
|
+
if (
|
|
2637
|
+
(dm := node.deploymode) == "oldsim"
|
|
2638
|
+
or dm == "obs_oldsim"
|
|
2639
|
+
or dm == "oldsim_bi"
|
|
2640
|
+
or dm == "obs_oldsim_bi"
|
|
2641
|
+
):
|
|
2642
|
+
funcs.append(node.sequences.fastaccess.load_simdata)
|
|
2643
|
+
elif dm == "newsim" or dm == "obs" or dm == "obs_newsim" or dm == "obs_bi":
|
|
2644
|
+
funcs.append(node.sequences.fastaccess.reset)
|
|
2645
|
+
else:
|
|
2646
|
+
assert_never(dm)
|
|
2647
|
+
funcs.append(node.sequences.fastaccess.load_obsdata)
|
|
2648
|
+
for device in self.deviceorder:
|
|
2649
|
+
if isinstance(device, devicetools.Element):
|
|
2650
|
+
funcs.append(device.model.simulate)
|
|
2651
|
+
elif (
|
|
2652
|
+
(dm := device.deploymode) == "obs_newsim"
|
|
2653
|
+
or dm == "obs_oldsim"
|
|
2654
|
+
or dm == "obs_oldsim_bi"
|
|
2655
|
+
):
|
|
2656
|
+
funcs.append(device.sequences.fastaccess.fill_obsdata)
|
|
2657
|
+
elif not (
|
|
2658
|
+
dm == "newsim"
|
|
2659
|
+
or dm == "oldsim"
|
|
2660
|
+
or dm == "obs"
|
|
2661
|
+
or dm == "oldsim_bi"
|
|
2662
|
+
or dm == "obs_bi"
|
|
2663
|
+
):
|
|
2664
|
+
assert_never(dm)
|
|
2665
|
+
elements = self.collectives
|
|
2666
|
+
for element in elements:
|
|
2667
|
+
funcs.append(element.model.update_senders)
|
|
2668
|
+
for element in elements:
|
|
2669
|
+
funcs.append(element.model.update_receivers)
|
|
2670
|
+
for element in elements:
|
|
2671
|
+
funcs.append(element.model.save_data)
|
|
2672
|
+
for node in self.nodes:
|
|
2673
|
+
if (
|
|
2674
|
+
(dm := node.deploymode) == "obs_newsim"
|
|
2675
|
+
or dm == "obs_oldsim"
|
|
2676
|
+
or dm == "obs_oldsim_bi"
|
|
2677
|
+
):
|
|
2678
|
+
funcs.append(node.sequences.fastaccess.reset_obsdata)
|
|
2679
|
+
elif not (
|
|
2680
|
+
dm == "newsim"
|
|
2681
|
+
or dm == "oldsim"
|
|
2682
|
+
or dm == "obs"
|
|
2683
|
+
or dm == "oldsim_bi"
|
|
2684
|
+
or dm == "obs_bi"
|
|
2685
|
+
):
|
|
2686
|
+
assert_never(dm)
|
|
2687
|
+
funcs.append(node.sequences.fastaccess.save_simdata)
|
|
2688
|
+
funcs.append(node.sequences.fastaccess.save_obsdata)
|
|
2689
|
+
if exceptiontools.attrready(hydpy.pub, "sequencemanager"):
|
|
2690
|
+
funcs.append(hydpy.pub.sequencemanager.write_netcdfslices)
|
|
2691
|
+
return funcs
|
|
2692
|
+
|
|
2693
|
+
@printtools.print_progress
|
|
2694
|
+
def simulate(self) -> None:
|
|
2695
|
+
"""Perform a simulation run over the actual simulation period defined by the
|
|
2696
|
+
|Timegrids| object stored in module |pub|.
|
|
2697
|
+
|
|
2698
|
+
We let function |prepare_full_example_2| prepare a runnable |HydPy| object
|
|
2699
|
+
related to the :ref:`HydPy-H-Lahn` example project:
|
|
2700
|
+
|
|
2701
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
2702
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
2703
|
+
|
|
2704
|
+
First, we execute a default simulation run covering the whole simulation period
|
|
2705
|
+
and inspect the discharge series simulated at the outlet of the river basin,
|
|
2706
|
+
represented by node `lahn_kalk`:
|
|
2707
|
+
|
|
2708
|
+
>>> hp.simulate()
|
|
2709
|
+
>>> from hydpy import round_
|
|
2710
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2711
|
+
54.019337, 37.257561, 31.865308, 28.359542
|
|
2712
|
+
|
|
2713
|
+
After resetting the initial conditions via method |HydPy.reset_conditions|, we
|
|
2714
|
+
repeat the simulation run and get the same results:
|
|
2715
|
+
|
|
2716
|
+
>>> hp.reset_conditions()
|
|
2717
|
+
>>> hp.simulate()
|
|
2718
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2719
|
+
54.019337, 37.257561, 31.865308, 28.359542
|
|
2720
|
+
|
|
2721
|
+
Simulation runs do not need to cover the whole initialisation period at once.
|
|
2722
|
+
After setting the |Timegrid.lastdate| property of the `sim` |Timegrid| of the
|
|
2723
|
+
|Timegrids| objects stored within module |pub| to the middle of the
|
|
2724
|
+
initialisation period, method |HydPy.simulate| calculates the first two
|
|
2725
|
+
discharge values only:
|
|
2726
|
+
|
|
2727
|
+
>>> hp.reset_conditions()
|
|
2728
|
+
>>> hp.nodes.lahn_kalk.sequences.sim.series = 0.0
|
|
2729
|
+
>>> pub.timegrids.sim.lastdate = "1996-01-03"
|
|
2730
|
+
>>> hp.simulate()
|
|
2731
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2732
|
+
54.019337, 37.257561, 0.0, 0.0
|
|
2733
|
+
|
|
2734
|
+
After adjusting both the |Timegrid.firstdate| and |Timegrid.lastdate| of the
|
|
2735
|
+
`sim` |Timegrid| to the second half of the initialisation period,
|
|
2736
|
+
|HydPy.simulate| completes the time series:
|
|
2737
|
+
|
|
2738
|
+
>>> pub.timegrids.sim.firstdate = "1996-01-03"
|
|
2739
|
+
>>> pub.timegrids.sim.lastdate = "1996-01-05"
|
|
2740
|
+
>>> hp.simulate()
|
|
2741
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2742
|
+
54.019337, 37.257561, 31.865308, 28.359542
|
|
2743
|
+
|
|
2744
|
+
In the above examples, each |Model| object (handled by an |Element| object)
|
|
2745
|
+
passes its simulated values via a |Node| object to its downstream |Model|
|
|
2746
|
+
object. There are four ways to deviate from this default behaviour that can be
|
|
2747
|
+
selected for each node individually via the property |Node.deploymode|. We
|
|
2748
|
+
focus on node `lahn_leun` as the upstream neighbour of node `lahn_kalk`. So
|
|
2749
|
+
far, its deploy mode is `newsim`, meaning that the node passes newly calculated
|
|
2750
|
+
simulation values to the downstream element `stream_lahn_leun_lahn_kalk`:
|
|
2751
|
+
|
|
2752
|
+
>>> hp.nodes.lahn_leun.deploymode
|
|
2753
|
+
'newsim'
|
|
2754
|
+
|
|
2755
|
+
Under the second option, `oldsim`, node `lahn_leun` does not pass the discharge
|
|
2756
|
+
values simulated in the next simulation run, but the "old" discharge values
|
|
2757
|
+
already available by the |IOSequence.series| array of the |Sim| sequence. This
|
|
2758
|
+
behaviour can, for example, be useful when calibrating subsequent subareas of a
|
|
2759
|
+
river basin sequentially, beginning with the headwaters and continuing with
|
|
2760
|
+
their downstream neighbours. For the clarity of this example, we decrease all
|
|
2761
|
+
values of the "old" simulated series of node `lahn_leun` by 10 m³/s:
|
|
2762
|
+
|
|
2763
|
+
>>> round_(hp.nodes.lahn_leun.sequences.sim.series)
|
|
2764
|
+
42.346475, 27.157472, 22.88099, 20.156836
|
|
2765
|
+
>>> hp.nodes.lahn_leun.deploymode = "oldsim"
|
|
2766
|
+
>>> hp.nodes.lahn_leun.sequences.sim.series -= 10.0
|
|
2767
|
+
|
|
2768
|
+
After performing another simulation run (over the whole initialisation period,
|
|
2769
|
+
again), the modified discharge values of node `lahn_leun` are unchanged. The
|
|
2770
|
+
simulated values of node `lahn_kalk` are, compared to the `newsim` runs,
|
|
2771
|
+
decreased by 10 m³/s (there is no time delay or dampening of the discharge
|
|
2772
|
+
values between both nodes due to the lag time of application model
|
|
2773
|
+
|musk_classic| being shorter than the simulation time step):
|
|
2774
|
+
|
|
2775
|
+
>>> hp.reset_conditions()
|
|
2776
|
+
>>> pub.timegrids.sim.firstdate = "1996-01-01"
|
|
2777
|
+
>>> pub.timegrids.sim.lastdate = "1996-01-05"
|
|
2778
|
+
>>> hp.simulate()
|
|
2779
|
+
>>> round_(hp.nodes.lahn_leun.sequences.sim.series)
|
|
2780
|
+
32.346475, 17.157472, 12.88099, 10.156836
|
|
2781
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2782
|
+
44.019337, 27.257561, 21.865308, 18.359542
|
|
2783
|
+
|
|
2784
|
+
The third option is `obs`, where node `lahn_leun` receives and stores the values
|
|
2785
|
+
from its upstream models but passes other, observed values, handled by sequence
|
|
2786
|
+
|Obs|, which we, for simplicity, set to zero for the complete initialisation
|
|
2787
|
+
and simulation period (more often, one would read measured data from files via
|
|
2788
|
+
methods as |HydPy.load_obsseries|):
|
|
2789
|
+
|
|
2790
|
+
>>> hp.nodes.lahn_leun.deploymode = "obs"
|
|
2791
|
+
>>> hp.nodes.lahn_leun.sequences.obs.series = 0.0
|
|
2792
|
+
|
|
2793
|
+
Now, the simulated values of node `lahn_leun` are identical with the ones of the
|
|
2794
|
+
`newsim` example, but the simulated values of node `lahn_kalk` are lower due to
|
|
2795
|
+
receiving the observed instead of the simulated values from upstream:
|
|
2796
|
+
|
|
2797
|
+
>>> hp.reset_conditions()
|
|
2798
|
+
>>> hp.nodes.lahn_kalk.sequences.sim.series = 0.0
|
|
2799
|
+
>>> hp.simulate()
|
|
2800
|
+
>>> round_(hp.nodes.lahn_leun.sequences.obs.series)
|
|
2801
|
+
0.0, 0.0, 0.0, 0.0
|
|
2802
|
+
>>> round_(hp.nodes.lahn_leun.sequences.sim.series)
|
|
2803
|
+
42.346475, 27.157472, 22.88099, 20.156836
|
|
2804
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2805
|
+
11.672862, 10.100089, 8.984317, 8.202706
|
|
2806
|
+
|
|
2807
|
+
Unfortunately, observation time series are often incomplete. *HydPy* generally
|
|
2808
|
+
uses |numpy| |numpy.nan| to represent missing values. Passing |numpy.nan|
|
|
2809
|
+
inputs to a model usually results in |numpy.nan| outputs. Hence, after
|
|
2810
|
+
assigning |numpy.nan| to some entries of the observation series of node
|
|
2811
|
+
`lahn_leun`, the simulation series of node `lahn_kalk` also contains |numpy.nan|
|
|
2812
|
+
values:
|
|
2813
|
+
|
|
2814
|
+
>>> from numpy import nan
|
|
2815
|
+
>>> with pub.options.checkseries(False):
|
|
2816
|
+
... hp.nodes.lahn_leun.sequences.obs.series= 0.0, nan, 0.0, nan
|
|
2817
|
+
>>> hp.reset_conditions()
|
|
2818
|
+
>>> hp.nodes.lahn_kalk.sequences.sim.series = 0.0
|
|
2819
|
+
>>> hp.simulate()
|
|
2820
|
+
>>> round_(hp.nodes.lahn_leun.sequences.obs.series)
|
|
2821
|
+
0.0, nan, 0.0, nan
|
|
2822
|
+
>>> round_(hp.nodes.lahn_leun.sequences.sim.series)
|
|
2823
|
+
42.346475, 27.157472, 22.88099, 20.156836
|
|
2824
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2825
|
+
11.672862, nan, 8.984317, nan
|
|
2826
|
+
|
|
2827
|
+
To avoid calculating |numpy.nan| values, one can select the fourth option,
|
|
2828
|
+
`obs_newsim`. Now, the priority for node `lahn_leun` is to deploy its observed
|
|
2829
|
+
values. However, for each missing observation, it deploys its newly simulated
|
|
2830
|
+
value instead:
|
|
2831
|
+
|
|
2832
|
+
>>> hp.nodes.lahn_leun.deploymode = "obs_newsim"
|
|
2833
|
+
>>> hp.reset_conditions()
|
|
2834
|
+
>>> hp.simulate()
|
|
2835
|
+
>>> round_(hp.nodes.lahn_leun.sequences.obs.series)
|
|
2836
|
+
0.0, nan, 0.0, nan
|
|
2837
|
+
>>> round_(hp.nodes.lahn_leun.sequences.sim.series)
|
|
2838
|
+
42.346475, 27.157472, 22.88099, 20.156836
|
|
2839
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2840
|
+
11.672862, 37.257561, 8.984317, 28.359542
|
|
2841
|
+
|
|
2842
|
+
The fifth option, `obs_oldsim`, serves the same purpose as option `obs_newsim`
|
|
2843
|
+
but uses already available "old" simulation results as substitutes:
|
|
2844
|
+
|
|
2845
|
+
>>> hp.nodes.lahn_leun.deploymode = "obs_oldsim"
|
|
2846
|
+
>>> hp.reset_conditions()
|
|
2847
|
+
>>> hp.nodes.lahn_leun.sequences.sim.series = (
|
|
2848
|
+
... 32.3697, 17.210443, 12.930066, 10.20133)
|
|
2849
|
+
>>> hp.simulate()
|
|
2850
|
+
>>> round_(hp.nodes.lahn_leun.sequences.obs.series)
|
|
2851
|
+
0.0, nan, 0.0, nan
|
|
2852
|
+
>>> round_(hp.nodes.lahn_leun.sequences.sim.series)
|
|
2853
|
+
32.3697, 17.210443, 12.930066, 10.20133
|
|
2854
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2855
|
+
11.672862, 27.310532, 8.984317, 18.404036
|
|
2856
|
+
|
|
2857
|
+
The last example shows that resetting option |Node.deploymode| to `newsim`
|
|
2858
|
+
results in the default behaviour of the method |HydPy.simulate| again:
|
|
2859
|
+
|
|
2860
|
+
>>> hp.nodes.lahn_leun.deploymode = "newsim"
|
|
2861
|
+
>>> hp.reset_conditions()
|
|
2862
|
+
>>> hp.simulate()
|
|
2863
|
+
>>> round_(hp.nodes.lahn_leun.sequences.sim.series)
|
|
2864
|
+
42.346475, 27.157472, 22.88099, 20.156836
|
|
2865
|
+
>>> round_(hp.nodes.lahn_kalk.sequences.sim.series)
|
|
2866
|
+
54.019337, 37.257561, 31.865308, 28.359542
|
|
2867
|
+
"""
|
|
2868
|
+
idx_start, idx_end = hydpy.pub.timegrids.simindices
|
|
2869
|
+
methodorder = self.methodorder
|
|
2870
|
+
cm: AbstractContextManager[None] = contextlib.nullcontext()
|
|
2871
|
+
if exceptiontools.attrready(hydpy.pub, "sequencemanager"):
|
|
2872
|
+
cm = hydpy.pub.sequencemanager.provide_netcdfjitaccess(self.deviceorder)
|
|
2873
|
+
with cm:
|
|
2874
|
+
for idx in printtools.progressbar(range(idx_start, idx_end)):
|
|
2875
|
+
for func in methodorder:
|
|
2876
|
+
func(idx)
|
|
2877
|
+
|
|
2878
|
+
def doit(self) -> None:
|
|
2879
|
+
"""Deprecated! Use method |HydPy.simulate| instead.
|
|
2880
|
+
|
|
2881
|
+
>>> from hydpy import HydPy
|
|
2882
|
+
>>> from hydpy.core.testtools import warn_later
|
|
2883
|
+
>>> from unittest import mock
|
|
2884
|
+
>>> with warn_later(), mock.patch.object(HydPy, "simulate") as mocked:
|
|
2885
|
+
... hp = HydPy("test")
|
|
2886
|
+
... hp.doit()
|
|
2887
|
+
HydPyDeprecationWarning: Method `doit` of class `HydPy` is deprecated. Use \
|
|
2888
|
+
method `simulate` instead.
|
|
2889
|
+
>>> mocked.call_args_list
|
|
2890
|
+
[call()]
|
|
2891
|
+
"""
|
|
2892
|
+
self.simulate()
|
|
2893
|
+
warnings.warn(
|
|
2894
|
+
"Method `doit` of class `HydPy` is deprecated. Use method "
|
|
2895
|
+
"`simulate` instead.",
|
|
2896
|
+
exceptiontools.HydPyDeprecationWarning,
|
|
2897
|
+
)
|
|
2898
|
+
|
|
2899
|
+
def prepare_allseries(self, allocate_ram: bool = True, jit: bool = False) -> None:
|
|
2900
|
+
"""Tell all current |IOSequence| objects how to handle time series data.
|
|
2901
|
+
|
|
2902
|
+
Assign |True| to the `allocate_ram` argument (default) to activate the
|
|
2903
|
+
|IOSequence.series| property of all sequences so that their time series data
|
|
2904
|
+
can become available in RAM.
|
|
2905
|
+
|
|
2906
|
+
Assign |True| to the `jit` argument to activate the "just-in-time" reading from
|
|
2907
|
+
NetCDF files for all |InputSequence| and |Obs| objects and to activate the
|
|
2908
|
+
"just-in-time" writing of NetCDF files for all |FactorSequence|, |FluxSequence|,
|
|
2909
|
+
|StateSequence| and |Sim| objects.
|
|
2910
|
+
|
|
2911
|
+
See the main documentation on class |HydPy| for further information.
|
|
2912
|
+
"""
|
|
2913
|
+
self.prepare_modelseries(allocate_ram=allocate_ram, jit=jit)
|
|
2914
|
+
self.prepare_nodeseries(allocate_ram=allocate_ram, jit=jit)
|
|
2915
|
+
|
|
2916
|
+
def prepare_modelseries(self, allocate_ram: bool = True, jit: bool = False) -> None:
|
|
2917
|
+
"""An alternative method for |HydPy.prepare_allseries| specialised for model
|
|
2918
|
+
sequences."""
|
|
2919
|
+
self.elements.prepare_allseries(allocate_ram=allocate_ram, jit=jit)
|
|
2920
|
+
|
|
2921
|
+
def prepare_inputseries(
|
|
2922
|
+
self, allocate_ram: bool = True, read_jit: bool = False, write_jit: bool = False
|
|
2923
|
+
) -> None:
|
|
2924
|
+
"""An alternative method for |HydPy.prepare_allseries| specialised for model
|
|
2925
|
+
input sequences."""
|
|
2926
|
+
self.elements.prepare_inputseries(
|
|
2927
|
+
allocate_ram=allocate_ram, read_jit=read_jit, write_jit=write_jit
|
|
2928
|
+
)
|
|
2929
|
+
|
|
2930
|
+
def prepare_factorseries(
|
|
2931
|
+
self, allocate_ram: bool = True, write_jit: bool = False
|
|
2932
|
+
) -> None:
|
|
2933
|
+
"""An alternative method for |HydPy.prepare_allseries| specialised for model
|
|
2934
|
+
factor sequences."""
|
|
2935
|
+
self.elements.prepare_factorseries(
|
|
2936
|
+
allocate_ram=allocate_ram, write_jit=write_jit
|
|
2937
|
+
)
|
|
2938
|
+
|
|
2939
|
+
def prepare_fluxseries(
|
|
2940
|
+
self, allocate_ram: bool = True, write_jit: bool = False
|
|
2941
|
+
) -> None:
|
|
2942
|
+
"""An alternative method for |HydPy.prepare_allseries| specialised for model
|
|
2943
|
+
flux sequences."""
|
|
2944
|
+
self.elements.prepare_fluxseries(allocate_ram=allocate_ram, write_jit=write_jit)
|
|
2945
|
+
|
|
2946
|
+
def prepare_stateseries(
|
|
2947
|
+
self, allocate_ram: bool = True, write_jit: bool = False
|
|
2948
|
+
) -> None:
|
|
2949
|
+
"""An alternative method for |HydPy.prepare_allseries| specialised for model
|
|
2950
|
+
state sequences."""
|
|
2951
|
+
self.elements.prepare_stateseries(
|
|
2952
|
+
allocate_ram=allocate_ram, write_jit=write_jit
|
|
2953
|
+
)
|
|
2954
|
+
|
|
2955
|
+
def prepare_nodeseries(self, allocate_ram: bool = True, jit: bool = False) -> None:
|
|
2956
|
+
"""An alternative method for |HydPy.prepare_allseries| specialised for node
|
|
2957
|
+
sequences."""
|
|
2958
|
+
self.nodes.prepare_allseries(allocate_ram=allocate_ram, jit=jit)
|
|
2959
|
+
|
|
2960
|
+
def prepare_simseries(
|
|
2961
|
+
self, allocate_ram: bool = True, read_jit: bool = False, write_jit: bool = False
|
|
2962
|
+
) -> None:
|
|
2963
|
+
"""An alternative method for |HydPy.prepare_allseries| specialised for
|
|
2964
|
+
simulation sequences of nodes."""
|
|
2965
|
+
self.nodes.prepare_simseries(
|
|
2966
|
+
allocate_ram=allocate_ram, read_jit=read_jit, write_jit=write_jit
|
|
2967
|
+
)
|
|
2968
|
+
|
|
2969
|
+
def prepare_obsseries(
|
|
2970
|
+
self, allocate_ram: bool = True, read_jit: bool = False, write_jit: bool = False
|
|
2971
|
+
) -> None:
|
|
2972
|
+
"""An alternative method for |HydPy.prepare_allseries| specialised for
|
|
2973
|
+
observation sequences of nodes."""
|
|
2974
|
+
self.nodes.prepare_obsseries(
|
|
2975
|
+
allocate_ram=allocate_ram, read_jit=read_jit, write_jit=write_jit
|
|
2976
|
+
)
|
|
2977
|
+
|
|
2978
|
+
def save_allseries(self) -> None:
|
|
2979
|
+
"""Write the time series data of all current |IOSequence| objects at once to
|
|
2980
|
+
data file(s).
|
|
2981
|
+
|
|
2982
|
+
See the main documentation on class |HydPy| for further information.
|
|
2983
|
+
"""
|
|
2984
|
+
self.save_modelseries()
|
|
2985
|
+
self.save_nodeseries()
|
|
2986
|
+
|
|
2987
|
+
def save_modelseries(self) -> None:
|
|
2988
|
+
"""An alternative method for |HydPy.save_modelseries| specialised for model
|
|
2989
|
+
sequences."""
|
|
2990
|
+
self.elements.save_allseries()
|
|
2991
|
+
|
|
2992
|
+
def save_inputseries(self) -> None:
|
|
2993
|
+
"""An alternative method for |HydPy.save_modelseries| specialised for model
|
|
2994
|
+
input sequences."""
|
|
2995
|
+
self.elements.save_inputseries()
|
|
2996
|
+
|
|
2997
|
+
def save_factorseries(self) -> None:
|
|
2998
|
+
"""An alternative method for |HydPy.save_modelseries| specialised for model
|
|
2999
|
+
factor sequences."""
|
|
3000
|
+
self.elements.save_factorseries()
|
|
3001
|
+
|
|
3002
|
+
def save_fluxseries(self) -> None:
|
|
3003
|
+
"""An alternative method for |HydPy.save_modelseries| specialised for model
|
|
3004
|
+
flux sequences."""
|
|
3005
|
+
self.elements.save_fluxseries()
|
|
3006
|
+
|
|
3007
|
+
def save_stateseries(self) -> None:
|
|
3008
|
+
"""An alternative method for |HydPy.save_modelseries| specialised for model
|
|
3009
|
+
state sequences."""
|
|
3010
|
+
self.elements.save_stateseries()
|
|
3011
|
+
|
|
3012
|
+
def save_nodeseries(self) -> None:
|
|
3013
|
+
"""An alternative method for |HydPy.save_modelseries| specialised for node
|
|
3014
|
+
sequences."""
|
|
3015
|
+
self.nodes.save_allseries()
|
|
3016
|
+
|
|
3017
|
+
def save_simseries(self) -> None:
|
|
3018
|
+
"""An alternative method for |HydPy.save_modelseries| specialised for
|
|
3019
|
+
simulation sequences of nodes."""
|
|
3020
|
+
self.nodes.save_simseries()
|
|
3021
|
+
|
|
3022
|
+
def save_obsseries(self) -> None:
|
|
3023
|
+
"""An alternative method for |HydPy.save_modelseries| specialised for
|
|
3024
|
+
observation sequences of nodes."""
|
|
3025
|
+
self.nodes.save_obsseries()
|
|
3026
|
+
|
|
3027
|
+
def load_allseries(self) -> None:
|
|
3028
|
+
"""Read the time series data of all current |IOSequence| objects at once from
|
|
3029
|
+
data file(s).
|
|
3030
|
+
|
|
3031
|
+
See the main documentation on class |HydPy| for further information.
|
|
3032
|
+
"""
|
|
3033
|
+
self.load_modelseries()
|
|
3034
|
+
self.load_nodeseries()
|
|
3035
|
+
|
|
3036
|
+
def load_modelseries(self) -> None:
|
|
3037
|
+
"""An alternative method for |HydPy.load_modelseries| specialised for model
|
|
3038
|
+
sequences."""
|
|
3039
|
+
self.elements.load_allseries()
|
|
3040
|
+
|
|
3041
|
+
def load_inputseries(self) -> None:
|
|
3042
|
+
"""An alternative method for |HydPy.load_modelseries| specialised for model
|
|
3043
|
+
input sequences."""
|
|
3044
|
+
self.elements.load_inputseries()
|
|
3045
|
+
|
|
3046
|
+
def load_factorseries(self) -> None:
|
|
3047
|
+
"""An alternative method for |HydPy.load_modelseries| specialised for model
|
|
3048
|
+
factor sequences."""
|
|
3049
|
+
self.elements.load_factorseries()
|
|
3050
|
+
|
|
3051
|
+
def load_fluxseries(self) -> None:
|
|
3052
|
+
"""An alternative method for |HydPy.load_modelseries| specialised for model
|
|
3053
|
+
flux sequences."""
|
|
3054
|
+
self.elements.load_fluxseries()
|
|
3055
|
+
|
|
3056
|
+
def load_stateseries(self) -> None:
|
|
3057
|
+
"""An alternative method for |HydPy.load_modelseries| specialised for model
|
|
3058
|
+
state sequences."""
|
|
3059
|
+
self.elements.load_stateseries()
|
|
3060
|
+
|
|
3061
|
+
def load_nodeseries(self) -> None:
|
|
3062
|
+
"""An alternative method for |HydPy.load_modelseries| specialised for node
|
|
3063
|
+
sequences."""
|
|
3064
|
+
self.nodes.load_allseries()
|
|
3065
|
+
|
|
3066
|
+
def load_simseries(self) -> None:
|
|
3067
|
+
"""An alternative method for |HydPy.load_modelseries| specialised for
|
|
3068
|
+
simulation sequences of nodes."""
|
|
3069
|
+
self.nodes.load_simseries()
|
|
3070
|
+
|
|
3071
|
+
def load_obsseries(self) -> None:
|
|
3072
|
+
"""An alternative method for |HydPy.load_modelseries| specialised for
|
|
3073
|
+
observation sequences of nodes."""
|
|
3074
|
+
self.nodes.load_obsseries()
|
|
3075
|
+
|
|
3076
|
+
|
|
3077
|
+
def create_directedgraph(
|
|
3078
|
+
nodes: devicetools.Nodes, elements: devicetools.Elements
|
|
3079
|
+
) -> networkx.DiGraph:
|
|
3080
|
+
"""Create a directed graph based on the given devices."""
|
|
3081
|
+
digraph = networkx.DiGraph()
|
|
3082
|
+
digraph.add_nodes_from(elements)
|
|
3083
|
+
digraph.add_nodes_from(nodes)
|
|
3084
|
+
for element in elements:
|
|
3085
|
+
for node in itertools.chain(element.inlets, element.inputs):
|
|
3086
|
+
digraph.add_edge(node, element)
|
|
3087
|
+
for node in itertools.chain(element.outlets, element.outputs):
|
|
3088
|
+
digraph.add_edge(element, node)
|
|
3089
|
+
return digraph
|