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/exe/servertools.py
ADDED
|
@@ -0,0 +1,2348 @@
|
|
|
1
|
+
"""This module facilitates using *HydPy* as an HTTP server application.
|
|
2
|
+
|
|
3
|
+
.. _`OpenDA`: https://www.openda.org/
|
|
4
|
+
.. _`curl`: https://curl.haxx.se/
|
|
5
|
+
.. _`HydPy-OpenDA-Black-Box-Model-Wrapper`: \
|
|
6
|
+
https://github.com/hydpy-dev/OpenDA/tree/master/extensions/\
|
|
7
|
+
HydPyOpenDABBModelWrapper
|
|
8
|
+
.. _`issue`: https://github.com/hydpy-dev/OpenDA/issues
|
|
9
|
+
|
|
10
|
+
*HydPy* is designed to be used interactively or by executing individual Python scripts.
|
|
11
|
+
Consider the typical steps of calibrating model parameters. Usually, one first
|
|
12
|
+
prepares an instance of class |HydPy|, then changes some parameter values and performs
|
|
13
|
+
a simulation, and finally inspects whether the new simulation results are better than
|
|
14
|
+
the ones of the original parameterisation or not. One can perform these steps
|
|
15
|
+
manually (in a Python console) or apply optimisation tools like those provided by
|
|
16
|
+
|scipy| (usually in a Python script).
|
|
17
|
+
|
|
18
|
+
Performing or implementing such procedures is relatively simple, as long as all tools
|
|
19
|
+
are written in Python or come with a Python interface, which is not the case for some
|
|
20
|
+
relevant optimisation tools. One example is `OpenDA`_, being written in Java, which
|
|
21
|
+
was the original reason for adding module |servertools| to the *HydPy* framework.
|
|
22
|
+
|
|
23
|
+
Module |servertools| solves such integration problems by running *HydPy* within an
|
|
24
|
+
HTTP server. After starting such a server, one can use any HTTP client (e.g. `curl`_)
|
|
25
|
+
to perform the above steps.
|
|
26
|
+
|
|
27
|
+
The server's API is relatively simple, allowing performing a "normal" calibration using
|
|
28
|
+
only a few server methods. However, it is also more restrictive than controlling
|
|
29
|
+
*HydPy* within a Python process. Within a Python process, you are free to do anything.
|
|
30
|
+
Using the *HydPy* server, you are much more restricted to what was anticipated by the
|
|
31
|
+
framework developers.
|
|
32
|
+
|
|
33
|
+
Commonly but not mandatory, one configures the initial state of a *HydPy* server with
|
|
34
|
+
an XML file. As an example, we prepare the `HydPy-H-Lahn` project by calling function
|
|
35
|
+
|prepare_full_example_1|, which contains the XML configuration file
|
|
36
|
+
`multiple_runs_alpha.xml`:
|
|
37
|
+
|
|
38
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
39
|
+
>>> prepare_full_example_1()
|
|
40
|
+
|
|
41
|
+
To start the server in a new process, open a command-line tool and insert the following
|
|
42
|
+
command (see module |hyd| for general information on how to use *HydPy* via the command
|
|
43
|
+
line):
|
|
44
|
+
|
|
45
|
+
>>> command = "hyd.py start_server 8080 HydPy-H-Lahn multiple_runs_alpha.xml"
|
|
46
|
+
>>> from hydpy import run_subprocess, TestIO
|
|
47
|
+
>>> with TestIO():
|
|
48
|
+
... process = run_subprocess(command, blocking=False, verbose=False)
|
|
49
|
+
... result = run_subprocess("hyd.py await_server 8080 10", verbose=False)
|
|
50
|
+
|
|
51
|
+
The *HydPy* server should now be running on port 8080. You can use any HTTP client to
|
|
52
|
+
check it is working. For example, you can type the following URLs in your web browser
|
|
53
|
+
to get information on the types and initial values of the exchange items defined in
|
|
54
|
+
`multiple_runs_alpha.xml` (in a format required by the
|
|
55
|
+
`HydPy-OpenDA-Black-Box-Model-Wrapper`_):
|
|
56
|
+
|
|
57
|
+
>>> from urllib import request
|
|
58
|
+
>>> url = "http://127.0.0.1:8080/query_itemtypes"
|
|
59
|
+
>>> print(str(request.urlopen(url).read(), encoding="utf-8"))
|
|
60
|
+
alpha = Double0D
|
|
61
|
+
dill_assl_nodes_sim_series = TimeSeries0D
|
|
62
|
+
|
|
63
|
+
>>> url = "http://127.0.0.1:8080/query_initialitemvalues"
|
|
64
|
+
>>> print(str(request.urlopen(url).read(), encoding="utf-8"))
|
|
65
|
+
alpha = 2.0
|
|
66
|
+
dill_assl_nodes_sim_series = [nan, nan, nan, nan, nan]
|
|
67
|
+
|
|
68
|
+
It is generally possible to control the *HydPy* server via invoking each method with a
|
|
69
|
+
separate HTTP request. However, alternatively, one can use methods
|
|
70
|
+
|HydPyServer.GET_execute| and |HydPyServer.POST_execute| to execute many methods with
|
|
71
|
+
only one HTTP request. We now define three such metafunctions. The first one changes
|
|
72
|
+
the value of the parameter |hland_control.Alpha| The second one runs a simulation.
|
|
73
|
+
The third one prints the newly calculated discharge at the outlet of the headwater
|
|
74
|
+
catchment `Dill`. All of this is very similar to what the
|
|
75
|
+
`HydPy-OpenDA-Black-Box-Model-Wrapper`_ does.
|
|
76
|
+
|
|
77
|
+
Function `set_itemvalues` wraps the POST methods
|
|
78
|
+
|HydPyServer.POST_register_simulationdates|,
|
|
79
|
+
|HydPyServer.POST_register_parameteritemvalues|, and
|
|
80
|
+
|HydPyServer.POST_register_conditionitemvalues|. The *HydPy* server will execute
|
|
81
|
+
these methods in the given order. The arguments `firstdate_sim`, `lastdate_sim`,
|
|
82
|
+
and `alpha` allow changing the start and end date of the simulation period and the
|
|
83
|
+
value of parameter |hland_control.alpha| later:
|
|
84
|
+
|
|
85
|
+
>>> def set_itemvalues(id_, firstdate, lastdate, alpha):
|
|
86
|
+
... content = (f"firstdate_sim = {firstdate}\\n"
|
|
87
|
+
... f"lastdate_sim = {lastdate}\\n"
|
|
88
|
+
... f"alpha = {alpha}").encode("utf-8")
|
|
89
|
+
... methods = ",".join(("POST_register_simulationdates",
|
|
90
|
+
... "POST_register_parameteritemvalues",
|
|
91
|
+
... "POST_register_conditionitemvalues"))
|
|
92
|
+
... url = f"http://127.0.0.1:8080/execute?id={id_}&methods={methods}"
|
|
93
|
+
... request.urlopen(url, data=content)
|
|
94
|
+
|
|
95
|
+
Function `simulate` wraps only GET methods and triggers the next simulation run. As
|
|
96
|
+
for all GET and POST methods, one should pass the query parameter `id`, used by the
|
|
97
|
+
*HydPy* server for internal bookmarking:
|
|
98
|
+
|
|
99
|
+
>>> def simulate(id_):
|
|
100
|
+
... methods = ",".join(("GET_activate_simulationdates",
|
|
101
|
+
... "GET_activate_parameteritemvalues",
|
|
102
|
+
... "GET_load_internalconditions",
|
|
103
|
+
... "GET_activate_conditionitemvalues",
|
|
104
|
+
... "GET_simulate",
|
|
105
|
+
... "GET_save_internalconditions",
|
|
106
|
+
... "GET_update_conditionitemvalues",
|
|
107
|
+
... "GET_update_getitemvalues"))
|
|
108
|
+
... url = f"http://127.0.0.1:8080/execute?id={id_}&methods={methods}"
|
|
109
|
+
... request.urlopen(url)
|
|
110
|
+
|
|
111
|
+
Function `print_itemvalues` also wraps only GET methods and prints the current value of
|
|
112
|
+
parameter |hland_control.Alpha| as well as the lastly simulated discharge values
|
|
113
|
+
corresponding to the given `id` value:
|
|
114
|
+
|
|
115
|
+
>>> from hydpy import print_vector
|
|
116
|
+
>>> def print_itemvalues(id_):
|
|
117
|
+
... methods = ",".join(("GET_query_simulationdates",
|
|
118
|
+
... "GET_query_parameteritemvalues",
|
|
119
|
+
... "GET_query_conditionitemvalues",
|
|
120
|
+
... "GET_query_getitemvalues"))
|
|
121
|
+
... url = f"http://127.0.0.1:8080/execute?id={id_}&methods={methods}"
|
|
122
|
+
... data = str(request.urlopen(url).read(), encoding="utf-8")
|
|
123
|
+
... for line in data.split("\\n"):
|
|
124
|
+
... if line.startswith("alpha"):
|
|
125
|
+
... alpha = line.split("=")[1].strip()
|
|
126
|
+
... if line.startswith("dill_assl"):
|
|
127
|
+
... discharge = eval(line.split("=")[1])
|
|
128
|
+
... print(f"{alpha}: ", end="")
|
|
129
|
+
... print_vector(discharge)
|
|
130
|
+
|
|
131
|
+
For the sake of brevity, we also define `do_everything` for calling the other functions
|
|
132
|
+
at once:
|
|
133
|
+
|
|
134
|
+
>>> def do_everything(id_, firstdate, lastdate, alpha):
|
|
135
|
+
... set_itemvalues(id_, firstdate, lastdate, alpha)
|
|
136
|
+
... simulate(id_)
|
|
137
|
+
... print_itemvalues(id_)
|
|
138
|
+
|
|
139
|
+
In the simplest example, we perform a simulation throughout five days for an
|
|
140
|
+
|hland_control.Alpha| value of 2:
|
|
141
|
+
|
|
142
|
+
>>> do_everything("1a", "1996-01-01", "1996-01-06", 2.0)
|
|
143
|
+
2.0: 35.494358, 7.730125, 5.01782, 4.508775, 4.244626
|
|
144
|
+
|
|
145
|
+
The following example shows interlocked simulation runs. The first call only triggers
|
|
146
|
+
a simulation run for the first initialised day:
|
|
147
|
+
|
|
148
|
+
>>> do_everything("1b", "1996-01-01", "1996-01-02", 2.0)
|
|
149
|
+
2.0: 35.494358
|
|
150
|
+
|
|
151
|
+
The second call repeats the first one with a different `id` value:
|
|
152
|
+
|
|
153
|
+
>>> do_everything("2", "1996-01-01", "1996-01-02", 2.0)
|
|
154
|
+
2.0: 35.494358
|
|
155
|
+
|
|
156
|
+
The third call covers the first three initialisation days:
|
|
157
|
+
|
|
158
|
+
>>> do_everything("3", "1996-01-01", "1996-01-04", 2.0)
|
|
159
|
+
2.0: 35.494358, 7.730125, 5.01782
|
|
160
|
+
|
|
161
|
+
The fourth call continues the simulation of the first call, covering the last four
|
|
162
|
+
initialised days:
|
|
163
|
+
|
|
164
|
+
>>> do_everything("1b", "1996-01-02", "1996-01-06", 2.0)
|
|
165
|
+
2.0: 7.730125, 5.01782, 4.508775, 4.244626
|
|
166
|
+
|
|
167
|
+
The results of the very first call of function `do_everything` (with`id=1`) are
|
|
168
|
+
identical with the pulled-together discharge values of the calls with `id=1b`, made
|
|
169
|
+
possible by the internal bookmarking feature of the *HydPy* server. Here we use
|
|
170
|
+
numbers, but any other strings are valid `id` values.
|
|
171
|
+
|
|
172
|
+
This example extends the last one by applying different parameter values:
|
|
173
|
+
|
|
174
|
+
>>> do_everything("4", "1996-01-01", "1996-01-04", 2.0)
|
|
175
|
+
2.0: 35.494358, 7.730125, 5.01782
|
|
176
|
+
>>> do_everything("5", "1996-01-01", "1996-01-04", 1.0)
|
|
177
|
+
1.0: 11.757526, 8.865079, 7.101815
|
|
178
|
+
>>> do_everything("4", "1996-01-04", "1996-01-06", 2.0)
|
|
179
|
+
2.0: 4.508775, 4.244626
|
|
180
|
+
>>> do_everything("5", "1996-01-04", "1996-01-06", 1.0)
|
|
181
|
+
1.0: 5.994195, 5.301584
|
|
182
|
+
>>> do_everything("5", "1996-01-01", "1996-01-06", 1.0)
|
|
183
|
+
1.0: 11.757526, 8.865079, 7.101815, 5.994195, 5.301584
|
|
184
|
+
|
|
185
|
+
The order in which function `do_everything` calls its subfunctions seems quite natural,
|
|
186
|
+
but some tools might require do deviate from it. For example, `OpenDA`_ offers
|
|
187
|
+
ensemble-based algorithms triggering the simulation of all memberse before starting to
|
|
188
|
+
query any simulation results. The final example shows that the underlying atomic
|
|
189
|
+
methods support such an execution sequence:
|
|
190
|
+
|
|
191
|
+
>>> set_itemvalues("6", "1996-01-01", "1996-01-03", 2.0)
|
|
192
|
+
>>> simulate("6")
|
|
193
|
+
>>> set_itemvalues("7", "1996-01-01", "1996-01-03", 1.0)
|
|
194
|
+
>>> simulate("7")
|
|
195
|
+
>>> print_itemvalues("6")
|
|
196
|
+
2.0: 35.494358, 7.730125
|
|
197
|
+
>>> print_itemvalues("7")
|
|
198
|
+
1.0: 11.757526, 8.865079
|
|
199
|
+
|
|
200
|
+
When working in parallel mode, `OpenDA`_ might not always call the functions
|
|
201
|
+
`set_itemvalues` and `simulate` for the same `id` directly one after another, which
|
|
202
|
+
also causes no problem:
|
|
203
|
+
|
|
204
|
+
>>> set_itemvalues("6", "1996-01-03", "1996-01-06", 2.0)
|
|
205
|
+
>>> set_itemvalues("7", "1996-01-03", "1996-01-06", 1.0)
|
|
206
|
+
>>> simulate("6")
|
|
207
|
+
>>> simulate("7")
|
|
208
|
+
>>> print_itemvalues("6")
|
|
209
|
+
2.0: 5.01782, 4.508775, 4.244626
|
|
210
|
+
>>> print_itemvalues("7")
|
|
211
|
+
1.0: 7.101815, 5.994195, 5.301584
|
|
212
|
+
|
|
213
|
+
Finally, we close the server and kill its process (just closing your command-line tool
|
|
214
|
+
works likewise):
|
|
215
|
+
|
|
216
|
+
>>> _ = request.urlopen("http://127.0.0.1:8080/close_server")
|
|
217
|
+
>>> process.kill()
|
|
218
|
+
>>> _ = process.communicate()
|
|
219
|
+
|
|
220
|
+
The above description focussed on coupling *HydPy* to `OpenDA`_. However, the applied
|
|
221
|
+
atomic submethods of class |HydPyServer| also allow coupling *HydPy* with other
|
|
222
|
+
software products. See the documentation on class |HydPyServer| for further information.
|
|
223
|
+
"""
|
|
224
|
+
|
|
225
|
+
# import...
|
|
226
|
+
# ...from standard library
|
|
227
|
+
from __future__ import annotations
|
|
228
|
+
import collections
|
|
229
|
+
import mimetypes
|
|
230
|
+
import os
|
|
231
|
+
|
|
232
|
+
# import http.server # moved below for efficiency reasons
|
|
233
|
+
import threading
|
|
234
|
+
import time
|
|
235
|
+
import urllib.error
|
|
236
|
+
import urllib.parse
|
|
237
|
+
import urllib.request
|
|
238
|
+
import types
|
|
239
|
+
|
|
240
|
+
# ...from site-packages
|
|
241
|
+
import numpy
|
|
242
|
+
|
|
243
|
+
# ...from HydPy
|
|
244
|
+
import hydpy
|
|
245
|
+
from hydpy import conf
|
|
246
|
+
from hydpy import config
|
|
247
|
+
from hydpy.core import hydpytools
|
|
248
|
+
from hydpy.core import itemtools
|
|
249
|
+
from hydpy.core import objecttools
|
|
250
|
+
from hydpy.core import timetools
|
|
251
|
+
from hydpy.exe import commandtools
|
|
252
|
+
from hydpy.exe import xmltools
|
|
253
|
+
from hydpy.core.typingtools import *
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# pylint: disable=wrong-import-position, wrong-import-order
|
|
257
|
+
# see the documentation on method `start_server` for explanations
|
|
258
|
+
mimetypes.inited = True
|
|
259
|
+
import http.server
|
|
260
|
+
|
|
261
|
+
mimetypes.inited = False
|
|
262
|
+
# pylint: enable=wrong-import-position, wrong-import-order
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
ID = NewType("ID", str)
|
|
266
|
+
ID.__doc__ = """Type for strings that identify "artificial" *HydPy* instances (from a
|
|
267
|
+
client's point of view)."""
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class ServerState:
|
|
271
|
+
"""Singleton class handling states like the current |HydPy| instance exchange items.
|
|
272
|
+
|
|
273
|
+
The instance of class |ServerState| is available as the member `state` of class
|
|
274
|
+
|HydPyServer| after calling the function |start_server|. You could create other
|
|
275
|
+
instances (like we do in the following examples), but you most likely shouldn't.
|
|
276
|
+
The primary purpose of this instance is to store information between successive
|
|
277
|
+
initialisations of class |HydPyServer|.
|
|
278
|
+
|
|
279
|
+
We use the `HydPy-H-Lahn` project and its (complicated) XML configuration file
|
|
280
|
+
`multiple_runs.xml` as an example (module |xmltools| provides information on
|
|
281
|
+
interpreting this file):
|
|
282
|
+
|
|
283
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
284
|
+
>>> prepare_full_example_1()
|
|
285
|
+
>>> from hydpy import print_vector, TestIO
|
|
286
|
+
>>> from hydpy.exe.servertools import ServerState
|
|
287
|
+
>>> with TestIO(): # doctest: +ELLIPSIS
|
|
288
|
+
... state = ServerState("HydPy-H-Lahn", "multiple_runs.xml")
|
|
289
|
+
Start HydPy project `HydPy-H-Lahn` (...).
|
|
290
|
+
Read configuration file `multiple_runs.xml` (...).
|
|
291
|
+
Interpret the defined options (...).
|
|
292
|
+
Interpret the defined period (...).
|
|
293
|
+
Read all network files (...).
|
|
294
|
+
Activate the selected network (...).
|
|
295
|
+
Read the required control files (...).
|
|
296
|
+
Read the required condition files (...).
|
|
297
|
+
Read the required time series files (...).
|
|
298
|
+
|
|
299
|
+
After initialisation, all defined exchange items are available:
|
|
300
|
+
|
|
301
|
+
>>> for item in state.parameteritems:
|
|
302
|
+
... print(item)
|
|
303
|
+
SetItem(name="alpha", master="hland_96", target="control.alpha", level="global")
|
|
304
|
+
SetItem(name="beta", master="hland_96", target="control.beta", level="global")
|
|
305
|
+
SetItem(name="lag", master="musk_classic", target="control.nmbsegments", \
|
|
306
|
+
keyword="lag", level="global")
|
|
307
|
+
SetItem(name="damp", master="musk_classic", target="control.coefficients", \
|
|
308
|
+
keyword="damp", level="global")
|
|
309
|
+
AddItem(name="sfcf_1", master="hland_96", target="control.sfcf", \
|
|
310
|
+
base="control.rfcf", level="global")
|
|
311
|
+
AddItem(name="sfcf_2", master="hland_96", target="control.sfcf", \
|
|
312
|
+
base="control.rfcf", level="global")
|
|
313
|
+
AddItem(name="sfcf_3", master="hland_96", target="control.sfcf", \
|
|
314
|
+
base="control.rfcf", level="subunit")
|
|
315
|
+
MultiplyItem(name="k4", master="hland_96", target="control.k4", base="control.k", \
|
|
316
|
+
level="global")
|
|
317
|
+
>>> for item in state.conditionitems:
|
|
318
|
+
... print(item)
|
|
319
|
+
SetItem(name="ic_lahn_leun", master="hland_96", target="states.ic", level="device")
|
|
320
|
+
SetItem(name="ic_lahn_marb", master="hland_96", target="states.ic", level="subunit")
|
|
321
|
+
SetItem(name="sm_lahn_leun", master="hland_96", target="states.sm", level="device")
|
|
322
|
+
SetItem(name="sm_lahn_marb", master="hland_96", target="states.sm", level="subunit")
|
|
323
|
+
SetItem(name="quh", master="rconc_uh", target="logs.quh", level="device")
|
|
324
|
+
>>> for item in state.getitems:
|
|
325
|
+
... print(item)
|
|
326
|
+
GetItem(name="?", master="hland_96", target="factors.contriarea")
|
|
327
|
+
GetItem(name="current_discharge", master="hland_96", target="fluxes.qt")
|
|
328
|
+
GetItem(name="entire_discharge_series", master="hland_96", \
|
|
329
|
+
target="fluxes.qt.series")
|
|
330
|
+
GetItem(name="?", master="hland_96", target="states.sm")
|
|
331
|
+
GetItem(name="?", master="hland_96", target="states.sm.series")
|
|
332
|
+
GetItem(name="?", master="nodes", target="nodes.sim.series")
|
|
333
|
+
|
|
334
|
+
The initialisation also memorises the initial conditions of all elements:
|
|
335
|
+
|
|
336
|
+
>>> for element in state.init_conditions:
|
|
337
|
+
... print(element)
|
|
338
|
+
land_dill_assl
|
|
339
|
+
land_lahn_kalk
|
|
340
|
+
land_lahn_leun
|
|
341
|
+
land_lahn_marb
|
|
342
|
+
stream_dill_assl_lahn_leun
|
|
343
|
+
stream_lahn_leun_lahn_kalk
|
|
344
|
+
stream_lahn_marb_lahn_leun
|
|
345
|
+
|
|
346
|
+
The initialisation also prepares all selected series arrays and reads the
|
|
347
|
+
required input data:
|
|
348
|
+
|
|
349
|
+
>>> print_vector(state.hp.elements.land_dill_assl.model.sequences.inputs.t.series)
|
|
350
|
+
0.0, -0.5, -2.4, -6.8, -7.8
|
|
351
|
+
>>> state.hp.nodes.dill_assl.sequences.sim.series
|
|
352
|
+
InfoArray([nan, nan, nan, nan, nan])
|
|
353
|
+
"""
|
|
354
|
+
|
|
355
|
+
interface: xmltools.XMLInterface
|
|
356
|
+
hp: hydpytools.HydPy
|
|
357
|
+
parameteritems: list[itemtools.ChangeItem]
|
|
358
|
+
inputitems: list[itemtools.SetItem]
|
|
359
|
+
conditionitems: list[itemtools.SetItem]
|
|
360
|
+
outputitems: list[itemtools.SetItem]
|
|
361
|
+
getitems: list[itemtools.GetItem]
|
|
362
|
+
conditions: dict[ID, dict[int, Conditions]]
|
|
363
|
+
parameteritemvalues: dict[ID, dict[Name, Any]]
|
|
364
|
+
inputitemvalues: dict[ID, dict[Name, Any]]
|
|
365
|
+
conditionitemvalues: dict[ID, dict[Name, Any]]
|
|
366
|
+
outputitemvalues: dict[ID, dict[Name, Any]]
|
|
367
|
+
getitemvalues: dict[ID, dict[Name, str]]
|
|
368
|
+
initialparameteritemvalues: dict[Name, Any]
|
|
369
|
+
initialinputitemvalues: dict[Name, Any]
|
|
370
|
+
initialconditionitemvalues: dict[Name, Any]
|
|
371
|
+
initialgetitemvalues: dict[Name, Any]
|
|
372
|
+
timegrids: dict[ID, timetools.Timegrid]
|
|
373
|
+
init_conditions: Conditions
|
|
374
|
+
inputconditiondirs: dict[ID, str]
|
|
375
|
+
outputconditiondirs: dict[ID, str]
|
|
376
|
+
serieswriterdirs: dict[ID, str]
|
|
377
|
+
seriesreaderdirs: dict[ID, str]
|
|
378
|
+
outputcontroldirs: dict[ID, str]
|
|
379
|
+
idx1: int
|
|
380
|
+
idx2: int
|
|
381
|
+
|
|
382
|
+
def __init__(
|
|
383
|
+
self,
|
|
384
|
+
projectname: str,
|
|
385
|
+
xmlfile: str,
|
|
386
|
+
load_conditions: bool = True,
|
|
387
|
+
load_series: bool = True,
|
|
388
|
+
) -> None:
|
|
389
|
+
write = commandtools.print_textandtime
|
|
390
|
+
write(f"Start HydPy project `{projectname}`")
|
|
391
|
+
hp = hydpytools.HydPy(projectname)
|
|
392
|
+
write(f"Read configuration file `{xmlfile}`")
|
|
393
|
+
self.interface = xmltools.XMLInterface(xmlfile)
|
|
394
|
+
write("Interpret the defined options")
|
|
395
|
+
self.interface.update_options()
|
|
396
|
+
write("Interpret the defined period")
|
|
397
|
+
self.interface.update_timegrids()
|
|
398
|
+
write("Read all network files")
|
|
399
|
+
self.interface.network_io.prepare_network()
|
|
400
|
+
write("Create the custom selections (if defined)")
|
|
401
|
+
self.interface.update_selections()
|
|
402
|
+
write("Activate the selected network")
|
|
403
|
+
hp.update_devices(selection=self.interface.fullselection, silent=True)
|
|
404
|
+
write("Read the required control files")
|
|
405
|
+
self.interface.control_io.prepare_models()
|
|
406
|
+
if load_conditions:
|
|
407
|
+
write("Read the required condition files")
|
|
408
|
+
self.interface.conditions_io.load_conditions()
|
|
409
|
+
if load_series:
|
|
410
|
+
write("Read the required time series files")
|
|
411
|
+
self.interface.series_io.prepare_series()
|
|
412
|
+
self.interface.exchange.prepare_series()
|
|
413
|
+
if load_series:
|
|
414
|
+
self.interface.series_io.load_series()
|
|
415
|
+
self.hp = hp
|
|
416
|
+
self.parameteritems = self.interface.exchange.parameteritems
|
|
417
|
+
self.inputitems = self.interface.exchange.inputitems
|
|
418
|
+
self.conditionitems = self.interface.exchange.conditionitems
|
|
419
|
+
self.outputitems = self.interface.exchange.outputitems
|
|
420
|
+
self.getitems = self.interface.exchange.getitems
|
|
421
|
+
self.initialparameteritemvalues = {
|
|
422
|
+
item.name: item.value for item in self.parameteritems
|
|
423
|
+
}
|
|
424
|
+
self.initialinputitemvalues = {
|
|
425
|
+
item.name: item.value for item in self.inputitems
|
|
426
|
+
}
|
|
427
|
+
self.initialconditionitemvalues = {
|
|
428
|
+
item.name: item.value for item in self.conditionitems
|
|
429
|
+
}
|
|
430
|
+
self.initialoutputitemvalues = {
|
|
431
|
+
item.name: item.value for item in self.outputitems
|
|
432
|
+
}
|
|
433
|
+
self.initialgetitemvalues = {
|
|
434
|
+
name: value
|
|
435
|
+
for item in self.getitems
|
|
436
|
+
for name, value in item.yield_name2value(*hydpy.pub.timegrids.simindices)
|
|
437
|
+
}
|
|
438
|
+
self.conditions = {}
|
|
439
|
+
self.parameteritemvalues = {}
|
|
440
|
+
self.inputitemvalues = {}
|
|
441
|
+
self.conditionitemvalues = {}
|
|
442
|
+
self.outputitemvalues = {}
|
|
443
|
+
self.getitemvalues = {}
|
|
444
|
+
self.init_conditions = hp.conditions
|
|
445
|
+
self.timegrids = {}
|
|
446
|
+
self.serieswriterdirs = {}
|
|
447
|
+
self.seriesreaderdirs = {}
|
|
448
|
+
self.inputconditiondirs = {}
|
|
449
|
+
self.outputconditiondirs = {}
|
|
450
|
+
self.outputcontroldirs = {}
|
|
451
|
+
self.idx1 = 0
|
|
452
|
+
self.idx2 = 0
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
class HydPyServer(http.server.BaseHTTPRequestHandler):
|
|
456
|
+
"""The API of the *HydPy* server.
|
|
457
|
+
|
|
458
|
+
Technically and strictly speaking, |HydPyServer| is, only the HTTP request handler
|
|
459
|
+
for the real HTTP server class (from the standard library).
|
|
460
|
+
|
|
461
|
+
After initialising the *HydPy* server, each communication via a GET or POST request
|
|
462
|
+
is handled by a new instance of |HydPyServer|. This handling occurs in a unified
|
|
463
|
+
way using either method |HydPyServer.do_GET| or [HydPyServer.do_POST|, which select
|
|
464
|
+
and apply the actual GET or POST method. All methods provided by class
|
|
465
|
+
|HydPyServer| starting with "GET" or "POST" are accessible via HTTP.
|
|
466
|
+
|
|
467
|
+
In the main documentation on module |servertools|, we use the
|
|
468
|
+
`multiple_runs_alpha.xml` file of the `HydPy-H-Lahn` project as an example.
|
|
469
|
+
However, now we select the more complex XML configuration file `multiple_runs.xml`,
|
|
470
|
+
covering a higher number of cases:
|
|
471
|
+
|
|
472
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
473
|
+
>>> prepare_full_example_1()
|
|
474
|
+
>>> from hydpy import run_subprocess, TestIO
|
|
475
|
+
>>> with TestIO():
|
|
476
|
+
... process = run_subprocess(
|
|
477
|
+
... "hyd.py start_server 8080 HydPy-H-Lahn multiple_runs.xml "
|
|
478
|
+
... "debugging=enable",
|
|
479
|
+
... blocking=False,
|
|
480
|
+
... verbose=False,
|
|
481
|
+
... )
|
|
482
|
+
... result = run_subprocess("hyd.py await_server 8080 10", verbose=False)
|
|
483
|
+
|
|
484
|
+
We define a test function that simplifies sending the following requests and offers
|
|
485
|
+
two optional arguments. When passing a value to `id_`, `test` adds this value as
|
|
486
|
+
the query parameter `id` to the URL. When passing a string to `data`, `test` sends
|
|
487
|
+
a POST request containing the given data; otherwise, a GET request without
|
|
488
|
+
additional data:
|
|
489
|
+
|
|
490
|
+
>>> from urllib import request
|
|
491
|
+
>>> def test(name, id_=None, data=None, return_result=False):
|
|
492
|
+
... url = f"http://127.0.0.1:8080/{name}"
|
|
493
|
+
... if id_:
|
|
494
|
+
... url = f"{url}?id={id_}"
|
|
495
|
+
... if data:
|
|
496
|
+
... data = bytes(data, encoding="utf-8")
|
|
497
|
+
... response = request.urlopen(url, data=data)
|
|
498
|
+
... result = str(response.read(), encoding="utf-8")
|
|
499
|
+
... print(result)
|
|
500
|
+
... return result if return_result else None
|
|
501
|
+
|
|
502
|
+
Asking for its status tells us that the server is ready (which may take a while,
|
|
503
|
+
depending on the project's size):
|
|
504
|
+
|
|
505
|
+
>>> test("status")
|
|
506
|
+
status = ready
|
|
507
|
+
|
|
508
|
+
You can query the current version number of the *HydPy* installation used to start
|
|
509
|
+
the server:
|
|
510
|
+
|
|
511
|
+
>>> result = test("version", return_result=True) # doctest: +ELLIPSIS
|
|
512
|
+
version = ...
|
|
513
|
+
>>> hydpy.__version__ in result
|
|
514
|
+
True
|
|
515
|
+
|
|
516
|
+
|HydPyServer| returns the error code `400` if it realises the URL to be wrong:
|
|
517
|
+
|
|
518
|
+
>>> test("missing")
|
|
519
|
+
Traceback (most recent call last):
|
|
520
|
+
...
|
|
521
|
+
urllib.error.HTTPError: HTTP Error 400: RuntimeError: No method `GET_missing` \
|
|
522
|
+
available.
|
|
523
|
+
|
|
524
|
+
The error code is `500` in all other cases of error:
|
|
525
|
+
|
|
526
|
+
>>> test("register_parameteritemvalues", id_="0", data="alpha = []")
|
|
527
|
+
Traceback (most recent call last):
|
|
528
|
+
...
|
|
529
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
530
|
+
method `POST_register_parameteritemvalues`, the following error occurred: A value for \
|
|
531
|
+
parameter item `beta` is missing.
|
|
532
|
+
|
|
533
|
+
Some methods require identity information, passed as query parameter `id`, used for
|
|
534
|
+
internal bookmarking:
|
|
535
|
+
|
|
536
|
+
>>> test("query_parameteritemvalues")
|
|
537
|
+
Traceback (most recent call last):
|
|
538
|
+
...
|
|
539
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
540
|
+
method `GET_query_parameteritemvalues`, the following error occurred: For the GET \
|
|
541
|
+
method `query_parameteritemvalues` no query parameter `id` is given.
|
|
542
|
+
|
|
543
|
+
POST methods always expect an arbitrary number of lines, each one assigning some
|
|
544
|
+
values to some variable (in most cases, numbers to exchange items):
|
|
545
|
+
|
|
546
|
+
>>> test("parameteritemvalues",
|
|
547
|
+
... id_="a",
|
|
548
|
+
... data=("x = y\\n"
|
|
549
|
+
... " \\n"
|
|
550
|
+
... "x == y\\n"
|
|
551
|
+
... "x = y"))
|
|
552
|
+
Traceback (most recent call last):
|
|
553
|
+
...
|
|
554
|
+
urllib.error.HTTPError: HTTP Error 400: RuntimeError: The POST method \
|
|
555
|
+
`parameteritemvalues` received a wrongly formated data body. The following line has \
|
|
556
|
+
been extracted but cannot be further processed: `x == y`.
|
|
557
|
+
|
|
558
|
+
Before explaining the more offical methods, we introduce the method
|
|
559
|
+
|HydPyServer.POST_evaluate|, which evaluates arbitrary valid Python code within the
|
|
560
|
+
server process. Its most likely use-case is to access the (sub)attributes of the
|
|
561
|
+
single instance of class |ServerState|, available as a member of class
|
|
562
|
+
|HydPyServer|. This method can help when being puzzled about the state of the
|
|
563
|
+
*HydPy* server. Use it, for example, to find out which |Node| objects are
|
|
564
|
+
available and to see which one is the outlet node of the |Element| object
|
|
565
|
+
`land_dill_assl`:
|
|
566
|
+
|
|
567
|
+
>>> test("evaluate",
|
|
568
|
+
... data=("nodes = HydPyServer.state.hp.nodes\\n"
|
|
569
|
+
... "elements = HydPyServer.state.hp.elements.land_dill_assl"))
|
|
570
|
+
nodes = Nodes("dill_assl", "lahn_kalk", "lahn_leun", "lahn_marb")
|
|
571
|
+
elements = Element("land_dill_assl", outlets="dill_assl", keywords="catchment")
|
|
572
|
+
|
|
573
|
+
Method |HydPyServer.GET_query_itemtypes|, already described in the main
|
|
574
|
+
documentation of module |servertools|, returns all available exchange item types
|
|
575
|
+
at once. However, it is also possible to query those that are related to setting
|
|
576
|
+
parameter values (|HydPyServer.GET_query_parameteritemtypes|), setting condition
|
|
577
|
+
values (|HydPyServer.GET_query_conditionitemtypes|), setting input time series
|
|
578
|
+
(|HydPyServer.GET_query_inputitemtypes|), getting values or series of factors or
|
|
579
|
+
fluxes in the "setitem style" (|HydPyServer.GET_query_outputitemtypes|) and getting
|
|
580
|
+
different kinds of values or series in the "getitem style"
|
|
581
|
+
(|HydPyServer.GET_query_getitemtypes|) separately:
|
|
582
|
+
|
|
583
|
+
>>> test("query_parameteritemtypes")
|
|
584
|
+
alpha = Double0D
|
|
585
|
+
beta = Double0D
|
|
586
|
+
lag = Double0D
|
|
587
|
+
damp = Double0D
|
|
588
|
+
sfcf_1 = Double0D
|
|
589
|
+
sfcf_2 = Double0D
|
|
590
|
+
sfcf_3 = Double1D
|
|
591
|
+
k4 = Double0D
|
|
592
|
+
>>> test("query_conditionitemtypes")
|
|
593
|
+
ic_lahn_leun = Double1D
|
|
594
|
+
ic_lahn_marb = Double1D
|
|
595
|
+
sm_lahn_leun = Double1D
|
|
596
|
+
sm_lahn_marb = Double1D
|
|
597
|
+
quh = Double1D
|
|
598
|
+
>>> test("query_inputitemtypes")
|
|
599
|
+
t_headwaters = TimeSeries1D
|
|
600
|
+
>>> test("query_outputitemtypes")
|
|
601
|
+
swe_headwaters = TimeSeries1D
|
|
602
|
+
>>> test("query_getitemtypes")
|
|
603
|
+
land_dill_assl_factors_contriarea = Double0D
|
|
604
|
+
land_dill_assl_fluxes_qt = Double0D
|
|
605
|
+
land_dill_assl_fluxes_qt_series = TimeSeries0D
|
|
606
|
+
land_dill_assl_states_sm = Double1D
|
|
607
|
+
land_lahn_kalk_states_sm = Double1D
|
|
608
|
+
land_lahn_leun_states_sm = Double1D
|
|
609
|
+
land_lahn_marb_states_sm = Double1D
|
|
610
|
+
land_lahn_kalk_states_sm_series = TimeSeries1D
|
|
611
|
+
dill_assl_nodes_sim_series = TimeSeries0D
|
|
612
|
+
|
|
613
|
+
The same holds for the initial values of the exchange items. Method
|
|
614
|
+
|HydPyServer.GET_query_initialitemvalues| returns them all at once, while the
|
|
615
|
+
methods |HydPyServer.GET_query_initialparameteritemvalues|,
|
|
616
|
+
|HydPyServer.GET_query_initialconditionitemvalues|,
|
|
617
|
+
|HydPyServer.GET_query_initialinputitemvalues|,
|
|
618
|
+
|HydPyServer.GET_query_initialoutputitemvalues|, and
|
|
619
|
+
(|HydPyServer.GET_query_initialgetitemvalues| return the relevant subgroup only.
|
|
620
|
+
Note that for the exchange items related to state sequence |hland_states.SM|
|
|
621
|
+
(`sm_lahn_marb` and `sm_lahn_leun`), the initial values stem from the XML file.
|
|
622
|
+
For the items related to state sequence |hland_states.Ic| and input sequence
|
|
623
|
+
|hland_inputs.T|, the XML file does not provide such information. Thus, the
|
|
624
|
+
initial values of `ic_lahn_marb`, `ic_lahn_leun`, and `t_headwaters` stem from the
|
|
625
|
+
corresponding sequences themselves (and thus, indirectly, from the respective
|
|
626
|
+
condition and time series files):
|
|
627
|
+
|
|
628
|
+
>>> test("query_initialparameteritemvalues")
|
|
629
|
+
alpha = 2.0
|
|
630
|
+
beta = 1.0
|
|
631
|
+
lag = 5.0
|
|
632
|
+
damp = 0.5
|
|
633
|
+
sfcf_1 = 0.3
|
|
634
|
+
sfcf_2 = 0.2
|
|
635
|
+
sfcf_3 = [0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 0.2]
|
|
636
|
+
k4 = 10.0
|
|
637
|
+
>>> test("query_initialconditionitemvalues")
|
|
638
|
+
ic_lahn_leun = [1.184948]
|
|
639
|
+
ic_lahn_marb = [0.96404, 1.36332, 0.96458, 1.46458, 0.96512, 1.46512, 0.96565, \
|
|
640
|
+
1.46569, 0.96617, 1.46617, 0.96668, 1.46668, 1.46719]
|
|
641
|
+
sm_lahn_leun = [123.0]
|
|
642
|
+
sm_lahn_marb = [110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 170.0, 180.0, 190.0, \
|
|
643
|
+
200.0, 210.0, 220.0, 230.0]
|
|
644
|
+
quh = [10.0]
|
|
645
|
+
>>> test("query_initialinputitemvalues")
|
|
646
|
+
t_headwaters = [[0.0, -0.5, -2.4, -6.8, -7.8], [-0.7, -1.5, -4.6, -8.2, -8.7]]
|
|
647
|
+
>>> test("query_initialoutputitemvalues")
|
|
648
|
+
swe_headwaters = [[nan, nan, nan, nan, nan], [nan, nan, nan, nan, nan]]
|
|
649
|
+
>>> test("query_initialgetitemvalues") # doctest: +ELLIPSIS
|
|
650
|
+
land_dill_assl_factors_contriarea = nan
|
|
651
|
+
land_dill_assl_fluxes_qt = nan
|
|
652
|
+
land_dill_assl_fluxes_qt_series = [nan, nan, nan, nan, nan]
|
|
653
|
+
land_dill_assl_states_sm = [185.13164...]
|
|
654
|
+
land_lahn_kalk_states_sm = [101.31248...]
|
|
655
|
+
land_lahn_leun_states_sm = [138.31396...]
|
|
656
|
+
land_lahn_marb_states_sm = [99.27505...]
|
|
657
|
+
land_lahn_kalk_states_sm_series = [[nan, ...], [nan, ...], ..., [nan, ...]]
|
|
658
|
+
dill_assl_nodes_sim_series = [nan, nan, nan, nan, nan]
|
|
659
|
+
|
|
660
|
+
Some external tools require ways to identify specific sub-values of different
|
|
661
|
+
exchange items. For example, they need to map those sub-values to location data
|
|
662
|
+
available in a separate database. Method |HydPyServer.GET_query_itemsubnames|
|
|
663
|
+
provides artificial sub names suitable for such a mapping. See property
|
|
664
|
+
|ChangeItem.subnames| of class |ChangeItem| and method |GetItem.yield_name2subnames|
|
|
665
|
+
of class |GetItem| for the specification of the sub names. Here, note the special
|
|
666
|
+
handling for change items addressing the `global` level, for which we cannot define
|
|
667
|
+
a meaningful sub name. Method |HydPyServer.GET_query_itemsubnames| returns the
|
|
668
|
+
string `*global*` in such cases:
|
|
669
|
+
|
|
670
|
+
>>> test("query_itemsubnames") # doctest: +ELLIPSIS
|
|
671
|
+
alpha = *global*
|
|
672
|
+
beta = *global*
|
|
673
|
+
lag = *global*
|
|
674
|
+
damp = *global*
|
|
675
|
+
sfcf_1 = *global*
|
|
676
|
+
sfcf_2 = *global*
|
|
677
|
+
sfcf_3 = [land_lahn_kalk_0, ..., land_lahn_kalk_13]
|
|
678
|
+
k4 = *global*
|
|
679
|
+
t_headwaters = [land_dill_assl, land_lahn_marb]
|
|
680
|
+
ic_lahn_leun = [land_lahn_leun]
|
|
681
|
+
ic_lahn_marb = [land_lahn_marb_0, ..., land_lahn_marb_12]
|
|
682
|
+
sm_lahn_leun = [land_lahn_leun]
|
|
683
|
+
sm_lahn_marb = [land_lahn_marb_0, ..., land_lahn_marb_12]
|
|
684
|
+
quh = [land_lahn_leun]
|
|
685
|
+
swe_headwaters = [land_dill_assl, land_lahn_marb]
|
|
686
|
+
land_dill_assl_factors_contriarea = land_dill_assl
|
|
687
|
+
land_dill_assl_fluxes_qt = land_dill_assl
|
|
688
|
+
land_dill_assl_fluxes_qt_series = land_dill_assl
|
|
689
|
+
land_dill_assl_states_sm = ('land_dill_assl_0', ..., 'land_dill_assl_11')
|
|
690
|
+
land_lahn_kalk_states_sm = ('land_lahn_kalk_0', ..., 'land_lahn_kalk_13')
|
|
691
|
+
land_lahn_leun_states_sm = ('land_lahn_leun_0', ..., 'land_lahn_leun_9')
|
|
692
|
+
land_lahn_marb_states_sm = ('land_lahn_marb_0', ..., 'land_lahn_marb_12')
|
|
693
|
+
land_lahn_kalk_states_sm_series = ('land_lahn_kalk_0', ..., 'land_lahn_kalk_13')
|
|
694
|
+
dill_assl_nodes_sim_series = dill_assl
|
|
695
|
+
|
|
696
|
+
The |Timegrids.init| time grid is immutable once the server is ready. Method
|
|
697
|
+
|HydPyServer.GET_query_initialisationtimegrid| returns the fixed first date, last
|
|
698
|
+
date, and stepsize of the whole initialised period:
|
|
699
|
+
|
|
700
|
+
>>> test("query_initialisationtimegrid")
|
|
701
|
+
firstdate_init = 1996-01-01T00:00:00+01:00
|
|
702
|
+
lastdate_init = 1996-01-06T00:00:00+01:00
|
|
703
|
+
stepsize = 1d
|
|
704
|
+
|
|
705
|
+
The dates of the |Timegrids.sim| time grid, on the other hand, are mutable and can
|
|
706
|
+
vary for different `id` query parameters. This flexibility makes things a little
|
|
707
|
+
more complicated, as the |Timegrids| object of the global |pub| module handles only
|
|
708
|
+
one |Timegrids.sim| object at once. Hence, we differentiate between registered
|
|
709
|
+
simulation dates of the respective `id` values and the current simulation dates of
|
|
710
|
+
the |Timegrids| object.
|
|
711
|
+
|
|
712
|
+
Method |HydPyServer.GET_query_simulationdates| asks for registered simulation dates
|
|
713
|
+
and thus fails at first:
|
|
714
|
+
|
|
715
|
+
>>> test("query_simulationdates", id_="0")
|
|
716
|
+
Traceback (most recent call last):
|
|
717
|
+
...
|
|
718
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
719
|
+
method `GET_query_simulationdates`, the following error occurred: Nothing registered \
|
|
720
|
+
under the id `0`. There is nothing registered, so far.
|
|
721
|
+
|
|
722
|
+
After logging new simulation dates via the POST method
|
|
723
|
+
|HydPyServer.POST_register_simulationdates|, method
|
|
724
|
+
|HydPyServer.GET_query_simulationdates| returns them correctly:
|
|
725
|
+
|
|
726
|
+
>>> test("register_simulationdates", id_="0",
|
|
727
|
+
... data=("firstdate_sim = 1996-01-01\\n"
|
|
728
|
+
... "lastdate_sim = 1996-01-02"))
|
|
729
|
+
<BLANKLINE>
|
|
730
|
+
>>> test("query_simulationdates", id_="0")
|
|
731
|
+
firstdate_sim = 1996-01-01T00:00:00+01:00
|
|
732
|
+
lastdate_sim = 1996-01-02T00:00:00+01:00
|
|
733
|
+
|
|
734
|
+
Our initial call to the POST method |HydPyServer.POST_register_simulationdates| did
|
|
735
|
+
not affect the currently active simulation dates. We need to do this manually by
|
|
736
|
+
calling method |HydPyServer.GET_activate_simulationdates|:
|
|
737
|
+
|
|
738
|
+
>>> test("evaluate", data="lastdate = hydpy.pub.timegrids.sim.lastdate")
|
|
739
|
+
lastdate = Date("1996-01-06T00:00:00")
|
|
740
|
+
>>> test("activate_simulationdates", id_="0")
|
|
741
|
+
<BLANKLINE>
|
|
742
|
+
>>> test("evaluate", data="lastdate = hydpy.pub.timegrids.sim.lastdate")
|
|
743
|
+
lastdate = Date("1996-01-02 00:00:00")
|
|
744
|
+
|
|
745
|
+
Generally, passing a missing `id` while others are available results in error
|
|
746
|
+
messages like the following:
|
|
747
|
+
|
|
748
|
+
>>> test("activate_simulationdates", id_="1")
|
|
749
|
+
Traceback (most recent call last):
|
|
750
|
+
...
|
|
751
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
752
|
+
method `GET_activate_simulationdates`, the following error occurred: Nothing \
|
|
753
|
+
registered under the id `1`. The available ids are: 0.
|
|
754
|
+
|
|
755
|
+
The logic of the parameter-related GET and POST methods is very similar to the one
|
|
756
|
+
of the simulation date-related methods discussed above. Method
|
|
757
|
+
|HydPyServer.POST_register_parameteritemvalues| registers new values of the
|
|
758
|
+
exchange items, and method |HydPyServer.GET_activate_parameteritemvalues| activates
|
|
759
|
+
them (assigns them to the relevant parameters):
|
|
760
|
+
|
|
761
|
+
>>> test("register_parameteritemvalues", id_="0",
|
|
762
|
+
... data=("alpha = 3.0\\n"
|
|
763
|
+
... "beta = 2.0\\n"
|
|
764
|
+
... "lag = 1.0\\n"
|
|
765
|
+
... "damp = 0.5\\n"
|
|
766
|
+
... "sfcf_1 = 0.3\\n"
|
|
767
|
+
... "sfcf_2 = 0.2\\n"
|
|
768
|
+
... "sfcf_3 = 0.1\\n"
|
|
769
|
+
... "k4 = 10.0\\n"))
|
|
770
|
+
<BLANKLINE>
|
|
771
|
+
>>> control = ("HydPyServer.state.hp.elements.land_dill_assl.model.parameters."
|
|
772
|
+
... "control")
|
|
773
|
+
>>> test("evaluate",
|
|
774
|
+
... data=(f"alpha = {control}.alpha\\n"
|
|
775
|
+
... f"sfcf = {control}.sfcf"))
|
|
776
|
+
alpha = alpha(1.0)
|
|
777
|
+
sfcf = sfcf(1.1)
|
|
778
|
+
|
|
779
|
+
>>> test("activate_parameteritemvalues", id_="0")
|
|
780
|
+
<BLANKLINE>
|
|
781
|
+
>>> test("evaluate",
|
|
782
|
+
... data=(f"alpha = {control}.alpha\\n"
|
|
783
|
+
... f"sfcf = {control}.sfcf"))
|
|
784
|
+
alpha = alpha(3.0)
|
|
785
|
+
sfcf = sfcf(1.34283)
|
|
786
|
+
|
|
787
|
+
The list of exchange items must be complete:
|
|
788
|
+
|
|
789
|
+
>>> test("register_parameteritemvalues", id_="0",
|
|
790
|
+
... data=("alpha = 3.0\\n"
|
|
791
|
+
... "beta = 2.0"))
|
|
792
|
+
Traceback (most recent call last):
|
|
793
|
+
...
|
|
794
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
795
|
+
method `POST_register_parameteritemvalues`, the following error occurred: A value for \
|
|
796
|
+
parameter item `lag` is missing.
|
|
797
|
+
|
|
798
|
+
Note that the related query method (|HydPyServer.GET_query_parameteritemvalues|)
|
|
799
|
+
returns the logged values of the |ChangeItem| objects instead of the (eventually
|
|
800
|
+
modified) values of the |Parameter| objects:
|
|
801
|
+
|
|
802
|
+
>>> test("query_parameteritemvalues", id_="0")
|
|
803
|
+
alpha = 3.0
|
|
804
|
+
beta = 2.0
|
|
805
|
+
lag = 1.0
|
|
806
|
+
damp = 0.5
|
|
807
|
+
sfcf_1 = 0.3
|
|
808
|
+
sfcf_2 = 0.2
|
|
809
|
+
sfcf_3 = 0.1
|
|
810
|
+
k4 = 10.0
|
|
811
|
+
|
|
812
|
+
The condition-related methods |HydPyServer.POST_register_conditionitemvalues|,
|
|
813
|
+
|HydPyServer.GET_activate_conditionitemvalues|, and
|
|
814
|
+
|HydPyServer.GET_query_conditionitemvalues| work like the parameter-related
|
|
815
|
+
methods described above:
|
|
816
|
+
|
|
817
|
+
>>> test("register_conditionitemvalues", id_="0",
|
|
818
|
+
... data=("sm_lahn_leun = 246.0\\n"
|
|
819
|
+
... "sm_lahn_marb = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]\\n"
|
|
820
|
+
... "ic_lahn_leun = 642.0\\n"
|
|
821
|
+
... "ic_lahn_marb = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\\n"
|
|
822
|
+
... "quh = 1.0\\n"))
|
|
823
|
+
<BLANKLINE>
|
|
824
|
+
>>> test("query_conditionitemvalues", id_="0")
|
|
825
|
+
ic_lahn_leun = 642.0
|
|
826
|
+
ic_lahn_marb = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
|
|
827
|
+
sm_lahn_leun = 246.0
|
|
828
|
+
sm_lahn_marb = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
|
829
|
+
quh = 1.0
|
|
830
|
+
|
|
831
|
+
Note the trimming of the too-high value for the state sequence |hland_states.SM| to
|
|
832
|
+
its highest possible value defined by control parameter |hland_control.FC|):
|
|
833
|
+
|
|
834
|
+
>>> for element in ("land_lahn_marb", "land_lahn_leun"):
|
|
835
|
+
... path_element = f"HydPyServer.state.hp.elements.{element}"
|
|
836
|
+
... path_sequences_model = f"{path_element}.model.sequences"
|
|
837
|
+
... path_sequences_submodel = f"{path_element}.model.rconcmodel.sequences"
|
|
838
|
+
... test("evaluate", # doctest: +ELLIPSIS
|
|
839
|
+
... data=(f"sm = {path_sequences_model}.states.sm \\n"
|
|
840
|
+
... f"quh = {path_sequences_submodel}.logs.quh"))
|
|
841
|
+
sm = sm(99.27505, ..., 142.84148)
|
|
842
|
+
quh = quh(0.0)
|
|
843
|
+
sm = sm(138.31396, ..., 164.63255)
|
|
844
|
+
quh = quh(0.7, 0.0)
|
|
845
|
+
>>> test("activate_conditionitemvalues", id_="0")
|
|
846
|
+
<BLANKLINE>
|
|
847
|
+
>>> for element in ("land_lahn_marb", "land_lahn_leun"):
|
|
848
|
+
... path_element = f"HydPyServer.state.hp.elements.{element}"
|
|
849
|
+
... path_sequences_model = f"{path_element}.model.sequences"
|
|
850
|
+
... path_sequences_submodel = f"{path_element}.model.rconcmodel.sequences"
|
|
851
|
+
... test("evaluate", # doctest: +ELLIPSIS
|
|
852
|
+
... data=(f"sm = {path_sequences_model}.states.sm \\n"
|
|
853
|
+
... f"quh = {path_sequences_submodel}.logs.quh"))
|
|
854
|
+
sm = sm(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0)
|
|
855
|
+
quh = quh(0.0)
|
|
856
|
+
sm = sm(197.0, 197.0, 197.0, 197.0, 197.0, 197.0, 197.0, 197.0, 197.0, 197.0)
|
|
857
|
+
quh = quh(1.0, 0.0)
|
|
858
|
+
|
|
859
|
+
The methods |HydPyServer.POST_register_inputitemvalues|,
|
|
860
|
+
|HydPyServer.GET_activate_inputitemvalues|, and
|
|
861
|
+
|HydPyServer.GET_query_inputitemvalues| always focus on the currently relevant
|
|
862
|
+
simulation time grid:
|
|
863
|
+
|
|
864
|
+
>>> test("update_inputitemvalues", id_="0")
|
|
865
|
+
<BLANKLINE>
|
|
866
|
+
>>> test("query_inputitemvalues", id_="0")
|
|
867
|
+
t_headwaters = [[0.0], [-0.7]]
|
|
868
|
+
>>> t = "HydPyServer.state.hp.elements.land_lahn_marb.model.sequences.inputs.t"
|
|
869
|
+
>>> test("evaluate", data=(f"t_series = {t}.series\\n"
|
|
870
|
+
... f"t_simseries = {t}.simseries\\n"))
|
|
871
|
+
t_series = InfoArray([-0.7, -1.5, -4.6, -8.2, -8.7])
|
|
872
|
+
t_simseries = InfoArray([-0.7])
|
|
873
|
+
|
|
874
|
+
>>> test("register_inputitemvalues", id_="0",
|
|
875
|
+
... data="t_headwaters = [[1.0], [2.0]]\\n")
|
|
876
|
+
<BLANKLINE>
|
|
877
|
+
>>> test("activate_inputitemvalues", id_="0")
|
|
878
|
+
<BLANKLINE>
|
|
879
|
+
>>> test("evaluate", data=(f"t_series = {t}.series\\n"
|
|
880
|
+
... f"t_simseries = {t}.simseries\\n"))
|
|
881
|
+
t_series = InfoArray([ 2. , -1.5, -4.6, -8.2, -8.7])
|
|
882
|
+
t_simseries = InfoArray([2.])
|
|
883
|
+
|
|
884
|
+
The "official" way to gain information on modified parameters or conditions is to
|
|
885
|
+
use the method |HydPyServer.GET_query_getitemvalues|:
|
|
886
|
+
|
|
887
|
+
>>> test("query_getitemvalues", id_="0")
|
|
888
|
+
Traceback (most recent call last):
|
|
889
|
+
...
|
|
890
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
891
|
+
method `GET_query_getitemvalues`, the following error occurred: Nothing registered \
|
|
892
|
+
under the id `0`. There is nothing registered, so far.
|
|
893
|
+
|
|
894
|
+
As the error message explains, we first need to fill the registry for the given
|
|
895
|
+
`id` parameter. Unlike the examples above, we do not do this by sending external
|
|
896
|
+
data via a POST request but by retrieving the server's currently active data. We
|
|
897
|
+
accomplish this task by calling the GET method
|
|
898
|
+
|HydPyServer.GET_update_getitemvalues|:
|
|
899
|
+
|
|
900
|
+
>>> test("update_getitemvalues", id_="0")
|
|
901
|
+
<BLANKLINE>
|
|
902
|
+
>>> test("query_getitemvalues", id_="0") # doctest: +ELLIPSIS
|
|
903
|
+
land_dill_assl_factors_contriarea = nan
|
|
904
|
+
land_dill_assl_fluxes_qt = nan
|
|
905
|
+
land_dill_assl_fluxes_qt_series = [nan]
|
|
906
|
+
land_dill_assl_states_sm = [185.13164, ...]
|
|
907
|
+
land_lahn_kalk_states_sm = [101.31248, ...]
|
|
908
|
+
land_lahn_leun_states_sm = [197.0, ..., 197.0]
|
|
909
|
+
land_lahn_marb_states_sm = [1.0, 2.0, ..., 12.0, 13.0]
|
|
910
|
+
land_lahn_kalk_states_sm_series = [[nan, ..., nan]]
|
|
911
|
+
dill_assl_nodes_sim_series = [nan]
|
|
912
|
+
|
|
913
|
+
Besides the "official" way for retrieving information (which we sometimes call the
|
|
914
|
+
"getitem style"), some sequences types (namely those derived from |FactorSequence|
|
|
915
|
+
and |FluxSequence|) also allow retrieving information in the so-called "setitem
|
|
916
|
+
style" via the methods |HydPyServer.GET_update_outputitemvalues| and
|
|
917
|
+
|HydPyServer.GET_query_outputitemvalues|:
|
|
918
|
+
|
|
919
|
+
>>> test("query_outputitemvalues", id_="0")
|
|
920
|
+
Traceback (most recent call last):
|
|
921
|
+
...
|
|
922
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
923
|
+
method `GET_query_outputitemvalues`, the following error occurred: Nothing registered \
|
|
924
|
+
under the id `0`. There is nothing registered, so far.
|
|
925
|
+
>>> test("update_outputitemvalues", id_="0")
|
|
926
|
+
<BLANKLINE>
|
|
927
|
+
>>> test("query_outputitemvalues", id_="0")
|
|
928
|
+
swe_headwaters = [[nan], [nan]]
|
|
929
|
+
|
|
930
|
+
We now modify the parameter, condition, and input time series values again, but
|
|
931
|
+
this time in one step through calling |HydPyServer.POST_register_changeitemvalues|
|
|
932
|
+
and |HydPyServer.GET_activate_changeitemvalues|:
|
|
933
|
+
|
|
934
|
+
>>> test("register_changeitemvalues", id_="0",
|
|
935
|
+
... data=("alpha = 1.0\\n"
|
|
936
|
+
... "beta = 1.0\\n"
|
|
937
|
+
... "lag = 0.0\\n"
|
|
938
|
+
... "damp = 0.0\\n"
|
|
939
|
+
... "sfcf_1 = 0.0\\n"
|
|
940
|
+
... "sfcf_2 = 0.0\\n"
|
|
941
|
+
... "sfcf_3 = 0.0\\n"
|
|
942
|
+
... "k4 = 5.0\\n"
|
|
943
|
+
... "ic_lahn_marb = 1.0\\n"
|
|
944
|
+
... "ic_lahn_leun = 2.0\\n"
|
|
945
|
+
... "sm_lahn_marb = 50.0\\n"
|
|
946
|
+
... "sm_lahn_leun = 100.0\\n"
|
|
947
|
+
... "quh = 0.0\\n"
|
|
948
|
+
... "t_headwaters = [[-0.29884643], [-0.70539496]]\\n"))
|
|
949
|
+
<BLANKLINE>
|
|
950
|
+
>>> test("activate_changeitemvalues", id_="0")
|
|
951
|
+
<BLANKLINE>
|
|
952
|
+
>>> test("query_changeitemvalues", id_="0") # doctest: +ELLIPSIS
|
|
953
|
+
alpha = 1.0
|
|
954
|
+
beta = 1.0
|
|
955
|
+
lag = 0.0
|
|
956
|
+
damp = 0.0
|
|
957
|
+
sfcf_1 = 0.0
|
|
958
|
+
sfcf_2 = 0.0
|
|
959
|
+
sfcf_3 = 0.0
|
|
960
|
+
k4 = 5.0
|
|
961
|
+
t_headwaters = [[-0.29884...], [-0.70539...]]
|
|
962
|
+
ic_lahn_leun = 2.0
|
|
963
|
+
ic_lahn_marb = 1.0
|
|
964
|
+
sm_lahn_leun = 100.0
|
|
965
|
+
sm_lahn_marb = 50.0
|
|
966
|
+
quh = 0.0
|
|
967
|
+
|
|
968
|
+
Next, we trigger a simulation run by calling the GET method
|
|
969
|
+
|HydPyServer.GET_simulate|:
|
|
970
|
+
|
|
971
|
+
>>> test("simulate", id_="0")
|
|
972
|
+
<BLANKLINE>
|
|
973
|
+
|
|
974
|
+
Calling methods |HydPyServer.GET_update_getitemvalues| and
|
|
975
|
+
|HydPyServer.GET_query_getitemvalues| as well as methods
|
|
976
|
+
|HydPyServer.GET_update_outputitemvalues| and
|
|
977
|
+
|HydPyServer.GET_query_outputitemvalues| reveals how the simulation results:
|
|
978
|
+
|
|
979
|
+
>>> test("update_getitemvalues", id_="0")
|
|
980
|
+
<BLANKLINE>
|
|
981
|
+
>>> test("query_getitemvalues", id_="0") # doctest: +ELLIPSIS
|
|
982
|
+
land_dill_assl_factors_contriarea = 0.759579
|
|
983
|
+
land_dill_assl_fluxes_qt = 5.508952
|
|
984
|
+
...
|
|
985
|
+
land_lahn_leun_states_sm = [100.341052, ..., 100.0]
|
|
986
|
+
...
|
|
987
|
+
dill_assl_nodes_sim_series = [5.508952]
|
|
988
|
+
>>> test("update_outputitemvalues", id_="0")
|
|
989
|
+
<BLANKLINE>
|
|
990
|
+
>>> test("query_outputitemvalues", id_="0")
|
|
991
|
+
swe_headwaters = [[0.074231], [0.0]]
|
|
992
|
+
|
|
993
|
+
So far, we have explained how the *HydPy* server memorises different exchange item
|
|
994
|
+
values for different values of query parameter `id`. Complicating matters,
|
|
995
|
+
memorising condition values must also consider the relevant time point. You load
|
|
996
|
+
conditions for the simulation period's current start date with method
|
|
997
|
+
|HydPyServer.GET_load_internalconditions| and save them for the current end date
|
|
998
|
+
with method |HydPyServer.GET_save_internalconditions|. For example, we first save
|
|
999
|
+
the states calculated for the end time of the last simulation run (January 2):
|
|
1000
|
+
|
|
1001
|
+
>>> test("query_simulationdates", id_="0")
|
|
1002
|
+
firstdate_sim = 1996-01-01T00:00:00+01:00
|
|
1003
|
+
lastdate_sim = 1996-01-02T00:00:00+01:00
|
|
1004
|
+
>>> test("evaluate",
|
|
1005
|
+
... data=f"sm_lahn2 = {path_sequences_model}.states.sm") # doctest: +ELLIPSIS
|
|
1006
|
+
sm_lahn2 = sm(100.341052, ..., 100.0)
|
|
1007
|
+
>>> test("save_internalconditions", id_="0")
|
|
1008
|
+
<BLANKLINE>
|
|
1009
|
+
|
|
1010
|
+
Calling method |HydPyServer.GET_load_internalconditions| without changing the
|
|
1011
|
+
simulation dates reloads the initial conditions for January 1, originally read from
|
|
1012
|
+
disk:
|
|
1013
|
+
|
|
1014
|
+
>>> test("load_internalconditions", id_="0")
|
|
1015
|
+
<BLANKLINE>
|
|
1016
|
+
>>> test("evaluate",
|
|
1017
|
+
... data=f"sm_lahn2 = {path_sequences_model}.states.sm") # doctest: +ELLIPSIS
|
|
1018
|
+
sm_lahn2 = sm(138.31396, ..., 164.63255)
|
|
1019
|
+
|
|
1020
|
+
If we set the first date of the simulation period to January 2, method
|
|
1021
|
+
|HydPyServer.GET_load_internalconditions| loads the conditions we saved for
|
|
1022
|
+
January 2 previously:
|
|
1023
|
+
|
|
1024
|
+
>>> test("register_simulationdates", id_="0",
|
|
1025
|
+
... data=("firstdate_sim = 1996-01-02\\n"
|
|
1026
|
+
... "lastdate_sim = 1996-01-03"))
|
|
1027
|
+
<BLANKLINE>
|
|
1028
|
+
>>> test("activate_simulationdates", id_="0")
|
|
1029
|
+
<BLANKLINE>
|
|
1030
|
+
>>> test("load_internalconditions", id_="0")
|
|
1031
|
+
<BLANKLINE>
|
|
1032
|
+
>>> test("evaluate",
|
|
1033
|
+
... data=f"sm_lahn2 = {path_sequences_model}.states.sm") # doctest: +ELLIPSIS
|
|
1034
|
+
sm_lahn2 = sm(100.341052, ..., 100.0)
|
|
1035
|
+
|
|
1036
|
+
Loading condition values for a specific time point requires saving them before:
|
|
1037
|
+
|
|
1038
|
+
>>> test("register_simulationdates", id_="0",
|
|
1039
|
+
... data=("firstdate_sim = 1996-01-03\\n"
|
|
1040
|
+
... "lastdate_sim = 1996-01-05"))
|
|
1041
|
+
<BLANKLINE>
|
|
1042
|
+
>>> test("activate_simulationdates", id_="0")
|
|
1043
|
+
<BLANKLINE>
|
|
1044
|
+
>>> test("load_internalconditions", id_="0")
|
|
1045
|
+
Traceback (most recent call last):
|
|
1046
|
+
...
|
|
1047
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
1048
|
+
method `GET_load_internalconditions`, the following error occurred: Conditions for \
|
|
1049
|
+
ID `0` and time point `1996-01-03 00:00:00` are required, but have not been \
|
|
1050
|
+
calculated so far.
|
|
1051
|
+
|
|
1052
|
+
For example, when restarting data assimilation subsequent forecasting periods, you
|
|
1053
|
+
might need to get and set all internal conditions from the client side. Then, you
|
|
1054
|
+
have two options. The more efficient way relies on methods
|
|
1055
|
+
|HydPyServer.GET_query_internalconditions| and
|
|
1056
|
+
|HydPyServer.POST_register_internalconditions|. Method
|
|
1057
|
+
|HydPyServer.GET_query_internalconditions| returns the information registered for
|
|
1058
|
+
the end of the current simulation period. All data is within a single nested
|
|
1059
|
+
|dict| object (created by the |HydPy.conditions| property of class |HydPy|):
|
|
1060
|
+
|
|
1061
|
+
>>> test("register_simulationdates", id_="0",
|
|
1062
|
+
... data=("firstdate_sim = 1996-01-01\\n"
|
|
1063
|
+
... "lastdate_sim = 1996-01-02"))
|
|
1064
|
+
<BLANKLINE>
|
|
1065
|
+
>>> test("activate_simulationdates", id_="0")
|
|
1066
|
+
<BLANKLINE>
|
|
1067
|
+
>>> conditions = test("query_internalconditions", id_="0",
|
|
1068
|
+
... return_result=True)[13:] # doctest: +ELLIPSIS
|
|
1069
|
+
conditions = {'land_dill_assl': {'model': {'states': {'ic': array([0.73040403, \
|
|
1070
|
+
1.23040403, 0.73046025...
|
|
1071
|
+
|
|
1072
|
+
Due to the steps above, the returned dictionary agrees with the current state of
|
|
1073
|
+
the |HydPy| instance:
|
|
1074
|
+
|
|
1075
|
+
>>> sequences = f"HydPyServer.state.hp.elements.land_dill_assl.model.sequences"
|
|
1076
|
+
>>> test("evaluate",
|
|
1077
|
+
... data=f"ic_dill_assl = {sequences}.states.ic") # doctest: +ELLIPSIS
|
|
1078
|
+
ic_dill_assl = ic(0.730404, 1.230404, 0.73046,...
|
|
1079
|
+
|
|
1080
|
+
To show that registering new internal conditions also works, we first convert the
|
|
1081
|
+
string representation of the data to actual Python objects by using Python's |eval|
|
|
1082
|
+
function. Therefore, we need to clarify that "array" means the array creation
|
|
1083
|
+
function |numpy.array| of |numpy|:
|
|
1084
|
+
|
|
1085
|
+
>>> import numpy
|
|
1086
|
+
>>> conditions = eval(conditions, {"array": numpy.array})
|
|
1087
|
+
|
|
1088
|
+
Next, we modify an arbitrary state and convert the dictionary back to a single-line
|
|
1089
|
+
string:
|
|
1090
|
+
|
|
1091
|
+
>>> conditions["land_dill_assl"]["model"]["states"]["ic"][:2] = 0.5, 2.0
|
|
1092
|
+
>>> conditions = str(conditions).replace("\\n", " ")
|
|
1093
|
+
|
|
1094
|
+
Now we can send the modified data back to the server by using the
|
|
1095
|
+
|HydPyServer.POST_register_internalconditions| method, which stores it for the
|
|
1096
|
+
start of the simulation period:
|
|
1097
|
+
|
|
1098
|
+
>>> test("register_internalconditions", id_="0", data=f"conditions = {conditions}")
|
|
1099
|
+
<BLANKLINE>
|
|
1100
|
+
>>> ic_dill_assl = ("self.state.conditions['0'][0]['land_dill_assl']['model']"
|
|
1101
|
+
... "['states']['ic']")
|
|
1102
|
+
>>> test("evaluate",
|
|
1103
|
+
... data=f"ic_dill_assl = {ic_dill_assl}") # doctest: +ELLIPSIS
|
|
1104
|
+
ic_dill_assl = array([0.5 , 2. , 0.73046025...
|
|
1105
|
+
|
|
1106
|
+
After calling method |HydPyServer.GET_load_internalconditions|, the freshly
|
|
1107
|
+
registered states are ready to be used by the next simulation run:
|
|
1108
|
+
|
|
1109
|
+
>>> test("load_internalconditions", id_="0")
|
|
1110
|
+
<BLANKLINE>
|
|
1111
|
+
>>> test("evaluate",
|
|
1112
|
+
... data=f"ic_dill_assl = {sequences}.states.ic") # doctest: +ELLIPSIS
|
|
1113
|
+
ic_dill_assl = ic(0.5, 2.0, 0.73046,...
|
|
1114
|
+
|
|
1115
|
+
Keeping the internal conditions for multiple time points can use plenty of RAM.
|
|
1116
|
+
Use the GET method |HydPyServer.GET_deregister_internalconditions| to remove all
|
|
1117
|
+
conditions data available under the given `id` to avoid that:
|
|
1118
|
+
|
|
1119
|
+
>>> test("query_internalconditions", id_="0") # doctest: +ELLIPSIS
|
|
1120
|
+
conditions = {'land_dill_assl': {'model': {'states': {'ic': array([0.7304...
|
|
1121
|
+
>>> test("deregister_internalconditions", id_="0")
|
|
1122
|
+
<BLANKLINE>
|
|
1123
|
+
>>> test("query_internalconditions", id_="0")
|
|
1124
|
+
Traceback (most recent call last):
|
|
1125
|
+
...
|
|
1126
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
1127
|
+
method `GET_query_internalconditions`, the following error occurred: No internal \
|
|
1128
|
+
conditions registered under the id `0` for `1996-01-02 00:00:00`.
|
|
1129
|
+
|
|
1130
|
+
Some algorithms provide new information about initial conditions and require
|
|
1131
|
+
information on how they evolve during a simulation. For such purposes, you can
|
|
1132
|
+
use method |HydPyServer.GET_update_conditionitemvalues| to store the current
|
|
1133
|
+
conditions under an arbitrary `id` and use method
|
|
1134
|
+
|HydPyServer.GET_query_conditionitemvalues| to query them later. Note that this
|
|
1135
|
+
approach so far only works when using |SetItem| objects that modify their target
|
|
1136
|
+
sequence on the `device` or `subunit` level (please tell us if you encounter other
|
|
1137
|
+
relevant use-cases):
|
|
1138
|
+
|
|
1139
|
+
>>> test("update_conditionitemvalues", id_="0")
|
|
1140
|
+
<BLANKLINE>
|
|
1141
|
+
>>> test("query_conditionitemvalues", id_="0") # doctest: +ELLIPSIS
|
|
1142
|
+
ic_lahn_leun = [0.955701]
|
|
1143
|
+
ic_lahn_marb = [0.7421...]
|
|
1144
|
+
sm_lahn_leun = [100.1983...]
|
|
1145
|
+
sm_lahn_marb = [49.9304...]
|
|
1146
|
+
quh = [0.000395]
|
|
1147
|
+
|
|
1148
|
+
The second option for handling multiple "simultaneous" initial conditions is
|
|
1149
|
+
telling the *HydPy* server to read them from and write them to disk, which is
|
|
1150
|
+
easier but often less efficient due to higher IO activity. Use methods
|
|
1151
|
+
|HydPyServer.GET_load_conditions| and |HydPyServer.GET_save_conditions| for this
|
|
1152
|
+
purpose. Reading from or writing to different directories than those defined in
|
|
1153
|
+
`multiple_runs.xml` requires registering them beforehand. If we, for example,
|
|
1154
|
+
create a new empty directory with method
|
|
1155
|
+
|HydPyServer.POST_register_inputconditiondir|, loading conditions from it must
|
|
1156
|
+
fail:
|
|
1157
|
+
|
|
1158
|
+
>>> test("register_inputconditiondir", id_="0", data="inputconditiondir = new")
|
|
1159
|
+
<BLANKLINE>
|
|
1160
|
+
>>> test("load_conditions", id_="0") # doctest: +ELLIPSIS
|
|
1161
|
+
Traceback (most recent call last):
|
|
1162
|
+
...
|
|
1163
|
+
urllib.error.HTTPError: HTTP Error 500: FileNotFoundError: While trying to \
|
|
1164
|
+
execute method `GET_load_conditions`, the following error occurred: While trying to \
|
|
1165
|
+
load the initial conditions of element `land_dill_assl`, the following error occurred: \
|
|
1166
|
+
[Errno 2] No such file or directory: ...land_dill_assl.py'
|
|
1167
|
+
|
|
1168
|
+
>>> test("register_outputconditiondir", id_="0", data="outputconditiondir = new")
|
|
1169
|
+
<BLANKLINE>
|
|
1170
|
+
>>> test("save_conditions", id_="0")
|
|
1171
|
+
<BLANKLINE>
|
|
1172
|
+
|
|
1173
|
+
Hence, we better first write suitable conditions into the new directory:
|
|
1174
|
+
|
|
1175
|
+
>>> lz_dill_assl = "self.state.hp.elements.land_dill_assl.model.sequences.states.lz"
|
|
1176
|
+
>>> test("evaluate", data=f"lz_dill_assl = {lz_dill_assl}") # doctest: +ELLIPSIS
|
|
1177
|
+
lz_dill_assl = lz(9.493...)
|
|
1178
|
+
|
|
1179
|
+
To prove reading and writing conditions works, we first set the current value of
|
|
1180
|
+
sequence |hland_states.LZ| of catchment "Dill" to zero:
|
|
1181
|
+
|
|
1182
|
+
>>> test("evaluate", data=f"nothing = {lz_dill_assl}(0.0)")
|
|
1183
|
+
nothing = None
|
|
1184
|
+
>>> test("evaluate", data=f"lz_dill_assl = {lz_dill_assl}")
|
|
1185
|
+
lz_dill_assl = lz(0.0)
|
|
1186
|
+
|
|
1187
|
+
As expected, applying |HydPyServer.GET_load_conditions| on the previously written
|
|
1188
|
+
data resets the value of |hland_states.LZ|:
|
|
1189
|
+
|
|
1190
|
+
>>> test("load_conditions", id_="0")
|
|
1191
|
+
<BLANKLINE>
|
|
1192
|
+
>>> test("evaluate", data=f"lz_dill_assl = {lz_dill_assl}") # doctest: +ELLIPSIS
|
|
1193
|
+
lz_dill_assl = lz(9.493...)
|
|
1194
|
+
|
|
1195
|
+
Use the GET methods |HydPyServer.GET_query_inputconditiondir| and
|
|
1196
|
+
|HydPyServer.GET_deregister_inputconditiondir| to query or remove the currently
|
|
1197
|
+
registered input condition directory:
|
|
1198
|
+
|
|
1199
|
+
>>> test("query_inputconditiondir", id_="0")
|
|
1200
|
+
inputconditiondir = new
|
|
1201
|
+
>>> test("deregister_inputconditiondir", id_="0")
|
|
1202
|
+
<BLANKLINE>
|
|
1203
|
+
>>> test("query_inputconditiondir", id_="0")
|
|
1204
|
+
Traceback (most recent call last):
|
|
1205
|
+
...
|
|
1206
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
1207
|
+
method `GET_query_inputconditiondir`, the following error occurred: Nothing \
|
|
1208
|
+
registered under the id `0`. There is nothing registered, so far.
|
|
1209
|
+
|
|
1210
|
+
Use the GET methods |HydPyServer.GET_query_outputconditiondir| and
|
|
1211
|
+
|HydPyServer.GET_deregister_outputconditiondir| to query or remove the currently
|
|
1212
|
+
registered output condition directory:
|
|
1213
|
+
|
|
1214
|
+
>>> test("query_outputconditiondir", id_="0")
|
|
1215
|
+
outputconditiondir = new
|
|
1216
|
+
>>> test("deregister_outputconditiondir", id_="0")
|
|
1217
|
+
<BLANKLINE>
|
|
1218
|
+
>>> test("query_outputconditiondir", id_="0")
|
|
1219
|
+
Traceback (most recent call last):
|
|
1220
|
+
...
|
|
1221
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
1222
|
+
method `GET_query_outputconditiondir`, the following error occurred: Nothing \
|
|
1223
|
+
registered under the id `0`. There is nothing registered, so far.
|
|
1224
|
+
|
|
1225
|
+
Above, we explained the recommended way to query the initial values of all or a
|
|
1226
|
+
subgroup of the available exchange items. Alternatively, you can first register
|
|
1227
|
+
the initial values and query them later, which is a workaround for retrieving
|
|
1228
|
+
initial and intermediate values with the same HTTP request (an `OpenDA`_
|
|
1229
|
+
requirement):
|
|
1230
|
+
|
|
1231
|
+
>>> test("register_initialitemvalues", id_="1")
|
|
1232
|
+
<BLANKLINE>
|
|
1233
|
+
>>> test("query_itemvalues", id_="1") # doctest: +ELLIPSIS
|
|
1234
|
+
alpha = 2.0
|
|
1235
|
+
beta = 1.0
|
|
1236
|
+
lag = 5.0
|
|
1237
|
+
damp = 0.5
|
|
1238
|
+
sfcf_1 = 0.3
|
|
1239
|
+
sfcf_2 = 0.2
|
|
1240
|
+
sfcf_3 = [0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 0.2]
|
|
1241
|
+
k4 = 10.0
|
|
1242
|
+
t_headwaters = [[0.0, -0.5, -2.4, -6.8, -7.8], [-0.7, -1.5, -4.6, -8.2, -8.7]]
|
|
1243
|
+
ic_lahn_leun = [1.18494...]
|
|
1244
|
+
ic_lahn_marb = [0.96404...]
|
|
1245
|
+
sm_lahn_leun = [123.0]
|
|
1246
|
+
sm_lahn_marb = [110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 170.0, 180.0, 190.0, \
|
|
1247
|
+
200.0, 210.0, 220.0, 230.0]
|
|
1248
|
+
quh = [10.0]
|
|
1249
|
+
swe_headwaters = [[nan, nan, nan, nan, nan], [nan, nan, nan, nan, nan]]
|
|
1250
|
+
land_dill_assl_factors_contriarea = nan
|
|
1251
|
+
land_dill_assl_fluxes_qt = nan
|
|
1252
|
+
land_dill_assl_fluxes_qt_series = [nan, nan, nan, nan, nan]
|
|
1253
|
+
land_dill_assl_states_sm = [185.13164...]
|
|
1254
|
+
land_lahn_kalk_states_sm = [101.31248...]
|
|
1255
|
+
land_lahn_leun_states_sm = [138.31396...]
|
|
1256
|
+
land_lahn_marb_states_sm = [99.27505...]
|
|
1257
|
+
land_lahn_kalk_states_sm_series = [[nan, ...], [nan, ...], ..., [nan, ...]]
|
|
1258
|
+
dill_assl_nodes_sim_series = [nan, nan, nan, nan, nan]
|
|
1259
|
+
|
|
1260
|
+
In contrast to running a single simulation via method |run_simulation|, the *HydPy*
|
|
1261
|
+
server does (usually) not write calculated time series automatically. Instead, one
|
|
1262
|
+
must manually call method |HydPyServer.GET_save_allseries|:
|
|
1263
|
+
|
|
1264
|
+
>>> test("save_allseries", id_="0")
|
|
1265
|
+
<BLANKLINE>
|
|
1266
|
+
|
|
1267
|
+
According to the fixed configuration of `multiple_runs.xml`,
|
|
1268
|
+
|HydPyServer.GET_save_allseries| wrote averaged soil moisture values into the
|
|
1269
|
+
directory `mean_sm`:
|
|
1270
|
+
|
|
1271
|
+
>>> import netCDF4
|
|
1272
|
+
>>> from hydpy import print_vector
|
|
1273
|
+
>>> filepath = "HydPy-H-Lahn/series/mean_sm/hland_96_state_sm_mean.nc"
|
|
1274
|
+
>>> with TestIO(), netCDF4.Dataset(filepath) as ncfile:
|
|
1275
|
+
... print_vector(ncfile["hland_96_state_sm_mean"][:, 0])
|
|
1276
|
+
211.467386, 0.0, 0.0, 0.0, 0.0
|
|
1277
|
+
|
|
1278
|
+
To save the results of subsequent simulations without overwriting the previous
|
|
1279
|
+
ones, change the current series writer directory by the GET method
|
|
1280
|
+
|HydPyServer.POST_register_serieswriterdir|:
|
|
1281
|
+
|
|
1282
|
+
>>> test("register_serieswriterdir", id_="0", data="serieswriterdir = sm_averaged")
|
|
1283
|
+
<BLANKLINE>
|
|
1284
|
+
>>> test("save_allseries", id_="0")
|
|
1285
|
+
<BLANKLINE>
|
|
1286
|
+
>>> filepath = "HydPy-H-Lahn/series/sm_averaged/hland_96_state_sm_mean.nc"
|
|
1287
|
+
>>> with TestIO(), netCDF4.Dataset(filepath) as ncfile:
|
|
1288
|
+
... print_vector(ncfile["hland_96_state_sm_mean"][:, 0])
|
|
1289
|
+
211.467386, 0.0, 0.0, 0.0, 0.0
|
|
1290
|
+
|
|
1291
|
+
|HydPyServer.GET_deregister_serieswriterdir| removes the currently set directory
|
|
1292
|
+
from the registry so that the HydPy server falls back to the
|
|
1293
|
+
configuration of `multiple_runs.xml`:
|
|
1294
|
+
|
|
1295
|
+
>>> test("query_serieswriterdir", id_="0")
|
|
1296
|
+
serieswriterdir = sm_averaged
|
|
1297
|
+
>>> test("deregister_serieswriterdir", id_="0")
|
|
1298
|
+
<BLANKLINE>
|
|
1299
|
+
>>> test("query_serieswriterdir", id_="0")
|
|
1300
|
+
Traceback (most recent call last):
|
|
1301
|
+
...
|
|
1302
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
1303
|
+
method `GET_query_serieswriterdir`, the following error occurred: Nothing registered \
|
|
1304
|
+
under the id `0`. There is nothing registered, so far.
|
|
1305
|
+
|
|
1306
|
+
The same holds for time series to be written "just in time" during simulation runs.
|
|
1307
|
+
The `temperature` writer in `multiple_runs.xml` select the `jit` mode. This
|
|
1308
|
+
setting triggered that the *HydPy* server wrote the time series of sequences
|
|
1309
|
+
|hland_inputs.T| and |evap_inputs.NormalAirTemperature| to the directory
|
|
1310
|
+
`temperature` during the last simulation:
|
|
1311
|
+
|
|
1312
|
+
>>> filepath = "HydPy-H-Lahn/series/temperature/hland_96_input_t.nc"
|
|
1313
|
+
>>> with TestIO(), netCDF4.Dataset(filepath) as ncfile:
|
|
1314
|
+
... print_vector(ncfile["hland_96_input_t"][:, 0])
|
|
1315
|
+
-0.298846, 0.0, 0.0, 0.0, 0.0
|
|
1316
|
+
|
|
1317
|
+
The input sequences |hland_inputs.P| and |evap_inputs.NormalEvapotranspiration| are
|
|
1318
|
+
instead reading their time series "just in time" (reading and writing data for the
|
|
1319
|
+
same |IOSequence| object is not supported). We query the last read value of
|
|
1320
|
+
|evap_inputs.NormalEvapotranspiration| for the Dill catchment:
|
|
1321
|
+
|
|
1322
|
+
>>> submodel = ("HydPyServer.state.hp.elements.land_dill_assl.model.aetmodel."
|
|
1323
|
+
... "petmodel")
|
|
1324
|
+
>>> net = f"{submodel}.sequences.inputs.normalevapotranspiration"
|
|
1325
|
+
>>> test("evaluate", data=f"net_dill_assl = {net}") # doctest: +ELLIPSIS
|
|
1326
|
+
net_dill_assl = normalevapotranspiration(0.3)
|
|
1327
|
+
|
|
1328
|
+
We can change the series writer directory before starting another simulation run to
|
|
1329
|
+
write the time series of |hland_inputs.T| and |evap_inputs.NormalAirTemperature| to
|
|
1330
|
+
another
|
|
1331
|
+
directory:
|
|
1332
|
+
|
|
1333
|
+
>>> test("register_serieswriterdir", id_="0", data="serieswriterdir = temp")
|
|
1334
|
+
<BLANKLINE>
|
|
1335
|
+
>>> test("simulate", id_="0")
|
|
1336
|
+
<BLANKLINE>
|
|
1337
|
+
>>> filepath = "HydPy-H-Lahn/series/temp/hland_96_input_t.nc"
|
|
1338
|
+
>>> with TestIO(), netCDF4.Dataset(filepath) as ncfile:
|
|
1339
|
+
... print_vector(ncfile["hland_96_input_t"][:, 0])
|
|
1340
|
+
-0.298846, 0.0, 0.0, 0.0, 0.0
|
|
1341
|
+
|
|
1342
|
+
The "just in time" reading of the series of |hland_inputs.P| and
|
|
1343
|
+
|evap_inputs.NormalEvapotranspiration| still worked, showing the registered series
|
|
1344
|
+
directory "temp" only applied for writing data:
|
|
1345
|
+
|
|
1346
|
+
>>> test("evaluate", data=f"net_dill_assl = {net}") # doctest: +ELLIPSIS
|
|
1347
|
+
net_dill_assl = normalevapotranspiration(0.3)
|
|
1348
|
+
|
|
1349
|
+
Changing the series reader directory works as explained for the series writer
|
|
1350
|
+
directory. After setting it to an empty folder, |HydPyServer.GET_load_allseries|
|
|
1351
|
+
and |HydPyServer.GET_simulate| cannot find suitable files and report this problem:
|
|
1352
|
+
|
|
1353
|
+
>>> test("register_seriesreaderdir", id_="0", data="seriesreaderdir = no_data")
|
|
1354
|
+
<BLANKLINE>
|
|
1355
|
+
>>> test("query_seriesreaderdir", id_="0")
|
|
1356
|
+
seriesreaderdir = no_data
|
|
1357
|
+
|
|
1358
|
+
>>> test("load_allseries", id_="0") # doctest: +ELLIPSIS
|
|
1359
|
+
Traceback (most recent call last):
|
|
1360
|
+
...
|
|
1361
|
+
urllib.error.HTTPError: HTTP Error 500: FileNotFoundError: While trying to \
|
|
1362
|
+
execute method `GET_load_allseries`, the following error occurred: While trying to \
|
|
1363
|
+
load the time series data of sequence `t` of element `land_dill_assl`, the following \
|
|
1364
|
+
error occurred: [Errno 2] No such file or directory: \
|
|
1365
|
+
...land_dill_assl_hland_96_input_t.asc'
|
|
1366
|
+
|
|
1367
|
+
>>> test("simulate", id_="0") # doctest: +ELLIPSIS
|
|
1368
|
+
Traceback (most recent call last):
|
|
1369
|
+
...
|
|
1370
|
+
urllib.error.HTTPError: HTTP Error 500: FileNotFoundError: While trying to \
|
|
1371
|
+
execute method `GET_simulate`, the following error occurred: While trying to prepare \
|
|
1372
|
+
NetCDF files for reading or writing data "just in time" during the current simulation \
|
|
1373
|
+
run, the following error occurred: No file `...hland_96_input_p.nc` available for \
|
|
1374
|
+
reading.
|
|
1375
|
+
|
|
1376
|
+
After deregistering the "no_data" directory, both methods work again:
|
|
1377
|
+
|
|
1378
|
+
>>> test("deregister_seriesreaderdir", id_="0")
|
|
1379
|
+
<BLANKLINE>
|
|
1380
|
+
>>> test("query_seriesreaderdir", id_="0")
|
|
1381
|
+
Traceback (most recent call last):
|
|
1382
|
+
...
|
|
1383
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
1384
|
+
method `GET_query_seriesreaderdir`, the following error occurred: Nothing registered \
|
|
1385
|
+
under the id `0`. There is nothing registered, so far.
|
|
1386
|
+
|
|
1387
|
+
>>> test("load_allseries", id_="0")
|
|
1388
|
+
<BLANKLINE>
|
|
1389
|
+
>>> test("simulate", id_="0")
|
|
1390
|
+
<BLANKLINE>
|
|
1391
|
+
|
|
1392
|
+
As described for time series, one must explicitly pass (comparable) requests to
|
|
1393
|
+
the *HydPy* Server to let it write parameter control files. The control files
|
|
1394
|
+
reflect the current parameter values of all model instances:
|
|
1395
|
+
|
|
1396
|
+
>>> test("register_outputcontroldir", id_="0", data="outputcontroldir = calibrated")
|
|
1397
|
+
<BLANKLINE>
|
|
1398
|
+
>>> test("query_outputcontroldir", id_="0")
|
|
1399
|
+
outputcontroldir = calibrated
|
|
1400
|
+
|
|
1401
|
+
>>> test("save_controls", id_="0")
|
|
1402
|
+
<BLANKLINE>
|
|
1403
|
+
>>> with TestIO(), open("HydPy-H-Lahn/control/calibrated/"
|
|
1404
|
+
... "land_dill_assl.py") as file_:
|
|
1405
|
+
... print(file_.read()) # doctest: +ELLIPSIS
|
|
1406
|
+
from hydpy.models.hland_96 import *
|
|
1407
|
+
from hydpy.models import evap_aet_hbv96
|
|
1408
|
+
from hydpy.models import evap_pet_hbv96
|
|
1409
|
+
from hydpy.models import rconc_uh
|
|
1410
|
+
<BLANKLINE>
|
|
1411
|
+
simulationstep("1d")
|
|
1412
|
+
parameterstep("1d")
|
|
1413
|
+
...
|
|
1414
|
+
beta(1.0)
|
|
1415
|
+
...
|
|
1416
|
+
|
|
1417
|
+
>>> parameterstep = "hydpy.pub.options.parameterstep"
|
|
1418
|
+
>>> simulationstep = "hydpy.pub.options.simulationstep"
|
|
1419
|
+
>>> beta = ("HydPyServer.state.hp.elements.land_dill_assl.model.parameters."
|
|
1420
|
+
... "control.beta")
|
|
1421
|
+
>>> test("evaluate", data=(f"simulationstep = {simulationstep}\\n"
|
|
1422
|
+
... f"parameterstep = {parameterstep}\\n"
|
|
1423
|
+
... f"beta = {beta}"))
|
|
1424
|
+
simulationstep = Period("1d")
|
|
1425
|
+
parameterstep = Period("1d")
|
|
1426
|
+
beta = beta(1.0)
|
|
1427
|
+
|
|
1428
|
+
>>> test("deregister_outputcontroldir", id_="0")
|
|
1429
|
+
<BLANKLINE>
|
|
1430
|
+
>>> test("query_outputcontroldir", id_="0")
|
|
1431
|
+
Traceback (most recent call last):
|
|
1432
|
+
...
|
|
1433
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
1434
|
+
method `GET_query_outputcontroldir`, the following error occurred: Nothing registered \
|
|
1435
|
+
under the id `0`. There is nothing registered, so far.
|
|
1436
|
+
|
|
1437
|
+
To close the *HydPy* server, call |HydPyServer.GET_close_server|:
|
|
1438
|
+
|
|
1439
|
+
>>> test("close_server")
|
|
1440
|
+
<BLANKLINE>
|
|
1441
|
+
>>> process.kill()
|
|
1442
|
+
>>> _ = process.communicate()
|
|
1443
|
+
"""
|
|
1444
|
+
|
|
1445
|
+
# pylint: disable=invalid-name
|
|
1446
|
+
# due to "GET" and "POST" method names in accordance with BaseHTTPRequestHandler
|
|
1447
|
+
|
|
1448
|
+
server: _HTTPServerBase
|
|
1449
|
+
state: ClassVar[ServerState]
|
|
1450
|
+
extensions_map: ClassVar[dict[str, str]]
|
|
1451
|
+
_requesttype: Literal["GET", "POST"]
|
|
1452
|
+
_statuscode: Literal[200, 400, 500]
|
|
1453
|
+
_inputs: dict[str, str]
|
|
1454
|
+
_outputs: dict[str, object]
|
|
1455
|
+
|
|
1456
|
+
def do_GET(self) -> None:
|
|
1457
|
+
"""Select and apply the currently requested GET method."""
|
|
1458
|
+
self._requesttype = "GET"
|
|
1459
|
+
self._do_get_or_post()
|
|
1460
|
+
|
|
1461
|
+
def do_POST(self) -> None:
|
|
1462
|
+
"""Select and apply the currently requested POST method."""
|
|
1463
|
+
self._requesttype = "POST"
|
|
1464
|
+
self._do_get_or_post()
|
|
1465
|
+
|
|
1466
|
+
def _do_get_or_post(self) -> None:
|
|
1467
|
+
self._statuscode = 200
|
|
1468
|
+
try:
|
|
1469
|
+
if self._requesttype == "POST":
|
|
1470
|
+
self._prepare_inputs()
|
|
1471
|
+
self._outputs = collections.OrderedDict()
|
|
1472
|
+
method = self._get_method(self._methodname)
|
|
1473
|
+
self._apply_method(method)
|
|
1474
|
+
self._write_output()
|
|
1475
|
+
except BaseException as exc:
|
|
1476
|
+
if self._statuscode not in (200, 400):
|
|
1477
|
+
self._statuscode = 500
|
|
1478
|
+
self.send_error(self._statuscode, f"{type(exc).__name__}: {exc}")
|
|
1479
|
+
|
|
1480
|
+
def _prepare_inputs(self) -> None:
|
|
1481
|
+
content_length = int(self.headers["Content-Length"])
|
|
1482
|
+
string = str(self.rfile.read(content_length), encoding="utf-8")
|
|
1483
|
+
self._inputs = collections.OrderedDict()
|
|
1484
|
+
for line in string.split("\n"):
|
|
1485
|
+
try:
|
|
1486
|
+
line = line.strip()
|
|
1487
|
+
if line:
|
|
1488
|
+
key, value = line.split("=")
|
|
1489
|
+
self._inputs[key.strip()] = value.strip()
|
|
1490
|
+
except BaseException as exc:
|
|
1491
|
+
self._statuscode = 400
|
|
1492
|
+
raise RuntimeError(
|
|
1493
|
+
f"The POST method `{self._externalname}` received a wrongly "
|
|
1494
|
+
f"formated data body. The following line has been extracted but "
|
|
1495
|
+
f"cannot be further processed: `{line}`."
|
|
1496
|
+
) from exc
|
|
1497
|
+
|
|
1498
|
+
@property
|
|
1499
|
+
def _id(self) -> ID:
|
|
1500
|
+
return self._get_queryparameter("id")
|
|
1501
|
+
|
|
1502
|
+
def _get_queryparameter(self, name: str) -> ID:
|
|
1503
|
+
query = urllib.parse.urlparse(self.path).query
|
|
1504
|
+
try:
|
|
1505
|
+
return cast(ID, urllib.parse.parse_qs(query)[name][0])
|
|
1506
|
+
except KeyError:
|
|
1507
|
+
self._statuscode = 400
|
|
1508
|
+
raise RuntimeError(
|
|
1509
|
+
f"For the {self._requesttype} method `{self._externalname}` no query "
|
|
1510
|
+
f"parameter `{name}` is given."
|
|
1511
|
+
) from None
|
|
1512
|
+
|
|
1513
|
+
@property
|
|
1514
|
+
def _externalname(self) -> str:
|
|
1515
|
+
return urllib.parse.urlparse(self.path).path[1:]
|
|
1516
|
+
|
|
1517
|
+
@property
|
|
1518
|
+
def _methodname(self) -> str:
|
|
1519
|
+
return f"{self._requesttype}_{self._externalname}"
|
|
1520
|
+
|
|
1521
|
+
def _get_method(self, name: str) -> types.MethodType:
|
|
1522
|
+
try:
|
|
1523
|
+
method = getattr(self, name)
|
|
1524
|
+
assert isinstance(method, types.MethodType)
|
|
1525
|
+
return method
|
|
1526
|
+
except AttributeError:
|
|
1527
|
+
self._statuscode = 400
|
|
1528
|
+
raise RuntimeError(f"No method `{name}` available.") from None
|
|
1529
|
+
|
|
1530
|
+
def _apply_method(self, method: types.MethodType) -> None:
|
|
1531
|
+
try:
|
|
1532
|
+
method()
|
|
1533
|
+
except BaseException:
|
|
1534
|
+
self._statuscode = 500
|
|
1535
|
+
objecttools.augment_excmessage(
|
|
1536
|
+
f"While trying to execute method `{method.__name__}`"
|
|
1537
|
+
)
|
|
1538
|
+
|
|
1539
|
+
def _write_output(self) -> None:
|
|
1540
|
+
string = "\n".join(f"{key} = {value}" for key, value in self._outputs.items())
|
|
1541
|
+
bstring = bytes(string, encoding="utf-8")
|
|
1542
|
+
self.send_response(self._statuscode)
|
|
1543
|
+
self.send_header("Content-type", "text/html")
|
|
1544
|
+
self.end_headers()
|
|
1545
|
+
self.wfile.write(bstring)
|
|
1546
|
+
|
|
1547
|
+
def GET_execute(self) -> None:
|
|
1548
|
+
"""Execute an arbitrary number of GET methods.
|
|
1549
|
+
|
|
1550
|
+
The method names must be passed as query parameters, as explained in the main
|
|
1551
|
+
documentation on module |servertools|.
|
|
1552
|
+
"""
|
|
1553
|
+
self._execute()
|
|
1554
|
+
|
|
1555
|
+
def POST_execute(self) -> None:
|
|
1556
|
+
"""Execute an arbitrary number of POST and GET methods.
|
|
1557
|
+
|
|
1558
|
+
The method names must be passed as query parameters, as explained in the main
|
|
1559
|
+
documentation on module |servertools|.
|
|
1560
|
+
"""
|
|
1561
|
+
self._execute()
|
|
1562
|
+
|
|
1563
|
+
def _execute(self) -> None:
|
|
1564
|
+
for name in self._get_queryparameter("methods").split(","):
|
|
1565
|
+
self._apply_method(self._get_method(name))
|
|
1566
|
+
|
|
1567
|
+
def POST_evaluate(self) -> None:
|
|
1568
|
+
"""Evaluate any valid Python expression with the *HydPy* server process and get
|
|
1569
|
+
its result.
|
|
1570
|
+
|
|
1571
|
+
Method |HydPyServer.POST_evaluate| serves to test and debug, primarily. The
|
|
1572
|
+
main documentation on class |HydPyServer| explains its usage.
|
|
1573
|
+
|
|
1574
|
+
For safety purposes, method |HydPyServer.POST_evaluate| only works if you start
|
|
1575
|
+
the *HydPy* Server in debug mode by writing "debugging=enable", as we do in the
|
|
1576
|
+
examples of the main documentation on class |HydPyServer|. When not working in
|
|
1577
|
+
debug mode, invoking this method results in the following error message:
|
|
1578
|
+
|
|
1579
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
1580
|
+
>>> prepare_full_example_1()
|
|
1581
|
+
>>> from hydpy import run_subprocess, TestIO
|
|
1582
|
+
>>> with TestIO():
|
|
1583
|
+
... process = run_subprocess(
|
|
1584
|
+
... "hyd.py start_server 8080 HydPy-H-Lahn multiple_runs_alpha.xml",
|
|
1585
|
+
... blocking=False, verbose=False)
|
|
1586
|
+
... _ = run_subprocess("hyd.py await_server 8080 10", verbose=False)
|
|
1587
|
+
>>> from urllib import request
|
|
1588
|
+
>>> request.urlopen("http://127.0.0.1:8080/evaluate", data=b"")
|
|
1589
|
+
Traceback (most recent call last):
|
|
1590
|
+
...
|
|
1591
|
+
urllib.error.HTTPError: HTTP Error 500: RuntimeError: While trying to execute \
|
|
1592
|
+
method `POST_evaluate`, the following error occurred: You can only use the POST \
|
|
1593
|
+
method `evaluate` if you have started the `HydPy Server` in debugging mode.
|
|
1594
|
+
|
|
1595
|
+
>>> _ = request.urlopen("http://127.0.0.1:8080/close_server")
|
|
1596
|
+
>>> process.kill()
|
|
1597
|
+
>>> _ = process.communicate()
|
|
1598
|
+
"""
|
|
1599
|
+
if not self.server.debugmode:
|
|
1600
|
+
raise RuntimeError(
|
|
1601
|
+
"You can only use the POST method `evaluate` if you have started the "
|
|
1602
|
+
"`HydPy Server` in debugging mode."
|
|
1603
|
+
)
|
|
1604
|
+
for name, value in self._inputs.items():
|
|
1605
|
+
result = eval(value)
|
|
1606
|
+
self._outputs[name] = objecttools.flatten_repr(result)
|
|
1607
|
+
|
|
1608
|
+
def GET_status(self) -> None:
|
|
1609
|
+
"""Return "status = ready" as soon as possible."""
|
|
1610
|
+
self._outputs["status"] = "ready"
|
|
1611
|
+
|
|
1612
|
+
def GET_version(self) -> None:
|
|
1613
|
+
"""Return Hydpy's version number."""
|
|
1614
|
+
self._outputs["version"] = hydpy.__version__
|
|
1615
|
+
|
|
1616
|
+
def GET_close_server(self) -> None:
|
|
1617
|
+
"""Stop and close the *HydPy* server."""
|
|
1618
|
+
|
|
1619
|
+
def _close_server() -> None:
|
|
1620
|
+
self.server.shutdown()
|
|
1621
|
+
self.server.server_close()
|
|
1622
|
+
|
|
1623
|
+
shutter = threading.Thread(target=_close_server)
|
|
1624
|
+
shutter.start()
|
|
1625
|
+
|
|
1626
|
+
@staticmethod
|
|
1627
|
+
def _get_query_itemtype(item: itemtools.ExchangeItem) -> str:
|
|
1628
|
+
if item.targetspecs.series:
|
|
1629
|
+
return f"TimeSeries{item.ndim-1}D"
|
|
1630
|
+
return f"Double{item.ndim}D"
|
|
1631
|
+
|
|
1632
|
+
def GET_query_itemtypes(self) -> None:
|
|
1633
|
+
"""Get the types of all current exchange items."""
|
|
1634
|
+
self.GET_query_changeitemtypes()
|
|
1635
|
+
self.GET_query_outputitemtypes()
|
|
1636
|
+
self.GET_query_getitemtypes()
|
|
1637
|
+
|
|
1638
|
+
def GET_query_changeitemtypes(self) -> None:
|
|
1639
|
+
"""Get the types of all current exchange items supposed to change the values of
|
|
1640
|
+
|Parameter|, |StateSequence|, or |LogSequence| objects."""
|
|
1641
|
+
self.GET_query_parameteritemtypes()
|
|
1642
|
+
self.GET_query_inputitemtypes()
|
|
1643
|
+
self.GET_query_conditionitemtypes()
|
|
1644
|
+
|
|
1645
|
+
def GET_query_parameteritemtypes(self) -> None:
|
|
1646
|
+
"""Get the types of all current exchange items supposed to change the values of
|
|
1647
|
+
|Parameter| objects."""
|
|
1648
|
+
for item in self.state.parameteritems:
|
|
1649
|
+
self._outputs[item.name] = self._get_query_itemtype(item)
|
|
1650
|
+
|
|
1651
|
+
def GET_query_inputitemtypes(self) -> None:
|
|
1652
|
+
"""Get the types of all current exchange items supposed to change the series of
|
|
1653
|
+
|InputSequence| objects."""
|
|
1654
|
+
for item in self.state.inputitems:
|
|
1655
|
+
self._outputs[item.name] = self._get_query_itemtype(item)
|
|
1656
|
+
|
|
1657
|
+
def GET_query_conditionitemtypes(self) -> None:
|
|
1658
|
+
"""Get the types of all current exchange items supposed to change the values of
|
|
1659
|
+
|StateSequence| or |LogSequence| objects."""
|
|
1660
|
+
for item in self.state.conditionitems:
|
|
1661
|
+
self._outputs[item.name] = self._get_query_itemtype(item)
|
|
1662
|
+
|
|
1663
|
+
def GET_query_outputitemtypes(self) -> None:
|
|
1664
|
+
"""Get the types of all current exchange items supposed to return the values or
|
|
1665
|
+
series of |FactorSequence| or |FluxSequence| objects in the "setitem style"."""
|
|
1666
|
+
for item in self.state.outputitems:
|
|
1667
|
+
self._outputs[item.name] = self._get_query_itemtype(item)
|
|
1668
|
+
|
|
1669
|
+
def GET_query_getitemtypes(self) -> None:
|
|
1670
|
+
"""Get the types of all current exchange items supposed to return the values of
|
|
1671
|
+
|Parameter| or |Sequence_| objects or the time series of |IOSequence|
|
|
1672
|
+
objects in the "getitem style"."""
|
|
1673
|
+
for item in self.state.getitems:
|
|
1674
|
+
type_ = self._get_query_itemtype(item)
|
|
1675
|
+
for name, _ in item.yield_name2value():
|
|
1676
|
+
self._outputs[name] = type_
|
|
1677
|
+
|
|
1678
|
+
def GET_query_itemsubnames(self) -> None:
|
|
1679
|
+
"""Get names (suitable as IDs) describing the individual values of all current
|
|
1680
|
+
exchange objects."""
|
|
1681
|
+
self.GET_query_changeitemsubnames()
|
|
1682
|
+
self.GET_query_outputitemnames()
|
|
1683
|
+
self.GET_query_getitemsubnames()
|
|
1684
|
+
|
|
1685
|
+
def GET_query_changeitemsubnames(self) -> None:
|
|
1686
|
+
"""Get names (suitable as IDs) describing the individual values of all current
|
|
1687
|
+
exchange objects supposed to change the values of |Parameter|, |StateSequence|,
|
|
1688
|
+
or |LogSequence| objects."""
|
|
1689
|
+
self.GET_query_parameteritemnames()
|
|
1690
|
+
self.GET_query_inputitemnames()
|
|
1691
|
+
self.GET_query_conditionitemnames()
|
|
1692
|
+
|
|
1693
|
+
def GET_query_parameteritemnames(self) -> None:
|
|
1694
|
+
"""Get names (suitable as IDs) describing the individual values of all current
|
|
1695
|
+
exchange objects supposed to change the values of |Parameter| objects."""
|
|
1696
|
+
self._query_changeitemsubnames(self.state.parameteritems)
|
|
1697
|
+
|
|
1698
|
+
def GET_query_inputitemnames(self) -> None:
|
|
1699
|
+
"""Get names (suitable as IDs) describing the individual values of all current
|
|
1700
|
+
exchange objects supposed to change the values of |InputSequence| objects."""
|
|
1701
|
+
self._query_changeitemsubnames(self.state.inputitems)
|
|
1702
|
+
|
|
1703
|
+
def GET_query_conditionitemnames(self) -> None:
|
|
1704
|
+
"""Get names (suitable as IDs) describing the individual values of all current
|
|
1705
|
+
exchange objects supposed to change the values of |StateSequence| or
|
|
1706
|
+
|LogSequence| objects."""
|
|
1707
|
+
self._query_changeitemsubnames(self.state.conditionitems)
|
|
1708
|
+
|
|
1709
|
+
def GET_query_outputitemnames(self) -> None:
|
|
1710
|
+
"""Get names (suitable as IDs) describing the individual values of all current
|
|
1711
|
+
exchange objects supposed to return the values of or series of |FactorSequence|
|
|
1712
|
+
or |FluxSequence| objects in the "setitem style"."""
|
|
1713
|
+
self._query_changeitemsubnames(self.state.outputitems)
|
|
1714
|
+
|
|
1715
|
+
def GET_query_getitemsubnames(self) -> None:
|
|
1716
|
+
"""Get names (suitable as IDs) describing the individual values of all current
|
|
1717
|
+
exchange objects supposed to return the values of |Parameter| or |Sequence_|
|
|
1718
|
+
objects or the time series of |IOSequence| objects in the "getitem style"."""
|
|
1719
|
+
for item in self.state.getitems:
|
|
1720
|
+
for name, subnames in item.yield_name2subnames():
|
|
1721
|
+
self._outputs[name] = subnames
|
|
1722
|
+
|
|
1723
|
+
def _query_changeitemsubnames(self, items: Iterable[itemtools.ChangeItem]) -> None:
|
|
1724
|
+
for item in items:
|
|
1725
|
+
subnames = item.subnames
|
|
1726
|
+
if subnames is None:
|
|
1727
|
+
self._outputs[item.name] = "*global*"
|
|
1728
|
+
else:
|
|
1729
|
+
self._outputs[item.name] = f"[{', '.join(subnames)}]"
|
|
1730
|
+
|
|
1731
|
+
def GET_query_initialitemvalues(self) -> None:
|
|
1732
|
+
"""Get the initial values of all current exchange items."""
|
|
1733
|
+
self.GET_query_initialchangeitemvalues()
|
|
1734
|
+
self.GET_query_initialoutputitemvalues()
|
|
1735
|
+
self.GET_query_initialgetitemvalues()
|
|
1736
|
+
|
|
1737
|
+
def GET_register_initialitemvalues(self) -> None:
|
|
1738
|
+
"""Register the initial values of all current exchange items under the given
|
|
1739
|
+
`id`.
|
|
1740
|
+
|
|
1741
|
+
Implemented as a workaround to support `OpenDA`_. Better use method
|
|
1742
|
+
|HydPyServer.GET_query_initialitemvalues|.
|
|
1743
|
+
"""
|
|
1744
|
+
self.GET_register_initialchangeitemvalues()
|
|
1745
|
+
self.GET_register_initialoutputitemvalues()
|
|
1746
|
+
self.GET_register_initialgetitemvalues()
|
|
1747
|
+
|
|
1748
|
+
def GET_query_initialchangeitemvalues(self) -> None:
|
|
1749
|
+
"""Get the initial values of all current exchange items supposed to change the
|
|
1750
|
+
values of |Parameter|, |InputSequence|, |StateSequence|, or |LogSequence|
|
|
1751
|
+
objects."""
|
|
1752
|
+
self.GET_query_initialparameteritemvalues()
|
|
1753
|
+
self.GET_query_initialinputitemvalues()
|
|
1754
|
+
self.GET_query_initialconditionitemvalues()
|
|
1755
|
+
|
|
1756
|
+
def GET_register_initialchangeitemvalues(self) -> None:
|
|
1757
|
+
"""Register the initial values of all current exchange items supposed to change
|
|
1758
|
+
the values of |Parameter|, |InputSequence|, |StateSequence|, or |LogSequence|
|
|
1759
|
+
objects under the given `id`.
|
|
1760
|
+
|
|
1761
|
+
Implemented as a workaround to support `OpenDA`_. Better use method
|
|
1762
|
+
|HydPyServer.GET_query_initialchangeitemvalues|.
|
|
1763
|
+
"""
|
|
1764
|
+
self.GET_register_initialparameteritemvalues()
|
|
1765
|
+
self.GET_register_initialinputitemvalues()
|
|
1766
|
+
self.GET_register_initialconditionitemvalues()
|
|
1767
|
+
|
|
1768
|
+
@staticmethod
|
|
1769
|
+
def _array2output(values: float | VectorInputObject | MatrixInputObject) -> str:
|
|
1770
|
+
# duck-typing for simplicity:
|
|
1771
|
+
try:
|
|
1772
|
+
try:
|
|
1773
|
+
return objecttools.assignrepr_list2(
|
|
1774
|
+
values, prefix="" # type: ignore[arg-type]
|
|
1775
|
+
).replace("\n", "")
|
|
1776
|
+
except TypeError:
|
|
1777
|
+
return objecttools.repr_list(values) # type: ignore[arg-type]
|
|
1778
|
+
except TypeError:
|
|
1779
|
+
return objecttools.repr_(values)
|
|
1780
|
+
|
|
1781
|
+
def GET_query_initialparameteritemvalues(self) -> None:
|
|
1782
|
+
"""Get the initial values of all current exchange items supposed to change the
|
|
1783
|
+
values of |Parameter| objects."""
|
|
1784
|
+
for name, value in self.state.initialparameteritemvalues.items():
|
|
1785
|
+
self._outputs[name] = self._array2output(value)
|
|
1786
|
+
|
|
1787
|
+
def GET_register_initialparameteritemvalues(self) -> None:
|
|
1788
|
+
"""Register the initial values of all current exchange items supposed to change
|
|
1789
|
+
the values of |Parameter| objects under the given `id`.
|
|
1790
|
+
|
|
1791
|
+
Implemented as a workaround to support `OpenDA`_. Better use method
|
|
1792
|
+
|HydPyServer.GET_query_initialparameteritemvalues|.
|
|
1793
|
+
"""
|
|
1794
|
+
state = self.state
|
|
1795
|
+
state.parameteritemvalues[self._id] = state.initialparameteritemvalues.copy()
|
|
1796
|
+
|
|
1797
|
+
def GET_query_initialinputitemvalues(self) -> None:
|
|
1798
|
+
"""Get the initial values of all current exchange items supposed to change the
|
|
1799
|
+
series of |InputSequence| objects."""
|
|
1800
|
+
for name, value in self.state.initialinputitemvalues.items():
|
|
1801
|
+
self._outputs[name] = self._array2output(value)
|
|
1802
|
+
|
|
1803
|
+
def GET_register_initialinputitemvalues(self) -> None:
|
|
1804
|
+
"""Register the initial series of all current exchange items supposed to change
|
|
1805
|
+
the values of |InputSequence| objects under the given `id`.
|
|
1806
|
+
|
|
1807
|
+
Implemented as a workaround to support `OpenDA`_. Better use method
|
|
1808
|
+
|HydPyServer.GET_query_initialinputitemvalues|.
|
|
1809
|
+
"""
|
|
1810
|
+
self.state.inputitemvalues[self._id] = self.state.initialinputitemvalues.copy()
|
|
1811
|
+
|
|
1812
|
+
def GET_query_initialconditionitemvalues(self) -> None:
|
|
1813
|
+
"""Get the initial values of all current exchange items supposed to change the
|
|
1814
|
+
values of |StateSequence| or |LogSequence| objects."""
|
|
1815
|
+
for name, value in self.state.initialconditionitemvalues.items():
|
|
1816
|
+
self._outputs[name] = self._array2output(value)
|
|
1817
|
+
|
|
1818
|
+
def GET_register_initialconditionitemvalues(self) -> None:
|
|
1819
|
+
"""Register the initial values of all current exchange items supposed to change
|
|
1820
|
+
the values of |StateSequence| or |LogSequence| objects under the given `id`.
|
|
1821
|
+
|
|
1822
|
+
Implemented as a workaround to support `OpenDA`_. Better use method
|
|
1823
|
+
|HydPyServer.GET_query_initialconditionitemvalues|.
|
|
1824
|
+
"""
|
|
1825
|
+
state = self.state
|
|
1826
|
+
state.conditionitemvalues[self._id] = state.initialconditionitemvalues.copy()
|
|
1827
|
+
|
|
1828
|
+
def GET_query_initialoutputitemvalues(self) -> None:
|
|
1829
|
+
"""Get the initial values of all current exchange items supposed to return the
|
|
1830
|
+
values or sequences of |FactorSequence| or |FluxSequence| objects in the
|
|
1831
|
+
"setitem style"."""
|
|
1832
|
+
for name, value in self.state.initialoutputitemvalues.items():
|
|
1833
|
+
self._outputs[name] = self._array2output(value)
|
|
1834
|
+
|
|
1835
|
+
def GET_register_initialoutputitemvalues(self) -> None:
|
|
1836
|
+
"""Register the initial values of all current exchange items supposed to return
|
|
1837
|
+
the values or sequences of |FactorSequence| or |FluxSequence| objects in the
|
|
1838
|
+
"setitem style" under the given `id`.
|
|
1839
|
+
|
|
1840
|
+
Implemented as a workaround to support `OpenDA`_. Better use method
|
|
1841
|
+
|HydPyServer.GET_query_initialoutputitemvalues|.
|
|
1842
|
+
"""
|
|
1843
|
+
state = self.state
|
|
1844
|
+
state.outputitemvalues[self._id] = state.initialoutputitemvalues.copy()
|
|
1845
|
+
|
|
1846
|
+
def GET_query_initialgetitemvalues(self) -> None:
|
|
1847
|
+
"""Get the initial values of all current exchange items supposed to return the
|
|
1848
|
+
values of |Parameter| or |Sequence_| objects or the time series of |IOSequence|
|
|
1849
|
+
objects in the "getitems style"."""
|
|
1850
|
+
for name, value in self.state.initialgetitemvalues.items():
|
|
1851
|
+
self._outputs[name] = value
|
|
1852
|
+
|
|
1853
|
+
def GET_register_initialgetitemvalues(self) -> None:
|
|
1854
|
+
"""Register the initial values of all current exchange items supposed to return
|
|
1855
|
+
the values of |Parameter| or |Sequence_| objects or the time series of
|
|
1856
|
+
|IOSequence| objects in the "getitem style" under the given `id`.
|
|
1857
|
+
|
|
1858
|
+
Implemented as a workaround to support `OpenDA`_. Better use method
|
|
1859
|
+
|HydPyServer.GET_query_initialgetitemvalues|.
|
|
1860
|
+
"""
|
|
1861
|
+
self.state.getitemvalues[self._id] = self.state.initialgetitemvalues.copy()
|
|
1862
|
+
|
|
1863
|
+
def GET_query_initialisationtimegrid(self) -> None:
|
|
1864
|
+
"""Return the general |Timegrids.init| time grid."""
|
|
1865
|
+
tg = hydpy.pub.timegrids.init
|
|
1866
|
+
utc = hydpy.pub.options.utcoffset
|
|
1867
|
+
self._outputs["firstdate_init"] = tg.firstdate.to_string("iso1", utc)
|
|
1868
|
+
self._outputs["lastdate_init"] = tg.lastdate.to_string("iso1", utc)
|
|
1869
|
+
self._outputs["stepsize"] = tg.stepsize
|
|
1870
|
+
|
|
1871
|
+
def _get_registered_content(self, dict_: dict[ID, T]) -> T:
|
|
1872
|
+
try:
|
|
1873
|
+
return dict_[self._id]
|
|
1874
|
+
except KeyError:
|
|
1875
|
+
message = f"Nothing registered under the id `{self._id}`."
|
|
1876
|
+
if dict_:
|
|
1877
|
+
message += f" The available ids are: {objecttools.enumeration(dict_)}."
|
|
1878
|
+
else:
|
|
1879
|
+
message += " There is nothing registered, so far."
|
|
1880
|
+
raise RuntimeError(message) from None
|
|
1881
|
+
|
|
1882
|
+
def POST_register_simulationdates(self) -> None:
|
|
1883
|
+
"""Register the send simulation dates under the given `id`."""
|
|
1884
|
+
self.state.timegrids[self._id] = timetools.Timegrid(
|
|
1885
|
+
firstdate=self._inputs["firstdate_sim"],
|
|
1886
|
+
lastdate=self._inputs["lastdate_sim"],
|
|
1887
|
+
stepsize=hydpy.pub.timegrids.stepsize,
|
|
1888
|
+
)
|
|
1889
|
+
|
|
1890
|
+
def GET_activate_simulationdates(self) -> None:
|
|
1891
|
+
"""Activate the simulation dates registered under the given `id`."""
|
|
1892
|
+
init = hydpy.pub.timegrids.init
|
|
1893
|
+
sim = hydpy.pub.timegrids.sim
|
|
1894
|
+
sim.dates = self._get_registered_content(self.state.timegrids).dates
|
|
1895
|
+
self.state.idx1 = init[sim.firstdate]
|
|
1896
|
+
self.state.idx2 = init[sim.lastdate]
|
|
1897
|
+
|
|
1898
|
+
def GET_query_simulationdates(self) -> None:
|
|
1899
|
+
"""Return the simulation dates registered under the given `id`."""
|
|
1900
|
+
tg = self._get_registered_content(self.state.timegrids)
|
|
1901
|
+
utc = hydpy.pub.options.utcoffset
|
|
1902
|
+
self._outputs["firstdate_sim"] = tg.firstdate.to_string("iso1", utc)
|
|
1903
|
+
self._outputs["lastdate_sim"] = tg.lastdate.to_string("iso1", utc)
|
|
1904
|
+
|
|
1905
|
+
def GET_query_itemvalues(self) -> None:
|
|
1906
|
+
"""Get the values of all |ExchangeItem| objects registered under the given
|
|
1907
|
+
`id`."""
|
|
1908
|
+
self.GET_query_changeitemvalues()
|
|
1909
|
+
self.GET_query_outputitemvalues()
|
|
1910
|
+
self.GET_query_getitemvalues()
|
|
1911
|
+
|
|
1912
|
+
def POST_register_changeitemvalues(self) -> None:
|
|
1913
|
+
"""Register the send values of all |ChangeItem| objects under the given `id`."""
|
|
1914
|
+
self.POST_register_parameteritemvalues()
|
|
1915
|
+
self.POST_register_inputitemvalues()
|
|
1916
|
+
self.POST_register_conditionitemvalues()
|
|
1917
|
+
|
|
1918
|
+
def GET_activate_changeitemvalues(self) -> None:
|
|
1919
|
+
"""Activate the values of the |ChangeItem| objects registered under the given
|
|
1920
|
+
`id`."""
|
|
1921
|
+
self.GET_activate_parameteritemvalues()
|
|
1922
|
+
self.GET_activate_inputitemvalues()
|
|
1923
|
+
self.GET_activate_conditionitemvalues()
|
|
1924
|
+
|
|
1925
|
+
def GET_query_changeitemvalues(self) -> None:
|
|
1926
|
+
"""Get the values of all |ChangeItem| objects registered under the given
|
|
1927
|
+
`id`."""
|
|
1928
|
+
self.GET_query_parameteritemvalues()
|
|
1929
|
+
self.GET_query_inputitemvalues()
|
|
1930
|
+
self.GET_query_conditionitemvalues()
|
|
1931
|
+
|
|
1932
|
+
def _post_register_itemvalues(
|
|
1933
|
+
self,
|
|
1934
|
+
typename: str,
|
|
1935
|
+
items: Iterable[itemtools.ChangeItem],
|
|
1936
|
+
itemvalues: dict[ID, dict[Name, Any]],
|
|
1937
|
+
) -> None:
|
|
1938
|
+
item2value: dict[Name, Any] = {}
|
|
1939
|
+
for item in items:
|
|
1940
|
+
try:
|
|
1941
|
+
value = self._inputs[item.name]
|
|
1942
|
+
except KeyError:
|
|
1943
|
+
self._statuscode = 500
|
|
1944
|
+
raise RuntimeError(
|
|
1945
|
+
f"A value for {typename} item `{item.name}` is missing."
|
|
1946
|
+
) from None
|
|
1947
|
+
item2value[item.name] = eval(value)
|
|
1948
|
+
itemvalues[self._id] = item2value
|
|
1949
|
+
|
|
1950
|
+
def POST_register_parameteritemvalues(self) -> None:
|
|
1951
|
+
"""Register the send parameter values under the given `id`."""
|
|
1952
|
+
self._post_register_itemvalues(
|
|
1953
|
+
typename="parameter",
|
|
1954
|
+
items=self.state.parameteritems,
|
|
1955
|
+
itemvalues=self.state.parameteritemvalues,
|
|
1956
|
+
)
|
|
1957
|
+
|
|
1958
|
+
def GET_activate_parameteritemvalues(self) -> None:
|
|
1959
|
+
"""Activate the parameter values registered under the given `id`."""
|
|
1960
|
+
item2value = self._get_registered_content(self.state.parameteritemvalues)
|
|
1961
|
+
for item in self.state.parameteritems:
|
|
1962
|
+
item.value = item2value[item.name]
|
|
1963
|
+
item.update_variables()
|
|
1964
|
+
|
|
1965
|
+
def GET_query_parameteritemvalues(self) -> None:
|
|
1966
|
+
"""Return the parameter values registered under the given `id`."""
|
|
1967
|
+
item2value = self._get_registered_content(self.state.parameteritemvalues)
|
|
1968
|
+
for item, value in item2value.items():
|
|
1969
|
+
self._outputs[item] = self._array2output(value)
|
|
1970
|
+
|
|
1971
|
+
def POST_register_inputitemvalues(self) -> None:
|
|
1972
|
+
"""Register the send input item values under the given `id`."""
|
|
1973
|
+
self._post_register_itemvalues(
|
|
1974
|
+
typename="input",
|
|
1975
|
+
items=self.state.inputitems,
|
|
1976
|
+
itemvalues=self.state.inputitemvalues,
|
|
1977
|
+
)
|
|
1978
|
+
|
|
1979
|
+
def GET_activate_inputitemvalues(self) -> None:
|
|
1980
|
+
"""Apply the input item values registered under the given `id` to modify the
|
|
1981
|
+
current |InputSequence| values."""
|
|
1982
|
+
item2value = self._get_registered_content(self.state.inputitemvalues)
|
|
1983
|
+
for item in self.state.inputitems:
|
|
1984
|
+
item.value = item2value[item.name]
|
|
1985
|
+
item.update_variables()
|
|
1986
|
+
|
|
1987
|
+
def GET_update_inputitemvalues(self) -> None:
|
|
1988
|
+
"""Convert the current |InputSequence| values to input item values (when
|
|
1989
|
+
necessary) and register them under the given `id`."""
|
|
1990
|
+
item2value = {}
|
|
1991
|
+
for item in self.state.inputitems:
|
|
1992
|
+
item.extract_values()
|
|
1993
|
+
item2value[item.name] = item.value
|
|
1994
|
+
self.state.inputitemvalues[self._id] = item2value
|
|
1995
|
+
|
|
1996
|
+
def GET_query_inputitemvalues(self) -> None:
|
|
1997
|
+
"""Return the input item values registered under the given `id`."""
|
|
1998
|
+
item2value = self._get_registered_content(self.state.inputitemvalues)
|
|
1999
|
+
for item, value in item2value.items():
|
|
2000
|
+
self._outputs[item] = self._array2output(value)
|
|
2001
|
+
|
|
2002
|
+
def POST_register_conditionitemvalues(self) -> None:
|
|
2003
|
+
"""Register the send condition item values under the given `id`."""
|
|
2004
|
+
self._post_register_itemvalues(
|
|
2005
|
+
typename="condition",
|
|
2006
|
+
items=self.state.conditionitems,
|
|
2007
|
+
itemvalues=self.state.conditionitemvalues,
|
|
2008
|
+
)
|
|
2009
|
+
|
|
2010
|
+
def GET_activate_conditionitemvalues(self) -> None:
|
|
2011
|
+
"""Apply the condition item values registered under the given `id` to modify
|
|
2012
|
+
the current |StateSequence| and |LogSequence| values."""
|
|
2013
|
+
item2value = self._get_registered_content(self.state.conditionitemvalues)
|
|
2014
|
+
for item in self.state.conditionitems:
|
|
2015
|
+
item.value = item2value[item.name]
|
|
2016
|
+
item.update_variables()
|
|
2017
|
+
|
|
2018
|
+
def GET_update_conditionitemvalues(self) -> None:
|
|
2019
|
+
"""Convert the current |StateSequence| and |LogSequence| values to condition
|
|
2020
|
+
item values (when necessary) and register them under the given `id`."""
|
|
2021
|
+
item2value = {}
|
|
2022
|
+
for item in self.state.conditionitems:
|
|
2023
|
+
item.extract_values()
|
|
2024
|
+
item2value[item.name] = item.value
|
|
2025
|
+
self.state.conditionitemvalues[self._id] = item2value
|
|
2026
|
+
|
|
2027
|
+
def GET_query_conditionitemvalues(self) -> None:
|
|
2028
|
+
"""Return the condition item values registered under the given `id`."""
|
|
2029
|
+
item2value = self._get_registered_content(self.state.conditionitemvalues)
|
|
2030
|
+
for item, value in item2value.items():
|
|
2031
|
+
self._outputs[item] = self._array2output(value)
|
|
2032
|
+
|
|
2033
|
+
def GET_update_outputitemvalues(self) -> None:
|
|
2034
|
+
"""Convert the current |FactorSequence| and |FluxSequence| values or series to
|
|
2035
|
+
output item values (when necessary) and register them under the given `id`."""
|
|
2036
|
+
item2value = {}
|
|
2037
|
+
for item in self.state.outputitems:
|
|
2038
|
+
item.extract_values()
|
|
2039
|
+
item2value[item.name] = item.value
|
|
2040
|
+
self.state.outputitemvalues[self._id] = item2value
|
|
2041
|
+
|
|
2042
|
+
def GET_query_outputitemvalues(self) -> None:
|
|
2043
|
+
"""Return the output item values registered under the given `id`."""
|
|
2044
|
+
item2value = self._get_registered_content(self.state.outputitemvalues)
|
|
2045
|
+
for item, value in item2value.items():
|
|
2046
|
+
self._outputs[item] = self._array2output(value)
|
|
2047
|
+
|
|
2048
|
+
def GET_save_internalconditions(self) -> None:
|
|
2049
|
+
"""Register the |StateSequence| and |LogSequence| values of the |HydPy|
|
|
2050
|
+
instance for the current simulation endpoint under the given `id`."""
|
|
2051
|
+
self.state.conditions[self._id] = self.state.conditions.get(self._id, {})
|
|
2052
|
+
self.state.conditions[self._id][self.state.idx2] = self.state.hp.conditions
|
|
2053
|
+
|
|
2054
|
+
def GET_load_internalconditions(self) -> None:
|
|
2055
|
+
"""Activate the |StateSequence| or |LogSequence| values registered for the
|
|
2056
|
+
current simulation start point under the given `id`.
|
|
2057
|
+
|
|
2058
|
+
When the simulation start point is identical with the initialisation time
|
|
2059
|
+
point, and you do not register alternative conditions manually, method
|
|
2060
|
+
|HydPyServer.GET_load_internalconditions| uses the "original" initial
|
|
2061
|
+
conditions of the current process (usually those of the conditions files of the
|
|
2062
|
+
respective *HydPy* project).
|
|
2063
|
+
"""
|
|
2064
|
+
try:
|
|
2065
|
+
self.state.hp.conditions = self.state.conditions[self._id][self.state.idx1]
|
|
2066
|
+
except KeyError:
|
|
2067
|
+
if self.state.idx1:
|
|
2068
|
+
self._statuscode = 500
|
|
2069
|
+
raise RuntimeError(
|
|
2070
|
+
f"Conditions for ID `{self._id}` and time point "
|
|
2071
|
+
f"`{hydpy.pub.timegrids.sim.firstdate}` are required, but have "
|
|
2072
|
+
f"not been calculated so far."
|
|
2073
|
+
) from None
|
|
2074
|
+
self.state.hp.conditions = self.state.init_conditions
|
|
2075
|
+
|
|
2076
|
+
def POST_register_internalconditions(self) -> None:
|
|
2077
|
+
"""Register the send internal conditions under the given `id`."""
|
|
2078
|
+
conditions = eval(self._inputs["conditions"], {"array": numpy.array})
|
|
2079
|
+
self.state.conditions[self._id][self.state.idx1] = conditions
|
|
2080
|
+
|
|
2081
|
+
def GET_deregister_internalconditions(self) -> None:
|
|
2082
|
+
"""Remove all internal condition directories registered under the given `id`."""
|
|
2083
|
+
self.state.conditions[self._id] = {}
|
|
2084
|
+
|
|
2085
|
+
def GET_query_internalconditions(self) -> None:
|
|
2086
|
+
"""Get the internal conditions registered under the given `id`."""
|
|
2087
|
+
all_conditions = self._get_registered_content(self.state.conditions)
|
|
2088
|
+
try:
|
|
2089
|
+
relevant_conditons = all_conditions[self.state.idx2]
|
|
2090
|
+
except KeyError:
|
|
2091
|
+
raise RuntimeError(
|
|
2092
|
+
f"No internal conditions registered under the id `{self._id}` for "
|
|
2093
|
+
f"`{self.state.timegrids[self._id].lastdate}`."
|
|
2094
|
+
) from None
|
|
2095
|
+
self._outputs["conditions"] = str(relevant_conditons).replace("\n", " ")
|
|
2096
|
+
|
|
2097
|
+
def POST_register_inputconditiondir(self) -> None:
|
|
2098
|
+
"""Register the send input condition directory under the given `id`."""
|
|
2099
|
+
self.state.inputconditiondirs[self._id] = self._inputs["inputconditiondir"]
|
|
2100
|
+
|
|
2101
|
+
def GET_deregister_inputconditiondir(self) -> None:
|
|
2102
|
+
"""Remove the input condition directory registered under the `id`."""
|
|
2103
|
+
self.state.inputconditiondirs.pop(self._id, None)
|
|
2104
|
+
|
|
2105
|
+
def GET_query_inputconditiondir(self) -> None:
|
|
2106
|
+
"""Return the input condition directory registered under the `id`."""
|
|
2107
|
+
dir_ = self._get_registered_content(self.state.inputconditiondirs)
|
|
2108
|
+
self._outputs["inputconditiondir"] = dir_
|
|
2109
|
+
|
|
2110
|
+
def POST_register_outputconditiondir(self) -> None:
|
|
2111
|
+
"""Register the send output condition directory under the given `id`."""
|
|
2112
|
+
self.state.outputconditiondirs[self._id] = self._inputs["outputconditiondir"]
|
|
2113
|
+
|
|
2114
|
+
def GET_deregister_outputconditiondir(self) -> None:
|
|
2115
|
+
"""Remove the output condition directory registered under the `id`."""
|
|
2116
|
+
self.state.outputconditiondirs.pop(self._id, None)
|
|
2117
|
+
|
|
2118
|
+
def GET_query_outputconditiondir(self) -> None:
|
|
2119
|
+
"""Return the output condition directory registered under the `id`."""
|
|
2120
|
+
dir_ = self._get_registered_content(self.state.outputconditiondirs)
|
|
2121
|
+
self._outputs["outputconditiondir"] = dir_
|
|
2122
|
+
|
|
2123
|
+
def GET_load_conditions(self) -> None:
|
|
2124
|
+
"""Load the (initial) conditions."""
|
|
2125
|
+
dir_ = self.state.inputconditiondirs.get(self._id)
|
|
2126
|
+
self.state.interface.conditions_io.load_conditions(dir_)
|
|
2127
|
+
|
|
2128
|
+
def GET_save_conditions(self) -> None:
|
|
2129
|
+
"""Save the (resulting) conditions."""
|
|
2130
|
+
dir_ = self.state.outputconditiondirs.get(self._id)
|
|
2131
|
+
self.state.interface.conditions_io.save_conditions(dir_)
|
|
2132
|
+
|
|
2133
|
+
def GET_update_getitemvalues(self) -> None:
|
|
2134
|
+
"""Register the current |GetItem| values under the given `id`.
|
|
2135
|
+
|
|
2136
|
+
For |GetItem| objects observing time series, method
|
|
2137
|
+
|HydPyServer.GET_update_getitemvalues| registers only the values within the
|
|
2138
|
+
current simulation period.
|
|
2139
|
+
"""
|
|
2140
|
+
item2value = {}
|
|
2141
|
+
for item in self.state.getitems:
|
|
2142
|
+
for name, value in item.yield_name2value(self.state.idx1, self.state.idx2):
|
|
2143
|
+
item2value[name] = value
|
|
2144
|
+
self.state.getitemvalues[self._id] = item2value
|
|
2145
|
+
|
|
2146
|
+
def GET_query_getitemvalues(self) -> None:
|
|
2147
|
+
"""Get the |GetItem| values registered under the given `id`."""
|
|
2148
|
+
item2value = self._get_registered_content(self.state.getitemvalues)
|
|
2149
|
+
for name, value in item2value.items():
|
|
2150
|
+
self._outputs[name] = value
|
|
2151
|
+
|
|
2152
|
+
def GET_simulate(self) -> None:
|
|
2153
|
+
"""Perform a simulation run."""
|
|
2154
|
+
readerdir = self.state.seriesreaderdirs.get(self._id, None)
|
|
2155
|
+
writerdir = self.state.serieswriterdirs.get(self._id, None)
|
|
2156
|
+
sio = self.state.interface.series_io
|
|
2157
|
+
with sio.modify_inputdir(readerdir), sio.modify_outputdir(writerdir):
|
|
2158
|
+
self.state.hp.simulate()
|
|
2159
|
+
|
|
2160
|
+
def POST_register_seriesreaderdir(self) -> None:
|
|
2161
|
+
"""Register the send series reader directory under the given `id`."""
|
|
2162
|
+
self.state.seriesreaderdirs[self._id] = self._inputs["seriesreaderdir"]
|
|
2163
|
+
|
|
2164
|
+
def GET_deregister_seriesreaderdir(self) -> None:
|
|
2165
|
+
"""Remove the series reader directory registered under the `id`."""
|
|
2166
|
+
self.state.seriesreaderdirs.pop(self._id, None)
|
|
2167
|
+
|
|
2168
|
+
def GET_query_seriesreaderdir(self) -> None:
|
|
2169
|
+
"""Return the series reader directory registered under the `id`."""
|
|
2170
|
+
dir_ = self._get_registered_content(self.state.seriesreaderdirs)
|
|
2171
|
+
self._outputs["seriesreaderdir"] = dir_
|
|
2172
|
+
|
|
2173
|
+
def POST_register_serieswriterdir(self) -> None:
|
|
2174
|
+
"""Register the send series writer directory under the given `id`."""
|
|
2175
|
+
self.state.serieswriterdirs[self._id] = self._inputs["serieswriterdir"]
|
|
2176
|
+
|
|
2177
|
+
def GET_deregister_serieswriterdir(self) -> None:
|
|
2178
|
+
"""Remove the series writer directory registered under the `id`."""
|
|
2179
|
+
self.state.serieswriterdirs.pop(self._id, None)
|
|
2180
|
+
|
|
2181
|
+
def GET_query_serieswriterdir(self) -> None:
|
|
2182
|
+
"""Return the series writer directory registered under the `id`."""
|
|
2183
|
+
dir_ = self._get_registered_content(self.state.serieswriterdirs)
|
|
2184
|
+
self._outputs["serieswriterdir"] = dir_
|
|
2185
|
+
|
|
2186
|
+
def GET_load_allseries(self) -> None:
|
|
2187
|
+
"""Load the time series of all sequences selected for (non-jit) reading."""
|
|
2188
|
+
state = self.state
|
|
2189
|
+
state.interface.series_io.load_series(state.seriesreaderdirs.get(self._id))
|
|
2190
|
+
|
|
2191
|
+
def GET_save_allseries(self) -> None:
|
|
2192
|
+
"""Save the time series of all sequences selected for (non-jit) writing."""
|
|
2193
|
+
state = self.state
|
|
2194
|
+
state.interface.series_io.save_series(state.serieswriterdirs.get(self._id))
|
|
2195
|
+
|
|
2196
|
+
def POST_register_outputcontroldir(self) -> None:
|
|
2197
|
+
"""Register the send output control directory under the given `id`."""
|
|
2198
|
+
self.state.outputcontroldirs[self._id] = self._inputs["outputcontroldir"]
|
|
2199
|
+
|
|
2200
|
+
def GET_deregister_outputcontroldir(self) -> None:
|
|
2201
|
+
"""Remove the output control directory registered under the `id`."""
|
|
2202
|
+
self.state.outputcontroldirs.pop(self._id, None)
|
|
2203
|
+
|
|
2204
|
+
def GET_query_outputcontroldir(self) -> None:
|
|
2205
|
+
"""Return the output control directory registered under the `id`."""
|
|
2206
|
+
dir_ = self._get_registered_content(self.state.outputcontroldirs)
|
|
2207
|
+
self._outputs["outputcontroldir"] = dir_
|
|
2208
|
+
|
|
2209
|
+
def GET_save_controls(self) -> None:
|
|
2210
|
+
"""Save the control files of all model instances."""
|
|
2211
|
+
state = self.state
|
|
2212
|
+
controldir = self._get_registered_content(state.outputcontroldirs)
|
|
2213
|
+
hydpy.pub.controlmanager.currentdir = controldir
|
|
2214
|
+
state.hp.save_controls()
|
|
2215
|
+
|
|
2216
|
+
|
|
2217
|
+
class _HTTPServerBase(http.server.HTTPServer):
|
|
2218
|
+
debugmode: bool = False
|
|
2219
|
+
|
|
2220
|
+
|
|
2221
|
+
def start_server(
|
|
2222
|
+
socket: int | str,
|
|
2223
|
+
projectname: str,
|
|
2224
|
+
xmlfilename: str,
|
|
2225
|
+
*,
|
|
2226
|
+
load_conditions: bool | str = True,
|
|
2227
|
+
load_series: bool | str = True,
|
|
2228
|
+
maxrequests: int | str = 5,
|
|
2229
|
+
debugging: Literal["enable", "disable"] = "disable",
|
|
2230
|
+
) -> None:
|
|
2231
|
+
"""Start the *HydPy* server using the given socket.
|
|
2232
|
+
|
|
2233
|
+
The folder with the given `projectname` must be available within the current
|
|
2234
|
+
working directory. The XML configuration file must be placed within the project
|
|
2235
|
+
folder unless `xmlfilename` is an absolute file path. The XML configuration file
|
|
2236
|
+
must be valid concerning the schema file `HydPyConfigMultipleRuns.xsd` (see class
|
|
2237
|
+
|ServerState| for further information).
|
|
2238
|
+
|
|
2239
|
+
The |HydPyServer| allows for five still unhandled requests before refusing new
|
|
2240
|
+
connections by default. Use the optional `maxrequests` argument to increase this
|
|
2241
|
+
number (which might be necessary when parallelising optimisation or data
|
|
2242
|
+
assimilation):
|
|
2243
|
+
|
|
2244
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
2245
|
+
>>> prepare_full_example_1()
|
|
2246
|
+
>>> command = (
|
|
2247
|
+
... "hyd.py start_server 8080 HydPy-H-Lahn multiple_runs_alpha.xml "
|
|
2248
|
+
... "debugging=enable maxrequests=100")
|
|
2249
|
+
>>> from hydpy import run_subprocess, TestIO
|
|
2250
|
+
>>> with TestIO():
|
|
2251
|
+
... process = run_subprocess(command, blocking=False, verbose=False)
|
|
2252
|
+
... result = run_subprocess("hyd.py await_server 8080 10", verbose=False)
|
|
2253
|
+
|
|
2254
|
+
>>> from urllib import request
|
|
2255
|
+
>>> command = "maxrequests = self.server.request_queue_size"
|
|
2256
|
+
>>> response = request.urlopen("http://127.0.0.1:8080/evaluate",
|
|
2257
|
+
... data=bytes(command, encoding="utf-8"))
|
|
2258
|
+
>>> print(str(response.read(), encoding="utf-8"))
|
|
2259
|
+
maxrequests = 100
|
|
2260
|
+
|
|
2261
|
+
>>> _ = request.urlopen("http://127.0.0.1:8080/close_server")
|
|
2262
|
+
>>> process.kill()
|
|
2263
|
+
>>> _ = process.communicate()
|
|
2264
|
+
|
|
2265
|
+
Please see the documentation on method |HydPyServer.POST_evaluate| that explains
|
|
2266
|
+
the "debugging" argument.
|
|
2267
|
+
|
|
2268
|
+
Note that function |start_server| tries to read the "mime types" from a dictionary
|
|
2269
|
+
stored in the file `mimetypes.txt` available in subpackage `conf` and passes it as
|
|
2270
|
+
attribute `extension_map` to class |HydPyServer|. The reason is to avoid the long
|
|
2271
|
+
computation time of function |mimetypes.init| of module |mimetypes|, usually called
|
|
2272
|
+
when defining class `BaseHTTPRequestHandler` of module `http.server`. If file
|
|
2273
|
+
`mimetypes.txt` does not exist or does not work for , |start_server| calls
|
|
2274
|
+
|mimetypes.init| as usual, (over)writes `mimetypes.txt` and tries to proceed as
|
|
2275
|
+
expected.
|
|
2276
|
+
"""
|
|
2277
|
+
confpath: str = conf.__path__[0]
|
|
2278
|
+
filepath = os.path.join(confpath, "mimetypes.txt")
|
|
2279
|
+
try:
|
|
2280
|
+
with open(filepath, encoding=config.ENCODING) as file_:
|
|
2281
|
+
types_map: dict[str, str] = eval(str(file_.read()))
|
|
2282
|
+
except BaseException:
|
|
2283
|
+
mimetypes.init()
|
|
2284
|
+
types_map = mimetypes.types_map.copy()
|
|
2285
|
+
types_map.update(
|
|
2286
|
+
{
|
|
2287
|
+
"": "application/octet-stream",
|
|
2288
|
+
".py": "text/plain",
|
|
2289
|
+
".c": "text/plain",
|
|
2290
|
+
".h": "text/plain",
|
|
2291
|
+
}
|
|
2292
|
+
)
|
|
2293
|
+
with open(filepath, "w", encoding=config.ENCODING) as file_:
|
|
2294
|
+
file_.write(str(types_map))
|
|
2295
|
+
HydPyServer.extensions_map = types_map
|
|
2296
|
+
HydPyServer.state = ServerState(
|
|
2297
|
+
projectname=projectname,
|
|
2298
|
+
xmlfile=xmlfilename,
|
|
2299
|
+
load_conditions=objecttools.value2bool("load_conditions", load_conditions),
|
|
2300
|
+
load_series=objecttools.value2bool("load_series", load_series),
|
|
2301
|
+
)
|
|
2302
|
+
|
|
2303
|
+
class _HTTPServer(_HTTPServerBase):
|
|
2304
|
+
debugmode = debugging == "enable"
|
|
2305
|
+
request_queue_size = int(maxrequests)
|
|
2306
|
+
|
|
2307
|
+
server = _HTTPServer(("", int(socket)), HydPyServer)
|
|
2308
|
+
server.serve_forever()
|
|
2309
|
+
|
|
2310
|
+
|
|
2311
|
+
def await_server(port: int | str, seconds: float | str) -> None:
|
|
2312
|
+
"""Block the current process until either the *HydPy* server is responding on the
|
|
2313
|
+
given `port` or the given number of `seconds` elapsed.
|
|
2314
|
+
|
|
2315
|
+
>>> from hydpy import run_subprocess, TestIO
|
|
2316
|
+
>>> with TestIO(): # doctest: +ELLIPSIS
|
|
2317
|
+
... result = run_subprocess("hyd.py await_server 8080 0.1")
|
|
2318
|
+
Invoking hyd.py with arguments `await_server, 8080, 0.1` resulted in the \
|
|
2319
|
+
following error:
|
|
2320
|
+
<urlopen error Waited for 0.1 seconds without response on port 8080.>
|
|
2321
|
+
...
|
|
2322
|
+
|
|
2323
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
2324
|
+
>>> prepare_full_example_1()
|
|
2325
|
+
>>> with TestIO():
|
|
2326
|
+
... process = run_subprocess(
|
|
2327
|
+
... "hyd.py start_server 8080 HydPy-H-Lahn multiple_runs.xml",
|
|
2328
|
+
... blocking=False, verbose=False)
|
|
2329
|
+
... result = run_subprocess("hyd.py await_server 8080 10", verbose=False)
|
|
2330
|
+
|
|
2331
|
+
>>> from urllib import request
|
|
2332
|
+
>>> _ = request.urlopen("http://127.0.0.1:8080/close_server")
|
|
2333
|
+
>>> process.kill()
|
|
2334
|
+
>>> _ = process.communicate()
|
|
2335
|
+
"""
|
|
2336
|
+
now = time.perf_counter()
|
|
2337
|
+
end = now + float(seconds)
|
|
2338
|
+
while now <= end:
|
|
2339
|
+
try:
|
|
2340
|
+
with urllib.request.urlopen(f"http://127.0.0.1:{port}/status"):
|
|
2341
|
+
break
|
|
2342
|
+
except urllib.error.URLError:
|
|
2343
|
+
time.sleep(0.1)
|
|
2344
|
+
now = time.perf_counter()
|
|
2345
|
+
else:
|
|
2346
|
+
raise urllib.error.URLError(
|
|
2347
|
+
f"Waited for {seconds} seconds without response on port {port}."
|
|
2348
|
+
)
|