HydPy 6.2.dev1__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hydpy/__init__.py +275 -0
- hydpy/aliases.py +2554 -0
- hydpy/auxs/__init__.py +0 -0
- hydpy/auxs/anntools.py +1305 -0
- hydpy/auxs/armatools.py +883 -0
- hydpy/auxs/calibtools.py +3337 -0
- hydpy/auxs/interptools.py +1094 -0
- hydpy/auxs/iuhtools.py +543 -0
- hydpy/auxs/networktools.py +597 -0
- hydpy/auxs/ppolytools.py +809 -0
- hydpy/auxs/quadtools.py +61 -0
- hydpy/auxs/roottools.py +228 -0
- hydpy/auxs/smoothtools.py +273 -0
- hydpy/auxs/statstools.py +2125 -0
- hydpy/auxs/validtools.py +81 -0
- hydpy/conf/HydPyConfigBase.xsd +68637 -0
- hydpy/conf/HydPyConfigBase.xsdt +358 -0
- hydpy/conf/HydPyConfigMultipleRuns.xsd +25 -0
- hydpy/conf/HydPyConfigSingleRun.xsd +24 -0
- hydpy/conf/__init__.py +0 -0
- hydpy/conf/a_coefficients_explicit_lobatto_sequence.npy +0 -0
- hydpy/conf/support_points_for_smoothpar_logistic2.npy +0 -0
- hydpy/config.py +42 -0
- hydpy/core/__init__.py +0 -0
- hydpy/core/aliastools.py +214 -0
- hydpy/core/autodoctools.py +1947 -0
- hydpy/core/auxfiletools.py +1169 -0
- hydpy/core/devicetools.py +3810 -0
- hydpy/core/exceptiontools.py +269 -0
- hydpy/core/filetools.py +1985 -0
- hydpy/core/hydpytools.py +3089 -0
- hydpy/core/importtools.py +1398 -0
- hydpy/core/indextools.py +345 -0
- hydpy/core/itemtools.py +1849 -0
- hydpy/core/masktools.py +460 -0
- hydpy/core/modeltools.py +4868 -0
- hydpy/core/netcdftools.py +2683 -0
- hydpy/core/objecttools.py +2023 -0
- hydpy/core/optiontools.py +1045 -0
- hydpy/core/parametertools.py +4674 -0
- hydpy/core/printtools.py +222 -0
- hydpy/core/propertytools.py +643 -0
- hydpy/core/pubtools.py +254 -0
- hydpy/core/selectiontools.py +1571 -0
- hydpy/core/sequencetools.py +4476 -0
- hydpy/core/seriestools.py +339 -0
- hydpy/core/testtools.py +2483 -0
- hydpy/core/timetools.py +3567 -0
- hydpy/core/typingtools.py +333 -0
- hydpy/core/variabletools.py +2615 -0
- hydpy/cythons/__init__.py +24 -0
- hydpy/cythons/annutils.pxd +33 -0
- hydpy/cythons/annutils.pyi +25 -0
- hydpy/cythons/annutils.pyx +120 -0
- hydpy/cythons/autogen/__init__.py +0 -0
- hydpy/cythons/autogen/annutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/annutils.pxd +42 -0
- hydpy/cythons/autogen/annutils.pyx +129 -0
- hydpy/cythons/autogen/c_arma.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_arma.pxd +179 -0
- hydpy/cythons/autogen/c_arma.pyx +356 -0
- hydpy/cythons/autogen/c_arma_rimorido.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_arma_rimorido.pxd +179 -0
- hydpy/cythons/autogen/c_arma_rimorido.pyx +356 -0
- hydpy/cythons/autogen/c_conv.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_conv.pxd +198 -0
- hydpy/cythons/autogen/c_conv.pyx +491 -0
- hydpy/cythons/autogen/c_conv_idw.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_conv_idw.pxd +124 -0
- hydpy/cythons/autogen/c_conv_idw.pyx +264 -0
- hydpy/cythons/autogen/c_conv_idw_ed.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_conv_idw_ed.pxd +197 -0
- hydpy/cythons/autogen/c_conv_idw_ed.pyx +481 -0
- hydpy/cythons/autogen/c_conv_nn.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_conv_nn.pxd +120 -0
- hydpy/cythons/autogen/c_conv_nn.pyx +224 -0
- hydpy/cythons/autogen/c_dam.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam.pxd +805 -0
- hydpy/cythons/autogen/c_dam.pyx +1477 -0
- hydpy/cythons/autogen/c_dam_llake.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_llake.pxd +364 -0
- hydpy/cythons/autogen/c_dam_llake.pyx +705 -0
- hydpy/cythons/autogen/c_dam_lreservoir.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_lreservoir.pxd +365 -0
- hydpy/cythons/autogen/c_dam_lreservoir.pyx +708 -0
- hydpy/cythons/autogen/c_dam_lretention.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_lretention.pxd +340 -0
- hydpy/cythons/autogen/c_dam_lretention.pyx +625 -0
- hydpy/cythons/autogen/c_dam_pump.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_pump.pxd +402 -0
- hydpy/cythons/autogen/c_dam_pump.pyx +724 -0
- hydpy/cythons/autogen/c_dam_pump_sluice.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_pump_sluice.pxd +452 -0
- hydpy/cythons/autogen/c_dam_pump_sluice.pyx +829 -0
- hydpy/cythons/autogen/c_dam_sluice.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_sluice.pxd +404 -0
- hydpy/cythons/autogen/c_dam_sluice.pyx +726 -0
- hydpy/cythons/autogen/c_dam_v001.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v001.pxd +452 -0
- hydpy/cythons/autogen/c_dam_v001.pyx +816 -0
- hydpy/cythons/autogen/c_dam_v002.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v002.pxd +394 -0
- hydpy/cythons/autogen/c_dam_v002.pyx +703 -0
- hydpy/cythons/autogen/c_dam_v003.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v003.pxd +417 -0
- hydpy/cythons/autogen/c_dam_v003.pyx +744 -0
- hydpy/cythons/autogen/c_dam_v004.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v004.pxd +486 -0
- hydpy/cythons/autogen/c_dam_v004.pyx +891 -0
- hydpy/cythons/autogen/c_dam_v005.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dam_v005.pxd +524 -0
- hydpy/cythons/autogen/c_dam_v005.pyx +928 -0
- hydpy/cythons/autogen/c_dummy.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy.pxd +151 -0
- hydpy/cythons/autogen/c_dummy.pyx +263 -0
- hydpy/cythons/autogen/c_dummy_interceptedwater.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_interceptedwater.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_interceptedwater.pyx +104 -0
- hydpy/cythons/autogen/c_dummy_node2node.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_node2node.pxd +89 -0
- hydpy/cythons/autogen/c_dummy_node2node.pyx +148 -0
- hydpy/cythons/autogen/c_dummy_snowalbedo.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_snowalbedo.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_snowalbedo.pyx +104 -0
- hydpy/cythons/autogen/c_dummy_snowcover.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_snowcover.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_snowcover.pyx +104 -0
- hydpy/cythons/autogen/c_dummy_snowycanopy.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_snowycanopy.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_snowycanopy.pyx +104 -0
- hydpy/cythons/autogen/c_dummy_soilwater.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_dummy_soilwater.pxd +69 -0
- hydpy/cythons/autogen/c_dummy_soilwater.pyx +104 -0
- hydpy/cythons/autogen/c_evap.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap.pxd +1029 -0
- hydpy/cythons/autogen/c_evap.pyx +2601 -0
- hydpy/cythons/autogen/c_evap_aet_hbv96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_aet_hbv96.pxd +227 -0
- hydpy/cythons/autogen/c_evap_aet_hbv96.pyx +584 -0
- hydpy/cythons/autogen/c_evap_aet_minhas.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_aet_minhas.pxd +193 -0
- hydpy/cythons/autogen/c_evap_aet_minhas.pyx +478 -0
- hydpy/cythons/autogen/c_evap_aet_morsim.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_aet_morsim.pxd +681 -0
- hydpy/cythons/autogen/c_evap_aet_morsim.pyx +1642 -0
- hydpy/cythons/autogen/c_evap_pet_ambav1.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_pet_ambav1.pxd +532 -0
- hydpy/cythons/autogen/c_evap_pet_ambav1.pyx +1296 -0
- hydpy/cythons/autogen/c_evap_pet_hbv96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_pet_hbv96.pxd +179 -0
- hydpy/cythons/autogen/c_evap_pet_hbv96.pyx +328 -0
- hydpy/cythons/autogen/c_evap_pet_m.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_pet_m.pxd +124 -0
- hydpy/cythons/autogen/c_evap_pet_m.pyx +214 -0
- hydpy/cythons/autogen/c_evap_pet_mlc.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_pet_mlc.pxd +126 -0
- hydpy/cythons/autogen/c_evap_pet_mlc.pyx +214 -0
- hydpy/cythons/autogen/c_evap_ret_fao56.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_ret_fao56.pxd +305 -0
- hydpy/cythons/autogen/c_evap_ret_fao56.pyx +624 -0
- hydpy/cythons/autogen/c_evap_ret_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_ret_io.pxd +112 -0
- hydpy/cythons/autogen/c_evap_ret_io.pyx +176 -0
- hydpy/cythons/autogen/c_evap_ret_tw2002.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_evap_ret_tw2002.pxd +139 -0
- hydpy/cythons/autogen/c_evap_ret_tw2002.pyx +273 -0
- hydpy/cythons/autogen/c_exch.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_exch.pxd +230 -0
- hydpy/cythons/autogen/c_exch.pyx +462 -0
- hydpy/cythons/autogen/c_exch_branch_hbv96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_exch_branch_hbv96.pxd +134 -0
- hydpy/cythons/autogen/c_exch_branch_hbv96.pyx +255 -0
- hydpy/cythons/autogen/c_exch_waterlevel.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_exch_waterlevel.pxd +54 -0
- hydpy/cythons/autogen/c_exch_waterlevel.pyx +78 -0
- hydpy/cythons/autogen/c_exch_weir_hbv96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_exch_weir_hbv96.pxd +156 -0
- hydpy/cythons/autogen/c_exch_weir_hbv96.pyx +282 -0
- hydpy/cythons/autogen/c_ga.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_ga.pxd +353 -0
- hydpy/cythons/autogen/c_ga.pyx +1204 -0
- hydpy/cythons/autogen/c_ga_garto.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_ga_garto.pxd +330 -0
- hydpy/cythons/autogen/c_ga_garto.pyx +1105 -0
- hydpy/cythons/autogen/c_ga_garto_submodel1.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_ga_garto_submodel1.pxd +236 -0
- hydpy/cythons/autogen/c_ga_garto_submodel1.pyx +944 -0
- hydpy/cythons/autogen/c_gland.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_gland.pxd +437 -0
- hydpy/cythons/autogen/c_gland.pyx +726 -0
- hydpy/cythons/autogen/c_gland_gr4.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_gland_gr4.pxd +382 -0
- hydpy/cythons/autogen/c_gland_gr4.pyx +605 -0
- hydpy/cythons/autogen/c_gland_gr5.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_gland_gr5.pxd +368 -0
- hydpy/cythons/autogen/c_gland_gr5.pyx +568 -0
- hydpy/cythons/autogen/c_gland_gr6.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_gland_gr6.pxd +420 -0
- hydpy/cythons/autogen/c_gland_gr6.pyx +673 -0
- hydpy/cythons/autogen/c_hland.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_hland.pxd +855 -0
- hydpy/cythons/autogen/c_hland.pyx +2486 -0
- hydpy/cythons/autogen/c_hland_96.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_hland_96.pxd +631 -0
- hydpy/cythons/autogen/c_hland_96.pyx +1724 -0
- hydpy/cythons/autogen/c_hland_96c.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_hland_96c.pxd +621 -0
- hydpy/cythons/autogen/c_hland_96c.pyx +1822 -0
- hydpy/cythons/autogen/c_hland_96p.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_hland_96p.pxd +683 -0
- hydpy/cythons/autogen/c_hland_96p.pyx +1911 -0
- hydpy/cythons/autogen/c_kinw.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_kinw.pxd +509 -0
- hydpy/cythons/autogen/c_kinw.pyx +965 -0
- hydpy/cythons/autogen/c_kinw_williams.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_kinw_williams.pxd +409 -0
- hydpy/cythons/autogen/c_kinw_williams.pyx +763 -0
- hydpy/cythons/autogen/c_kinw_williams_ext.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_kinw_williams_ext.pxd +220 -0
- hydpy/cythons/autogen/c_kinw_williams_ext.pyx +440 -0
- hydpy/cythons/autogen/c_lland.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_lland.pxd +1386 -0
- hydpy/cythons/autogen/c_lland.pyx +3679 -0
- hydpy/cythons/autogen/c_lland_dd.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_lland_dd.pxd +679 -0
- hydpy/cythons/autogen/c_lland_dd.pyx +1719 -0
- hydpy/cythons/autogen/c_lland_knauf.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_lland_knauf.pxd +1096 -0
- hydpy/cythons/autogen/c_lland_knauf.pyx +2784 -0
- hydpy/cythons/autogen/c_lland_knauf_ic.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_lland_knauf_ic.pxd +1369 -0
- hydpy/cythons/autogen/c_lland_knauf_ic.pyx +3625 -0
- hydpy/cythons/autogen/c_meteo.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo.pxd +469 -0
- hydpy/cythons/autogen/c_meteo.pyx +879 -0
- hydpy/cythons/autogen/c_meteo_clear_glob_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_clear_glob_io.pxd +75 -0
- hydpy/cythons/autogen/c_meteo_clear_glob_io.pyx +107 -0
- hydpy/cythons/autogen/c_meteo_glob_fao56.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_glob_fao56.pxd +209 -0
- hydpy/cythons/autogen/c_meteo_glob_fao56.pyx +339 -0
- hydpy/cythons/autogen/c_meteo_glob_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_glob_io.pxd +63 -0
- hydpy/cythons/autogen/c_meteo_glob_io.pyx +91 -0
- hydpy/cythons/autogen/c_meteo_glob_morsim.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_glob_morsim.pxd +289 -0
- hydpy/cythons/autogen/c_meteo_glob_morsim.pyx +527 -0
- hydpy/cythons/autogen/c_meteo_precip_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_precip_io.pxd +112 -0
- hydpy/cythons/autogen/c_meteo_precip_io.pyx +176 -0
- hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.pxd +87 -0
- hydpy/cythons/autogen/c_meteo_psun_sun_glob_io.pyx +123 -0
- hydpy/cythons/autogen/c_meteo_sun_fao56.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_sun_fao56.pxd +209 -0
- hydpy/cythons/autogen/c_meteo_sun_fao56.pyx +343 -0
- hydpy/cythons/autogen/c_meteo_sun_morsim.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_sun_morsim.pxd +286 -0
- hydpy/cythons/autogen/c_meteo_sun_morsim.pyx +519 -0
- hydpy/cythons/autogen/c_meteo_temp_io.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_meteo_temp_io.pxd +112 -0
- hydpy/cythons/autogen/c_meteo_temp_io.pyx +176 -0
- hydpy/cythons/autogen/c_musk.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_musk.pxd +282 -0
- hydpy/cythons/autogen/c_musk.pyx +605 -0
- hydpy/cythons/autogen/c_musk_classic.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_musk_classic.pxd +138 -0
- hydpy/cythons/autogen/c_musk_classic.pyx +226 -0
- hydpy/cythons/autogen/c_musk_mct.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_musk_mct.pxd +282 -0
- hydpy/cythons/autogen/c_musk_mct.pyx +609 -0
- hydpy/cythons/autogen/c_rconc.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_rconc.pxd +119 -0
- hydpy/cythons/autogen/c_rconc.pyx +174 -0
- hydpy/cythons/autogen/c_rconc_nash.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_rconc_nash.pxd +111 -0
- hydpy/cythons/autogen/c_rconc_nash.pyx +185 -0
- hydpy/cythons/autogen/c_rconc_uh.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_rconc_uh.pxd +92 -0
- hydpy/cythons/autogen/c_rconc_uh.pyx +125 -0
- hydpy/cythons/autogen/c_sw1d.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d.pxd +511 -0
- hydpy/cythons/autogen/c_sw1d.pyx +1263 -0
- hydpy/cythons/autogen/c_sw1d_channel.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_channel.pxd +119 -0
- hydpy/cythons/autogen/c_sw1d_channel.pyx +300 -0
- hydpy/cythons/autogen/c_sw1d_gate_out.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_gate_out.pxd +240 -0
- hydpy/cythons/autogen/c_sw1d_gate_out.pyx +476 -0
- hydpy/cythons/autogen/c_sw1d_lias.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_lias.pxd +320 -0
- hydpy/cythons/autogen/c_sw1d_lias.pyx +619 -0
- hydpy/cythons/autogen/c_sw1d_lias_sluice.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_lias_sluice.pxd +325 -0
- hydpy/cythons/autogen/c_sw1d_lias_sluice.pyx +644 -0
- hydpy/cythons/autogen/c_sw1d_network.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_network.pxd +90 -0
- hydpy/cythons/autogen/c_sw1d_network.pyx +246 -0
- hydpy/cythons/autogen/c_sw1d_pump.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_pump.pxd +256 -0
- hydpy/cythons/autogen/c_sw1d_pump.pyx +502 -0
- hydpy/cythons/autogen/c_sw1d_q_in.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_q_in.pxd +224 -0
- hydpy/cythons/autogen/c_sw1d_q_in.pyx +383 -0
- hydpy/cythons/autogen/c_sw1d_q_out.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_q_out.pxd +224 -0
- hydpy/cythons/autogen/c_sw1d_q_out.pyx +383 -0
- hydpy/cythons/autogen/c_sw1d_storage.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_storage.pxd +193 -0
- hydpy/cythons/autogen/c_sw1d_storage.pyx +349 -0
- hydpy/cythons/autogen/c_sw1d_weir_out.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_sw1d_weir_out.pxd +212 -0
- hydpy/cythons/autogen/c_sw1d_weir_out.pyx +404 -0
- hydpy/cythons/autogen/c_test.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_test.pxd +175 -0
- hydpy/cythons/autogen/c_test.pyx +348 -0
- hydpy/cythons/autogen/c_test_discontinous.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_test_discontinous.pxd +146 -0
- hydpy/cythons/autogen/c_test_discontinous.pyx +256 -0
- hydpy/cythons/autogen/c_test_stiff0d.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_test_stiff0d.pxd +146 -0
- hydpy/cythons/autogen/c_test_stiff0d.pyx +250 -0
- hydpy/cythons/autogen/c_test_stiff1d.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_test_stiff1d.pxd +145 -0
- hydpy/cythons/autogen/c_test_stiff1d.pyx +294 -0
- hydpy/cythons/autogen/c_whmod.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_whmod.pxd +482 -0
- hydpy/cythons/autogen/c_whmod.pyx +1156 -0
- hydpy/cythons/autogen/c_whmod_rural.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_whmod_rural.pxd +411 -0
- hydpy/cythons/autogen/c_whmod_rural.pyx +982 -0
- hydpy/cythons/autogen/c_whmod_urban.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_whmod_urban.pxd +482 -0
- hydpy/cythons/autogen/c_whmod_urban.pyx +1155 -0
- hydpy/cythons/autogen/c_wland.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wland.pxd +842 -0
- hydpy/cythons/autogen/c_wland.pyx +1890 -0
- hydpy/cythons/autogen/c_wland_gd.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wland_gd.pxd +829 -0
- hydpy/cythons/autogen/c_wland_gd.pyx +1847 -0
- hydpy/cythons/autogen/c_wland_wag.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wland_wag.pxd +810 -0
- hydpy/cythons/autogen/c_wland_wag.pyx +1780 -0
- hydpy/cythons/autogen/c_wq.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wq.pxd +275 -0
- hydpy/cythons/autogen/c_wq.pyx +652 -0
- hydpy/cythons/autogen/c_wq_trapeze.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wq_trapeze.pxd +170 -0
- hydpy/cythons/autogen/c_wq_trapeze.pyx +400 -0
- hydpy/cythons/autogen/c_wq_trapeze_strickler.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wq_trapeze_strickler.pxd +243 -0
- hydpy/cythons/autogen/c_wq_trapeze_strickler.pyx +578 -0
- hydpy/cythons/autogen/c_wq_walrus.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/c_wq_walrus.pxd +61 -0
- hydpy/cythons/autogen/c_wq_walrus.pyx +82 -0
- hydpy/cythons/autogen/configutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/configutils.pxd +17 -0
- hydpy/cythons/autogen/configutils.pyx +119 -0
- hydpy/cythons/autogen/interfaceutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/interfaceutils.pxd +31 -0
- hydpy/cythons/autogen/interfaceutils.pyx +82 -0
- hydpy/cythons/autogen/interputils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/interputils.pxd +42 -0
- hydpy/cythons/autogen/interputils.pyx +118 -0
- hydpy/cythons/autogen/masterinterface.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/masterinterface.pxd +153 -0
- hydpy/cythons/autogen/masterinterface.pyx +222 -0
- hydpy/cythons/autogen/pointerutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/pointerutils.pxd +31 -0
- hydpy/cythons/autogen/pointerutils.pyx +650 -0
- hydpy/cythons/autogen/ppolyutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/ppolyutils.pxd +35 -0
- hydpy/cythons/autogen/ppolyutils.pyx +59 -0
- hydpy/cythons/autogen/quadutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/quadutils.pxd +26 -0
- hydpy/cythons/autogen/quadutils.pyx +973 -0
- hydpy/cythons/autogen/rootutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/rootutils.pxd +28 -0
- hydpy/cythons/autogen/rootutils.pyx +109 -0
- hydpy/cythons/autogen/sequenceutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/sequenceutils.pxd +45 -0
- hydpy/cythons/autogen/sequenceutils.pyx +101 -0
- hydpy/cythons/autogen/smoothutils.cp313-win_amd64.pyd +0 -0
- hydpy/cythons/autogen/smoothutils.pxd +29 -0
- hydpy/cythons/autogen/smoothutils.pyx +833 -0
- hydpy/cythons/configutils.pxd +8 -0
- hydpy/cythons/configutils.pyi +5 -0
- hydpy/cythons/configutils.pyx +110 -0
- hydpy/cythons/interfaceutils.pxd +22 -0
- hydpy/cythons/interfaceutils.pyi +15 -0
- hydpy/cythons/interfaceutils.pyx +73 -0
- hydpy/cythons/interputils.pxd +33 -0
- hydpy/cythons/interputils.pyi +32 -0
- hydpy/cythons/interputils.pyx +109 -0
- hydpy/cythons/modelutils.py +2990 -0
- hydpy/cythons/pointerutils.pxd +22 -0
- hydpy/cythons/pointerutils.pyi +89 -0
- hydpy/cythons/pointerutils.pyx +641 -0
- hydpy/cythons/ppolyutils.pxd +26 -0
- hydpy/cythons/ppolyutils.pyi +21 -0
- hydpy/cythons/ppolyutils.pyx +50 -0
- hydpy/cythons/quadutils.pxd +17 -0
- hydpy/cythons/quadutils.pyi +13 -0
- hydpy/cythons/quadutils.pyx +964 -0
- hydpy/cythons/rootutils.pxd +19 -0
- hydpy/cythons/rootutils.pyi +21 -0
- hydpy/cythons/rootutils.pyx +100 -0
- hydpy/cythons/sequenceutils.pxd +36 -0
- hydpy/cythons/sequenceutils.pyi +7 -0
- hydpy/cythons/sequenceutils.pyx +92 -0
- hydpy/cythons/smoothutils.pxd +20 -0
- hydpy/cythons/smoothutils.pyi +15 -0
- hydpy/cythons/smoothutils.pyx +824 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_dill_assl.py +13 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_kalk.py +13 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_leun.py +14 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_lahn_marb.py +13 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_dill_assl_lahn_leun.py +5 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_lahn_leun_lahn_kalk.py +5 -0
- hydpy/data/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/stream_lahn_marb_lahn_leun.py +5 -0
- hydpy/data/HydPy-H-Lahn/control/default/land.py +9 -0
- hydpy/data/HydPy-H-Lahn/control/default/land_dill_assl.py +57 -0
- hydpy/data/HydPy-H-Lahn/control/default/land_lahn_kalk.py +57 -0
- hydpy/data/HydPy-H-Lahn/control/default/land_lahn_leun.py +56 -0
- hydpy/data/HydPy-H-Lahn/control/default/land_lahn_marb.py +57 -0
- hydpy/data/HydPy-H-Lahn/control/default/stream_dill_assl_lahn_leun.py +7 -0
- hydpy/data/HydPy-H-Lahn/control/default/stream_lahn_leun_lahn_kalk.py +7 -0
- hydpy/data/HydPy-H-Lahn/control/default/stream_lahn_marb_lahn_leun.py +7 -0
- hydpy/data/HydPy-H-Lahn/multiple_runs.xml +309 -0
- hydpy/data/HydPy-H-Lahn/multiple_runs_alpha.xml +71 -0
- hydpy/data/HydPy-H-Lahn/network/default/headwaters.py +11 -0
- hydpy/data/HydPy-H-Lahn/network/default/nonheadwaters.py +11 -0
- hydpy/data/HydPy-H-Lahn/network/default/streams.py +8 -0
- hydpy/data/HydPy-H-Lahn/series/default/dill_assl_obs_q.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/evap_pet_hbv96_input_normalairtemperature.nc +0 -0
- hydpy/data/HydPy-H-Lahn/series/default/evap_pet_hbv96_input_normalevapotranspiration.nc +0 -0
- hydpy/data/HydPy-H-Lahn/series/default/hland_96_input_p.nc +0 -0
- hydpy/data/HydPy-H-Lahn/series/default/hland_96_input_t.nc +0 -0
- hydpy/data/HydPy-H-Lahn/series/default/lahn_kalk_obs_q.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/lahn_leun_obs_q.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/lahn_marb_obs_q.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_hland_96_input_p.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_dill_assl_hland_96_input_t.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_hland_96_input_p.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_kalk_hland_96_input_t.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_hland_96_input_p.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_leun_hland_96_input_t.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_evap_pet_hbv96_input_normalairtemperature.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_evap_pet_hbv96_input_normalevapotranspiration.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_hland_96_input_p.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/land_lahn_marb_hland_96_input_t.asc +11387 -0
- hydpy/data/HydPy-H-Lahn/series/default/obs_q.nc +0 -0
- hydpy/data/HydPy-H-Lahn/single_run.xml +152 -0
- hydpy/data/HydPy-H-Lahn/single_run.xmlt +143 -0
- hydpy/data/__init__.py +17 -0
- hydpy/docs/__init__.py +0 -0
- hydpy/docs/autofigs/__init__.py +0 -0
- hydpy/docs/bib/__init__.py +0 -0
- hydpy/docs/bib/refs.bib +566 -0
- hydpy/docs/combine_docversions.py +133 -0
- hydpy/docs/draw_model_sketches.py +1301 -0
- hydpy/docs/enable_autodoc.py +7 -0
- hydpy/docs/figs/HydPy-G-GR4.png +0 -0
- hydpy/docs/figs/HydPy-G-GR5.png +0 -0
- hydpy/docs/figs/HydPy-G-GR6.png +0 -0
- hydpy/docs/figs/HydPy-H-HBV96-COSERO.png +0 -0
- hydpy/docs/figs/HydPy-H-HBV96-PREVAH.png +0 -0
- hydpy/docs/figs/HydPy-H-HBV96.png +0 -0
- hydpy/docs/figs/HydPy-H-Lahn.png +0 -0
- hydpy/docs/figs/HydPy-KinW-Williams.png +0 -0
- hydpy/docs/figs/HydPy-L-DD.png +0 -0
- hydpy/docs/figs/HydPy-W-Wag.png +0 -0
- hydpy/docs/figs/HydPy_Logo.png +0 -0
- hydpy/docs/figs/HydPy_Logo_Text.png +0 -0
- hydpy/docs/figs/IDLE-editor.png +0 -0
- hydpy/docs/figs/IDLE-shell.png +0 -0
- hydpy/docs/figs/LAWA_river-basin-bumbers.png +0 -0
- hydpy/docs/figs/__init__.py +0 -0
- hydpy/docs/html_/__init__.py +0 -0
- hydpy/docs/polish_html.py +57 -0
- hydpy/docs/prepare.py +224 -0
- hydpy/docs/publish_docs.py +53 -0
- hydpy/docs/rst/HydPy-ARMA.rst +27 -0
- hydpy/docs/rst/HydPy-Conv.rst +22 -0
- hydpy/docs/rst/HydPy-Dam.rst +79 -0
- hydpy/docs/rst/HydPy-Dummy.rst +21 -0
- hydpy/docs/rst/HydPy-Evap.rst +26 -0
- hydpy/docs/rst/HydPy-Exch.rst +36 -0
- hydpy/docs/rst/HydPy-G.rst +40 -0
- hydpy/docs/rst/HydPy-GA.rst +34 -0
- hydpy/docs/rst/HydPy-H.rst +24 -0
- hydpy/docs/rst/HydPy-KinW.rst +32 -0
- hydpy/docs/rst/HydPy-L.rst +42 -0
- hydpy/docs/rst/HydPy-Meteo.rst +28 -0
- hydpy/docs/rst/HydPy-Musk.rst +21 -0
- hydpy/docs/rst/HydPy-Rconc.rst +17 -0
- hydpy/docs/rst/HydPy-SW1D.rst +49 -0
- hydpy/docs/rst/HydPy-Test.rst +19 -0
- hydpy/docs/rst/HydPy-W.rst +20 -0
- hydpy/docs/rst/HydPy-WHMod.rst +19 -0
- hydpy/docs/rst/HydPy-WQ.rst +20 -0
- hydpy/docs/rst/__init__.py +0 -0
- hydpy/docs/rst/additional_repositories.rst +40 -0
- hydpy/docs/rst/auxiliaries.rst +31 -0
- hydpy/docs/rst/continuous_integration.rst +75 -0
- hydpy/docs/rst/core.rst +75 -0
- hydpy/docs/rst/cythons.rst +47 -0
- hydpy/docs/rst/definitions.rst +506 -0
- hydpy/docs/rst/developer_guide.rst +54 -0
- hydpy/docs/rst/example_projects.rst +40 -0
- hydpy/docs/rst/execution.rst +22 -0
- hydpy/docs/rst/framework_tools.rst +56 -0
- hydpy/docs/rst/how_to_read_the_reference_manual.rst +156 -0
- hydpy/docs/rst/hydpydependencies.rst +55 -0
- hydpy/docs/rst/index.rst +125 -0
- hydpy/docs/rst/installation.rst +155 -0
- hydpy/docs/rst/model_families.rst +79 -0
- hydpy/docs/rst/model_overview.rst +291 -0
- hydpy/docs/rst/modelimports.rst +10 -0
- hydpy/docs/rst/options.rst +119 -0
- hydpy/docs/rst/programming_style.rst +572 -0
- hydpy/docs/rst/project_structure.rst +520 -0
- hydpy/docs/rst/quickstart.rst +304 -0
- hydpy/docs/rst/reference_manual.rst +29 -0
- hydpy/docs/rst/required_tools.rst +50 -0
- hydpy/docs/rst/simulation.rst +514 -0
- hydpy/docs/rst/submodel_interfaces.rst +32 -0
- hydpy/docs/rst/tests_and_documentation.rst +85 -0
- hydpy/docs/rst/user_guide.rst +38 -0
- hydpy/docs/rst/version_control.rst +116 -0
- hydpy/docs/rst/zbibliography.rst +8 -0
- hydpy/docs/sphinx/__init__.py +0 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/changes/frameset.html +11 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/changes/rstsource.html +15 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/changes/versionchanges.html +33 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/defindex.html +35 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/domainindex.html +56 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/genindex-single.html +63 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/genindex-split.html +41 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/genindex.html +76 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/globaltoc.html +11 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/layout.html +221 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/localtoc.html +15 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/opensearch.xml +13 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/page.html +13 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/relations.html +23 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/search.html +65 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/searchbox.html +21 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/searchfield.html +23 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/sourcelink.html +18 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/basic.css_t +925 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/doctools.js +156 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/documentation_options.js_t +13 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/file.png +0 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/language_data.js_t +26 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/minus.png +0 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/plus.png +0 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/searchtools.js +574 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/static/sphinx_highlight.js +154 -0
- hydpy/docs/sphinx/_themes/basic_hydpy/theme.conf +16 -0
- hydpy/docs/sphinx/_themes/classic_hydpy/layout.html +23 -0
- hydpy/docs/sphinx/_themes/classic_hydpy/static/classic.css_t +358 -0
- hydpy/docs/sphinx/_themes/classic_hydpy/static/sidebar.js_t +72 -0
- hydpy/docs/sphinx/_themes/classic_hydpy/theme.conf +32 -0
- hydpy/docs/sphinx/conf.py +398 -0
- hydpy/docs/sphinx/defaultlinks_extension.py +36 -0
- hydpy/docs/sphinx/integrationtest_extension.py +104 -0
- hydpy/docs/sphinx/projectstructure_extension.py +58 -0
- hydpy/docs/sphinx/submodelgraph_extension.py +53 -0
- hydpy/exe/__init__.py +0 -0
- hydpy/exe/commandtools.py +651 -0
- hydpy/exe/hyd.py +277 -0
- hydpy/exe/modelimports.py +41 -0
- hydpy/exe/replacetools.py +216 -0
- hydpy/exe/servertools.py +2348 -0
- hydpy/exe/xmltools.py +3280 -0
- hydpy/interfaces/__init__.py +0 -0
- hydpy/interfaces/aetinterfaces.py +94 -0
- hydpy/interfaces/dischargeinterfaces.py +45 -0
- hydpy/interfaces/petinterfaces.py +117 -0
- hydpy/interfaces/precipinterfaces.py +42 -0
- hydpy/interfaces/radiationinterfaces.py +79 -0
- hydpy/interfaces/rconcinterfaces.py +30 -0
- hydpy/interfaces/routinginterfaces.py +324 -0
- hydpy/interfaces/soilinterfaces.py +96 -0
- hydpy/interfaces/stateinterfaces.py +98 -0
- hydpy/interfaces/tempinterfaces.py +46 -0
- hydpy/models/__init__.py +0 -0
- hydpy/models/arma/__init__.py +14 -0
- hydpy/models/arma/arma_control.py +383 -0
- hydpy/models/arma/arma_derived.py +204 -0
- hydpy/models/arma/arma_fluxes.py +41 -0
- hydpy/models/arma/arma_inlets.py +11 -0
- hydpy/models/arma/arma_logs.py +19 -0
- hydpy/models/arma/arma_model.py +461 -0
- hydpy/models/arma/arma_outlets.py +11 -0
- hydpy/models/arma_rimorido.py +381 -0
- hydpy/models/conv/__init__.py +12 -0
- hydpy/models/conv/conv_control.py +303 -0
- hydpy/models/conv/conv_derived.py +271 -0
- hydpy/models/conv/conv_fluxes.py +54 -0
- hydpy/models/conv/conv_inlets.py +11 -0
- hydpy/models/conv/conv_model.py +687 -0
- hydpy/models/conv/conv_outlets.py +11 -0
- hydpy/models/conv_idw.py +120 -0
- hydpy/models/conv_idw_ed.py +184 -0
- hydpy/models/conv_nn.py +112 -0
- hydpy/models/dam/__init__.py +16 -0
- hydpy/models/dam/dam_aides.py +17 -0
- hydpy/models/dam/dam_control.py +346 -0
- hydpy/models/dam/dam_derived.py +559 -0
- hydpy/models/dam/dam_factors.py +46 -0
- hydpy/models/dam/dam_fluxes.py +179 -0
- hydpy/models/dam/dam_inlets.py +29 -0
- hydpy/models/dam/dam_logs.py +52 -0
- hydpy/models/dam/dam_model.py +5011 -0
- hydpy/models/dam/dam_outlets.py +23 -0
- hydpy/models/dam/dam_receivers.py +41 -0
- hydpy/models/dam/dam_senders.py +23 -0
- hydpy/models/dam/dam_solver.py +75 -0
- hydpy/models/dam/dam_states.py +11 -0
- hydpy/models/dam_llake.py +499 -0
- hydpy/models/dam_lreservoir.py +548 -0
- hydpy/models/dam_lretention.py +343 -0
- hydpy/models/dam_pump.py +278 -0
- hydpy/models/dam_pump_sluice.py +339 -0
- hydpy/models/dam_sluice.py +319 -0
- hydpy/models/dam_v001.py +1127 -0
- hydpy/models/dam_v002.py +381 -0
- hydpy/models/dam_v003.py +422 -0
- hydpy/models/dam_v004.py +665 -0
- hydpy/models/dam_v005.py +479 -0
- hydpy/models/dummy/__init__.py +15 -0
- hydpy/models/dummy/dummy_control.py +22 -0
- hydpy/models/dummy/dummy_fluxes.py +11 -0
- hydpy/models/dummy/dummy_inlets.py +11 -0
- hydpy/models/dummy/dummy_inputs.py +41 -0
- hydpy/models/dummy/dummy_model.py +196 -0
- hydpy/models/dummy/dummy_outlets.py +11 -0
- hydpy/models/dummy_interceptedwater.py +85 -0
- hydpy/models/dummy_node2node.py +83 -0
- hydpy/models/dummy_snowalbedo.py +84 -0
- hydpy/models/dummy_snowcover.py +84 -0
- hydpy/models/dummy_snowycanopy.py +86 -0
- hydpy/models/dummy_soilwater.py +85 -0
- hydpy/models/evap/__init__.py +13 -0
- hydpy/models/evap/evap_control.py +354 -0
- hydpy/models/evap/evap_derived.py +236 -0
- hydpy/models/evap/evap_factors.py +188 -0
- hydpy/models/evap/evap_fixed.py +68 -0
- hydpy/models/evap/evap_fluxes.py +150 -0
- hydpy/models/evap/evap_inputs.py +54 -0
- hydpy/models/evap/evap_logs.py +91 -0
- hydpy/models/evap/evap_masks.py +48 -0
- hydpy/models/evap/evap_model.py +9170 -0
- hydpy/models/evap/evap_parameters.py +149 -0
- hydpy/models/evap/evap_sequences.py +32 -0
- hydpy/models/evap/evap_states.py +18 -0
- hydpy/models/evap_aet_hbv96.py +372 -0
- hydpy/models/evap_aet_minhas.py +331 -0
- hydpy/models/evap_aet_morsim.py +627 -0
- hydpy/models/evap_pet_ambav1.py +483 -0
- hydpy/models/evap_pet_hbv96.py +147 -0
- hydpy/models/evap_pet_m.py +94 -0
- hydpy/models/evap_pet_mlc.py +107 -0
- hydpy/models/evap_ret_fao56.py +265 -0
- hydpy/models/evap_ret_io.py +74 -0
- hydpy/models/evap_ret_tw2002.py +165 -0
- hydpy/models/exch/__init__.py +14 -0
- hydpy/models/exch/exch_control.py +262 -0
- hydpy/models/exch/exch_derived.py +36 -0
- hydpy/models/exch/exch_factors.py +26 -0
- hydpy/models/exch/exch_fluxes.py +48 -0
- hydpy/models/exch/exch_inlets.py +11 -0
- hydpy/models/exch/exch_logs.py +12 -0
- hydpy/models/exch/exch_model.py +451 -0
- hydpy/models/exch/exch_outlets.py +17 -0
- hydpy/models/exch/exch_receivers.py +17 -0
- hydpy/models/exch_branch_hbv96.py +186 -0
- hydpy/models/exch_waterlevel.py +73 -0
- hydpy/models/exch_weir_hbv96.py +609 -0
- hydpy/models/ga/__init__.py +14 -0
- hydpy/models/ga/ga_aides.py +17 -0
- hydpy/models/ga/ga_control.py +208 -0
- hydpy/models/ga/ga_derived.py +77 -0
- hydpy/models/ga/ga_fluxes.py +83 -0
- hydpy/models/ga/ga_inputs.py +26 -0
- hydpy/models/ga/ga_logs.py +17 -0
- hydpy/models/ga/ga_model.py +2952 -0
- hydpy/models/ga/ga_states.py +87 -0
- hydpy/models/ga_garto.py +1001 -0
- hydpy/models/ga_garto_submodel1.py +79 -0
- hydpy/models/gland/__init__.py +14 -0
- hydpy/models/gland/gland_control.py +90 -0
- hydpy/models/gland/gland_derived.py +113 -0
- hydpy/models/gland/gland_fluxes.py +137 -0
- hydpy/models/gland/gland_inputs.py +12 -0
- hydpy/models/gland/gland_model.py +1439 -0
- hydpy/models/gland/gland_outlets.py +11 -0
- hydpy/models/gland/gland_states.py +90 -0
- hydpy/models/gland_gr4.py +501 -0
- hydpy/models/gland_gr5.py +463 -0
- hydpy/models/gland_gr6.py +487 -0
- hydpy/models/hland/__init__.py +20 -0
- hydpy/models/hland/hland_aides.py +19 -0
- hydpy/models/hland/hland_constants.py +37 -0
- hydpy/models/hland/hland_control.py +1530 -0
- hydpy/models/hland/hland_derived.py +683 -0
- hydpy/models/hland/hland_factors.py +57 -0
- hydpy/models/hland/hland_fixed.py +42 -0
- hydpy/models/hland/hland_fluxes.py +279 -0
- hydpy/models/hland/hland_inputs.py +19 -0
- hydpy/models/hland/hland_masks.py +107 -0
- hydpy/models/hland/hland_model.py +4664 -0
- hydpy/models/hland/hland_outlets.py +11 -0
- hydpy/models/hland/hland_parameters.py +227 -0
- hydpy/models/hland/hland_sequences.py +382 -0
- hydpy/models/hland/hland_states.py +236 -0
- hydpy/models/hland_96.py +1812 -0
- hydpy/models/hland_96c.py +1196 -0
- hydpy/models/hland_96p.py +1204 -0
- hydpy/models/kinw/__init__.py +18 -0
- hydpy/models/kinw/kinw_aides.py +306 -0
- hydpy/models/kinw/kinw_control.py +270 -0
- hydpy/models/kinw/kinw_derived.py +197 -0
- hydpy/models/kinw/kinw_fixed.py +33 -0
- hydpy/models/kinw/kinw_fluxes.py +37 -0
- hydpy/models/kinw/kinw_inlets.py +11 -0
- hydpy/models/kinw/kinw_model.py +3026 -0
- hydpy/models/kinw/kinw_outlets.py +11 -0
- hydpy/models/kinw/kinw_solver.py +45 -0
- hydpy/models/kinw/kinw_states.py +17 -0
- hydpy/models/kinw_williams.py +1299 -0
- hydpy/models/kinw_williams_ext.py +768 -0
- hydpy/models/lland/__init__.py +42 -0
- hydpy/models/lland/lland_aides.py +38 -0
- hydpy/models/lland/lland_constants.py +88 -0
- hydpy/models/lland/lland_control.py +1329 -0
- hydpy/models/lland/lland_derived.py +380 -0
- hydpy/models/lland/lland_factors.py +18 -0
- hydpy/models/lland/lland_fixed.py +128 -0
- hydpy/models/lland/lland_fluxes.py +626 -0
- hydpy/models/lland/lland_inlets.py +12 -0
- hydpy/models/lland/lland_inputs.py +33 -0
- hydpy/models/lland/lland_logs.py +17 -0
- hydpy/models/lland/lland_masks.py +212 -0
- hydpy/models/lland/lland_model.py +7690 -0
- hydpy/models/lland/lland_outlets.py +12 -0
- hydpy/models/lland/lland_parameters.py +195 -0
- hydpy/models/lland/lland_sequences.py +67 -0
- hydpy/models/lland/lland_states.py +280 -0
- hydpy/models/lland_dd.py +2270 -0
- hydpy/models/lland_knauf.py +2156 -0
- hydpy/models/lland_knauf_ic.py +1920 -0
- hydpy/models/meteo/__init__.py +12 -0
- hydpy/models/meteo/meteo_control.py +154 -0
- hydpy/models/meteo/meteo_derived.py +159 -0
- hydpy/models/meteo/meteo_factors.py +88 -0
- hydpy/models/meteo/meteo_fixed.py +19 -0
- hydpy/models/meteo/meteo_fluxes.py +46 -0
- hydpy/models/meteo/meteo_inputs.py +47 -0
- hydpy/models/meteo/meteo_logs.py +30 -0
- hydpy/models/meteo/meteo_model.py +2904 -0
- hydpy/models/meteo/meteo_parameters.py +14 -0
- hydpy/models/meteo/meteo_sequences.py +22 -0
- hydpy/models/meteo_clear_glob_io.py +77 -0
- hydpy/models/meteo_glob_fao56.py +217 -0
- hydpy/models/meteo_glob_io.py +68 -0
- hydpy/models/meteo_glob_morsim.py +444 -0
- hydpy/models/meteo_precip_io.py +76 -0
- hydpy/models/meteo_psun_sun_glob_io.py +83 -0
- hydpy/models/meteo_sun_fao56.py +188 -0
- hydpy/models/meteo_sun_morsim.py +466 -0
- hydpy/models/meteo_temp_io.py +76 -0
- hydpy/models/musk/__init__.py +15 -0
- hydpy/models/musk/musk_control.py +328 -0
- hydpy/models/musk/musk_derived.py +32 -0
- hydpy/models/musk/musk_factors.py +53 -0
- hydpy/models/musk/musk_fluxes.py +24 -0
- hydpy/models/musk/musk_inlets.py +11 -0
- hydpy/models/musk/musk_masks.py +15 -0
- hydpy/models/musk/musk_model.py +838 -0
- hydpy/models/musk/musk_outlets.py +11 -0
- hydpy/models/musk/musk_sequences.py +88 -0
- hydpy/models/musk/musk_solver.py +68 -0
- hydpy/models/musk/musk_states.py +64 -0
- hydpy/models/musk_classic.py +228 -0
- hydpy/models/musk_mct.py +1247 -0
- hydpy/models/rconc/__init__.py +12 -0
- hydpy/models/rconc/rconc_control.py +473 -0
- hydpy/models/rconc/rconc_derived.py +76 -0
- hydpy/models/rconc/rconc_fluxes.py +19 -0
- hydpy/models/rconc/rconc_logs.py +74 -0
- hydpy/models/rconc/rconc_model.py +260 -0
- hydpy/models/rconc/rconc_states.py +11 -0
- hydpy/models/rconc_nash.py +48 -0
- hydpy/models/rconc_uh.py +53 -0
- hydpy/models/sw1d/__init__.py +17 -0
- hydpy/models/sw1d/sw1d_control.py +356 -0
- hydpy/models/sw1d/sw1d_derived.py +85 -0
- hydpy/models/sw1d/sw1d_factors.py +78 -0
- hydpy/models/sw1d/sw1d_fixed.py +12 -0
- hydpy/models/sw1d/sw1d_fluxes.py +55 -0
- hydpy/models/sw1d/sw1d_inlets.py +17 -0
- hydpy/models/sw1d/sw1d_model.py +3385 -0
- hydpy/models/sw1d/sw1d_outlets.py +11 -0
- hydpy/models/sw1d/sw1d_receivers.py +11 -0
- hydpy/models/sw1d/sw1d_senders.py +11 -0
- hydpy/models/sw1d/sw1d_states.py +23 -0
- hydpy/models/sw1d_channel.py +2051 -0
- hydpy/models/sw1d_gate_out.py +599 -0
- hydpy/models/sw1d_lias.py +105 -0
- hydpy/models/sw1d_lias_sluice.py +531 -0
- hydpy/models/sw1d_network.py +1219 -0
- hydpy/models/sw1d_pump.py +448 -0
- hydpy/models/sw1d_q_in.py +79 -0
- hydpy/models/sw1d_q_out.py +81 -0
- hydpy/models/sw1d_storage.py +78 -0
- hydpy/models/sw1d_weir_out.py +75 -0
- hydpy/models/test/__init__.py +14 -0
- hydpy/models/test/test_control.py +28 -0
- hydpy/models/test/test_fluxes.py +17 -0
- hydpy/models/test/test_model.py +201 -0
- hydpy/models/test/test_solver.py +48 -0
- hydpy/models/test/test_states.py +17 -0
- hydpy/models/test_discontinous.py +46 -0
- hydpy/models/test_stiff0d.py +47 -0
- hydpy/models/test_stiff1d.py +42 -0
- hydpy/models/whmod/__init__.py +21 -0
- hydpy/models/whmod/whmod_constants.py +77 -0
- hydpy/models/whmod/whmod_control.py +333 -0
- hydpy/models/whmod/whmod_derived.py +210 -0
- hydpy/models/whmod/whmod_factors.py +9 -0
- hydpy/models/whmod/whmod_fluxes.py +105 -0
- hydpy/models/whmod/whmod_inputs.py +15 -0
- hydpy/models/whmod/whmod_masks.py +178 -0
- hydpy/models/whmod/whmod_model.py +2091 -0
- hydpy/models/whmod/whmod_parameters.py +155 -0
- hydpy/models/whmod/whmod_sequences.py +193 -0
- hydpy/models/whmod/whmod_states.py +73 -0
- hydpy/models/whmod_rural.py +794 -0
- hydpy/models/whmod_urban.py +1011 -0
- hydpy/models/wland/__init__.py +43 -0
- hydpy/models/wland/wland_aides.py +55 -0
- hydpy/models/wland/wland_constants.py +103 -0
- hydpy/models/wland/wland_control.py +508 -0
- hydpy/models/wland/wland_derived.py +330 -0
- hydpy/models/wland/wland_factors.py +11 -0
- hydpy/models/wland/wland_fixed.py +12 -0
- hydpy/models/wland/wland_fluxes.py +166 -0
- hydpy/models/wland/wland_inputs.py +33 -0
- hydpy/models/wland/wland_masks.py +54 -0
- hydpy/models/wland/wland_model.py +3755 -0
- hydpy/models/wland/wland_outlets.py +11 -0
- hydpy/models/wland/wland_parameters.py +214 -0
- hydpy/models/wland/wland_sequences.py +108 -0
- hydpy/models/wland/wland_solver.py +45 -0
- hydpy/models/wland/wland_states.py +56 -0
- hydpy/models/wland_gd.py +888 -0
- hydpy/models/wland_wag.py +1244 -0
- hydpy/models/wq/__init__.py +14 -0
- hydpy/models/wq/wq_control.py +117 -0
- hydpy/models/wq/wq_derived.py +182 -0
- hydpy/models/wq/wq_factors.py +79 -0
- hydpy/models/wq/wq_fluxes.py +17 -0
- hydpy/models/wq/wq_model.py +1889 -0
- hydpy/models/wq_trapeze.py +168 -0
- hydpy/models/wq_trapeze_strickler.py +101 -0
- hydpy/models/wq_walrus.py +57 -0
- hydpy/py.typed +0 -0
- hydpy/tests/.coveragerc +22 -0
- hydpy/tests/__init__.py +0 -0
- hydpy/tests/check_consistency.py +32 -0
- hydpy/tests/hydpydoctestcustomize.pth +1 -0
- hydpy/tests/hydpydoctestcustomize.py +15 -0
- hydpy/tests/iotesting/__init__.py +0 -0
- hydpy/tests/run_doctests.py +233 -0
- hydpy-6.2.dev1.data/scripts/hyd.py +277 -0
- hydpy-6.2.dev1.dist-info/LICENSE +165 -0
- hydpy-6.2.dev1.dist-info/METADATA +163 -0
- hydpy-6.2.dev1.dist-info/RECORD +890 -0
- hydpy-6.2.dev1.dist-info/WHEEL +5 -0
- hydpy-6.2.dev1.dist-info/licenses_hydpy_installer.txt +42 -0
- hydpy-6.2.dev1.dist-info/top_level.txt +1 -0
hydpy/core/filetools.py
ADDED
|
@@ -0,0 +1,1985 @@
|
|
|
1
|
+
"""This module provides features for handling the folder structure of *HydPy* projects
|
|
2
|
+
as well as loading data from and storing data to files."""
|
|
3
|
+
|
|
4
|
+
# import...
|
|
5
|
+
# ...from standard library
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
import contextlib
|
|
8
|
+
import os
|
|
9
|
+
import runpy
|
|
10
|
+
import shutil
|
|
11
|
+
import types
|
|
12
|
+
import warnings
|
|
13
|
+
import zipfile
|
|
14
|
+
|
|
15
|
+
# ...from site-packages
|
|
16
|
+
import numpy
|
|
17
|
+
|
|
18
|
+
# ...from HydPy
|
|
19
|
+
import hydpy
|
|
20
|
+
from hydpy import config
|
|
21
|
+
from hydpy.core import exceptiontools
|
|
22
|
+
from hydpy.core import devicetools
|
|
23
|
+
from hydpy.core import netcdftools
|
|
24
|
+
from hydpy.core import objecttools
|
|
25
|
+
from hydpy.core import optiontools
|
|
26
|
+
from hydpy.core import selectiontools
|
|
27
|
+
from hydpy.core import sequencetools
|
|
28
|
+
from hydpy.core import timetools
|
|
29
|
+
from hydpy.core.typingtools import *
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Folder2Path:
|
|
33
|
+
"""Map folder names to their pathnames.
|
|
34
|
+
|
|
35
|
+
You can pass positional or keyword arguments when initialising |Folder2Path|. For
|
|
36
|
+
positional arguments, the folder and its path are assumed to be identical. For
|
|
37
|
+
keyword arguments, the keyword corresponds to the folder name, and its value is the
|
|
38
|
+
pathname:
|
|
39
|
+
|
|
40
|
+
>>> from hydpy.core.filetools import Folder2Path
|
|
41
|
+
>>> Folder2Path()
|
|
42
|
+
Folder2Path()
|
|
43
|
+
>>> f2p = Folder2Path(
|
|
44
|
+
... "folder1", "folder2", folder3="folder3", folder4="path4")
|
|
45
|
+
>>> f2p
|
|
46
|
+
Folder2Path(folder1,
|
|
47
|
+
folder2,
|
|
48
|
+
folder3,
|
|
49
|
+
folder4=path4)
|
|
50
|
+
>>> print(f2p)
|
|
51
|
+
Folder2Path(folder1, folder2, folder3, folder4=path4)
|
|
52
|
+
|
|
53
|
+
To add folders after initialisation is supported:
|
|
54
|
+
|
|
55
|
+
>>> f2p.add("folder5")
|
|
56
|
+
>>> f2p.add("folder6", "path6")
|
|
57
|
+
>>> f2p
|
|
58
|
+
Folder2Path(folder1,
|
|
59
|
+
folder2,
|
|
60
|
+
folder3,
|
|
61
|
+
folder5,
|
|
62
|
+
folder4=path4,
|
|
63
|
+
folder6=path6)
|
|
64
|
+
|
|
65
|
+
Folder names are required to be valid Python identifiers:
|
|
66
|
+
|
|
67
|
+
>>> f2p.add("folder 7")
|
|
68
|
+
Traceback (most recent call last):
|
|
69
|
+
...
|
|
70
|
+
ValueError: The given name string `folder 7` does not define a valid variable \
|
|
71
|
+
identifier. Valid identifiers do not contain characters like `-` or empty spaces, do \
|
|
72
|
+
not start with numbers, cannot be mistaken with Python built-ins like `for`...)
|
|
73
|
+
|
|
74
|
+
You can query the folder and attribute names:
|
|
75
|
+
|
|
76
|
+
>>> f2p.folders
|
|
77
|
+
['folder1', 'folder2', 'folder3', 'folder4', 'folder5', 'folder6']
|
|
78
|
+
>>> f2p.paths
|
|
79
|
+
['folder1', 'folder2', 'folder3', 'path4', 'folder5', 'path6']
|
|
80
|
+
|
|
81
|
+
Attribute access and iteration are also supported:
|
|
82
|
+
|
|
83
|
+
>>> "folder1" in dir(f2p)
|
|
84
|
+
True
|
|
85
|
+
>>> f2p.folder1
|
|
86
|
+
'folder1'
|
|
87
|
+
>>> f2p.folder4
|
|
88
|
+
'path4'
|
|
89
|
+
|
|
90
|
+
>>> for folder, path in f2p:
|
|
91
|
+
... print(folder, path)
|
|
92
|
+
folder1 folder1
|
|
93
|
+
folder2 folder2
|
|
94
|
+
folder3 folder3
|
|
95
|
+
folder4 path4
|
|
96
|
+
folder5 folder5
|
|
97
|
+
folder6 path6
|
|
98
|
+
|
|
99
|
+
>>> len(f2p)
|
|
100
|
+
6
|
|
101
|
+
>>> bool(f2p)
|
|
102
|
+
True
|
|
103
|
+
>>> bool(Folder2Path())
|
|
104
|
+
False
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
def __init__(self, *args: str, **kwargs: str) -> None:
|
|
108
|
+
for arg in args:
|
|
109
|
+
self.add(arg)
|
|
110
|
+
for key, value in kwargs.items():
|
|
111
|
+
self.add(key, value)
|
|
112
|
+
|
|
113
|
+
def add(self, directory: str, path: str | None = None) -> None:
|
|
114
|
+
"""Add a directory and, optionally, its path."""
|
|
115
|
+
objecttools.valid_variable_identifier(directory)
|
|
116
|
+
if path is None:
|
|
117
|
+
path = directory
|
|
118
|
+
setattr(self, directory, path)
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def folders(self) -> list[str]:
|
|
122
|
+
"""The currently handled folder names."""
|
|
123
|
+
return [folder for folder, path in self]
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def paths(self) -> list[str]:
|
|
127
|
+
"""The currently handled path names."""
|
|
128
|
+
return [path for folder, path in self]
|
|
129
|
+
|
|
130
|
+
def __iter__(self) -> Iterator[tuple[str, str]]:
|
|
131
|
+
yield from sorted(vars(self).items())
|
|
132
|
+
|
|
133
|
+
def __len__(self) -> int:
|
|
134
|
+
return len(vars(self))
|
|
135
|
+
|
|
136
|
+
def __str__(self) -> str:
|
|
137
|
+
return " ".join(repr(self).split())
|
|
138
|
+
|
|
139
|
+
def __repr__(self) -> str:
|
|
140
|
+
if self:
|
|
141
|
+
args, kwargs = [], []
|
|
142
|
+
for key, value in self:
|
|
143
|
+
if key == value:
|
|
144
|
+
args.append(key)
|
|
145
|
+
else:
|
|
146
|
+
kwargs.append(f"{key}={objecttools.repr_(value)}")
|
|
147
|
+
lines = [f" {arg}," for arg in args + kwargs]
|
|
148
|
+
lines[0] = "Folder2Path(" + lines[0][12:]
|
|
149
|
+
lines[-1] = lines[-1][:-1] + ")"
|
|
150
|
+
return "\n".join(lines)
|
|
151
|
+
return "Folder2Path()"
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class FileManager:
|
|
155
|
+
"""Base class for |NetworkManager|, |ControlManager|, |ConditionManager|, and
|
|
156
|
+
|SequenceManager|."""
|
|
157
|
+
|
|
158
|
+
BASEDIR: str
|
|
159
|
+
DEFAULTDIR: str | None
|
|
160
|
+
|
|
161
|
+
_projectdir: str | None
|
|
162
|
+
_currentdir: str | None
|
|
163
|
+
|
|
164
|
+
def __init__(self) -> None:
|
|
165
|
+
self._projectdir = None
|
|
166
|
+
self._currentdir = None
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def projectdir(self) -> str:
|
|
170
|
+
"""The folder name of a project's root directory.
|
|
171
|
+
|
|
172
|
+
For the :ref:`HydPy-H-Lahn` example project, |FileManager.projectdir| is (not
|
|
173
|
+
surprisingly) `HydPy-H-Lahn` and is queried from the |pub| module. However,
|
|
174
|
+
you can define or change |FileManager.projectdir| interactively, which can be
|
|
175
|
+
useful for more complex tasks like copying (parts of) projects:
|
|
176
|
+
|
|
177
|
+
>>> from hydpy.core.filetools import FileManager
|
|
178
|
+
>>> from hydpy import pub
|
|
179
|
+
>>> pub.projectname = "project_A"
|
|
180
|
+
>>> filemanager = FileManager()
|
|
181
|
+
>>> filemanager.projectdir
|
|
182
|
+
'project_A'
|
|
183
|
+
|
|
184
|
+
>>> filemanager.projectdir = "project_B"
|
|
185
|
+
>>> filemanager.projectdir
|
|
186
|
+
'project_B'
|
|
187
|
+
|
|
188
|
+
>>> pub.projectname = "project_C"
|
|
189
|
+
>>> filemanager.projectdir
|
|
190
|
+
'project_B'
|
|
191
|
+
|
|
192
|
+
>>> del filemanager.projectdir
|
|
193
|
+
>>> filemanager.projectdir
|
|
194
|
+
'project_C'
|
|
195
|
+
|
|
196
|
+
>>> del pub.projectname
|
|
197
|
+
>>> filemanager.projectdir
|
|
198
|
+
Traceback (most recent call last):
|
|
199
|
+
...
|
|
200
|
+
hydpy.core.exceptiontools.AttributeNotReady: While trying to automatically \
|
|
201
|
+
determine the file manager's project root directory, the following error occurred: \
|
|
202
|
+
Attribute projectname of module `pub` is not defined at the moment.
|
|
203
|
+
"""
|
|
204
|
+
if (projectdir := self._projectdir) is None:
|
|
205
|
+
try:
|
|
206
|
+
return hydpy.pub.projectname
|
|
207
|
+
except BaseException:
|
|
208
|
+
objecttools.augment_excmessage(
|
|
209
|
+
f"While trying to automatically determine the {self._docname}'s "
|
|
210
|
+
f"project root directory"
|
|
211
|
+
)
|
|
212
|
+
return projectdir
|
|
213
|
+
|
|
214
|
+
@projectdir.setter
|
|
215
|
+
def projectdir(self, name: str) -> None:
|
|
216
|
+
self._projectdir = name
|
|
217
|
+
|
|
218
|
+
@projectdir.deleter
|
|
219
|
+
def projectdir(self) -> None:
|
|
220
|
+
self._projectdir = None
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def basepath(self) -> str:
|
|
224
|
+
"""The absolute path pointing to the available working directories.
|
|
225
|
+
|
|
226
|
+
>>> from hydpy.core.filetools import FileManager
|
|
227
|
+
>>> filemanager = FileManager()
|
|
228
|
+
>>> filemanager.BASEDIR = "basename"
|
|
229
|
+
>>> filemanager.projectdir = "projectname"
|
|
230
|
+
>>> from hydpy import repr_, TestIO
|
|
231
|
+
>>> with TestIO():
|
|
232
|
+
... repr_(filemanager.basepath) # doctest: +ELLIPSIS
|
|
233
|
+
'...hydpy/tests/iotesting/projectname/basename'
|
|
234
|
+
"""
|
|
235
|
+
return os.path.abspath(os.path.join(self.projectdir, self.BASEDIR))
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def availabledirs(self) -> Folder2Path:
|
|
239
|
+
"""The names and paths of the available working directories.
|
|
240
|
+
|
|
241
|
+
All possible working directories must be availablein the base directory of the
|
|
242
|
+
respective |FileManager| subclass. Folders with names starting with an
|
|
243
|
+
underscore do not count (use this for directories handling additional data
|
|
244
|
+
files, if you like), while zipped directories do count as available directories:
|
|
245
|
+
|
|
246
|
+
>>> from hydpy.core.filetools import FileManager
|
|
247
|
+
>>> filemanager = FileManager()
|
|
248
|
+
>>> filemanager.BASEDIR = "basename"
|
|
249
|
+
>>> filemanager.projectdir = "projectname"
|
|
250
|
+
>>> import os
|
|
251
|
+
>>> from hydpy import repr_, TestIO
|
|
252
|
+
>>> TestIO.clear()
|
|
253
|
+
>>> with TestIO():
|
|
254
|
+
... os.makedirs("projectname/basename/folder1")
|
|
255
|
+
... os.makedirs("projectname/basename/folder2")
|
|
256
|
+
... open("projectname/basename/folder3.zip", "w").close()
|
|
257
|
+
... os.makedirs("projectname/basename/_folder4")
|
|
258
|
+
... open("projectname/basename/folder5.tar", "w").close()
|
|
259
|
+
... filemanager.availabledirs # doctest: +ELLIPSIS
|
|
260
|
+
Folder2Path(folder1=.../projectname/basename/folder1,
|
|
261
|
+
folder2=.../projectname/basename/folder2,
|
|
262
|
+
folder3=.../projectname/basename/folder3.zip)
|
|
263
|
+
"""
|
|
264
|
+
directories = Folder2Path()
|
|
265
|
+
for directory in sorted(os.listdir(self.basepath)):
|
|
266
|
+
if not directory.startswith("_"):
|
|
267
|
+
path = os.path.join(self.basepath, directory)
|
|
268
|
+
if os.path.isdir(path):
|
|
269
|
+
directories.add(directory, path)
|
|
270
|
+
elif directory.endswith(".zip"):
|
|
271
|
+
directories.add(directory[:-4], path)
|
|
272
|
+
return directories
|
|
273
|
+
|
|
274
|
+
@property
|
|
275
|
+
def currentdir(self) -> str:
|
|
276
|
+
"""The name of the current working directory containing the relevant files.
|
|
277
|
+
|
|
278
|
+
To show most of the functionality of |property| |FileManager.currentdir| (we
|
|
279
|
+
explain unpacking zipped files on the fly in the documentation on function
|
|
280
|
+
|FileManager.zip_currentdir|), we first prepare a |FileManager| object with the
|
|
281
|
+
default |FileManager.basepath| `projectname/basename` and no
|
|
282
|
+
|FileManager.DEFAULTDIR| defined:
|
|
283
|
+
|
|
284
|
+
>>> from hydpy.core.filetools import FileManager
|
|
285
|
+
>>> filemanager = FileManager()
|
|
286
|
+
>>> filemanager.BASEDIR = "basename"
|
|
287
|
+
>>> filemanager.DEFAULTDIR = None
|
|
288
|
+
>>> filemanager.projectdir = "projectname"
|
|
289
|
+
>>> import os
|
|
290
|
+
>>> from hydpy import pub, repr_, TestIO
|
|
291
|
+
>>> TestIO.clear()
|
|
292
|
+
>>> with TestIO():
|
|
293
|
+
... os.makedirs("projectname/basename")
|
|
294
|
+
... repr_(filemanager.basepath) # doctest: +ELLIPSIS
|
|
295
|
+
'...hydpy/tests/iotesting/projectname/basename'
|
|
296
|
+
|
|
297
|
+
At first, the base directory is empty and asking for the current working
|
|
298
|
+
directory results in the following error:
|
|
299
|
+
|
|
300
|
+
>>> with TestIO():
|
|
301
|
+
... filemanager.currentdir # doctest: +ELLIPSIS
|
|
302
|
+
Traceback (most recent call last):
|
|
303
|
+
...
|
|
304
|
+
RuntimeError: The current working directory of the file manager has not been \
|
|
305
|
+
defined manually and cannot be determined automatically: `.../projectname/basename` \
|
|
306
|
+
does not contain any available directories.
|
|
307
|
+
|
|
308
|
+
If only one directory exists, it is considered the current working directory
|
|
309
|
+
automatically:
|
|
310
|
+
|
|
311
|
+
>>> with TestIO(), pub.options.printprogress(True):
|
|
312
|
+
... os.mkdir("projectname/basename/dir1")
|
|
313
|
+
... assert filemanager.currentdir == "dir1"
|
|
314
|
+
The name of the file manager's current working directory has not been \
|
|
315
|
+
previously defined and is hence set to `dir1`.
|
|
316
|
+
|
|
317
|
+
|property| |FileManager.currentdir| memorises the name of the current working
|
|
318
|
+
directory, even if another directory is added later to the base path:
|
|
319
|
+
|
|
320
|
+
>>> with TestIO():
|
|
321
|
+
... os.mkdir("projectname/basename/dir2")
|
|
322
|
+
... assert filemanager.currentdir == "dir1"
|
|
323
|
+
|
|
324
|
+
Set the value of |FileManager.currentdir| to |None| to let it forget the
|
|
325
|
+
memorised directory. After that, trying to query the current working directory
|
|
326
|
+
results in another error, as it is unclear which directory to select:
|
|
327
|
+
|
|
328
|
+
>>> with TestIO():
|
|
329
|
+
... filemanager.currentdir = None
|
|
330
|
+
... filemanager.currentdir # doctest: +ELLIPSIS
|
|
331
|
+
Traceback (most recent call last):
|
|
332
|
+
...
|
|
333
|
+
RuntimeError: The current working directory of the file manager has not been \
|
|
334
|
+
defined manually and cannot be determined automatically: `.../projectname/basename` \
|
|
335
|
+
does contain multiple available directories (dir1 and dir2).
|
|
336
|
+
|
|
337
|
+
Setting |FileManager.currentdir| manually solves the problem:
|
|
338
|
+
|
|
339
|
+
>>> with TestIO():
|
|
340
|
+
... filemanager.currentdir = "dir1"
|
|
341
|
+
... assert filemanager.currentdir == "dir1"
|
|
342
|
+
|
|
343
|
+
Remove the current working directory `dir1` with the `del` statement:
|
|
344
|
+
|
|
345
|
+
>>> with TestIO(), pub.options.printprogress(True): # doctest: +ELLIPSIS
|
|
346
|
+
... del filemanager.currentdir
|
|
347
|
+
... assert not os.path.exists("projectname/basename/dir1")
|
|
348
|
+
Directory ...dir1 has been removed.
|
|
349
|
+
|
|
350
|
+
|FileManager| subclasses can define a default directory name. When many
|
|
351
|
+
directories exist, and none is selected manually, the default directory is
|
|
352
|
+
chosen automatically. The following example shows an error message due to
|
|
353
|
+
multiple directories without any default name:
|
|
354
|
+
|
|
355
|
+
>>> with TestIO():
|
|
356
|
+
... os.mkdir("projectname/basename/dir1")
|
|
357
|
+
... filemanager.DEFAULTDIR = "dir3"
|
|
358
|
+
... del filemanager.currentdir
|
|
359
|
+
... filemanager.currentdir # doctest: +ELLIPSIS
|
|
360
|
+
Traceback (most recent call last):
|
|
361
|
+
...
|
|
362
|
+
RuntimeError: The current working directory of the file manager has not been \
|
|
363
|
+
defined manually and cannot be determined automatically: The default directory (dir3) \
|
|
364
|
+
is not among the available directories (dir1 and dir2).
|
|
365
|
+
|
|
366
|
+
We can fix this by manually adding the required default directory:
|
|
367
|
+
|
|
368
|
+
>>> with TestIO(), pub.options.printprogress(True):
|
|
369
|
+
... os.mkdir("projectname/basename/dir3")
|
|
370
|
+
... assert filemanager.currentdir == "dir3"
|
|
371
|
+
The name of the file manager's current working directory has not been \
|
|
372
|
+
previously defined and is hence set to `dir3`.
|
|
373
|
+
|
|
374
|
+
Setting the |FileManager.currentdir| to `dir4` not only overwrites the default
|
|
375
|
+
name but also creates the required folder:
|
|
376
|
+
|
|
377
|
+
>>> with TestIO(), pub.options.printprogress(True):
|
|
378
|
+
... filemanager.currentdir = "dir4"
|
|
379
|
+
... assert filemanager.currentdir == "dir4" # doctest: +ELLIPSIS
|
|
380
|
+
Directory ...dir4 has been created.
|
|
381
|
+
>>> with TestIO():
|
|
382
|
+
... dirs = os.listdir("projectname/basename")
|
|
383
|
+
... assert sorted(dirs) == ["dir1", "dir2", "dir3", "dir4"]
|
|
384
|
+
|
|
385
|
+
Failed attempts to remove directories result in error messages like the
|
|
386
|
+
following one:
|
|
387
|
+
|
|
388
|
+
>>> import shutil
|
|
389
|
+
>>> from unittest.mock import patch
|
|
390
|
+
>>> with TestIO(), patch.object(shutil, "rmtree", side_effect=AttributeError):
|
|
391
|
+
... del filemanager.currentdir # doctest: +ELLIPSIS
|
|
392
|
+
Traceback (most recent call last):
|
|
393
|
+
...
|
|
394
|
+
AttributeError: While trying to delete the current working directory \
|
|
395
|
+
`.../projectname/basename/dir4` of the file manager, the following error occurred: ...
|
|
396
|
+
|
|
397
|
+
Then, the current working directory still exists and is remembered by property
|
|
398
|
+
|FileManager.currentdir|:
|
|
399
|
+
|
|
400
|
+
>>> with TestIO():
|
|
401
|
+
... assert filemanager.currentdir == "dir4"
|
|
402
|
+
>>> with TestIO():
|
|
403
|
+
... dirs =os.listdir("projectname/basename")
|
|
404
|
+
... assert sorted(dirs) == ["dir1", "dir2", "dir3", "dir4"]
|
|
405
|
+
|
|
406
|
+
Assign the folder's absolute path if you need to work outside the current
|
|
407
|
+
project directory (for example, to archive simulated data):
|
|
408
|
+
|
|
409
|
+
>>> with TestIO(): # doctest: +ELLIPSIS
|
|
410
|
+
... os.mkdir("differentproject")
|
|
411
|
+
... filemanager.currentdir = os.path.abspath("differentproject/dir1")
|
|
412
|
+
... path = repr_(filemanager.currentpath)
|
|
413
|
+
... assert path.endswith("hydpy/tests/iotesting/differentproject/dir1")
|
|
414
|
+
... assert os.listdir("differentproject") == ["dir1"]
|
|
415
|
+
|
|
416
|
+
If a |FileManager| subclass defines its |FileManager.DEFAULTDIR| class
|
|
417
|
+
attribute, the above behaviour differs in the case of an initially empty base
|
|
418
|
+
directory. Then, |FileManager.currentdir| activates and creates an accordingly
|
|
419
|
+
named directory automatically:
|
|
420
|
+
|
|
421
|
+
>>> filemanager.currentdir = None
|
|
422
|
+
>>> filemanager.DEFAULTDIR = "default"
|
|
423
|
+
>>> TestIO.clear()
|
|
424
|
+
>>> with TestIO(), pub.options.printprogress(True): # doctest: +ELLIPSIS
|
|
425
|
+
... os.makedirs("projectname/basename")
|
|
426
|
+
... assert filemanager.currentdir == "default"
|
|
427
|
+
... assert os.path.exists("projectname/basename/default")
|
|
428
|
+
The name of the file manager's current working directory has not been \
|
|
429
|
+
previously defined and is hence set to `default`.
|
|
430
|
+
Directory ...default has been created.
|
|
431
|
+
"""
|
|
432
|
+
|
|
433
|
+
def _print_info(dirname: str, /) -> None:
|
|
434
|
+
if hydpy.pub.options.printprogress:
|
|
435
|
+
print(
|
|
436
|
+
f"The name of the {self._docname}'s current working directory "
|
|
437
|
+
f"has not been previously defined and is hence set to "
|
|
438
|
+
f"`{dirname}`."
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
currentdir = self._currentdir
|
|
442
|
+
if currentdir is None:
|
|
443
|
+
dirs = self.availabledirs.folders
|
|
444
|
+
if len(dirs) == 1:
|
|
445
|
+
_print_info(dirs[0])
|
|
446
|
+
currentdir = dirs[0]
|
|
447
|
+
elif (default := self.DEFAULTDIR) and (default in dirs or not dirs):
|
|
448
|
+
_print_info(default)
|
|
449
|
+
currentdir = default
|
|
450
|
+
else:
|
|
451
|
+
prefix = (
|
|
452
|
+
f"The current working directory of the {self._docname} has not "
|
|
453
|
+
f"been defined manually and cannot be determined automatically:"
|
|
454
|
+
)
|
|
455
|
+
if not dirs:
|
|
456
|
+
raise RuntimeError(
|
|
457
|
+
f"{prefix} `{objecttools.repr_(self.basepath)}` does not "
|
|
458
|
+
f"contain any available directories."
|
|
459
|
+
)
|
|
460
|
+
if default is None:
|
|
461
|
+
raise RuntimeError(
|
|
462
|
+
f"{prefix} `{objecttools.repr_(self.basepath)}` does contain "
|
|
463
|
+
f"multiple available directories "
|
|
464
|
+
f"({objecttools.enumeration(dirs)})."
|
|
465
|
+
)
|
|
466
|
+
raise RuntimeError(
|
|
467
|
+
f"{prefix} The default directory ({default}) is not among the "
|
|
468
|
+
f"available directories ({objecttools.enumeration(dirs)})."
|
|
469
|
+
)
|
|
470
|
+
self.currentdir = currentdir
|
|
471
|
+
return currentdir
|
|
472
|
+
|
|
473
|
+
@currentdir.setter
|
|
474
|
+
def currentdir(self, directory: str | None) -> None:
|
|
475
|
+
if directory is None:
|
|
476
|
+
self._currentdir = None
|
|
477
|
+
else:
|
|
478
|
+
dirpath = os.path.join(self.basepath, directory)
|
|
479
|
+
zippath = f"{dirpath}.zip"
|
|
480
|
+
if os.path.exists(zippath):
|
|
481
|
+
shutil.unpack_archive(
|
|
482
|
+
filename=zippath, extract_dir=dirpath, format="zip"
|
|
483
|
+
)
|
|
484
|
+
os.remove(zippath)
|
|
485
|
+
if hydpy.pub.options.printprogress:
|
|
486
|
+
print(
|
|
487
|
+
f"The zip file {zippath} has been extracted to directory "
|
|
488
|
+
f"{dirpath} and removed."
|
|
489
|
+
)
|
|
490
|
+
elif not os.path.exists(dirpath):
|
|
491
|
+
os.makedirs(dirpath)
|
|
492
|
+
if hydpy.pub.options.printprogress:
|
|
493
|
+
print(f"Directory {dirpath} has been created.")
|
|
494
|
+
self._currentdir = str(directory)
|
|
495
|
+
|
|
496
|
+
@currentdir.deleter
|
|
497
|
+
def currentdir(self) -> None:
|
|
498
|
+
path = os.path.join(self.basepath, self.currentdir)
|
|
499
|
+
if os.path.exists(path):
|
|
500
|
+
try:
|
|
501
|
+
shutil.rmtree(path)
|
|
502
|
+
if hydpy.pub.options.printprogress:
|
|
503
|
+
print(f"Directory {path} has been removed.")
|
|
504
|
+
except BaseException:
|
|
505
|
+
objecttools.augment_excmessage(
|
|
506
|
+
f"While trying to delete the current working directory "
|
|
507
|
+
f"`{objecttools.repr_(path)}` of the {self._docname}"
|
|
508
|
+
)
|
|
509
|
+
self._currentdir = None
|
|
510
|
+
|
|
511
|
+
@property
|
|
512
|
+
def currentpath(self) -> str:
|
|
513
|
+
"""The absolute path of the current working directory.
|
|
514
|
+
|
|
515
|
+
>>> from hydpy.core.filetools import FileManager
|
|
516
|
+
>>> filemanager = FileManager()
|
|
517
|
+
>>> filemanager.BASEDIR = "basename"
|
|
518
|
+
>>> filemanager.projectdir = "projectname"
|
|
519
|
+
>>> from hydpy import repr_, TestIO
|
|
520
|
+
>>> with TestIO():
|
|
521
|
+
... filemanager.currentdir = "testdir"
|
|
522
|
+
... repr_(filemanager.currentpath) # doctest: +ELLIPSIS
|
|
523
|
+
'...hydpy/tests/iotesting/projectname/basename/testdir'
|
|
524
|
+
"""
|
|
525
|
+
return os.path.join(self.basepath, self.currentdir)
|
|
526
|
+
|
|
527
|
+
@property
|
|
528
|
+
def filenames(self) -> list[str]:
|
|
529
|
+
"""The names of the files in the current working directory, except those
|
|
530
|
+
starting with an underscore.
|
|
531
|
+
|
|
532
|
+
>>> from hydpy.core.filetools import FileManager
|
|
533
|
+
>>> filemanager = FileManager()
|
|
534
|
+
>>> filemanager.BASEDIR = "basename"
|
|
535
|
+
>>> filemanager.projectdir = "projectname"
|
|
536
|
+
>>> from hydpy import TestIO
|
|
537
|
+
>>> with TestIO():
|
|
538
|
+
... filemanager.currentdir = "testdir"
|
|
539
|
+
... open("projectname/basename/testdir/file1.txt", "w").close()
|
|
540
|
+
... open("projectname/basename/testdir/file2.npy", "w").close()
|
|
541
|
+
... open("projectname/basename/testdir/_file1.nc", "w").close()
|
|
542
|
+
... filemanager.filenames
|
|
543
|
+
['file1.txt', 'file2.npy']
|
|
544
|
+
"""
|
|
545
|
+
return sorted(
|
|
546
|
+
fn for fn in os.listdir(self.currentpath) if not fn.startswith("_")
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
@property
|
|
550
|
+
def filepaths(self) -> list[str]:
|
|
551
|
+
"""The absolute path names of the files returned by property
|
|
552
|
+
|FileManager.filenames|.
|
|
553
|
+
|
|
554
|
+
>>> from hydpy.core.filetools import FileManager
|
|
555
|
+
>>> filemanager = FileManager()
|
|
556
|
+
>>> filemanager.BASEDIR = "basename"
|
|
557
|
+
>>> filemanager.projectdir = "projectname"
|
|
558
|
+
>>> from hydpy import repr_, TestIO
|
|
559
|
+
>>> with TestIO():
|
|
560
|
+
... filemanager.currentdir = "testdir"
|
|
561
|
+
... open("projectname/basename/testdir/file1.txt", "w").close()
|
|
562
|
+
... open("projectname/basename/testdir/file2.npy", "w").close()
|
|
563
|
+
... open("projectname/basename/testdir/_file1.nc", "w").close()
|
|
564
|
+
... for filepath in filemanager.filepaths:
|
|
565
|
+
... repr_(filepath) # doctest: +ELLIPSIS
|
|
566
|
+
'...hydpy/tests/iotesting/projectname/basename/testdir/file1.txt'
|
|
567
|
+
'...hydpy/tests/iotesting/projectname/basename/testdir/file2.npy'
|
|
568
|
+
"""
|
|
569
|
+
path = self.currentpath
|
|
570
|
+
return [os.path.join(path, name) for name in self.filenames]
|
|
571
|
+
|
|
572
|
+
def zip_currentdir(self) -> None:
|
|
573
|
+
"""Pack the current working directory in a `zip` file.
|
|
574
|
+
|
|
575
|
+
|FileManager| subclasses allow for manual packing and automatic unpacking of
|
|
576
|
+
working directories. The only supported format is "zip". The original
|
|
577
|
+
directories and zip files are removed after packing or unpacking to avoid
|
|
578
|
+
possible inconsistencies.
|
|
579
|
+
|
|
580
|
+
As an example scenario, we prepare a |FileManager| object with the current
|
|
581
|
+
working directory `folder` containing the files `test1.txt` and `text2.txt`:
|
|
582
|
+
|
|
583
|
+
>>> from hydpy.core.filetools import FileManager
|
|
584
|
+
>>> filemanager = FileManager()
|
|
585
|
+
>>> filemanager.BASEDIR = "basename"
|
|
586
|
+
>>> filemanager.DEFAULTDIR = None
|
|
587
|
+
>>> filemanager.projectdir = "projectname"
|
|
588
|
+
>>> import os
|
|
589
|
+
>>> from hydpy import pub, repr_, TestIO
|
|
590
|
+
>>> TestIO.clear()
|
|
591
|
+
>>> basepath = "projectname/basename"
|
|
592
|
+
>>> with TestIO():
|
|
593
|
+
... os.makedirs(basepath)
|
|
594
|
+
... filemanager.currentdir = "folder"
|
|
595
|
+
... open(f"{basepath}/folder/file1.txt", "w").close()
|
|
596
|
+
... open(f"{basepath}/folder/file2.txt", "w").close()
|
|
597
|
+
... filemanager.filenames
|
|
598
|
+
['file1.txt', 'file2.txt']
|
|
599
|
+
|
|
600
|
+
The directories under the base path are identical to the ones returned by
|
|
601
|
+
property |FileManager.availabledirs|:
|
|
602
|
+
|
|
603
|
+
>>> with TestIO():
|
|
604
|
+
... assert os.listdir(basepath) == ["folder"]
|
|
605
|
+
... filemanager.availabledirs # doctest: +ELLIPSIS
|
|
606
|
+
Folder2Path(folder=.../projectname/basename/folder)
|
|
607
|
+
|
|
608
|
+
After manually packing the current working directory, it still counts as an
|
|
609
|
+
available directory:
|
|
610
|
+
|
|
611
|
+
>>> with TestIO(), pub.options.printprogress(True):
|
|
612
|
+
... filemanager.zip_currentdir()
|
|
613
|
+
... assert os.listdir(basepath) == ["folder.zip"]
|
|
614
|
+
... filemanager.availabledirs # doctest: +ELLIPSIS
|
|
615
|
+
Directory ...folder has been removed.
|
|
616
|
+
Folder2Path(folder=.../projectname/basename/folder.zip)
|
|
617
|
+
|
|
618
|
+
Instead of the complete directory, only its files are packed:
|
|
619
|
+
|
|
620
|
+
>>> from zipfile import ZipFile
|
|
621
|
+
>>> with TestIO():
|
|
622
|
+
... with ZipFile("projectname/basename/folder.zip", "r") as zp:
|
|
623
|
+
... assert sorted(zp.namelist()) == ["file1.txt", "file2.txt"]
|
|
624
|
+
|
|
625
|
+
The zip file is unpacked again when `folder` becomes the current working
|
|
626
|
+
directory:
|
|
627
|
+
|
|
628
|
+
>>> with TestIO(), pub.options.printprogress(True): # doctest: +ELLIPSIS
|
|
629
|
+
... filemanager.currentdir = "folder"
|
|
630
|
+
... assert os.listdir(basepath) == ["folder"]
|
|
631
|
+
... assert sorted(filemanager.filenames) == ["file1.txt", "file2.txt"]
|
|
632
|
+
... filemanager.availabledirs
|
|
633
|
+
The zip file ...folder.zip has been extracted to directory ...folder and \
|
|
634
|
+
removed.
|
|
635
|
+
Folder2Path(folder=.../projectname/basename/folder)
|
|
636
|
+
"""
|
|
637
|
+
with zipfile.ZipFile(f"{self.currentpath}.zip", "w") as zipfile_:
|
|
638
|
+
for filepath, filename in zip(self.filepaths, self.filenames):
|
|
639
|
+
zipfile_.write(filename=filepath, arcname=filename)
|
|
640
|
+
del self.currentdir
|
|
641
|
+
|
|
642
|
+
@property
|
|
643
|
+
def _docname(self) -> str:
|
|
644
|
+
return f"{type(self).__name__[:-7].lower()} manager"
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
class NetworkManager(FileManager):
|
|
648
|
+
"""Manager for network files.
|
|
649
|
+
|
|
650
|
+
The base and default folder names of class |NetworkManager| are:
|
|
651
|
+
|
|
652
|
+
>>> from hydpy.core.filetools import NetworkManager
|
|
653
|
+
>>> NetworkManager.BASEDIR
|
|
654
|
+
'network'
|
|
655
|
+
>>> NetworkManager.DEFAULTDIR
|
|
656
|
+
'default'
|
|
657
|
+
|
|
658
|
+
The documentation of base class |FileManager| explains most aspects of using
|
|
659
|
+
|NetworkManager| objects. The following examples deal with the extended features
|
|
660
|
+
of class |NetworkManager|: reading, writing, and removing network files. For this
|
|
661
|
+
purpose, we prepare the example project `HydPy-H-Lahn` in the `iotesting` directory
|
|
662
|
+
by calling function |prepare_full_example_1|:
|
|
663
|
+
|
|
664
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
665
|
+
>>> prepare_full_example_1()
|
|
666
|
+
|
|
667
|
+
You can define the complete network structure of an `HydPy` project by an arbitrary
|
|
668
|
+
number of "network files". These valid Python files define |Node| and |Element|
|
|
669
|
+
objects and their connections. Network files are allowed to overlap, meaning two
|
|
670
|
+
or more files can define the same objects (in a consistent manner only, of course).
|
|
671
|
+
The primary purpose of class |NetworkManager| is to execute each network file
|
|
672
|
+
individually and pass its content to a |Selection| object, which is done by method
|
|
673
|
+
|NetworkManager.load_files|:
|
|
674
|
+
|
|
675
|
+
>>> networkmanager = NetworkManager()
|
|
676
|
+
>>> from hydpy import TestIO
|
|
677
|
+
>>> with TestIO():
|
|
678
|
+
... networkmanager.projectdir = "HydPy-H-Lahn"
|
|
679
|
+
... selections = networkmanager.load_files()
|
|
680
|
+
|
|
681
|
+
Method |NetworkManager.load_files| takes file names as selection names (without
|
|
682
|
+
file endings):
|
|
683
|
+
|
|
684
|
+
>>> selections
|
|
685
|
+
Selections("headwaters", "nonheadwaters", "streams")
|
|
686
|
+
>>> selections.headwaters
|
|
687
|
+
Selection("headwaters",
|
|
688
|
+
nodes=("dill_assl", "lahn_marb"),
|
|
689
|
+
elements=("land_dill_assl", "land_lahn_marb"))
|
|
690
|
+
|
|
691
|
+
The whole set of |Node| and |Element| objects is accessible via the property
|
|
692
|
+
|Selections.complete|:
|
|
693
|
+
|
|
694
|
+
>>> selections.complete
|
|
695
|
+
Selection("complete",
|
|
696
|
+
nodes=("dill_assl", "lahn_kalk", "lahn_leun", "lahn_marb"),
|
|
697
|
+
elements=("land_dill_assl", "land_lahn_kalk",
|
|
698
|
+
"land_lahn_leun", "land_lahn_marb",
|
|
699
|
+
"stream_dill_assl_lahn_leun",
|
|
700
|
+
"stream_lahn_leun_lahn_kalk",
|
|
701
|
+
"stream_lahn_marb_lahn_leun"))
|
|
702
|
+
|
|
703
|
+
Method |NetworkManager.save_files| writes all user-defined selections into separate
|
|
704
|
+
files. First, we change the current working directory to ensure we do not
|
|
705
|
+
overwrite already existing files:
|
|
706
|
+
|
|
707
|
+
>>> import os
|
|
708
|
+
>>> with TestIO():
|
|
709
|
+
... networkmanager.currentdir = "testdir"
|
|
710
|
+
... networkmanager.save_files(selections)
|
|
711
|
+
... sorted(os.listdir("HydPy-H-Lahn/network/testdir"))
|
|
712
|
+
['headwaters.py', 'nonheadwaters.py', 'streams.py']
|
|
713
|
+
|
|
714
|
+
Reloading and comparing with the still available |Selection| objects proves that
|
|
715
|
+
the contents of the original and the new network files are equivalent:
|
|
716
|
+
|
|
717
|
+
>>> with TestIO():
|
|
718
|
+
... selections == networkmanager.load_files()
|
|
719
|
+
True
|
|
720
|
+
|
|
721
|
+
Method |NetworkManager.delete_files| removes the network files of the given
|
|
722
|
+
|Selection| objects:
|
|
723
|
+
|
|
724
|
+
>>> selections -= selections.streams
|
|
725
|
+
>>> with TestIO():
|
|
726
|
+
... networkmanager.delete_files(selections)
|
|
727
|
+
... sorted(os.listdir("HydPy-H-Lahn/network/testdir"))
|
|
728
|
+
['streams.py']
|
|
729
|
+
|
|
730
|
+
When defining network files, many things can go wrong. In the following, we list
|
|
731
|
+
all specialised error messages of what we hope to be concrete enough to aid in
|
|
732
|
+
finding the relevant problems:
|
|
733
|
+
|
|
734
|
+
>>> with TestIO():
|
|
735
|
+
... networkmanager.delete_files(["headwaters"]) # doctest: +ELLIPSIS
|
|
736
|
+
Traceback (most recent call last):
|
|
737
|
+
...
|
|
738
|
+
FileNotFoundError: While trying to remove the network files of the selection(s) \
|
|
739
|
+
`headwaters`, the following error occurred: ...
|
|
740
|
+
|
|
741
|
+
>>> with TestIO():
|
|
742
|
+
... with open("HydPy-H-Lahn/network/testdir/streams.py", "w") as wrongfile:
|
|
743
|
+
... _ = wrongfile.write("x = y")
|
|
744
|
+
... networkmanager.load_files() # doctest: +ELLIPSIS
|
|
745
|
+
Traceback (most recent call last):
|
|
746
|
+
...
|
|
747
|
+
NameError: While trying to load the network file `...streams.py`, the following \
|
|
748
|
+
error occurred: name 'y' is not defined
|
|
749
|
+
|
|
750
|
+
>>> with TestIO():
|
|
751
|
+
... with open("HydPy-H-Lahn/network/testdir/streams.py", "w") as wrongfile:
|
|
752
|
+
... _ = wrongfile.write("from hydpy import Node")
|
|
753
|
+
... networkmanager.load_files() # doctest: +ELLIPSIS
|
|
754
|
+
Traceback (most recent call last):
|
|
755
|
+
...
|
|
756
|
+
RuntimeError: The class Element cannot be loaded from the network file \
|
|
757
|
+
`...streams.py`.
|
|
758
|
+
|
|
759
|
+
>>> with TestIO():
|
|
760
|
+
... with open("HydPy-H-Lahn/network/testdir/streams.py", "w") as wrongfile:
|
|
761
|
+
... _ = wrongfile.write("from hydpy import Element")
|
|
762
|
+
... networkmanager.load_files() # doctest: +ELLIPSIS
|
|
763
|
+
Traceback (most recent call last):
|
|
764
|
+
...
|
|
765
|
+
RuntimeError: The class Node cannot be loaded from the network file \
|
|
766
|
+
`...streams.py`.
|
|
767
|
+
|
|
768
|
+
>>> import shutil
|
|
769
|
+
>>> with TestIO():
|
|
770
|
+
... shutil.rmtree("HydPy-H-Lahn/network/testdir")
|
|
771
|
+
... networkmanager.save_files(selections) # doctest: +ELLIPSIS
|
|
772
|
+
Traceback (most recent call last):
|
|
773
|
+
...
|
|
774
|
+
FileNotFoundError: While trying to save the selection(s) `headwaters and \
|
|
775
|
+
nonheadwaters` into network files, the following error occurred: ...
|
|
776
|
+
"""
|
|
777
|
+
|
|
778
|
+
BASEDIR = "network"
|
|
779
|
+
DEFAULTDIR = "default"
|
|
780
|
+
|
|
781
|
+
def load_files(self) -> selectiontools.Selections:
|
|
782
|
+
"""Read all network files of the current working directory, structure their
|
|
783
|
+
contents in a |selectiontools.Selections| object, and return it.
|
|
784
|
+
|
|
785
|
+
See the main documentation of class |NetworkManager| for further information.
|
|
786
|
+
"""
|
|
787
|
+
selections = selectiontools.Selections()
|
|
788
|
+
if not self.filenames:
|
|
789
|
+
raise RuntimeError(
|
|
790
|
+
f"The directory `{self.currentpath}` does not contain any network "
|
|
791
|
+
f"files."
|
|
792
|
+
)
|
|
793
|
+
for filename, path in zip(self.filenames, self.filepaths):
|
|
794
|
+
# Ensure both `Node` and `Element`start with a `fresh` memory.
|
|
795
|
+
devicetools.Node.extract_new()
|
|
796
|
+
devicetools.Element.extract_new()
|
|
797
|
+
try:
|
|
798
|
+
info = runpy.run_path(path)
|
|
799
|
+
except BaseException:
|
|
800
|
+
objecttools.augment_excmessage(
|
|
801
|
+
f"While trying to load the network file `{path}`"
|
|
802
|
+
)
|
|
803
|
+
try:
|
|
804
|
+
node: devicetools.Node = info["Node"]
|
|
805
|
+
element: devicetools.Element = info["Element"]
|
|
806
|
+
selections += selectiontools.Selection(
|
|
807
|
+
filename.split(".")[0], node.extract_new(), element.extract_new()
|
|
808
|
+
)
|
|
809
|
+
except KeyError as exc:
|
|
810
|
+
raise RuntimeError(
|
|
811
|
+
f"The class {exc.args[0]} cannot be loaded from the network file "
|
|
812
|
+
f"`{path}`."
|
|
813
|
+
) from None
|
|
814
|
+
return selections
|
|
815
|
+
|
|
816
|
+
def save_files(self, selections: Iterable[selectiontools.Selection]) -> None:
|
|
817
|
+
"""Save the |Selection| objects contained in the given |Selections| instance to
|
|
818
|
+
separate network files.
|
|
819
|
+
|
|
820
|
+
See the main documentation on class |NetworkManager| for further information.
|
|
821
|
+
"""
|
|
822
|
+
selections = tuple(selections)
|
|
823
|
+
try:
|
|
824
|
+
currentpath = self.currentpath
|
|
825
|
+
for selection in selections:
|
|
826
|
+
path = os.path.join(currentpath, selection.name + ".py")
|
|
827
|
+
selection.save_networkfile(filepath=path)
|
|
828
|
+
except BaseException:
|
|
829
|
+
objecttools.augment_excmessage(
|
|
830
|
+
f"While trying to save the selection(s) "
|
|
831
|
+
f"`{objecttools.enumeration(selections)}` into network files"
|
|
832
|
+
)
|
|
833
|
+
|
|
834
|
+
def delete_files(self, selections: Iterable[selectiontools.Selection]) -> None:
|
|
835
|
+
"""Delete the network files corresponding to the given selections (e.g. a
|
|
836
|
+
|list| of |str| objects or a |Selections| object).
|
|
837
|
+
|
|
838
|
+
See the main documentation on class |NetworkManager| for further information.
|
|
839
|
+
"""
|
|
840
|
+
selections = tuple(selections)
|
|
841
|
+
try:
|
|
842
|
+
currentpath = self.currentpath
|
|
843
|
+
for selection in selections:
|
|
844
|
+
name = str(selection)
|
|
845
|
+
if not name.endswith(".py"):
|
|
846
|
+
name += ".py"
|
|
847
|
+
path = os.path.join(currentpath, name)
|
|
848
|
+
os.remove(path)
|
|
849
|
+
except BaseException:
|
|
850
|
+
objecttools.augment_excmessage(
|
|
851
|
+
f"While trying to remove the network files of the selection(s) "
|
|
852
|
+
f"`{objecttools.enumeration(selections)}`"
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
class ControlManager(FileManager):
|
|
857
|
+
"""Manager for control parameter files.
|
|
858
|
+
|
|
859
|
+
The base and default folder names of class |ControlManager| are:
|
|
860
|
+
|
|
861
|
+
>>> from hydpy.core.filetools import ControlManager
|
|
862
|
+
>>> ControlManager.BASEDIR
|
|
863
|
+
'control'
|
|
864
|
+
>>> ControlManager.DEFAULTDIR
|
|
865
|
+
'default'
|
|
866
|
+
|
|
867
|
+
Class |ControlManager| extends the functionalities of class |FileManager| only
|
|
868
|
+
slightly, which is why the documentation on class |FileManager| should serve as a
|
|
869
|
+
good starting point for understanding class |ControlManager|. Also, see the
|
|
870
|
+
documentation on method |HydPy.prepare_models| of class |HydPy|, which relies on
|
|
871
|
+
the functionalities of class |ControlManager|.
|
|
872
|
+
"""
|
|
873
|
+
|
|
874
|
+
# The following file path to content mapping is used to circumvent reading
|
|
875
|
+
# the same auxiliary control parameter file from disk multiple times.
|
|
876
|
+
_registry: dict[str, types.CodeType] = {}
|
|
877
|
+
_workingpath: str = "."
|
|
878
|
+
BASEDIR = "control"
|
|
879
|
+
DEFAULTDIR = "default"
|
|
880
|
+
|
|
881
|
+
def load_file(
|
|
882
|
+
self,
|
|
883
|
+
element: devicetools.Element | None = None,
|
|
884
|
+
filename: str | None = None,
|
|
885
|
+
clear_registry: bool = True,
|
|
886
|
+
) -> dict[str, Any]:
|
|
887
|
+
"""Return the namespace of the given file (and eventually of its corresponding
|
|
888
|
+
auxiliary subfiles).
|
|
889
|
+
|
|
890
|
+
By default, |ControlManager| clears the internal registry after loading a
|
|
891
|
+
control file and all its corresponding auxiliary files. You can change this
|
|
892
|
+
behaviour by passing `False` to the `clear_registry` argument, which might
|
|
893
|
+
decrease model initialisation times significantly. However, then it is your
|
|
894
|
+
own responsibility to call the method |ControlManager.clear_registry| when
|
|
895
|
+
necessary (usually before reloading a changed control file).
|
|
896
|
+
|
|
897
|
+
One advantage of using method |ControlManager.load_file| directly is that it
|
|
898
|
+
supports reading control files that are yet not correctly integrated into a
|
|
899
|
+
complete *HydPy* project by passing its name:
|
|
900
|
+
|
|
901
|
+
>>> from hydpy.core.testtools import prepare_full_example_1
|
|
902
|
+
>>> prepare_full_example_1()
|
|
903
|
+
|
|
904
|
+
>>> from hydpy.core.filetools import ControlManager
|
|
905
|
+
>>> controlmanager = ControlManager()
|
|
906
|
+
>>> from hydpy import pub, round_, TestIO
|
|
907
|
+
>>> pub.timegrids = "2000-01-01", "2001-01-01", "12h"
|
|
908
|
+
>>> with TestIO():
|
|
909
|
+
... controlmanager.projectdir = "HydPy-H-Lahn"
|
|
910
|
+
... results = controlmanager.load_file(filename="land_dill_assl")
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
>>> results["control"]
|
|
914
|
+
area(692.3)
|
|
915
|
+
nmbzones(12)
|
|
916
|
+
sclass(1)
|
|
917
|
+
zonetype(FIELD, FOREST, FIELD, FOREST, FIELD, FOREST, FIELD, FOREST,
|
|
918
|
+
FIELD, FOREST, FIELD, FOREST)
|
|
919
|
+
zonearea(14.41, 7.06, 70.83, 84.36, 70.97, 198.0, 27.75, 130.0, 27.28,
|
|
920
|
+
56.94, 1.09, 3.61)
|
|
921
|
+
psi(1.0)
|
|
922
|
+
zonez(2.0, 2.0, 3.0, 3.0, 4.0, 4.0, 5.0, 5.0, 6.0, 6.0, 7.0, 7.0)
|
|
923
|
+
pcorr(1.0)
|
|
924
|
+
pcalt(0.1)
|
|
925
|
+
rfcf(1.04283)
|
|
926
|
+
sfcf(1.1)
|
|
927
|
+
tcorr(0.0)
|
|
928
|
+
tcalt(0.6)
|
|
929
|
+
icmax(field=1.0, forest=1.5)
|
|
930
|
+
sfdist(1.0)
|
|
931
|
+
smax(inf)
|
|
932
|
+
sred(0.0)
|
|
933
|
+
tt(0.55824)
|
|
934
|
+
ttint(2.0)
|
|
935
|
+
dttm(0.0)
|
|
936
|
+
cfmax(field=4.55853, forest=2.735118)
|
|
937
|
+
cfvar(0.0)
|
|
938
|
+
gmelt(nan)
|
|
939
|
+
gvar(nan)
|
|
940
|
+
cfr(0.05)
|
|
941
|
+
whc(0.1)
|
|
942
|
+
fc(278.0)
|
|
943
|
+
beta(2.54011)
|
|
944
|
+
percmax(1.39636)
|
|
945
|
+
cflux(0.0)
|
|
946
|
+
resparea(True)
|
|
947
|
+
recstep(1200.0)
|
|
948
|
+
alpha(1.0)
|
|
949
|
+
k(0.005618)
|
|
950
|
+
k4(0.05646)
|
|
951
|
+
gamma(0.0)
|
|
952
|
+
|
|
953
|
+
>>> results["percmax"].values
|
|
954
|
+
0.69818
|
|
955
|
+
|
|
956
|
+
Passing neither a filename nor an |Element| object raises the following error:
|
|
957
|
+
|
|
958
|
+
>>> controlmanager.load_file()
|
|
959
|
+
Traceback (most recent call last):
|
|
960
|
+
...
|
|
961
|
+
RuntimeError: When trying to load a control file you must either pass its \
|
|
962
|
+
name or the responsible Element object.
|
|
963
|
+
"""
|
|
964
|
+
if not filename:
|
|
965
|
+
if element:
|
|
966
|
+
filename = element.name
|
|
967
|
+
else:
|
|
968
|
+
raise RuntimeError(
|
|
969
|
+
"When trying to load a control file you must either pass its name "
|
|
970
|
+
"or the responsible Element object."
|
|
971
|
+
)
|
|
972
|
+
type(self)._workingpath = self.currentpath
|
|
973
|
+
info = {}
|
|
974
|
+
if element:
|
|
975
|
+
info["element"] = element
|
|
976
|
+
try:
|
|
977
|
+
self.read2dict(filename, info)
|
|
978
|
+
finally:
|
|
979
|
+
type(self)._workingpath = "."
|
|
980
|
+
if clear_registry:
|
|
981
|
+
self._registry.clear()
|
|
982
|
+
return info
|
|
983
|
+
|
|
984
|
+
@classmethod
|
|
985
|
+
def read2dict(cls, filename: str, info: dict[str, Any]) -> None:
|
|
986
|
+
"""Read the control parameters from the given path (and its auxiliary paths,
|
|
987
|
+
where appropriate) and store them in the given |dict| object `info`.
|
|
988
|
+
|
|
989
|
+
Note that`info` can be used to feed information into the execution of control
|
|
990
|
+
files. Use this method only if you are entirely sure of how the control
|
|
991
|
+
parameter import of *HydPy* works. Otherwise, you should most probably prefer
|
|
992
|
+
to use the method |ControlManager.load_file|.
|
|
993
|
+
"""
|
|
994
|
+
if not filename.endswith(".py"):
|
|
995
|
+
filename += ".py"
|
|
996
|
+
filepath = os.path.abspath(os.path.join(cls._workingpath, filename))
|
|
997
|
+
with hydpy.pub.options.parameterstep(None):
|
|
998
|
+
try:
|
|
999
|
+
if filepath not in cls._registry:
|
|
1000
|
+
with open(filepath, encoding=config.ENCODING) as file_:
|
|
1001
|
+
cls._registry[filepath] = compile(
|
|
1002
|
+
source=file_.read(), filename=filepath, mode="exec"
|
|
1003
|
+
)
|
|
1004
|
+
exec(cls._registry[filepath], {}, info)
|
|
1005
|
+
except BaseException:
|
|
1006
|
+
objecttools.augment_excmessage(
|
|
1007
|
+
f"While trying to load the control file `{filepath}`"
|
|
1008
|
+
)
|
|
1009
|
+
if "model" not in info:
|
|
1010
|
+
raise RuntimeError(
|
|
1011
|
+
f"Model parameters cannot be loaded from control file `{filepath}`. "
|
|
1012
|
+
f"Please refer to the HydPy documentation on how to prepare control "
|
|
1013
|
+
f"files properly."
|
|
1014
|
+
)
|
|
1015
|
+
|
|
1016
|
+
@classmethod
|
|
1017
|
+
def clear_registry(cls) -> None:
|
|
1018
|
+
"""Clear the internal registry from control file information."""
|
|
1019
|
+
cls._registry.clear()
|
|
1020
|
+
|
|
1021
|
+
def save_file(self, filename: str, text: str) -> None:
|
|
1022
|
+
"""Save the given text under the given control filename and the current path."""
|
|
1023
|
+
if not filename.endswith(".py"):
|
|
1024
|
+
filename += ".py"
|
|
1025
|
+
path = os.path.join(self.currentpath, filename)
|
|
1026
|
+
with open(path, "w", encoding="utf-8") as file_:
|
|
1027
|
+
file_.write(text)
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
class ConditionManager(FileManager):
|
|
1031
|
+
"""Manager for condition files.
|
|
1032
|
+
|
|
1033
|
+
The base folder name of class |ConditionManager| is:
|
|
1034
|
+
|
|
1035
|
+
>>> from hydpy.core.filetools import ConditionManager
|
|
1036
|
+
>>> ConditionManager.BASEDIR
|
|
1037
|
+
'conditions'
|
|
1038
|
+
|
|
1039
|
+
Class |ConditionManager| generally works like class |FileManager|. The following
|
|
1040
|
+
examples, based on the `HydPy-H-Lahn` example project, explain the additional
|
|
1041
|
+
functionalities of the |ConditionManager| specific properties
|
|
1042
|
+
|ConditionManager.inputpath| and |ConditionManager.outputpath|:
|
|
1043
|
+
|
|
1044
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
1045
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
1046
|
+
|
|
1047
|
+
If the current directory named is not defined explicitly, both properties construct
|
|
1048
|
+
it following the actual simulation start or end date, respectively:
|
|
1049
|
+
|
|
1050
|
+
>>> from hydpy import repr_
|
|
1051
|
+
>>> with TestIO(), pub.options.printprogress(True): # doctest: +ELLIPSIS
|
|
1052
|
+
... repr_(pub.conditionmanager.inputpath)
|
|
1053
|
+
... repr_(pub.conditionmanager.outputpath)
|
|
1054
|
+
The condition manager's current working directory is not defined explicitly. \
|
|
1055
|
+
Hence, the condition manager reads its data from a directory named \
|
|
1056
|
+
`init_1996_01_01_00_00_00`.
|
|
1057
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00'
|
|
1058
|
+
The condition manager's current working directory is not defined explicitly. \
|
|
1059
|
+
Hence, the condition manager writes its data to a directory named \
|
|
1060
|
+
`init_1996_01_05_00_00_00`.
|
|
1061
|
+
Directory ...init_1996_01_05_00_00_00 has been created.
|
|
1062
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/init_1996_01_05_00_00_00'
|
|
1063
|
+
|
|
1064
|
+
>>> pub.timegrids.sim.firstdate += "1d"
|
|
1065
|
+
>>> pub.timegrids.sim.lastdate -= "1d"
|
|
1066
|
+
>>> pub.timegrids
|
|
1067
|
+
Timegrids(init=Timegrid("1996-01-01 00:00:00",
|
|
1068
|
+
"1996-01-05 00:00:00",
|
|
1069
|
+
"1d"),
|
|
1070
|
+
sim=Timegrid("1996-01-02 00:00:00",
|
|
1071
|
+
"1996-01-04 00:00:00",
|
|
1072
|
+
"1d"),
|
|
1073
|
+
eval_=Timegrid("1996-01-01 00:00:00",
|
|
1074
|
+
"1996-01-05 00:00:00",
|
|
1075
|
+
"1d"))
|
|
1076
|
+
|
|
1077
|
+
>>> with TestIO(): # doctest: +ELLIPSIS
|
|
1078
|
+
... repr_(pub.conditionmanager.inputpath)
|
|
1079
|
+
... repr_(pub.conditionmanager.outputpath)
|
|
1080
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/init_1996_01_02_00_00_00'
|
|
1081
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/init_1996_01_04_00_00_00'
|
|
1082
|
+
|
|
1083
|
+
Use the property |FileManager.currentdir| to change the values of both properties:
|
|
1084
|
+
|
|
1085
|
+
>>> with TestIO(): # doctest: +ELLIPSIS
|
|
1086
|
+
... pub.conditionmanager.currentdir = "test"
|
|
1087
|
+
... repr_(pub.conditionmanager.inputpath)
|
|
1088
|
+
... repr_(pub.conditionmanager.outputpath)
|
|
1089
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/test'
|
|
1090
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/test'
|
|
1091
|
+
|
|
1092
|
+
After deleting the custom value of property |FileManager.currentdir|, the
|
|
1093
|
+
properties |ConditionManager.inputpath| and |ConditionManager.outputpath| work as
|
|
1094
|
+
before:
|
|
1095
|
+
|
|
1096
|
+
>>> with TestIO(): # doctest: +ELLIPSIS
|
|
1097
|
+
... del pub.conditionmanager.currentdir
|
|
1098
|
+
... repr_(pub.conditionmanager.inputpath)
|
|
1099
|
+
... repr_(pub.conditionmanager.outputpath)
|
|
1100
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/init_1996_01_02_00_00_00'
|
|
1101
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/init_1996_01_04_00_00_00'
|
|
1102
|
+
|
|
1103
|
+
Use the |ConditionManager.prefix| option to configure the automatically determined
|
|
1104
|
+
folder names:
|
|
1105
|
+
|
|
1106
|
+
>>> with TestIO(), pub.conditionmanager.prefix("condi"): # doctest: +ELLIPSIS
|
|
1107
|
+
... repr_(pub.conditionmanager.inputpath)
|
|
1108
|
+
... repr_(pub.conditionmanager.outputpath)
|
|
1109
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/condi_1996_01_02_00_00_00'
|
|
1110
|
+
'.../hydpy/tests/iotesting/HydPy-H-Lahn/conditions/condi_1996_01_04_00_00_00'
|
|
1111
|
+
|
|
1112
|
+
The date-based construction of directory names requires a |Timegrids| object
|
|
1113
|
+
available in module |pub|:
|
|
1114
|
+
|
|
1115
|
+
>>> del pub.timegrids
|
|
1116
|
+
>>> with TestIO(): # doctest: +ELLIPSIS
|
|
1117
|
+
... repr_(pub.conditionmanager.inputpath)
|
|
1118
|
+
Traceback (most recent call last):
|
|
1119
|
+
...
|
|
1120
|
+
hydpy.core.exceptiontools.AttributeNotReady: While trying to determine the \
|
|
1121
|
+
currently relevant input path for loading conditions file, the following error \
|
|
1122
|
+
occurred: Attribute timegrids of module `pub` is not defined at the moment.
|
|
1123
|
+
|
|
1124
|
+
>>> del pub.timegrids
|
|
1125
|
+
>>> with TestIO(): # doctest: +ELLIPSIS
|
|
1126
|
+
... repr_(pub.conditionmanager.outputpath)
|
|
1127
|
+
Traceback (most recent call last):
|
|
1128
|
+
...
|
|
1129
|
+
hydpy.core.exceptiontools.AttributeNotReady: While trying to determine the \
|
|
1130
|
+
currently relevant output path for saving conditions file, the following error \
|
|
1131
|
+
occurred: Attribute timegrids of module `pub` is not defined at the moment.
|
|
1132
|
+
"""
|
|
1133
|
+
|
|
1134
|
+
BASEDIR = "conditions"
|
|
1135
|
+
DEFAULTDIR = None
|
|
1136
|
+
|
|
1137
|
+
prefix = optiontools.OptionPropertyStr(
|
|
1138
|
+
"init",
|
|
1139
|
+
"""The prefix of the automatically determined, time-dependent condition
|
|
1140
|
+
directory names.
|
|
1141
|
+
|
|
1142
|
+
The default prefix is `init`:
|
|
1143
|
+
|
|
1144
|
+
>>> from hydpy.core.testtools import prepare_full_example_2
|
|
1145
|
+
>>> hp, pub, TestIO = prepare_full_example_2()
|
|
1146
|
+
>>> cm = pub.conditionmanager
|
|
1147
|
+
>>> with TestIO():
|
|
1148
|
+
... assert cm.inputpath.endswith("init_1996_01_01_00_00_00")
|
|
1149
|
+
... assert cm.outputpath.endswith("init_1996_01_05_00_00_00")
|
|
1150
|
+
|
|
1151
|
+
For example, you can vary the prefix to store the conditions of different
|
|
1152
|
+
ensemble members in separate directories:
|
|
1153
|
+
|
|
1154
|
+
>>> with TestIO(), cm.prefix("member_01"):
|
|
1155
|
+
... assert cm.inputpath.endswith("member_01_1996_01_01_00_00_00")
|
|
1156
|
+
... assert cm.outputpath.endswith("member_01_1996_01_05_00_00_00")
|
|
1157
|
+
""",
|
|
1158
|
+
)
|
|
1159
|
+
|
|
1160
|
+
def _print_info(self, dirname, task) -> None:
|
|
1161
|
+
if hydpy.pub.options.printprogress:
|
|
1162
|
+
print(
|
|
1163
|
+
f"The {self._docname}'s current working directory is not defined "
|
|
1164
|
+
f"explicitly. Hence, the {self._docname} {task} a directory named "
|
|
1165
|
+
f"`{dirname}`."
|
|
1166
|
+
)
|
|
1167
|
+
|
|
1168
|
+
@property
|
|
1169
|
+
def inputpath(self) -> str:
|
|
1170
|
+
"""The directory path for loading initial conditions.
|
|
1171
|
+
|
|
1172
|
+
See the main documentation on class |ConditionManager| and its option
|
|
1173
|
+
|ConditionManager.prefix| for further information.
|
|
1174
|
+
"""
|
|
1175
|
+
currentdir = self._currentdir
|
|
1176
|
+
try:
|
|
1177
|
+
if not currentdir:
|
|
1178
|
+
to_string = hydpy.pub.timegrids.sim.firstdate.to_string
|
|
1179
|
+
autodir = f"{self.prefix}_{to_string('os')}"
|
|
1180
|
+
self._print_info(dirname=autodir, task="reads its data from")
|
|
1181
|
+
self.currentdir = autodir
|
|
1182
|
+
return self.currentpath
|
|
1183
|
+
except BaseException:
|
|
1184
|
+
objecttools.augment_excmessage(
|
|
1185
|
+
"While trying to determine the currently relevant input path for "
|
|
1186
|
+
"loading conditions file"
|
|
1187
|
+
)
|
|
1188
|
+
finally:
|
|
1189
|
+
self._currentdir = currentdir
|
|
1190
|
+
|
|
1191
|
+
@property
|
|
1192
|
+
def outputpath(self) -> str:
|
|
1193
|
+
"""The directory path for saving (final) conditions.
|
|
1194
|
+
|
|
1195
|
+
See the main documentation on class |ConditionManager| and its option
|
|
1196
|
+
|ConditionManager.prefix| for further information.
|
|
1197
|
+
"""
|
|
1198
|
+
currentdir = self._currentdir
|
|
1199
|
+
try:
|
|
1200
|
+
if not currentdir:
|
|
1201
|
+
to_string = hydpy.pub.timegrids.sim.lastdate.to_string
|
|
1202
|
+
autodir = f"{self.prefix}_{to_string('os')}"
|
|
1203
|
+
self._print_info(dirname=autodir, task="writes its data to")
|
|
1204
|
+
self.currentdir = autodir
|
|
1205
|
+
return self.currentpath
|
|
1206
|
+
except BaseException:
|
|
1207
|
+
objecttools.augment_excmessage(
|
|
1208
|
+
"While trying to determine the currently relevant output path for "
|
|
1209
|
+
"saving conditions file"
|
|
1210
|
+
)
|
|
1211
|
+
finally:
|
|
1212
|
+
self._currentdir = currentdir
|
|
1213
|
+
|
|
1214
|
+
|
|
1215
|
+
class SequenceManager(FileManager):
|
|
1216
|
+
"""Manager for sequence files.
|
|
1217
|
+
|
|
1218
|
+
Usually, there is only one |SequenceManager| used within each *HydPy* project,
|
|
1219
|
+
stored in module |pub|. This object is responsible for the actual I/O tasks
|
|
1220
|
+
related to |IOSequence| objects.
|
|
1221
|
+
|
|
1222
|
+
Working with a complete *HydPy* project, one often does not use the
|
|
1223
|
+
|SequenceManager| directly, except one wishes to load or save time series data in
|
|
1224
|
+
a way different from the default settings. The following examples show the
|
|
1225
|
+
essential features of class |SequenceManager| based on the example project
|
|
1226
|
+
configuration defined by function |prepare_io_example_1|.
|
|
1227
|
+
|
|
1228
|
+
We prepare the project and select one 0-dimensional sequence of type |Sim| and one
|
|
1229
|
+
1-dimensional sequence of type |lland_fluxes.NKor| for the following examples:
|
|
1230
|
+
|
|
1231
|
+
>>> from hydpy.core.testtools import prepare_io_example_1
|
|
1232
|
+
>>> nodes, elements = prepare_io_example_1()
|
|
1233
|
+
>>> sim = nodes.node2.sequences.sim
|
|
1234
|
+
>>> nkor = elements.element2.model.sequences.fluxes.nkor
|
|
1235
|
+
|
|
1236
|
+
We store the time series data of both sequences in ASCII files (methods
|
|
1237
|
+
|SequenceManager.save_file| and |IOSequence.save_series| are interchangeable here.
|
|
1238
|
+
The last one is only a convenience function for the first one):
|
|
1239
|
+
|
|
1240
|
+
>>> from hydpy import pub
|
|
1241
|
+
>>> pub.sequencemanager.filetype = "asc"
|
|
1242
|
+
>>> from hydpy import TestIO
|
|
1243
|
+
>>> with TestIO():
|
|
1244
|
+
... pub.sequencemanager.save_file(sim)
|
|
1245
|
+
... nkor.save_series()
|
|
1246
|
+
|
|
1247
|
+
We can load the file content from the output directory defined by
|
|
1248
|
+
|prepare_io_example_1| and print it to check this was successful:
|
|
1249
|
+
|
|
1250
|
+
>>> import os
|
|
1251
|
+
>>> from hydpy import round_
|
|
1252
|
+
>>> def print_file(filename):
|
|
1253
|
+
... path = os.path.join("project", "series", "default", filename)
|
|
1254
|
+
... with TestIO():
|
|
1255
|
+
... with open(path) as file_:
|
|
1256
|
+
... lines = file_.readlines()
|
|
1257
|
+
... print("".join(lines[:3]), end="")
|
|
1258
|
+
... for line in lines[3:]:
|
|
1259
|
+
... round_([float(x) for x in line.split()])
|
|
1260
|
+
|
|
1261
|
+
>>> print_file("node2_sim_t.asc")
|
|
1262
|
+
Timegrid("2000-01-01 00:00:00+01:00",
|
|
1263
|
+
"2000-01-05 00:00:00+01:00",
|
|
1264
|
+
"1d")
|
|
1265
|
+
64.0
|
|
1266
|
+
65.0
|
|
1267
|
+
66.0
|
|
1268
|
+
67.0
|
|
1269
|
+
>>> print_file("element2_lland_dd_flux_nkor.asc")
|
|
1270
|
+
Timegrid("2000-01-01 00:00:00+01:00",
|
|
1271
|
+
"2000-01-05 00:00:00+01:00",
|
|
1272
|
+
"1d")
|
|
1273
|
+
16.0, 17.0
|
|
1274
|
+
18.0, 19.0
|
|
1275
|
+
20.0, 21.0
|
|
1276
|
+
22.0, 23.0
|
|
1277
|
+
|
|
1278
|
+
To show that reloading the data works, we set the values of the time series of both
|
|
1279
|
+
objects to zero and recover the original values afterwards:
|
|
1280
|
+
|
|
1281
|
+
>>> sim.series = 0.0
|
|
1282
|
+
>>> sim.series
|
|
1283
|
+
InfoArray([0., 0., 0., 0.])
|
|
1284
|
+
>>> nkor.series = 0.0
|
|
1285
|
+
>>> nkor.series
|
|
1286
|
+
InfoArray([[0., 0.],
|
|
1287
|
+
[0., 0.],
|
|
1288
|
+
[0., 0.],
|
|
1289
|
+
[0., 0.]])
|
|
1290
|
+
>>> with TestIO():
|
|
1291
|
+
... pub.sequencemanager.load_file(sim)
|
|
1292
|
+
... nkor.load_series()
|
|
1293
|
+
>>> sim.series
|
|
1294
|
+
InfoArray([64., 65., 66., 67.])
|
|
1295
|
+
>>> nkor.series
|
|
1296
|
+
InfoArray([[16., 17.],
|
|
1297
|
+
[18., 19.],
|
|
1298
|
+
[20., 21.],
|
|
1299
|
+
[22., 23.]])
|
|
1300
|
+
|
|
1301
|
+
We now write two files that do not span the initialisation period.
|
|
1302
|
+
|
|
1303
|
+
>>> with TestIO():
|
|
1304
|
+
... for filename in ("incomplete_1.asc", "incomplete_2.asc"):
|
|
1305
|
+
... path = os.path.join("project", "series", "default", filename)
|
|
1306
|
+
... with open(path, "w") as file_:
|
|
1307
|
+
... _ = file_.write('Timegrid("2000-01-02 00:00:00+01:00",\\n'
|
|
1308
|
+
... ' "2000-01-04 00:00:00+01:00",\\n'
|
|
1309
|
+
... ' "1d")\\n')
|
|
1310
|
+
... for value in (1.0, 2.0):
|
|
1311
|
+
... if filename == "incomplete_1.asc":
|
|
1312
|
+
... _ = file_.write(f"{value}\\n")
|
|
1313
|
+
... else:
|
|
1314
|
+
... _ = file_.write(f"{value} {value + 1.0}\\n")
|
|
1315
|
+
|
|
1316
|
+
>>> print_file("incomplete_1.asc")
|
|
1317
|
+
Timegrid("2000-01-02 00:00:00+01:00",
|
|
1318
|
+
"2000-01-04 00:00:00+01:00",
|
|
1319
|
+
"1d")
|
|
1320
|
+
1.0
|
|
1321
|
+
2.0
|
|
1322
|
+
|
|
1323
|
+
>>> print_file("incomplete_2.asc")
|
|
1324
|
+
Timegrid("2000-01-02 00:00:00+01:00",
|
|
1325
|
+
"2000-01-04 00:00:00+01:00",
|
|
1326
|
+
"1d")
|
|
1327
|
+
1.0, 2.0
|
|
1328
|
+
2.0, 3.0
|
|
1329
|
+
|
|
1330
|
+
By default, trying to read such incomplete files results in an error:
|
|
1331
|
+
|
|
1332
|
+
>>> sim.filename = "incomplete_1.asc"
|
|
1333
|
+
>>> nkor.filename = "incomplete_2.asc"
|
|
1334
|
+
>>> with TestIO(): # doctest: +ELLIPSIS
|
|
1335
|
+
... pub.sequencemanager.load_file(sim)
|
|
1336
|
+
Traceback (most recent call last):
|
|
1337
|
+
...
|
|
1338
|
+
RuntimeError: While trying to load the time series data of sequence `sim` of node \
|
|
1339
|
+
`node2`, the following error occurred: For sequence `sim` of node `node2` the \
|
|
1340
|
+
initialisation time grid (Timegrid("2000-01-01 00:00:00", "2000-01-05 00:00:00", \
|
|
1341
|
+
"1d")) does not define a subset of the time grid of the data file \
|
|
1342
|
+
`...incomplete_1.asc` (Timegrid("2000-01-02 00:00:00", "2000-01-04 00:00:00", "1d")).
|
|
1343
|
+
|
|
1344
|
+
Setting option |Options.checkseries| to |False| turns this safety mechanism off:
|
|
1345
|
+
|
|
1346
|
+
>>> with TestIO(), pub.options.checkseries(False):
|
|
1347
|
+
... pub.sequencemanager.load_file(sim)
|
|
1348
|
+
... nkor.load_series()
|
|
1349
|
+
>>> sim.series
|
|
1350
|
+
InfoArray([nan, 1., 2., nan])
|
|
1351
|
+
>>> nkor.series
|
|
1352
|
+
InfoArray([[nan, nan],
|
|
1353
|
+
[ 1., 2.],
|
|
1354
|
+
[ 2., 3.],
|
|
1355
|
+
[nan, nan]])
|
|
1356
|
+
|
|
1357
|
+
Note that all previously available data outside the period supported by the read
|
|
1358
|
+
files has been set to |numpy.nan|, another safety mechanism to avoid accidentally
|
|
1359
|
+
mixing data. If you instead want to mix data from different sources, set option
|
|
1360
|
+
|SequenceManager.reset| to |True|:
|
|
1361
|
+
|
|
1362
|
+
>>> sim.series = 5.0, 6.0, 7.0, 8.0
|
|
1363
|
+
>>> nkor.series = [[5.0, 6.0], [6.0, 7.0], [7.0, 8.0], [8.0, 9.0]]
|
|
1364
|
+
>>> with TestIO(), pub.options.checkseries(False), pub.sequencemanager.reset(False):
|
|
1365
|
+
... pub.sequencemanager.load_file(sim)
|
|
1366
|
+
... nkor.load_series()
|
|
1367
|
+
>>> sim.series
|
|
1368
|
+
InfoArray([5., 1., 2., 8.])
|
|
1369
|
+
>>> nkor.series
|
|
1370
|
+
InfoArray([[5., 6.],
|
|
1371
|
+
[1., 2.],
|
|
1372
|
+
[2., 3.],
|
|
1373
|
+
[8., 9.]])
|
|
1374
|
+
|
|
1375
|
+
We reset the file names and data for the remaining tests:
|
|
1376
|
+
|
|
1377
|
+
>>> del sim.filename
|
|
1378
|
+
>>> del nkor.filename
|
|
1379
|
+
>>> with TestIO():
|
|
1380
|
+
... pub.sequencemanager.load_file(sim)
|
|
1381
|
+
... nkor.load_series()
|
|
1382
|
+
|
|
1383
|
+
Wrongly formatted ASCII files and incomplete data should result in understandable
|
|
1384
|
+
error messages:
|
|
1385
|
+
|
|
1386
|
+
>>> path = os.path.join("project", "series", "default", "node2_sim_t.asc")
|
|
1387
|
+
>>> with TestIO():
|
|
1388
|
+
... with open(path) as file_:
|
|
1389
|
+
... right = file_.read()
|
|
1390
|
+
... wrong = right.replace("Timegrid", "timegrid")
|
|
1391
|
+
... with open(path, "w") as file_:
|
|
1392
|
+
... _ = file_.write(wrong)
|
|
1393
|
+
>>> with TestIO():
|
|
1394
|
+
... pub.sequencemanager.load_file(sim)
|
|
1395
|
+
Traceback (most recent call last):
|
|
1396
|
+
...
|
|
1397
|
+
NameError: While trying to load the time series data of sequence `sim` of node \
|
|
1398
|
+
`node2`, the following error occurred: name 'timegrid' is not defined
|
|
1399
|
+
|
|
1400
|
+
>>> sim_series = sim.series.copy()
|
|
1401
|
+
>>> with TestIO():
|
|
1402
|
+
... lines = right.split("\\n")
|
|
1403
|
+
... lines[5] = "nan"
|
|
1404
|
+
... wrong = "\\n".join(lines)
|
|
1405
|
+
... with open(path, "w") as file_:
|
|
1406
|
+
... _ = file_.write(wrong)
|
|
1407
|
+
>>> with TestIO():
|
|
1408
|
+
... pub.sequencemanager.load_file(sim)
|
|
1409
|
+
Traceback (most recent call last):
|
|
1410
|
+
...
|
|
1411
|
+
RuntimeError: While trying to load the time series data of sequence `sim` of node \
|
|
1412
|
+
`node2`, the following error occurred: The series array of sequence `sim` of node \
|
|
1413
|
+
`node2` contains 1 nan value.
|
|
1414
|
+
>>> sim.series = sim_series
|
|
1415
|
+
|
|
1416
|
+
By default, overwriting existing time series files is disabled:
|
|
1417
|
+
|
|
1418
|
+
>>> with TestIO():
|
|
1419
|
+
... sim.save_series() # doctest: +ELLIPSIS
|
|
1420
|
+
Traceback (most recent call last):
|
|
1421
|
+
...
|
|
1422
|
+
OSError: While trying to save the time series data of sequence `sim` of \
|
|
1423
|
+
node `node2`, the following error occurred: Sequence `sim` of node `node2` is \
|
|
1424
|
+
not allowed to overwrite the existing file `...`.
|
|
1425
|
+
>>> pub.sequencemanager.overwrite = True
|
|
1426
|
+
>>> with TestIO():
|
|
1427
|
+
... sim.save_series()
|
|
1428
|
+
|
|
1429
|
+
When a sequence comes with a weighting parameter referenced by |property|
|
|
1430
|
+
|Variable.refweights|, one can save the averaged time series by using the method
|
|
1431
|
+
|IOSequence.save_mean|:
|
|
1432
|
+
|
|
1433
|
+
>>> with TestIO():
|
|
1434
|
+
... nkor.save_mean()
|
|
1435
|
+
>>> print_file("element2_lland_dd_flux_nkor_mean.asc")
|
|
1436
|
+
Timegrid("2000-01-01 00:00:00+01:00",
|
|
1437
|
+
"2000-01-05 00:00:00+01:00",
|
|
1438
|
+
"1d")
|
|
1439
|
+
16.5
|
|
1440
|
+
18.5
|
|
1441
|
+
20.5
|
|
1442
|
+
22.5
|
|
1443
|
+
|
|
1444
|
+
Method |IOSequence.save_mean| is strongly related to method
|
|
1445
|
+
|IOSequence.average_series|, meaning one can pass the same arguments. We show this
|
|
1446
|
+
by changing the land use classes of `element2` (parameter |lland_control.Lnk|) to
|
|
1447
|
+
field (|lland_constants.ACKER|) and water (|lland_constants.WASSER|) and averaging
|
|
1448
|
+
the values of sequence |lland_fluxes.NKor| for the single field area only:
|
|
1449
|
+
|
|
1450
|
+
>>> from hydpy.models.lland_dd import ACKER, WASSER
|
|
1451
|
+
>>> nkor.subseqs.seqs.model.parameters.control.lnk = ACKER, WASSER
|
|
1452
|
+
>>> with TestIO():
|
|
1453
|
+
... nkor.save_mean("acker")
|
|
1454
|
+
>>> print_file("element2_lland_dd_flux_nkor_mean.asc")
|
|
1455
|
+
Timegrid("2000-01-01 00:00:00+01:00",
|
|
1456
|
+
"2000-01-05 00:00:00+01:00",
|
|
1457
|
+
"1d")
|
|
1458
|
+
16.0
|
|
1459
|
+
18.0
|
|
1460
|
+
20.0
|
|
1461
|
+
22.0
|
|
1462
|
+
|
|
1463
|
+
All numbers are written in scientific notation under the default setting of option
|
|
1464
|
+
|Options.reprdigits| (-1):
|
|
1465
|
+
|
|
1466
|
+
>>> nodes.node1.sequences.sim.series = 0.12345678
|
|
1467
|
+
>>> with TestIO(), pub.options.reprdigits(-1):
|
|
1468
|
+
... nodes.node1.sequences.sim.save_series()
|
|
1469
|
+
>>> print_file("node1_sim_q.asc")
|
|
1470
|
+
Timegrid("2000-01-01 00:00:00+01:00",
|
|
1471
|
+
"2000-01-05 00:00:00+01:00",
|
|
1472
|
+
"1d")
|
|
1473
|
+
0.123457
|
|
1474
|
+
0.123457
|
|
1475
|
+
0.123457
|
|
1476
|
+
0.123457
|
|
1477
|
+
|
|
1478
|
+
If you set this option to two, for example, all numbers are written in the decimal
|
|
1479
|
+
form with at most two decimal places:
|
|
1480
|
+
|
|
1481
|
+
>>> with TestIO(), pub.options.reprdigits(2):
|
|
1482
|
+
... nodes.node1.sequences.sim.save_series()
|
|
1483
|
+
>>> print_file("node1_sim_q.asc")
|
|
1484
|
+
Timegrid("2000-01-01 00:00:00+01:00",
|
|
1485
|
+
"2000-01-05 00:00:00+01:00",
|
|
1486
|
+
"1d")
|
|
1487
|
+
0.12
|
|
1488
|
+
0.12
|
|
1489
|
+
0.12
|
|
1490
|
+
0.12
|
|
1491
|
+
|
|
1492
|
+
Another option is storing data using |numpy| binary files, which is good for saving
|
|
1493
|
+
computation times but possibly problematic for sharing data with colleagues:
|
|
1494
|
+
|
|
1495
|
+
>>> pub.sequencemanager.filetype = "npy"
|
|
1496
|
+
>>> with TestIO():
|
|
1497
|
+
... sim.save_series()
|
|
1498
|
+
... nkor.save_series()
|
|
1499
|
+
|
|
1500
|
+
The time information (without time zone information) is available within the first
|
|
1501
|
+
thirteen entries:
|
|
1502
|
+
|
|
1503
|
+
>>> path = os.path.join("project", "series", "default", "node2_sim_t.npy")
|
|
1504
|
+
>>> import numpy
|
|
1505
|
+
>>> from hydpy import print_vector, print_matrix
|
|
1506
|
+
>>> with TestIO():
|
|
1507
|
+
... print_vector(numpy.load(path))
|
|
1508
|
+
2000.0, 1.0, 1.0, 0.0, 0.0, 0.0, 2000.0, 1.0, 5.0, 0.0, 0.0, 0.0,
|
|
1509
|
+
86400.0, 64.0, 65.0, 66.0, 67.0
|
|
1510
|
+
|
|
1511
|
+
Reloading the data works as expected:
|
|
1512
|
+
|
|
1513
|
+
>>> sim.series = 0.0
|
|
1514
|
+
>>> nkor.series = 0.0
|
|
1515
|
+
>>> with TestIO():
|
|
1516
|
+
... sim.load_series()
|
|
1517
|
+
... nkor.load_series()
|
|
1518
|
+
>>> print_vector(sim.series)
|
|
1519
|
+
64.0, 65.0, 66.0, 67.0
|
|
1520
|
+
>>> print_matrix(nkor.series)
|
|
1521
|
+
| 16.0, 17.0 |
|
|
1522
|
+
| 18.0, 19.0 |
|
|
1523
|
+
| 20.0, 21.0 |
|
|
1524
|
+
| 22.0, 23.0 |
|
|
1525
|
+
|
|
1526
|
+
Writing mean values into |numpy| binary files is also supported:
|
|
1527
|
+
|
|
1528
|
+
>>> import numpy
|
|
1529
|
+
>>> from hydpy import print_vector
|
|
1530
|
+
>>> path = os.path.join(
|
|
1531
|
+
... "project", "series", "default", "element2_lland_dd_flux_nkor_mean.npy")
|
|
1532
|
+
>>> with TestIO():
|
|
1533
|
+
... nkor.save_mean("wasser")
|
|
1534
|
+
... print_vector(numpy.load(path)[-4:])
|
|
1535
|
+
17.0, 19.0, 21.0, 23.0
|
|
1536
|
+
|
|
1537
|
+
Generally, trying to load data for "deactivated" sequences results in the following
|
|
1538
|
+
error message:
|
|
1539
|
+
|
|
1540
|
+
>>> nkor.prepare_series(allocate_ram=False)
|
|
1541
|
+
>>> with TestIO(clear_all=True):
|
|
1542
|
+
... pub.sequencemanager.save_file(nkor)
|
|
1543
|
+
Traceback (most recent call last):
|
|
1544
|
+
...
|
|
1545
|
+
hydpy.core.exceptiontools.AttributeNotReady: Sequence `nkor` of element \
|
|
1546
|
+
`element2` is not requested to make any time series data available.
|
|
1547
|
+
|
|
1548
|
+
The third option is to store data in NetCDF files, which is explained separately in
|
|
1549
|
+
the documentation on module |netcdftools|.
|
|
1550
|
+
"""
|
|
1551
|
+
|
|
1552
|
+
SUPPORTED_MODES = "npy", "asc", "nc"
|
|
1553
|
+
BASEDIR = "series"
|
|
1554
|
+
DEFAULTDIR = "default"
|
|
1555
|
+
|
|
1556
|
+
filetype = optiontools.OptionPropertySeriesFileType(
|
|
1557
|
+
"asc",
|
|
1558
|
+
"""Currently active time series file type.
|
|
1559
|
+
|
|
1560
|
+
|SequenceManager.filetype| is an option based on |OptionPropertySeriesFileType|.
|
|
1561
|
+
See its documentation for further information.
|
|
1562
|
+
""",
|
|
1563
|
+
)
|
|
1564
|
+
reset = optiontools.OptionPropertyBool(
|
|
1565
|
+
True,
|
|
1566
|
+
"""A flag that indicates whether to reset already available time series data
|
|
1567
|
+
before reading incomplete time series files.
|
|
1568
|
+
|
|
1569
|
+
|SequenceManager.reset| is an option based on |OptionPropertyBool|. See its
|
|
1570
|
+
documentation for further information.
|
|
1571
|
+
""",
|
|
1572
|
+
)
|
|
1573
|
+
overwrite = optiontools.OptionPropertyBool(
|
|
1574
|
+
False,
|
|
1575
|
+
"""Currently active overwrite flag for time series files.
|
|
1576
|
+
|
|
1577
|
+
|SequenceManager.overwrite| is an option based on |OptionPropertyBool|. See
|
|
1578
|
+
its documentation for further information.
|
|
1579
|
+
""",
|
|
1580
|
+
)
|
|
1581
|
+
aggregation = optiontools.OptionPropertySeriesAggregation(
|
|
1582
|
+
"none",
|
|
1583
|
+
"""Currently active aggregation mode for writing time series files.
|
|
1584
|
+
|
|
1585
|
+
|SequenceManager.aggregation| is an option based on
|
|
1586
|
+
|OptionPropertySeriesAggregation|. See its documentation for further
|
|
1587
|
+
information.
|
|
1588
|
+
""",
|
|
1589
|
+
)
|
|
1590
|
+
convention = optiontools.OptionPropertySeriesConvention(
|
|
1591
|
+
"model-specific",
|
|
1592
|
+
"""Currently selected naming convention for reading and writing input time
|
|
1593
|
+
series files.
|
|
1594
|
+
|
|
1595
|
+
|SequenceManager.convention| is an option based on
|
|
1596
|
+
|OptionPropertySeriesConvention|. See its documentation for further
|
|
1597
|
+
information.
|
|
1598
|
+
""",
|
|
1599
|
+
)
|
|
1600
|
+
|
|
1601
|
+
_netcdfreader: netcdftools.NetCDFInterfaceReader | None = None
|
|
1602
|
+
_netcdfwriter: netcdftools.NetCDFInterfaceWriter | None = None
|
|
1603
|
+
_jitaccesshandler: netcdftools.JITAccessHandler | None = None
|
|
1604
|
+
|
|
1605
|
+
def load_file(self, sequence: sequencetools.IOSequence) -> None:
|
|
1606
|
+
"""Load data from a data file and pass it to the given |IOSequence|."""
|
|
1607
|
+
try:
|
|
1608
|
+
if sequence.filetype == "nc":
|
|
1609
|
+
self._load_nc(sequence)
|
|
1610
|
+
else:
|
|
1611
|
+
if sequence.filetype == "npy":
|
|
1612
|
+
timegrid, series = self._load_npy(sequence)
|
|
1613
|
+
elif sequence.filetype == "asc":
|
|
1614
|
+
timegrid, series = self._load_asc(sequence)
|
|
1615
|
+
else:
|
|
1616
|
+
assert_never(sequence.filetype)
|
|
1617
|
+
series = sequence.adjust_series(timegrid, series)
|
|
1618
|
+
sequence.apply_adjusted_series(timegrid, series)
|
|
1619
|
+
except BaseException:
|
|
1620
|
+
objecttools.augment_excmessage(
|
|
1621
|
+
f"While trying to load the time series data of sequence "
|
|
1622
|
+
f"{objecttools.devicephrase(sequence)}"
|
|
1623
|
+
)
|
|
1624
|
+
|
|
1625
|
+
@staticmethod
|
|
1626
|
+
def _load_npy(
|
|
1627
|
+
sequence: sequencetools.IOSequence,
|
|
1628
|
+
) -> tuple[timetools.Timegrid, NDArrayFloat]:
|
|
1629
|
+
data = numpy.load(sequence.filepath)
|
|
1630
|
+
timegrid_data = timetools.Timegrid.from_array(data)
|
|
1631
|
+
return timegrid_data, data[13:]
|
|
1632
|
+
|
|
1633
|
+
@staticmethod
|
|
1634
|
+
def _load_asc(
|
|
1635
|
+
sequence: sequencetools.IOSequence,
|
|
1636
|
+
) -> tuple[timetools.Timegrid, NDArrayFloat]:
|
|
1637
|
+
filepath = sequence.filepath
|
|
1638
|
+
with open(filepath, encoding=config.ENCODING) as file_:
|
|
1639
|
+
header = "\n".join([file_.readline() for _ in range(3)])
|
|
1640
|
+
timegrid_data = eval(header, {}, {"Timegrid": timetools.Timegrid})
|
|
1641
|
+
values = numpy.loadtxt( # type: ignore[call-overload]
|
|
1642
|
+
filepath, skiprows=3, ndmin=min(sequence.NDIM + 1, 2)
|
|
1643
|
+
)
|
|
1644
|
+
if sequence.NDIM == 2:
|
|
1645
|
+
values = values.reshape(*sequence.seriesshape)
|
|
1646
|
+
return timegrid_data, values
|
|
1647
|
+
|
|
1648
|
+
def _load_nc(self, sequence: sequencetools.IOSequence) -> None:
|
|
1649
|
+
self.netcdfreader.log(sequence)
|
|
1650
|
+
|
|
1651
|
+
def save_file(
|
|
1652
|
+
self,
|
|
1653
|
+
sequence: sequencetools.IOSequence,
|
|
1654
|
+
array: sequencetools.InfoArray | None = None,
|
|
1655
|
+
) -> None:
|
|
1656
|
+
"""Write the data stored in the |IOSequence.series| property of the given
|
|
1657
|
+
|IOSequence| into a data file."""
|
|
1658
|
+
if array is None:
|
|
1659
|
+
array = sequence.aggregate_series()
|
|
1660
|
+
try:
|
|
1661
|
+
if sequence.filetype == "nc":
|
|
1662
|
+
self._save_nc(sequence, array)
|
|
1663
|
+
else:
|
|
1664
|
+
filepath = sequence.filepath
|
|
1665
|
+
if not sequence.overwrite and os.path.exists(filepath):
|
|
1666
|
+
raise OSError(
|
|
1667
|
+
f"Sequence {objecttools.devicephrase(sequence)} is not allowed "
|
|
1668
|
+
f"to overwrite the existing file `{filepath}`."
|
|
1669
|
+
)
|
|
1670
|
+
if sequence.filetype == "npy":
|
|
1671
|
+
self._save_npy(array, filepath)
|
|
1672
|
+
elif sequence.filetype == "asc":
|
|
1673
|
+
self._save_asc(array, filepath)
|
|
1674
|
+
except BaseException:
|
|
1675
|
+
objecttools.augment_excmessage(
|
|
1676
|
+
f"While trying to save the time series data of sequence "
|
|
1677
|
+
f"{objecttools.devicephrase(sequence)}"
|
|
1678
|
+
)
|
|
1679
|
+
|
|
1680
|
+
@staticmethod
|
|
1681
|
+
def _save_npy(array: NDArrayFloat, filepath: str) -> None:
|
|
1682
|
+
numpy.save(filepath, hydpy.pub.timegrids.init.array2series(array))
|
|
1683
|
+
|
|
1684
|
+
@staticmethod
|
|
1685
|
+
def _save_asc(array: NDArrayFloat, filepath: str) -> None:
|
|
1686
|
+
with open(filepath, "w", encoding=config.ENCODING) as file_:
|
|
1687
|
+
file_.write(
|
|
1688
|
+
hydpy.pub.timegrids.init.assignrepr(
|
|
1689
|
+
prefix="", style="iso2", utcoffset=hydpy.pub.options.utcoffset
|
|
1690
|
+
)
|
|
1691
|
+
+ "\n"
|
|
1692
|
+
)
|
|
1693
|
+
if array.ndim == 3:
|
|
1694
|
+
array = array.reshape(array.shape[0], -1)
|
|
1695
|
+
with open(filepath, "a", encoding=config.ENCODING) as file_:
|
|
1696
|
+
digits = hydpy.pub.options.reprdigits
|
|
1697
|
+
format_ = "%.14e" if digits == -1 else f"%.{digits}f"
|
|
1698
|
+
numpy.savetxt(file_, array, fmt=format_, delimiter="\t")
|
|
1699
|
+
|
|
1700
|
+
def _save_nc(
|
|
1701
|
+
self, sequence: sequencetools.IOSequence, array: sequencetools.InfoArray
|
|
1702
|
+
) -> None:
|
|
1703
|
+
self.netcdfwriter.log(sequence, array)
|
|
1704
|
+
|
|
1705
|
+
@property
|
|
1706
|
+
def netcdfreader(self) -> netcdftools.NetCDFInterfaceReader:
|
|
1707
|
+
"""A |NetCDFInterfaceReader| object prepared by method
|
|
1708
|
+
|SequenceManager.open_netcdfreader| and to be finalised by method
|
|
1709
|
+
|SequenceManager.close_netcdfreader|.
|
|
1710
|
+
|
|
1711
|
+
>>> from hydpy.core.filetools import SequenceManager
|
|
1712
|
+
>>> sm = SequenceManager()
|
|
1713
|
+
>>> sm.netcdfreader
|
|
1714
|
+
Traceback (most recent call last):
|
|
1715
|
+
...
|
|
1716
|
+
hydpy.core.exceptiontools.AttributeNotReady: The sequence file manager \
|
|
1717
|
+
currently handles no NetCDF reader object. Consider applying the \
|
|
1718
|
+
`pub.sequencemanager.netcdfreading` context manager first (search in the \
|
|
1719
|
+
documentation for help).
|
|
1720
|
+
|
|
1721
|
+
>>> sm.open_netcdfreader()
|
|
1722
|
+
>>> from hydpy import classname
|
|
1723
|
+
>>> classname(sm.netcdfreader)
|
|
1724
|
+
'NetCDFInterfaceReader'
|
|
1725
|
+
|
|
1726
|
+
>>> sm.close_netcdfreader()
|
|
1727
|
+
>>> sm.netcdfreader
|
|
1728
|
+
Traceback (most recent call last):
|
|
1729
|
+
...
|
|
1730
|
+
hydpy.core.exceptiontools.AttributeNotReady: The sequence file manager \
|
|
1731
|
+
currently handles no NetCDF reader object. Consider applying the \
|
|
1732
|
+
`pub.sequencemanager.netcdfreading` context manager first (search in the \
|
|
1733
|
+
documentation for help).
|
|
1734
|
+
"""
|
|
1735
|
+
if self._netcdfreader is None:
|
|
1736
|
+
raise exceptiontools.AttributeNotReady(
|
|
1737
|
+
"The sequence file manager currently handles no NetCDF reader object. "
|
|
1738
|
+
"Consider applying the `pub.sequencemanager.netcdfreading` context "
|
|
1739
|
+
"manager first (search in the documentation for help)."
|
|
1740
|
+
)
|
|
1741
|
+
return self._netcdfreader
|
|
1742
|
+
|
|
1743
|
+
def open_netcdfreader(self) -> None:
|
|
1744
|
+
"""Prepare a new |NetCDFInterfaceReader| object for reading data."""
|
|
1745
|
+
self._netcdfreader = netcdftools.NetCDFInterfaceReader()
|
|
1746
|
+
|
|
1747
|
+
def close_netcdfreader(self) -> None:
|
|
1748
|
+
"""Read data with a prepared |NetCDFInterfaceReader| object and delete it
|
|
1749
|
+
afterwards."""
|
|
1750
|
+
self.netcdfreader.read()
|
|
1751
|
+
self._netcdfreader = None
|
|
1752
|
+
|
|
1753
|
+
@contextlib.contextmanager
|
|
1754
|
+
def netcdfreading(self) -> Iterator[None]:
|
|
1755
|
+
"""Prepare a new |NetCDFInterfaceReader| object for collecting data at the
|
|
1756
|
+
beginning of a with-block and read the data and delete the object at the end of
|
|
1757
|
+
the same with-block."""
|
|
1758
|
+
self.open_netcdfreader()
|
|
1759
|
+
yield
|
|
1760
|
+
self.close_netcdfreader()
|
|
1761
|
+
|
|
1762
|
+
@property
|
|
1763
|
+
def netcdfwriter(self) -> netcdftools.NetCDFInterfaceWriter:
|
|
1764
|
+
"""A |NetCDFInterfaceWriter| object prepared by method
|
|
1765
|
+
|SequenceManager.open_netcdfwriter| and to be finalised by method
|
|
1766
|
+
|SequenceManager.close_netcdfwriter|.
|
|
1767
|
+
|
|
1768
|
+
>>> from hydpy.core.filetools import SequenceManager
|
|
1769
|
+
>>> sm = SequenceManager()
|
|
1770
|
+
>>> sm.netcdfwriter
|
|
1771
|
+
Traceback (most recent call last):
|
|
1772
|
+
...
|
|
1773
|
+
hydpy.core.exceptiontools.AttributeNotReady: The sequence file manager \
|
|
1774
|
+
currently handles no NetCDF writer object. Consider applying the \
|
|
1775
|
+
`pub.sequencemanager.netcdfwriting` context manager first (search in the \
|
|
1776
|
+
documentation for help).
|
|
1777
|
+
|
|
1778
|
+
>>> sm.open_netcdfwriter()
|
|
1779
|
+
>>> from hydpy import classname
|
|
1780
|
+
>>> classname(sm.netcdfwriter)
|
|
1781
|
+
'NetCDFInterfaceWriter'
|
|
1782
|
+
|
|
1783
|
+
>>> sm.close_netcdfwriter()
|
|
1784
|
+
>>> sm.netcdfwriter
|
|
1785
|
+
Traceback (most recent call last):
|
|
1786
|
+
...
|
|
1787
|
+
hydpy.core.exceptiontools.AttributeNotReady: The sequence file manager \
|
|
1788
|
+
currently handles no NetCDF writer object. Consider applying the \
|
|
1789
|
+
`pub.sequencemanager.netcdfwriting` context manager first (search in the \
|
|
1790
|
+
documentation for help).
|
|
1791
|
+
"""
|
|
1792
|
+
if self._netcdfwriter is None:
|
|
1793
|
+
raise exceptiontools.AttributeNotReady(
|
|
1794
|
+
"The sequence file manager currently handles no NetCDF writer object. "
|
|
1795
|
+
"Consider applying the `pub.sequencemanager.netcdfwriting` context "
|
|
1796
|
+
"manager first (search in the documentation for help)."
|
|
1797
|
+
)
|
|
1798
|
+
return self._netcdfwriter
|
|
1799
|
+
|
|
1800
|
+
def open_netcdfwriter(self) -> None:
|
|
1801
|
+
"""Prepare a new |NetCDFInterfaceWriter| object for writing data."""
|
|
1802
|
+
self._netcdfwriter = netcdftools.NetCDFInterfaceWriter()
|
|
1803
|
+
|
|
1804
|
+
def close_netcdfwriter(self) -> None:
|
|
1805
|
+
"""Write data with a prepared |NetCDFInterfaceWriter| object and delete it
|
|
1806
|
+
afterwards."""
|
|
1807
|
+
self.netcdfwriter.write()
|
|
1808
|
+
self._netcdfwriter = None
|
|
1809
|
+
|
|
1810
|
+
@contextlib.contextmanager
|
|
1811
|
+
def netcdfwriting(self) -> Iterator[None]:
|
|
1812
|
+
"""Prepare a new |NetCDFInterfaceWriter| object for collecting data at the
|
|
1813
|
+
beginning of a with-block and write the data and delete the object at the end
|
|
1814
|
+
of the same with-block."""
|
|
1815
|
+
self.open_netcdfwriter()
|
|
1816
|
+
yield
|
|
1817
|
+
self.close_netcdfwriter()
|
|
1818
|
+
|
|
1819
|
+
@contextlib.contextmanager
|
|
1820
|
+
def provide_netcdfjitaccess(
|
|
1821
|
+
self, deviceorder: Iterable[devicetools.Node | devicetools.Element]
|
|
1822
|
+
) -> Iterator[None]:
|
|
1823
|
+
"""Open all required internal NetCDF time series files.
|
|
1824
|
+
|
|
1825
|
+
This method is only relevant for reading data from or writing data to NetCDF
|
|
1826
|
+
files "just in time" during simulation runs. See the main documentation on
|
|
1827
|
+
class |HydPy| for further information.
|
|
1828
|
+
"""
|
|
1829
|
+
try:
|
|
1830
|
+
interface = netcdftools.NetCDFInterfaceJIT()
|
|
1831
|
+
with interface.provide_jitaccess(deviceorder) as jitaccesshandler:
|
|
1832
|
+
self._jitaccesshandler = jitaccesshandler
|
|
1833
|
+
yield
|
|
1834
|
+
finally:
|
|
1835
|
+
self._jitaccesshandler = None
|
|
1836
|
+
|
|
1837
|
+
def read_netcdfslices(self, idx: int) -> None:
|
|
1838
|
+
"""Read the time slice relevant to the current simulation step.
|
|
1839
|
+
|
|
1840
|
+
This method is only relevant for reading data from or writing data to NetCDF
|
|
1841
|
+
files "just in time" during simulation runs. See the main documentation on
|
|
1842
|
+
class |HydPy| for further information.
|
|
1843
|
+
"""
|
|
1844
|
+
handler = self._jitaccesshandler
|
|
1845
|
+
if handler is not None:
|
|
1846
|
+
handler.read_slices(idx)
|
|
1847
|
+
|
|
1848
|
+
def write_netcdfslices(self, idx: int) -> None:
|
|
1849
|
+
"""Write the time slice relevant to the current simulation step.
|
|
1850
|
+
|
|
1851
|
+
This method is only relevant for reading data from or writing data to NetCDF
|
|
1852
|
+
files "just in time" during simulation runs. See the main documentation on
|
|
1853
|
+
class |HydPy| for further information.
|
|
1854
|
+
"""
|
|
1855
|
+
handler = self._jitaccesshandler
|
|
1856
|
+
if handler is not None:
|
|
1857
|
+
handler.write_slices(idx)
|
|
1858
|
+
|
|
1859
|
+
|
|
1860
|
+
_FILEMANAGERS = (NetworkManager, ControlManager, ConditionManager, SequenceManager)
|
|
1861
|
+
|
|
1862
|
+
|
|
1863
|
+
def check_projectstructure(projectpath: str) -> None:
|
|
1864
|
+
"""Raise a warning if the given project root directory does not exist or does not
|
|
1865
|
+
contain all relevant base directories.
|
|
1866
|
+
|
|
1867
|
+
First, |check_projectstructure| checks if the root directory exists:
|
|
1868
|
+
|
|
1869
|
+
>>> from hydpy import check_projectstructure, HydPy, pub, TestIO
|
|
1870
|
+
>>> TestIO.clear()
|
|
1871
|
+
>>> with TestIO():
|
|
1872
|
+
... check_projectstructure("my_project") # doctest: +ELLIPSIS
|
|
1873
|
+
Traceback (most recent call last):
|
|
1874
|
+
...
|
|
1875
|
+
UserWarning: The project root directory `...my_project` does not exists.
|
|
1876
|
+
|
|
1877
|
+
Second, it lists all missing base directories:
|
|
1878
|
+
|
|
1879
|
+
>>> import os
|
|
1880
|
+
>>> from hydpy.core.testtools import warn_later
|
|
1881
|
+
>>> with TestIO(), warn_later(), pub.options.checkprojectstructure(True):
|
|
1882
|
+
... os.makedirs(os.path.join("my_project", "control"))
|
|
1883
|
+
... hp = HydPy("my_project") # doctest: +ELLIPSIS
|
|
1884
|
+
UserWarning: The project root directory ...my_project has no base directory \
|
|
1885
|
+
named `network` as required by the network manager.
|
|
1886
|
+
UserWarning: The project root directory ...my_project has no base directory \
|
|
1887
|
+
named `conditions` as required by the condition manager.
|
|
1888
|
+
UserWarning: The project root directory ...my_project has no base directory \
|
|
1889
|
+
named `series` as required by the sequence manager.
|
|
1890
|
+
|
|
1891
|
+
Note that class |HydPy| calls function |check_projectstructure| automatically if
|
|
1892
|
+
option |Options.checkprojectstructure| is enabled:
|
|
1893
|
+
|
|
1894
|
+
>>> TestIO.clear()
|
|
1895
|
+
>>> with TestIO(), pub.options.checkprojectstructure(False):
|
|
1896
|
+
... hp = HydPy("my_project")
|
|
1897
|
+
|
|
1898
|
+
>>> with TestIO(), pub.options.checkprojectstructure(True):
|
|
1899
|
+
... hp = HydPy("my_project") # doctest: +ELLIPSIS
|
|
1900
|
+
Traceback (most recent call last):
|
|
1901
|
+
...
|
|
1902
|
+
UserWarning: The project root directory `...my_project` does not exists.
|
|
1903
|
+
"""
|
|
1904
|
+
|
|
1905
|
+
projectpath = os.path.abspath(projectpath)
|
|
1906
|
+
if os.path.exists(projectpath):
|
|
1907
|
+
for filemanager in _FILEMANAGERS:
|
|
1908
|
+
basepath = os.path.join(projectpath, filemanager.BASEDIR)
|
|
1909
|
+
if not os.path.exists(basepath):
|
|
1910
|
+
warnings.warn(
|
|
1911
|
+
f"The project root directory {projectpath} has no base directory "
|
|
1912
|
+
f"named `{filemanager.BASEDIR}` as required by the "
|
|
1913
|
+
f"{filemanager.__name__[:-7].lower()} manager."
|
|
1914
|
+
)
|
|
1915
|
+
else:
|
|
1916
|
+
warnings.warn(f"The project root directory `{projectpath}` does not exists.")
|
|
1917
|
+
|
|
1918
|
+
|
|
1919
|
+
def create_projectstructure(projectpath: str, overwrite: bool = False) -> None:
|
|
1920
|
+
"""Make the given project root directory and its base directories.
|
|
1921
|
+
|
|
1922
|
+
If everything works well, function |create_projectstructure| creates the required
|
|
1923
|
+
directories silently:
|
|
1924
|
+
|
|
1925
|
+
>>> from hydpy import create_projectstructure, TestIO
|
|
1926
|
+
>>> from hydpy.core.testtools import print_filestructure
|
|
1927
|
+
>>> TestIO.clear()
|
|
1928
|
+
>>> with TestIO():
|
|
1929
|
+
... create_projectstructure("my_project")
|
|
1930
|
+
... print_filestructure("my_project") # doctest: +ELLIPSIS
|
|
1931
|
+
* ...my_project
|
|
1932
|
+
- conditions
|
|
1933
|
+
- control
|
|
1934
|
+
- network
|
|
1935
|
+
- series
|
|
1936
|
+
|
|
1937
|
+
If the root directory already exists, it does not make any changes and instead
|
|
1938
|
+
raises the following error by default:
|
|
1939
|
+
|
|
1940
|
+
>>> with TestIO():
|
|
1941
|
+
... os.makedirs(os.path.join("my_project", "zap"))
|
|
1942
|
+
... create_projectstructure("my_project") # doctest: +ELLIPSIS
|
|
1943
|
+
Traceback (most recent call last):
|
|
1944
|
+
...
|
|
1945
|
+
FileExistsError: While trying to create the basic directory structure for project \
|
|
1946
|
+
`my_project`the directory ...iotesting, the following error occurred: The root \
|
|
1947
|
+
directory already exists and overwriting is not allowed.
|
|
1948
|
+
>>> with TestIO():
|
|
1949
|
+
... print_filestructure("my_project") # doctest: +ELLIPSIS
|
|
1950
|
+
* ...my_project
|
|
1951
|
+
- conditions
|
|
1952
|
+
- control
|
|
1953
|
+
- network
|
|
1954
|
+
- series
|
|
1955
|
+
- zap
|
|
1956
|
+
|
|
1957
|
+
Use the `overwrite` flag to let function |create_projectstructure| remove the
|
|
1958
|
+
existing directory and make a new one:
|
|
1959
|
+
|
|
1960
|
+
>>> with TestIO():
|
|
1961
|
+
... create_projectstructure("my_project", overwrite=True)
|
|
1962
|
+
... print_filestructure("my_project") # doctest: +ELLIPSIS
|
|
1963
|
+
* ...my_project
|
|
1964
|
+
- conditions
|
|
1965
|
+
- control
|
|
1966
|
+
- network
|
|
1967
|
+
- series
|
|
1968
|
+
"""
|
|
1969
|
+
projectpath = os.path.abspath(projectpath)
|
|
1970
|
+
try:
|
|
1971
|
+
if os.path.exists(projectpath):
|
|
1972
|
+
if overwrite:
|
|
1973
|
+
shutil.rmtree(projectpath)
|
|
1974
|
+
else:
|
|
1975
|
+
raise FileExistsError(
|
|
1976
|
+
"The root directory already exists and overwriting is not allowed."
|
|
1977
|
+
)
|
|
1978
|
+
for filenmanager in _FILEMANAGERS:
|
|
1979
|
+
os.makedirs(os.path.join(projectpath, filenmanager.BASEDIR))
|
|
1980
|
+
except BaseException:
|
|
1981
|
+
dirpath, projectname = os.path.split(projectpath)
|
|
1982
|
+
objecttools.augment_excmessage(
|
|
1983
|
+
f"While trying to create the basic directory structure for project "
|
|
1984
|
+
f"`{projectname}`the directory {dirpath}"
|
|
1985
|
+
)
|