├── doc ├── requirements.txt ├── pics │ ├── logo.PNG │ ├── logo_2.PNG │ ├── demo │ │ ├── Network.png │ │ ├── SingleNode.png │ │ ├── SingleUnit.png │ │ ├── Network_scheme.png │ │ ├── SingleReservoir.png │ │ ├── SingleNode_scheme.png │ │ ├── SingleUnit_scheme.png │ │ └── SingleReservoir_scheme.png │ ├── components │ │ ├── node.png │ │ ├── unit.png │ │ ├── linker.png │ │ ├── junction.png │ │ ├── network.png │ │ ├── splitter.png │ │ ├── transparent.png │ │ └── node_routing.png │ ├── logo_inverted_2.PNG │ ├── reference │ │ ├── uml.png │ │ └── class_uml.png │ ├── build_element │ │ ├── lag.png │ │ └── reservoir.png │ ├── elements_list │ │ └── lag.png │ ├── logo_transparent.PNG │ ├── popular_models │ │ ├── M4.png │ │ ├── gr4j.png │ │ └── hymod.png │ ├── contribute │ │ ├── schematic.png │ │ ├── schematic_2.png │ │ └── schematic_with_logo.png │ ├── logo_inverted_colors.PNG │ ├── logo_transparent_2.png │ ├── case_studies │ │ ├── ThurHESS2020.png │ │ ├── ThurSchemeNodes.png │ │ └── model_structure_thur.png │ └── numerical_solver │ │ └── bench_all.png ├── license.rst ├── components_code.py ├── share_models_code.py ├── numerical_solver_code.py ├── installation.rst ├── sfpy_in_literature.rst ├── testing.rst ├── customize_components_code.py ├── conf.py ├── interfaces_code.py ├── examples.rst ├── customize_components.rst ├── share_models.rst ├── reference.rst ├── changelog.rst ├── index.rst ├── contribute.rst ├── interfaces.rst ├── model_thur_hess2020.py └── case_studies.rst ├── requirements_dev.txt ├── requirements.txt ├── pyproject.toml ├── .gitignore ├── test ├── unittest │ ├── test_all.sh │ ├── test_requirements.txt │ ├── 01_FR.py │ └── 07_FR_2dt.py └── reference_results │ ├── 01_FR │ ├── flexConfig_ML01.dat │ ├── flexConfig_Areas.dat │ ├── Results.csv │ ├── SuperflexRes.dat │ ├── test.py │ ├── modelInfo.dat │ ├── test.INF_DAT │ ├── input.dat │ └── M01_main.dat │ ├── 02_UR │ ├── flexConfig_ML01.dat │ ├── flexConfig_Areas.dat │ ├── test.py │ ├── Results.csv │ ├── SuperflexRes.dat │ ├── modelInfo.dat │ ├── test.INF_DAT │ ├── input.dat │ └── M01_main.dat │ ├── 03_UR_FR │ ├── flexConfig_ML01.dat │ ├── flexConfig_Areas.dat │ ├── test.py │ ├── Results.csv │ ├── modelInfo.dat │ ├── SuperflexRes.dat │ ├── test.INF_DAT │ ├── input.dat │ └── M01_main.dat │ ├── 05_2HRUs │ ├── flexConfig_HRU1.dat │ ├── flexConfig_HRU2.dat │ ├── flexConfig_Areas.dat │ ├── test.py │ ├── modelInfo.dat │ ├── test.INF_DAT │ ├── input.dat │ ├── Results.csv │ ├── SuperflexRes.dat │ └── M01_main.dat │ ├── 07_FR_2dt │ ├── flexConfig_ML01.dat │ ├── flexConfig_Areas.dat │ ├── Results.csv │ ├── SuperflexRes.dat │ ├── test.py │ ├── modelInfo.dat │ ├── test.INF_DAT │ ├── input.dat │ └── M01_main.dat │ ├── 08_UR_2dt │ ├── flexConfig_ML01.dat │ ├── flexConfig_Areas.dat │ ├── test.py │ ├── Results.csv │ ├── SuperflexRes.dat │ ├── modelInfo.dat │ ├── test.INF_DAT │ ├── input.dat │ └── M01_main.dat │ ├── 04_UR_FR_SR │ ├── flexConfig_ML01.dat │ ├── flexConfig_Areas.dat │ ├── test.py │ ├── modelInfo.dat │ ├── test.INF_DAT │ ├── Results.csv │ ├── SuperflexRes.dat │ ├── input.dat │ └── M01_main.dat │ ├── 06_3Cats_2HRUs │ ├── flexConfig_HRU1.dat │ ├── flexConfig_HRU2.dat │ ├── flexConfig_Areas.dat │ ├── test.py │ ├── modelInfo.dat │ ├── test.INF_DAT │ └── input.dat │ └── README.md ├── .flake8 ├── AUTHORS ├── .github └── workflows │ ├── pre-commit.yaml │ ├── automatic_test.yml │ └── publish_to_pypi.yml ├── readthedocs.yml ├── .pre-commit-config.yaml ├── setup.py ├── README.md ├── superflexpy ├── __init__.py ├── framework │ └── __init__.py ├── implementation │ ├── root_finders │ │ ├── __init__.py │ │ └── explicit.py │ ├── models │ │ ├── __init__.py │ │ ├── m4_sf_2011.py │ │ ├── hymod.py │ │ └── gr4j.py │ ├── __init__.py │ ├── numerical_approximators │ │ └── __init__.py │ └── elements │ │ └── __init__.py └── utils │ ├── __init__.py │ └── root_finder.py └── examples └── README.md /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | superflexpy 2 | -------------------------------------------------------------------------------- /requirements_dev.txt: -------------------------------------------------------------------------------- 1 | pre-commit==3.5.0 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib==3.8.2 2 | numba==0.57.1 3 | numpy==1.24.3 4 | -------------------------------------------------------------------------------- /doc/pics/logo.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/logo.PNG -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.isort] 2 | profile = "black" 3 | [tool.black] 4 | line-length = 120 5 | -------------------------------------------------------------------------------- /doc/pics/logo_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/logo_2.PNG -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | build/ 3 | dist/ 4 | superflexpy.egg-info/ 5 | **/.ipynb_checkpoints 6 | -------------------------------------------------------------------------------- /doc/pics/demo/Network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/demo/Network.png -------------------------------------------------------------------------------- /test/unittest/test_all.sh: -------------------------------------------------------------------------------- 1 | cd test/unittest/ 2 | for f in *.py; do echo Running "$f"; python "$f"; done 3 | -------------------------------------------------------------------------------- /doc/pics/components/node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/components/node.png -------------------------------------------------------------------------------- /doc/pics/components/unit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/components/unit.png -------------------------------------------------------------------------------- /doc/pics/demo/SingleNode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/demo/SingleNode.png -------------------------------------------------------------------------------- /doc/pics/demo/SingleUnit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/demo/SingleUnit.png -------------------------------------------------------------------------------- /doc/pics/logo_inverted_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/logo_inverted_2.PNG -------------------------------------------------------------------------------- /doc/pics/reference/uml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/reference/uml.png -------------------------------------------------------------------------------- /test/unittest/test_requirements.txt: -------------------------------------------------------------------------------- 1 | pandas==2.1.3 2 | matplotlib==3.8.2 3 | numba==0.57.1 4 | numpy==1.24.3 5 | -------------------------------------------------------------------------------- /doc/pics/build_element/lag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/build_element/lag.png -------------------------------------------------------------------------------- /doc/pics/components/linker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/components/linker.png -------------------------------------------------------------------------------- /doc/pics/elements_list/lag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/elements_list/lag.png -------------------------------------------------------------------------------- /doc/pics/logo_transparent.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/logo_transparent.PNG -------------------------------------------------------------------------------- /doc/pics/popular_models/M4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/popular_models/M4.png -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | extend-ignore = E203 3 | max-line-length = 120 4 | exclude = doc,test,.git,.venv,__pycache__,venv 5 | -------------------------------------------------------------------------------- /doc/pics/components/junction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/components/junction.png -------------------------------------------------------------------------------- /doc/pics/components/network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/components/network.png -------------------------------------------------------------------------------- /doc/pics/components/splitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/components/splitter.png -------------------------------------------------------------------------------- /doc/pics/contribute/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/contribute/schematic.png -------------------------------------------------------------------------------- /doc/pics/demo/Network_scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/demo/Network_scheme.png -------------------------------------------------------------------------------- /doc/pics/demo/SingleReservoir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/demo/SingleReservoir.png -------------------------------------------------------------------------------- /doc/pics/logo_inverted_colors.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/logo_inverted_colors.PNG -------------------------------------------------------------------------------- /doc/pics/logo_transparent_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/logo_transparent_2.png -------------------------------------------------------------------------------- /doc/pics/popular_models/gr4j.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/popular_models/gr4j.png -------------------------------------------------------------------------------- /doc/pics/popular_models/hymod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/popular_models/hymod.png -------------------------------------------------------------------------------- /doc/pics/reference/class_uml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/reference/class_uml.png -------------------------------------------------------------------------------- /doc/pics/components/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/components/transparent.png -------------------------------------------------------------------------------- /doc/pics/contribute/schematic_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/contribute/schematic_2.png -------------------------------------------------------------------------------- /doc/pics/demo/SingleNode_scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/demo/SingleNode_scheme.png -------------------------------------------------------------------------------- /doc/pics/demo/SingleUnit_scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/demo/SingleUnit_scheme.png -------------------------------------------------------------------------------- /doc/pics/build_element/reservoir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/build_element/reservoir.png -------------------------------------------------------------------------------- /doc/pics/case_studies/ThurHESS2020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/case_studies/ThurHESS2020.png -------------------------------------------------------------------------------- /doc/pics/components/node_routing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/components/node_routing.png -------------------------------------------------------------------------------- /doc/pics/demo/SingleReservoir_scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/demo/SingleReservoir_scheme.png -------------------------------------------------------------------------------- /doc/pics/numerical_solver/bench_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/numerical_solver/bench_all.png -------------------------------------------------------------------------------- /doc/pics/case_studies/ThurSchemeNodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/case_studies/ThurSchemeNodes.png -------------------------------------------------------------------------------- /doc/pics/contribute/schematic_with_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/contribute/schematic_with_logo.png -------------------------------------------------------------------------------- /doc/pics/case_studies/model_structure_thur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/doc/pics/case_studies/model_structure_thur.png -------------------------------------------------------------------------------- /test/reference_results/01_FR/flexConfig_ML01.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/01_FR/flexConfig_ML01.dat -------------------------------------------------------------------------------- /test/reference_results/02_UR/flexConfig_ML01.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/02_UR/flexConfig_ML01.dat -------------------------------------------------------------------------------- /test/reference_results/03_UR_FR/flexConfig_ML01.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/03_UR_FR/flexConfig_ML01.dat -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/flexConfig_HRU1.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/05_2HRUs/flexConfig_HRU1.dat -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/flexConfig_HRU2.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/05_2HRUs/flexConfig_HRU2.dat -------------------------------------------------------------------------------- /test/reference_results/07_FR_2dt/flexConfig_ML01.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/07_FR_2dt/flexConfig_ML01.dat -------------------------------------------------------------------------------- /test/reference_results/08_UR_2dt/flexConfig_ML01.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/08_UR_2dt/flexConfig_ML01.dat -------------------------------------------------------------------------------- /test/reference_results/04_UR_FR_SR/flexConfig_ML01.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/04_UR_FR_SR/flexConfig_ML01.dat -------------------------------------------------------------------------------- /test/reference_results/06_3Cats_2HRUs/flexConfig_HRU1.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/06_3Cats_2HRUs/flexConfig_HRU1.dat -------------------------------------------------------------------------------- /test/reference_results/06_3Cats_2HRUs/flexConfig_HRU2.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dalmo1991/superflexPy/HEAD/test/reference_results/06_3Cats_2HRUs/flexConfig_HRU2.dat -------------------------------------------------------------------------------- /doc/license.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 16/10/2020 2 | 3 | .. _license: 4 | 5 | License 6 | ======= 7 | 8 | .. highlight:: none 9 | .. literalinclude:: LICENSE 10 | -------------------------------------------------------------------------------- /test/reference_results/01_FR/flexConfig_Areas.dat: -------------------------------------------------------------------------------- 1 | FLEX_HRU_CHARACTERISTICS_FILE_V1.1 2 | ! Description: HRUs characterisics (-1=NA, depending on mask Unit Presence Matrix) 3 | !======== 4 | AREAS (km2) 5 | 1.0 6 | -------------------------------------------------------------------------------- /test/reference_results/02_UR/flexConfig_Areas.dat: -------------------------------------------------------------------------------- 1 | FLEX_HRU_CHARACTERISTICS_FILE_V1.1 2 | ! Description: HRUs characterisics (-1=NA, depending on mask Unit Presence Matrix) 3 | !======== 4 | AREAS (km2) 5 | 1.0 6 | -------------------------------------------------------------------------------- /test/reference_results/03_UR_FR/flexConfig_Areas.dat: -------------------------------------------------------------------------------- 1 | FLEX_HRU_CHARACTERISTICS_FILE_V1.1 2 | ! Description: HRUs characterisics (-1=NA, depending on mask Unit Presence Matrix) 3 | !======== 4 | AREAS (km2) 5 | 1.0 6 | -------------------------------------------------------------------------------- /test/reference_results/07_FR_2dt/flexConfig_Areas.dat: -------------------------------------------------------------------------------- 1 | FLEX_HRU_CHARACTERISTICS_FILE_V1.1 2 | ! Description: HRUs characterisics (-1=NA, depending on mask Unit Presence Matrix) 3 | !======== 4 | AREAS (km2) 5 | 1.0 6 | -------------------------------------------------------------------------------- /test/reference_results/08_UR_2dt/flexConfig_Areas.dat: -------------------------------------------------------------------------------- 1 | FLEX_HRU_CHARACTERISTICS_FILE_V1.1 2 | ! Description: HRUs characterisics (-1=NA, depending on mask Unit Presence Matrix) 3 | !======== 4 | AREAS (km2) 5 | 1.0 6 | -------------------------------------------------------------------------------- /test/reference_results/04_UR_FR_SR/flexConfig_Areas.dat: -------------------------------------------------------------------------------- 1 | FLEX_HRU_CHARACTERISTICS_FILE_V1.1 2 | ! Description: HRUs characterisics (-1=NA, depending on mask Unit Presence Matrix) 3 | !======== 4 | AREAS (km2) 5 | 1.0 6 | -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/flexConfig_Areas.dat: -------------------------------------------------------------------------------- 1 | FLEX_HRU_CHARACTERISTICS_FILE_V1.1 2 | ! Description: HRUs characterisics (-1=NA, depending on mask Unit Presence Matrix) 3 | !======== 4 | AREAS (km2) 5 | 40.0 60.0 6 | -------------------------------------------------------------------------------- /doc/components_code.py: -------------------------------------------------------------------------------- 1 | e1 = Element(parameters={"p1": 0.1}, states={"S": 10.0}) 2 | 3 | u1 = Unit([e1]) 4 | u2 = Unit([e1]) 5 | 6 | e1.set_parameters({"e1_p1": 0.2}) 7 | u1.set_parameters({"u1_e1_p1": 0.3}) 8 | u2.set_parameters({"u2_e1_p1": 0.4}) 9 | -------------------------------------------------------------------------------- /test/reference_results/06_3Cats_2HRUs/flexConfig_Areas.dat: -------------------------------------------------------------------------------- 1 | FLEX_HRU_CHARACTERISTICS_FILE_V1.1 2 | ! Description: HRUs characterisics (-1=NA, depending on mask Unit Presence Matrix) 3 | !======== 4 | AREAS (km2) 5 | 2.5 7.5 6 | 8.0 12.0 7 | 24.0 6.0 8 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | List of contributors (alphabetical order) 2 | 3 | Format: Name Surname, Affiliation, e-mail 4 | 5 | Marco Dal Molin, EAWAG, marco.dalmolin.1991@gmail.com 6 | Fabrizio Fenicia, EAWAG, fabrizio.fenicia@eawag.ch 7 | Dmitri Kavetski, University of Adelaide, dmitri.kavetski@adelaide.edu.au 8 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yaml: -------------------------------------------------------------------------------- 1 | name: pre-commit 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [master] 7 | 8 | jobs: 9 | pre-commit: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: actions/setup-python@v3 14 | - uses: pre-commit/action@v3.0.0 15 | -------------------------------------------------------------------------------- /test/reference_results/01_FR/Results.csv: -------------------------------------------------------------------------------- 1 | # Q_FR, S_FR 2 | 3.159780226522707953e-05,9.996840219773421576e-02 3 | 3.166701113934160539e-01,3.983298290804318409e+00 4 | 2.663570722380119715e-01,3.716941218566306659e+00 5 | 4.951976392398618643e+00,1.196496482616768731e+01 6 | 3.707744781785232480e+00,1.065722004438245385e+01 7 | 9.457787016280562398e+00,1.549943302810189394e+01 8 | 6.532500080672547504e+00,1.336693294742934945e+01 9 | 4.038812792135322738e+00,1.102812015529402778e+01 10 | 2.270004410544121498e+00,8.758115744749906284e+00 11 | 5.176552544186736071e+01,3.059259030288254877e+01 12 | -------------------------------------------------------------------------------- /test/reference_results/07_FR_2dt/Results.csv: -------------------------------------------------------------------------------- 1 | # Q_FR, S_FR 2 | 1.780900587186331975e-04,1.996438198825627452e-01 3 | 1.064800016990280485e+00,6.470043785902002575e+00 4 | 6.234754642204936026e-01,5.223092857461010929e+00 5 | 8.415470448389710256e+00,1.479215196068158455e+01 6 | 4.196754269805919257e+00,1.119864342106974497e+01 7 | 1.151488566525114265e+01,1.676887209056745220e+01 8 | 6.227557886749018223e+00,1.311375631706941824e+01 9 | 3.220350228412992344e+00,1.007305586024343214e+01 10 | 1.413431427615711833e+00,7.246193005012008470e+00 11 | 6.089951208253958015e+01,3.264716883993278884e+01 12 | -------------------------------------------------------------------------------- /test/reference_results/README.md: -------------------------------------------------------------------------------- 1 | # Note 2 | 3 | This folder contains reference results for testing SuperflexPy. 4 | 5 | Only the files `Results.csv` and `input.dat` are relevant for testing. All the 6 | others are here only for reproducibility purposes, storing information on the 7 | configuration of Superflex (Fenicia et al., 2011). 8 | 9 | ### Bibliography 10 | 11 | Fenicia, F., D. Kavetski, and H. H. G. Savenije (2011), Elements of a flexible approach for conceptual hydrological modeling: 1. Motivation and theoretical development, Water Resources Research, 47(11), W11510, 10.1029/2010wr010174. 12 | -------------------------------------------------------------------------------- /.github/workflows/automatic_test.yml: -------------------------------------------------------------------------------- 1 | name: unittest on push 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | - release 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Prepare the repo 15 | uses: actions/checkout@master 16 | - name: Set up Python 3.11 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: 3.11 20 | - name: Install packages 21 | run: pip install -r test/unittest/test_requirements.txt 22 | - name: Test 23 | run: bash test/unittest/test_all.sh 24 | -------------------------------------------------------------------------------- /test/reference_results/01_FR/SuperflexRes.dat: -------------------------------------------------------------------------------- 1 | Data modelled by SF_ISO 2 | C1Wv%Qstream U1F1Wv%Sf[1] 3 | 3.15978022652271E-05 9.99684021977342E-02 4 | 3.16670111393416E-01 3.98329829080432E+00 5 | 2.66357072238012E-01 3.71694121856631E+00 6 | 4.95197639239862E+00 1.19649648261677E+01 7 | 3.70774478178523E+00 1.06572200443825E+01 8 | 9.45778701628056E+00 1.54994330281019E+01 9 | 6.53250008067255E+00 1.33669329474293E+01 10 | 4.03881279213532E+00 1.10281201552940E+01 11 | 2.27000441054412E+00 8.75811574474991E+00 12 | 5.17655254418674E+01 3.05925903028825E+01 13 | -------------------------------------------------------------------------------- /test/reference_results/07_FR_2dt/SuperflexRes.dat: -------------------------------------------------------------------------------- 1 | Data modelled by SF_ISO 2 | C1Wv%Qstream U1F1Wv%Sf[1] 3 | 1.78090058718633E-04 1.99643819882563E-01 4 | 1.06480001699028E+00 6.47004378590200E+00 5 | 6.23475464220494E-01 5.22309285746101E+00 6 | 8.41547044838971E+00 1.47921519606816E+01 7 | 4.19675426980592E+00 1.11986434210697E+01 8 | 1.15148856652511E+01 1.67688720905675E+01 9 | 6.22755788674902E+00 1.31137563170694E+01 10 | 3.22035022841299E+00 1.00730558602434E+01 11 | 1.41343142761571E+00 7.24619300501201E+00 12 | 6.08995120825396E+01 3.26471688399328E+01 13 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.11" 12 | 13 | # Build documentation in the docs/ directory with Sphinx 14 | sphinx: 15 | configuration: doc/conf.py 16 | 17 | # Optionally build your docs in additional formats such as PDF and ePub 18 | formats: all 19 | 20 | # Optionally set the version of Python and requirements required to build your docs 21 | python: 22 | install: 23 | - requirements: doc/requirements.txt 24 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.5.0 4 | hooks: 5 | - id: trailing-whitespace 6 | - id: end-of-file-fixer 7 | - id: check-yaml 8 | - id: check-added-large-files 9 | - repo: https://github.com/PyCQA/flake8 10 | rev: 6.1.0 11 | hooks: 12 | - id: flake8 13 | exclude: ^(doc/|^test/) 14 | - repo: https://github.com/pycqa/isort 15 | rev: 5.12.0 16 | hooks: 17 | - id: isort 18 | args: ["--profile", "black", "--filter-files"] 19 | - repo: https://github.com/psf/black 20 | rev: 23.11.0 21 | hooks: 22 | - id: black 23 | -------------------------------------------------------------------------------- /test/reference_results/07_FR_2dt/test.py: -------------------------------------------------------------------------------- 1 | """ 2 | File to create the results with Superflex 3 | """ 4 | 5 | import sys 6 | 7 | # Add the path where the Superflex module is 8 | sys.path.append("/home/dalmo/Documents/BitBucket/superflexPython/C_so/") 9 | from os import chdir, path 10 | 11 | import numpy as np 12 | from superflex import Superflex_C 13 | 14 | chdir(path.abspath(path.dirname(__file__))) 15 | 16 | # Initialize the class 17 | sup = Superflex_C() 18 | 19 | # Load the model 20 | dims = sup.load_model() 21 | 22 | # Initialize the parameters 23 | parameters = np.array([[]]) 24 | 25 | # Get the output 26 | output = sup.run_model(parameters) 27 | 28 | np.savetxt("Results.csv", X=output, delimiter=",", header="Q_FR, S_FR") 29 | -------------------------------------------------------------------------------- /test/reference_results/08_UR_2dt/test.py: -------------------------------------------------------------------------------- 1 | """ 2 | File to create the results with Superflex 3 | """ 4 | 5 | import sys 6 | 7 | # Add the path where the Superflex module is 8 | sys.path.append("/home/dalmo/Documents/BitBucket/superflexPython/C_so/") 9 | from os import chdir, path 10 | 11 | import numpy as np 12 | from superflex import Superflex_C 13 | 14 | chdir(path.abspath(path.dirname(__file__))) 15 | 16 | # Initialize the class 17 | sup = Superflex_C() 18 | 19 | # Load the model 20 | dims = sup.load_model() 21 | 22 | # Initialize the parameters 23 | parameters = np.array([[]]) 24 | 25 | # Get the output 26 | output = sup.run_model(parameters) 27 | 28 | np.savetxt("Results.csv", X=output, delimiter=",", header="Q_UR, E_UR, S_UR") 29 | -------------------------------------------------------------------------------- /test/reference_results/01_FR/test.py: -------------------------------------------------------------------------------- 1 | """ 2 | File to create the results with Superflex 3 | """ 4 | 5 | import sys 6 | 7 | # Add the path where the Superflex module is 8 | sys.path.append("/home/dalmo/Documents/BitBucket/superflexPython/C_so/") 9 | from os import chdir 10 | 11 | import numpy as np 12 | from superflex import Superflex_C 13 | 14 | chdir("/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/01_FR/") 15 | 16 | # Initialize the class 17 | sup = Superflex_C() 18 | 19 | # Load the model 20 | dims = sup.load_model() 21 | 22 | # Initialize the parameters 23 | parameters = np.array([[]]) 24 | 25 | # Get the output 26 | output = sup.run_model(parameters) 27 | 28 | np.savetxt("Results.csv", X=output, delimiter=",", header="Q_FR, S_FR") 29 | -------------------------------------------------------------------------------- /test/reference_results/02_UR/test.py: -------------------------------------------------------------------------------- 1 | """ 2 | File to create the results with Superflex 3 | """ 4 | 5 | import sys 6 | 7 | # Add the path where the Superflex module is 8 | sys.path.append("/home/dalmo/Documents/BitBucket/superflexPython/C_so/") 9 | from os import chdir 10 | 11 | import numpy as np 12 | from superflex import Superflex_C 13 | 14 | chdir("/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/02_UR/") 15 | 16 | # Initialize the class 17 | sup = Superflex_C() 18 | 19 | # Load the model 20 | dims = sup.load_model() 21 | 22 | # Initialize the parameters 23 | parameters = np.array([[]]) 24 | 25 | # Get the output 26 | output = sup.run_model(parameters) 27 | 28 | np.savetxt("Results.csv", X=output, delimiter=",", header="Q_UR, E_UR, S_UR") 29 | -------------------------------------------------------------------------------- /test/reference_results/03_UR_FR/test.py: -------------------------------------------------------------------------------- 1 | """ 2 | File to create the results with Superflex 3 | """ 4 | 5 | import sys 6 | 7 | # Add the path where the Superflex module is 8 | sys.path.append("/home/dalmo/Documents/BitBucket/superflexPython/C_so/") 9 | from os import chdir 10 | 11 | import numpy as np 12 | from superflex import Superflex_C 13 | 14 | chdir("/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/03_UR_FR/") 15 | 16 | # Initialize the class 17 | sup = Superflex_C() 18 | 19 | # Load the model 20 | dims = sup.load_model() 21 | 22 | # Initialize the parameters 23 | parameters = np.array([[]]) 24 | 25 | # Get the output 26 | output = sup.run_model(parameters) 27 | 28 | np.savetxt("Results.csv", X=output, delimiter=",", header="Q_out, E_UR, S_UR, S_FR") 29 | -------------------------------------------------------------------------------- /test/reference_results/04_UR_FR_SR/test.py: -------------------------------------------------------------------------------- 1 | """ 2 | File to create the results with Superflex 3 | """ 4 | 5 | import sys 6 | 7 | # Add the path where the Superflex module is 8 | sys.path.append("/home/dalmo/Documents/BitBucket/superflexPython/C_so/") 9 | from os import chdir 10 | 11 | import numpy as np 12 | from superflex import Superflex_C 13 | 14 | chdir("/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/04_UR_FR_SR/") 15 | 16 | # Initialize the class 17 | sup = Superflex_C() 18 | 19 | # Load the model 20 | dims = sup.load_model() 21 | 22 | # Initialize the parameters 23 | parameters = np.array([[]]) 24 | 25 | # Get the output 26 | output = sup.run_model(parameters) 27 | 28 | np.savetxt("Results.csv", X=output, delimiter=",", header="Q_out, E_UR, S_UR, S_FR, S_SR") 29 | -------------------------------------------------------------------------------- /test/reference_results/02_UR/Results.csv: -------------------------------------------------------------------------------- 1 | # Q_UR, E_UR, S_UR 2 | 3.009856864469894096e-03,5.258974893186536548e+00,4.838015249948993457e+00 3 | 8.864692811194890831e-02,5.130691213399449779e+00,3.818677108437596335e+00 4 | 0.000000000000000000e+00,3.202714842730908007e+00,6.159622657066883278e-01 5 | 7.808764814858565328e-01,5.443911796302973727e+00,7.591173987917855470e+00 6 | 6.872763881524802942e-02,5.242400307174300167e+00,4.680046041928307865e+00 7 | 1.635054241653562945e+00,5.566199717157565452e+00,1.177879208311717996e+01 8 | 4.077257815005328467e-01,5.532314801708615448e+00,1.023875149990803024e+01 9 | 7.918930542498503478e-02,5.386421012745326919e+00,6.473141181737718242e+00 10 | 0.000000000000000000e+00,4.586741093407180614e+00,1.886400088330537628e+00 11 | 3.774060787574933329e+01,5.713300529257533178e+00,3.203249168332367702e+01 12 | -------------------------------------------------------------------------------- /test/reference_results/08_UR_2dt/Results.csv: -------------------------------------------------------------------------------- 1 | # Q_UR, E_UR, S_UR 2 | 5.186073603391754125e-04,4.350451541277550405e+00,1.498059702724222175e+00 3 | 1.895615082737465290e-02,4.247304505087319271e+00,1.365538390894836418e+00 4 | 0.000000000000000000e+00,6.511671950550351751e-01,6.320400078476612338e-02 5 | 1.581811726237999594e+00,5.573191220252586398e+00,1.215319810780359155e+01 6 | 1.006375051760131228e-01,5.358518452123193221e+00,6.034886193205179161e+00 7 | 2.949405595047687623e+00,5.640889987188658417e+00,1.745429502873248850e+01 8 | 6.367529840457144541e-01,5.599342162879759499e+00,1.378210473488154264e+01 9 | 7.569693251013522028e-02,5.374656926342401775e+00,6.281397017176455044e+00 10 | 0.000000000000000000e+00,2.892244096750379967e+00,4.969088236756952215e-01 11 | 4.904745394822768390e+01,5.727410394778824632e+00,3.814718013766267291e+01 12 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import setuptools 4 | 5 | setuptools.setup( 6 | name="superflexpy", 7 | version="1.3.2", 8 | author="Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski", 9 | author_email="marco.dalmolin.1991@gmail.com", 10 | description="Framework for building hydrological models", 11 | long_description=open(os.path.join(os.path.dirname(__file__), "README.md")).read(), 12 | long_description_content_type="text/markdown", 13 | url="https://superflexpy.readthedocs.io/en/latest/", 14 | license="LGPL", 15 | packages=setuptools.find_packages(), 16 | classifiers=[ 17 | "Development Status :: 5 - Production/Stable", # https://martin-thoma.com/software-development-stages/ 18 | "Topic :: Scientific/Engineering :: Hydrology", 19 | ], 20 | install_requires=["numba==0.57.1", "numpy==1.24.3"], 21 | ) 22 | -------------------------------------------------------------------------------- /.github/workflows/publish_to_pypi.yml: -------------------------------------------------------------------------------- 1 | name: publish releases automatically on PyPI 2 | 3 | # Trigger on push on release branch 4 | on: 5 | push: 6 | branches: 7 | - release 8 | 9 | jobs: 10 | create_and_publish: 11 | name: publish releases automatically on PyPI 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Select branch 15 | uses: actions/checkout@master 16 | with: 17 | ref: 'release' # The default behavior is that it checkouts to the trigger so we don't need this 18 | - name: Set up Python 3.11 19 | uses: actions/setup-python@v1 20 | with: 21 | python-version: 3.11 22 | - name: Build the package 23 | run: python setup.py sdist 24 | - name: Publish on PyPI 25 | uses: pypa/gh-action-pypi-publish@master 26 | with: 27 | password: ${{ secrets.PYPI_ACCESS_TOKEN }} 28 | -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/test.py: -------------------------------------------------------------------------------- 1 | """ 2 | File to create the results with Superflex 3 | """ 4 | 5 | import sys 6 | 7 | # Add the path where the Superflex module is 8 | sys.path.append("/home/dalmo/Documents/BitBucket/superflexPython/C_so/") 9 | from os import chdir 10 | 11 | import numpy as np 12 | from superflex import Superflex_C 13 | 14 | chdir("/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/05_2HRUs/") 15 | 16 | # Initialize the class 17 | sup = Superflex_C() 18 | 19 | # Load the model 20 | dims = sup.load_model() 21 | 22 | # Initialize the parameters 23 | parameters = np.array([[]]) 24 | 25 | # Get the output 26 | output = sup.run_model(parameters) 27 | 28 | np.savetxt( 29 | "Results.csv", 30 | X=output, 31 | delimiter=",", 32 | header="Q_tot, Q_H1, E_FR_H1, S_FR_H1, Q_H2, E_UR_H2, S_UR_H2, S_FR_H2, S_SR_H2", 33 | ) 34 | -------------------------------------------------------------------------------- /test/reference_results/02_UR/SuperflexRes.dat: -------------------------------------------------------------------------------- 1 | Data modelled by SF_ISO 2 | C1Wv%Qstream U1F1Wv%Eact U1F1Wv%Su[1] 3 | 3.00985686446989E-03 5.25897489318654E+00 4.83801524994899E+00 4 | 8.86469281119489E-02 5.13069121339945E+00 3.81867710843760E+00 5 | 0.00000000000000E+00 3.20271484273091E+00 6.15962265706688E-01 6 | 7.80876481485857E-01 5.44391179630297E+00 7.59117398791786E+00 7 | 6.87276388152480E-02 5.24240030717430E+00 4.68004604192831E+00 8 | 1.63505424165356E+00 5.56619971715757E+00 1.17787920831172E+01 9 | 4.07725781500533E-01 5.53231480170862E+00 1.02387514999080E+01 10 | 7.91893054249850E-02 5.38642101274533E+00 6.47314118173772E+00 11 | 0.00000000000000E+00 4.58674109340718E+00 1.88640008833054E+00 12 | 3.77406078757493E+01 5.71330052925753E+00 3.20324916833237E+01 13 | -------------------------------------------------------------------------------- /test/reference_results/08_UR_2dt/SuperflexRes.dat: -------------------------------------------------------------------------------- 1 | Data modelled by SF_ISO 2 | C1Wv%Qstream U1F1Wv%Eact U1F1Wv%Su[1] 3 | 5.18607360339175E-04 4.35045154127755E+00 1.49805970272422E+00 4 | 1.89561508273747E-02 4.24730450508732E+00 1.36553839089484E+00 5 | 0.00000000000000E+00 6.51167195055035E-01 6.32040007847661E-02 6 | 1.58181172623800E+00 5.57319122025259E+00 1.21531981078036E+01 7 | 1.00637505176013E-01 5.35851845212319E+00 6.03488619320518E+00 8 | 2.94940559504769E+00 5.64088998718866E+00 1.74542950287325E+01 9 | 6.36752984045714E-01 5.59934216287976E+00 1.37821047348815E+01 10 | 7.56969325101352E-02 5.37465692634240E+00 6.28139701717646E+00 11 | 0.00000000000000E+00 2.89224409675038E+00 4.96908823675695E-01 12 | 4.90474539482277E+01 5.72741039477882E+00 3.81471801376627E+01 13 | -------------------------------------------------------------------------------- /test/reference_results/06_3Cats_2HRUs/test.py: -------------------------------------------------------------------------------- 1 | """ 2 | File to create the results with Superflex 3 | """ 4 | 5 | import sys 6 | 7 | # Add the path where the Superflex module is 8 | sys.path.append("/home/dalmo/Documents/BitBucket/superflexPython/C_so/") 9 | from os import chdir 10 | 11 | import numpy as np 12 | from superflex import Superflex_C 13 | 14 | chdir("/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/06_3Cats_2HRUs/") 15 | 16 | # Initialize the class 17 | sup = Superflex_C() 18 | 19 | # Load the model 20 | dims = sup.load_model() 21 | 22 | # Initialize the parameters 23 | parameters = np.array([[]]) 24 | 25 | # Get the output 26 | output = sup.run_model(parameters) 27 | 28 | np.savetxt( 29 | "Results.csv", 30 | X=output, 31 | delimiter=",", 32 | header="Q_c1, Q_c2, Q_c3, Q_c1_h1, S_c1_h1_FR, Q_c2_h1, S_c2_h1_FR, Q_c3_h1, S_c3_h1_FR, Q_c1_h2, E_c1_h2_UR, S_c1_h2_UR, S_c1_h2_FR, S_c1_h2_SR, Q_c2_h2, E_c2_h2_UR, S_c2_h2_UR, S_c2_h2_FR, S_c2_h2_SR, Q_c3_h2, E_c3_h2_UR, S_c3_h2_UR, S_c3_h2_FR, S_c3_h2_SR", 33 | ) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Actions Status](https://github.com/dalmo1991/superflexPy/workflows/unittest%20on%20push/badge.svg)](https://github.com/dalmo1991/superflexPy/actions) 2 | [![DOI](https://zenodo.org/badge/208847505.svg)](https://zenodo.org/badge/latestdoi/208847505) 3 | 4 | # SuperflexPy: The flexible language of hydrological modelling 5 | 6 | ![SuperflexPy logo](https://superflexpy.readthedocs.io/en/latest/_images/logo_transparent_2.png) 7 | 8 | SuperflexPy is an open-source framework written in Python for constructing 9 | flexible, conceptual, distributed hydrological models. 10 | 11 | Refer to the [documentation](https://superflexpy.readthedocs.io/) to learn to 12 | use the SuperflexPy, [install](https://pypi.org/project/superflexpy/) the 13 | package from here. [Examples](examples/) showing the basic usage of SuperflexPy 14 | are available. 15 | 16 | ## Development 17 | 18 | Please install all packages listed in the [requirements_dev.txt](requirements_dev.txt) file, 19 | the run `pre-commit install` to install the git hooks. This will enable code formatting and linting on every git commit. 20 | -------------------------------------------------------------------------------- /test/reference_results/03_UR_FR/Results.csv: -------------------------------------------------------------------------------- 1 | # Q_out, E_UR, S_UR, S_FR 2 | 4.970073536521080624e-09,5.258974893186536548e+00,4.838015249948993457e+00,3.009851894396357776e-03 3 | 2.541618578426108855e-05,5.130691213399449779e+00,3.818677108437596335e+00,9.163136382056072393e-02 4 | 2.539857716377526181e-05,3.202714842730908007e+00,6.159622657066883278e-01,9.160596524339441327e-02 5 | 6.969221550195355691e-03,5.443911796302973727e+00,7.591173987917855470e+00,8.655132251790572662e-01 6 | 8.251167171282486681e-03,5.242400307174300167e+00,4.680046041928307865e+00,9.259896968230227898e-01 7 | 9.545560128715058212e-02,5.566199717157565452e+00,1.177879208311717996e+01,2.465588337189435375e+00 8 | 1.251954915358534648e-01,5.532314801708615448e+00,1.023875149990803024e+01,2.748118627154114701e+00 9 | 1.205390933205765930e-01,5.386421012745326919e+00,6.473141181737718242e+00,2.706768839258514081e+00 10 | 1.087900105934205414e-01,4.586741093407180614e+00,1.886400088330537628e+00,2.597978828665093332e+00 11 | 1.959586382954269723e+01,5.713300529257533178e+00,3.203249168332367702e+01,2.074272287487173472e+01 12 | -------------------------------------------------------------------------------- /doc/share_models_code.py: -------------------------------------------------------------------------------- 1 | from superflexpy.framework.unit import Unit 2 | from superflexpy.implementation.elements.hbv import PowerReservoir, UnsaturatedReservoir 3 | from superflexpy.implementation.numerical_approximators.implicit_euler import ( 4 | ImplicitEulerPython, 5 | ) 6 | from superflexpy.implementation.root_finders.pegasus import PegasusPython 7 | 8 | root_finder = PegasusPython() 9 | numeric_approximator = ImplicitEulerPython(root_finder=root_finder) 10 | 11 | ur = UnsaturatedReservoir( 12 | parameters={"Smax": 50.0, "Ce": 1.0, "m": 0.01, "beta": 2.0}, 13 | states={"S0": 25.0}, 14 | approximation=numeric_approximator, 15 | id="UR", 16 | ) 17 | 18 | fr = PowerReservoir( 19 | parameters={"k": 0.1, "alpha": 1.0}, states={"S0": 10.0}, approximation=numeric_approximator, id="FR" 20 | ) 21 | 22 | model = Unit(layers=[[ur], [fr]], id="M4") 23 | 24 | from superflexpy.implementation.models.m4_sf_2011 import model 25 | 26 | model.set_input([P, E]) 27 | model.set_timestep(1.0) 28 | model.reset_states() 29 | 30 | output = model.get_output() 31 | 32 | from .my_new_model import model 33 | -------------------------------------------------------------------------------- /test/reference_results/03_UR_FR/modelInfo.dat: -------------------------------------------------------------------------------- 1 | FLEX_MODEL_INFO_FILE_V1.00 2 | "$(CASE_STUDIES)$" "/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/" relative path 3 | "$(CASE_STUDIES)$03_UR_FR/test.INF_DAT" inf_dat file (rel to case study path) 4 | "$(CASE_STUDIES)$03_UR_FR/M01_main.dat" flexConfig file 5 | "" fileNamePar (if blank uses parameters from flexConfig file) 6 | "$(CASE_STUDIES)$03_UR_FR/SuperflexRes.dat" fileNameOut (if blank if blank it no file is written) 7 | 2 parameter format (1:all, 2:fitted, 3:fitted matrix) 8 | 0, 0, 4 nX, nY, nS (0 if no output) 9 | 0 output X 10 | 0 output Y 11 | 1,4,5,6 output S 12 | -------------------------------------------------------------------------------- /test/reference_results/04_UR_FR_SR/modelInfo.dat: -------------------------------------------------------------------------------- 1 | FLEX_MODEL_INFO_FILE_V1.00 2 | "$(CASE_STUDIES)$" "/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/" relative path 3 | "$(CASE_STUDIES)$04_UR_FR_SR/test.INF_DAT" inf_dat file (rel to case study path) 4 | "$(CASE_STUDIES)$04_UR_FR_SR/M01_main.dat" flexConfig file 5 | "" fileNamePar (if blank uses parameters from flexConfig file) 6 | "$(CASE_STUDIES)$04_UR_FR_SR/SuperflexRes.dat" fileNameOut (if blank if blank it no file is written) 7 | 2 parameter format (1:all, 2:fitted, 3:fitted matrix) 8 | 0, 0, 5 nX, nY, nS (0 if no output) 9 | 0 output X 10 | 0 output Y 11 | 1,4,5,6,7 output S 12 | -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/modelInfo.dat: -------------------------------------------------------------------------------- 1 | FLEX_MODEL_INFO_FILE_V1.00 2 | "$(CASE_STUDIES)$" "/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/" relative path 3 | "$(CASE_STUDIES)$05_2HRUs/test.INF_DAT" inf_dat file (rel to case study path) 4 | "$(CASE_STUDIES)$05_2HRUs/M01_main.dat" flexConfig file 5 | "" fileNamePar (if blank uses parameters from flexConfig file) 6 | "$(CASE_STUDIES)$05_2HRUs/SuperflexRes.dat" fileNameOut (if blank if blank it no file is written) 7 | 2 parameter format (1:all, 2:fitted, 3:fitted matrix) 8 | 0, 0, 9 nX, nY, nS (0 if no output) 9 | 0 output X 10 | 0 output Y 11 | 1,2,4,5,6,8,9,10,11 output S 12 | -------------------------------------------------------------------------------- /test/reference_results/03_UR_FR/SuperflexRes.dat: -------------------------------------------------------------------------------- 1 | Data modelled by SF_ISO 2 | C1Wv%Qstream U1F1Wv%Eact U1F1Wv%Su[1] U1F1Wv%Sf[1] 3 | 4.97007353652108E-09 5.25897489318654E+00 4.83801524994899E+00 3.00985189439636E-03 4 | 2.54161857842611E-05 5.13069121339945E+00 3.81867710843760E+00 9.16313638205607E-02 5 | 2.53985771637753E-05 3.20271484273091E+00 6.15962265706688E-01 9.16059652433944E-02 6 | 6.96922155019536E-03 5.44391179630297E+00 7.59117398791786E+00 8.65513225179057E-01 7 | 8.25116717128249E-03 5.24240030717430E+00 4.68004604192831E+00 9.25989696823023E-01 8 | 9.54556012871506E-02 5.56619971715757E+00 1.17787920831172E+01 2.46558833718944E+00 9 | 1.25195491535853E-01 5.53231480170862E+00 1.02387514999080E+01 2.74811862715411E+00 10 | 1.20539093320577E-01 5.38642101274533E+00 6.47314118173772E+00 2.70676883925851E+00 11 | 1.08790010593421E-01 4.58674109340718E+00 1.88640008833054E+00 2.59797882866509E+00 12 | 1.95958638295427E+01 5.71330052925753E+00 3.20324916833237E+01 2.07427228748717E+01 13 | -------------------------------------------------------------------------------- /superflexpy/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | from . import framework, implementation, utils 27 | 28 | __all__ = ["framework", "implementation", "utils"] 29 | -------------------------------------------------------------------------------- /superflexpy/framework/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | from . import element, network, node, unit 27 | 28 | __all__ = ["element", "network", "node", "unit"] 29 | -------------------------------------------------------------------------------- /superflexpy/implementation/root_finders/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | from . import explicit, newton, pegasus 27 | 28 | __all__ = ["explicit", "newton", "pegasus"] 29 | -------------------------------------------------------------------------------- /superflexpy/implementation/models/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | from . import gr4j, hymod, m4_sf_2011, thur_M2 27 | 28 | __all__ = ["gr4j", "hymod", "m4_sf_2011", "thur_M2"] 29 | -------------------------------------------------------------------------------- /test/reference_results/01_FR/modelInfo.dat: -------------------------------------------------------------------------------- 1 | FLEX_MODEL_INFO_FILE_V1.00 2 | "$(CASE_STUDIES)$" "/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/" relative path 3 | "$(CASE_STUDIES)$01_FR/test.INF_DAT" inf_dat file (rel to case study path) 4 | "$(CASE_STUDIES)$01_FR/M01_main.dat" flexConfig file 5 | "" fileNamePar (if blank uses parameters from flexConfig file) 6 | "$(CASE_STUDIES)$01_FR/SuperflexRes.dat" fileNameOut (if blank if blank it no file is written) 7 | 2 parameter format (1:all, 2:fitted, 3:fitted matrix) 8 | 0, 0, 2 nX, nY, nS (0 if no output) 9 | 0 output X 10 | 0 output Y 11 | 1,5 output S 12 | -------------------------------------------------------------------------------- /test/reference_results/02_UR/modelInfo.dat: -------------------------------------------------------------------------------- 1 | FLEX_MODEL_INFO_FILE_V1.00 2 | "$(CASE_STUDIES)$" "/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/" relative path 3 | "$(CASE_STUDIES)$02_UR/test.INF_DAT" inf_dat file (rel to case study path) 4 | "$(CASE_STUDIES)$02_UR/M01_main.dat" flexConfig file 5 | "" fileNamePar (if blank uses parameters from flexConfig file) 6 | "$(CASE_STUDIES)$02_UR/SuperflexRes.dat" fileNameOut (if blank if blank it no file is written) 7 | 2 parameter format (1:all, 2:fitted, 3:fitted matrix) 8 | 0, 0, 3 nX, nY, nS (0 if no output) 9 | 0 output X 10 | 0 output Y 11 | 1,4,5 output S 12 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples of the usage of SuperflexPy 2 | 3 | This folder contains Jupyter notebooks with example models constructed using 4 | SuperflexPy. The examples can be visualized using GitHub or executed in a 5 | sandbox environment using [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/dalmo1991/superflexPy/master?filepath=examples) 6 | 7 | The examples are the following: 8 | 9 | - [Run a simple model](./01_run_simple_model.ipynb) 10 | - [Calibrate a model](./02_calibrate_a_model.ipynb) 11 | - [Initialize a single element model](./03_init_single_element_model.ipynb) 12 | - [Initialize a single unit model](./04_init_single_unit_model.ipynb) 13 | - [Initialize a simple node model](./05_init_single_node_model.ipynb) 14 | - [Initialize a complete (network) model](./06_init_complete_model.ipynb) 15 | - [Create a new reservoir](./07_create_reservoir.ipynb) 16 | - [Replicate GR4J](./08_GR4J.ipynb) 17 | - [Replicate Hymod](./09_Hymod.ipynb) 18 | - [Replicate M02 in Dal Molin et al., HESS, 2020](./10_Thur_M2.ipynb) 19 | - [Replicate M4 in Kavetski and Fenicia, WRR, 2011](./11_M4_sfPaper.ipynb) 20 | - [Modify M4 in Kavetski and Fenicia, WRR, 2011](./12_M4_sfPaper_changed.ipynb) 21 | -------------------------------------------------------------------------------- /superflexpy/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | from . import generic_component, numerical_approximator, root_finder 27 | 28 | __all__ = ["generic_component", "numerical_approximator", "root_finder"] 29 | -------------------------------------------------------------------------------- /test/reference_results/07_FR_2dt/modelInfo.dat: -------------------------------------------------------------------------------- 1 | FLEX_MODEL_INFO_FILE_V1.00 2 | "$(CASE_STUDIES)$" "/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/" relative path 3 | "$(CASE_STUDIES)$07_FR_2dt/test.INF_DAT" inf_dat file (rel to case study path) 4 | "$(CASE_STUDIES)$07_FR_2dt/M01_main.dat" flexConfig file 5 | "" fileNamePar (if blank uses parameters from flexConfig file) 6 | "$(CASE_STUDIES)$07_FR_2dt/SuperflexRes.dat" fileNameOut (if blank if blank it no file is written) 7 | 2 parameter format (1:all, 2:fitted, 3:fitted matrix) 8 | 0, 0, 2 nX, nY, nS (0 if no output) 9 | 0 output X 10 | 0 output Y 11 | 1,5 output S 12 | -------------------------------------------------------------------------------- /test/reference_results/08_UR_2dt/modelInfo.dat: -------------------------------------------------------------------------------- 1 | FLEX_MODEL_INFO_FILE_V1.00 2 | "$(CASE_STUDIES)$" "/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/" relative path 3 | "$(CASE_STUDIES)$08_UR_2dt/test.INF_DAT" inf_dat file (rel to case study path) 4 | "$(CASE_STUDIES)$08_UR_2dt/M01_main.dat" flexConfig file 5 | "" fileNamePar (if blank uses parameters from flexConfig file) 6 | "$(CASE_STUDIES)$08_UR_2dt/SuperflexRes.dat" fileNameOut (if blank if blank it no file is written) 7 | 2 parameter format (1:all, 2:fitted, 3:fitted matrix) 8 | 0, 0, 3 nX, nY, nS (0 if no output) 9 | 0 output X 10 | 0 output Y 11 | 1,4,5 output S 12 | -------------------------------------------------------------------------------- /test/reference_results/06_3Cats_2HRUs/modelInfo.dat: -------------------------------------------------------------------------------- 1 | FLEX_MODEL_INFO_FILE_V1.00 2 | "$(CASE_STUDIES)$" "/home/dalmo/Documents/BitBucket/superflexpy_aug2019/test/reference_results/" relative path 3 | "$(CASE_STUDIES)$06_3Cats_2HRUs/test.INF_DAT" inf_dat file (rel to case study path) 4 | "$(CASE_STUDIES)$06_3Cats_2HRUs/M01_main.dat" flexConfig file 5 | "" fileNamePar (if blank uses parameters from flexConfig file) 6 | "$(CASE_STUDIES)$06_3Cats_2HRUs/SuperflexRes.dat" fileNameOut (if blank if blank it no file is written) 7 | 2 parameter format (1:all, 2:fitted, 3:fitted matrix) 8 | 0, 0, 24 nX, nY, nS (0 if no output) 9 | 0 output X 10 | 0 output Y 11 | 1,2,3,4,7,8,11,12,15,16,18,19,20,21,22,24,25,26,27,28,30,31,32,33 output S 12 | -------------------------------------------------------------------------------- /superflexpy/implementation/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | from . import elements, models, numerical_approximators, root_finders 27 | 28 | __all__ = ["elements", "models", "numerical_approximators", "root_finders"] 29 | -------------------------------------------------------------------------------- /superflexpy/implementation/numerical_approximators/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | from . import explicit_euler, implicit_euler, runge_kutta_4 27 | 28 | __all__ = ["explicit_euler", "implicit_euler", "runge_kutta_4"] 29 | -------------------------------------------------------------------------------- /superflexpy/implementation/elements/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | from . import gr4j, hbv, hymod, structure_elements, thur_model_hess 27 | 28 | __all__ = ["gr4j", "hbv", "hymod", "structure_elements", "thur_model_hess"] 29 | -------------------------------------------------------------------------------- /test/reference_results/01_FR/test.INF_DAT: -------------------------------------------------------------------------------- 1 | DATA_SPEX_FILE_V1.3 2 | "Lacmalac data" ! file comment (not used) 3 | "$(CASE_STUDIES)$01_FR/input.dat" ! observation file 4 | 5 | 0 ! file format (unsupported), 0=standard 6 | 5 ! number of header lines to skip to format specification 7 | 7 ! number of header lines to the data cols 8 | 9 | 9 ! number of data columns in observation data file 10 | 11 | 2,1 ! number of columns for inputs (X) and others (Y) 12 | 7,8 ! column indices of observed input data 13 | 9 ! column indices of observed other data 14 | 15 | 1.e0,1.e0 ! conversion factors for input data 16 | 1.e0 ! conversion factors for other data 17 | 18 | 0 ! number of quality code columns (ie, number of distinct values on the next line) 19 | 0 ! indxQC: quality code columns for all data 20 | 0,0 ! quality code columns for observed input data (relative to indxQC) 21 | 0 ! quality code columns for observed other data (relative to indxQC) 22 | 23 | 1, 1, 10 ! iStartWarmInfern, iStartInfern, iEndInfern 1, 27, 679 / 1, 680, 1331 / 1, 27, 353 / 1, 27, 1331 / 1, 27, 6549 24 | -------------------------------------------------------------------------------- /test/reference_results/02_UR/test.INF_DAT: -------------------------------------------------------------------------------- 1 | DATA_SPEX_FILE_V1.3 2 | "Lacmalac data" ! file comment (not used) 3 | "$(CASE_STUDIES)$02_UR/input.dat" ! observation file 4 | 5 | 0 ! file format (unsupported), 0=standard 6 | 5 ! number of header lines to skip to format specification 7 | 7 ! number of header lines to the data cols 8 | 9 | 9 ! number of data columns in observation data file 10 | 11 | 2,1 ! number of columns for inputs (X) and others (Y) 12 | 7,8 ! column indices of observed input data 13 | 9 ! column indices of observed other data 14 | 15 | 1.e0,1.e0 ! conversion factors for input data 16 | 1.e0 ! conversion factors for other data 17 | 18 | 0 ! number of quality code columns (ie, number of distinct values on the next line) 19 | 0 ! indxQC: quality code columns for all data 20 | 0,0 ! quality code columns for observed input data (relative to indxQC) 21 | 0 ! quality code columns for observed other data (relative to indxQC) 22 | 23 | 1, 1, 10 ! iStartWarmInfern, iStartInfern, iEndInfern 1, 27, 679 / 1, 680, 1331 / 1, 27, 353 / 1, 27, 1331 / 1, 27, 6549 24 | -------------------------------------------------------------------------------- /test/reference_results/03_UR_FR/test.INF_DAT: -------------------------------------------------------------------------------- 1 | DATA_SPEX_FILE_V1.3 2 | "Lacmalac data" ! file comment (not used) 3 | "$(CASE_STUDIES)$03_UR_FR/input.dat" ! observation file 4 | 5 | 0 ! file format (unsupported), 0=standard 6 | 5 ! number of header lines to skip to format specification 7 | 7 ! number of header lines to the data cols 8 | 9 | 9 ! number of data columns in observation data file 10 | 11 | 2,1 ! number of columns for inputs (X) and others (Y) 12 | 7,8 ! column indices of observed input data 13 | 9 ! column indices of observed other data 14 | 15 | 1.e0,1.e0 ! conversion factors for input data 16 | 1.e0 ! conversion factors for other data 17 | 18 | 0 ! number of quality code columns (ie, number of distinct values on the next line) 19 | 0 ! indxQC: quality code columns for all data 20 | 0,0 ! quality code columns for observed input data (relative to indxQC) 21 | 0 ! quality code columns for observed other data (relative to indxQC) 22 | 23 | 1, 1, 10 ! iStartWarmInfern, iStartInfern, iEndInfern 1, 27, 679 / 1, 680, 1331 / 1, 27, 353 / 1, 27, 1331 / 1, 27, 6549 24 | -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/test.INF_DAT: -------------------------------------------------------------------------------- 1 | DATA_SPEX_FILE_V1.3 2 | "Lacmalac data" ! file comment (not used) 3 | "$(CASE_STUDIES)$05_2HRUs/input.dat" ! observation file 4 | 5 | 0 ! file format (unsupported), 0=standard 6 | 5 ! number of header lines to skip to format specification 7 | 7 ! number of header lines to the data cols 8 | 9 | 9 ! number of data columns in observation data file 10 | 11 | 2,1 ! number of columns for inputs (X) and others (Y) 12 | 7,8 ! column indices of observed input data 13 | 9 ! column indices of observed other data 14 | 15 | 1.e0,1.e0 ! conversion factors for input data 16 | 1.e0 ! conversion factors for other data 17 | 18 | 0 ! number of quality code columns (ie, number of distinct values on the next line) 19 | 0 ! indxQC: quality code columns for all data 20 | 0,0 ! quality code columns for observed input data (relative to indxQC) 21 | 0 ! quality code columns for observed other data (relative to indxQC) 22 | 23 | 1, 1, 10 ! iStartWarmInfern, iStartInfern, iEndInfern 1, 27, 679 / 1, 680, 1331 / 1, 27, 353 / 1, 27, 1331 / 1, 27, 6549 24 | -------------------------------------------------------------------------------- /test/reference_results/07_FR_2dt/test.INF_DAT: -------------------------------------------------------------------------------- 1 | DATA_SPEX_FILE_V1.3 2 | "Lacmalac data" ! file comment (not used) 3 | "$(CASE_STUDIES)$07_FR_2dt/input.dat" ! observation file 4 | 5 | 0 ! file format (unsupported), 0=standard 6 | 5 ! number of header lines to skip to format specification 7 | 7 ! number of header lines to the data cols 8 | 9 | 9 ! number of data columns in observation data file 10 | 11 | 2,1 ! number of columns for inputs (X) and others (Y) 12 | 7,8 ! column indices of observed input data 13 | 9 ! column indices of observed other data 14 | 15 | 1.e0,1.e0 ! conversion factors for input data 16 | 1.e0 ! conversion factors for other data 17 | 18 | 0 ! number of quality code columns (ie, number of distinct values on the next line) 19 | 0 ! indxQC: quality code columns for all data 20 | 0,0 ! quality code columns for observed input data (relative to indxQC) 21 | 0 ! quality code columns for observed other data (relative to indxQC) 22 | 23 | 1, 1, 10 ! iStartWarmInfern, iStartInfern, iEndInfern 1, 27, 679 / 1, 680, 1331 / 1, 27, 353 / 1, 27, 1331 / 1, 27, 6549 24 | -------------------------------------------------------------------------------- /test/reference_results/08_UR_2dt/test.INF_DAT: -------------------------------------------------------------------------------- 1 | DATA_SPEX_FILE_V1.3 2 | "Lacmalac data" ! file comment (not used) 3 | "$(CASE_STUDIES)$08_UR_2dt/input.dat" ! observation file 4 | 5 | 0 ! file format (unsupported), 0=standard 6 | 5 ! number of header lines to skip to format specification 7 | 7 ! number of header lines to the data cols 8 | 9 | 9 ! number of data columns in observation data file 10 | 11 | 2,1 ! number of columns for inputs (X) and others (Y) 12 | 7,8 ! column indices of observed input data 13 | 9 ! column indices of observed other data 14 | 15 | 1.e0,1.e0 ! conversion factors for input data 16 | 1.e0 ! conversion factors for other data 17 | 18 | 0 ! number of quality code columns (ie, number of distinct values on the next line) 19 | 0 ! indxQC: quality code columns for all data 20 | 0,0 ! quality code columns for observed input data (relative to indxQC) 21 | 0 ! quality code columns for observed other data (relative to indxQC) 22 | 23 | 1, 1, 10 ! iStartWarmInfern, iStartInfern, iEndInfern 1, 27, 679 / 1, 680, 1331 / 1, 27, 353 / 1, 27, 1331 / 1, 27, 6549 24 | -------------------------------------------------------------------------------- /test/reference_results/04_UR_FR_SR/test.INF_DAT: -------------------------------------------------------------------------------- 1 | DATA_SPEX_FILE_V1.3 2 | "Lacmalac data" ! file comment (not used) 3 | "$(CASE_STUDIES)$04_UR_FR_SR/input.dat" ! observation file 4 | 5 | 0 ! file format (unsupported), 0=standard 6 | 5 ! number of header lines to skip to format specification 7 | 7 ! number of header lines to the data cols 8 | 9 | 9 ! number of data columns in observation data file 10 | 11 | 2,1 ! number of columns for inputs (X) and others (Y) 12 | 7,8 ! column indices of observed input data 13 | 9 ! column indices of observed other data 14 | 15 | 1.e0,1.e0 ! conversion factors for input data 16 | 1.e0 ! conversion factors for other data 17 | 18 | 0 ! number of quality code columns (ie, number of distinct values on the next line) 19 | 0 ! indxQC: quality code columns for all data 20 | 0,0 ! quality code columns for observed input data (relative to indxQC) 21 | 0 ! quality code columns for observed other data (relative to indxQC) 22 | 23 | 1, 1, 10 ! iStartWarmInfern, iStartInfern, iEndInfern 1, 27, 679 / 1, 680, 1331 / 1, 27, 353 / 1, 27, 1331 / 1, 27, 6549 24 | -------------------------------------------------------------------------------- /doc/numerical_solver_code.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code contains a quick example to implement the nomerical approximator 3 | and the root finder. The only purpose of this code is being put in the 4 | documentation. 5 | """ 6 | 7 | from ...superflexpy.utils.numerical_approximator import NumericalApproximator 8 | from ...superflexpy.utils.root_finder import RootFinder 9 | 10 | 11 | class CustomRootFinder(RootFinder): 12 | def solve(self, diff_eq_fun, fluxes_fun, S0, dt, ind, args): 13 | # Some code here 14 | 15 | return root 16 | 17 | 18 | class CustomNumericalApproximator(NumericalApproximator): 19 | @staticmethod 20 | def _get_fluxes(fluxes_fun, S, S0, args, dt): 21 | # Some code here 22 | 23 | return fluxes 24 | 25 | @staticmethod 26 | def _differential_equation(fluxes_fun, S, S0, dt, args, ind): 27 | # Some code here 28 | 29 | return [diff_eq, min_val, max_val, d_diff_eq] 30 | 31 | 32 | class CustomODESolver: 33 | # The class may implement other methods 34 | 35 | def solve(self, fluxes_fun, S0, dt, args): 36 | # Some code here 37 | 38 | return states 39 | 40 | def get_fluxes(self, fluxes_fun, S, S0, dt, args): 41 | # Some code here 42 | 43 | return fluxes 44 | -------------------------------------------------------------------------------- /test/reference_results/06_3Cats_2HRUs/test.INF_DAT: -------------------------------------------------------------------------------- 1 | DATA_SPEX_FILE_V1.3 2 | "Lacmalac data" ! file comment (not used) 3 | "$(CASE_STUDIES)$06_3Cats_2HRUs/input.dat" ! observation file 4 | 5 | 0 ! file format (unsupported), 0=standard 6 | 5 ! number of header lines to skip to format specification 7 | 7 ! number of header lines to the data cols 8 | 9 | 17 ! number of data columns in observation data file 10 | 11 | 6,3 ! number of columns for inputs (X) and others (Y) 12 | 6,7,8,9,10,11 ! column indices of observed input data 13 | 12,14,16 ! column indices of observed other data 14 | 15 | 1.e0,1.e0,1.e0,1.e0,1.e0,1.e0 ! conversion factors for input data 16 | 1.e0,1.e0,1.e0 ! conversion factors for other data 17 | 18 | 0 ! number of quality code columns (ie, number of distinct values on the next line) 19 | 0 ! indxQC: quality code columns for all data 20 | 0,0 ! quality code columns for observed input data (relative to indxQC) 21 | 0 ! quality code columns for observed other data (relative to indxQC) 22 | 23 | 1, 1, 10 ! iStartWarmInfern, iStartInfern, iEndInfern 1, 27, 679 / 1, 680, 1331 / 1, 27, 353 / 1, 27, 1331 / 1, 27, 6549 24 | -------------------------------------------------------------------------------- /test/reference_results/04_UR_FR_SR/Results.csv: -------------------------------------------------------------------------------- 1 | # Q_out, E_UR, S_UR, S_FR, S_SR 2 | 2.109139143916991476e-07,5.258974893186536548e+00,4.838015249948993457e+00,9.029568143400985066e-04,2.106689136215304358e-03 3 | 7.668930222361160562e-06,5.130691213399449779e+00,3.818677108437596335e+00,2.749578163005263545e-02,6.415312350222930615e-02 4 | 7.668145885635599773e-06,3.202714842730908007e+00,6.159622657066883278e-01,2.749452815505013317e-02,6.414670883134616919e-02 5 | 4.104495408040214244e-04,5.443911796302973727e+00,7.591173987917855470e+00,2.614080929775984830e-01,6.106991759538503706e-01 6 | 4.867007414670093310e-04,5.242400307174300167e+00,4.680046041928307865e+00,2.816055581455917389e-01,6.587426488596379581e-01 7 | 5.331958260418389467e-03,5.566199717157565452e+00,1.177879208311717996e+01,7.669701824120410683e-01,1.803100307986333251e+00 8 | 7.514327856159554175e-03,5.532314801708615448e+00,1.023875149990803024e+01,8.819824189585497853e-01,2.088299525084197583e+00 9 | 7.858097956005493170e-03,5.386421012745326919e+00,6.473141181737718242e+00,8.980954643987495434e-01,2.143517687112975523e+00 10 | 7.699797584115572295e-03,4.586741093407180614e+00,1.886400088330537628e+00,8.906099971503117496e-01,2.143303356777297886e+00 11 | 2.755480883685404336e+00,5.713300529257533178e+00,3.203249168332367702e+01,9.460167363487958170e+00,2.855887298250357631e+01 12 | -------------------------------------------------------------------------------- /test/reference_results/04_UR_FR_SR/SuperflexRes.dat: -------------------------------------------------------------------------------- 1 | Data modelled by SF_ISO 2 | C1Wv%Qstream U1F1Wv%Eact U1F1Wv%Su[1] U1F1Wv%Sf[1] U1F1Wv%Ss[1] 3 | 2.10913914391699E-07 5.25897489318654E+00 4.83801524994899E+00 9.02956814340099E-04 2.10668913621530E-03 4 | 7.66893022236116E-06 5.13069121339945E+00 3.81867710843760E+00 2.74957816300526E-02 6.41531235022293E-02 5 | 7.66814588563560E-06 3.20271484273091E+00 6.15962265706688E-01 2.74945281550501E-02 6.41467088313462E-02 6 | 4.10449540804021E-04 5.44391179630297E+00 7.59117398791786E+00 2.61408092977598E-01 6.10699175953850E-01 7 | 4.86700741467009E-04 5.24240030717430E+00 4.68004604192831E+00 2.81605558145592E-01 6.58742648859638E-01 8 | 5.33195826041839E-03 5.56619971715757E+00 1.17787920831172E+01 7.66970182412041E-01 1.80310030798633E+00 9 | 7.51432785615955E-03 5.53231480170862E+00 1.02387514999080E+01 8.81982418958550E-01 2.08829952508420E+00 10 | 7.85809795600549E-03 5.38642101274533E+00 6.47314118173772E+00 8.98095464398750E-01 2.14351768711298E+00 11 | 7.69979758411557E-03 4.58674109340718E+00 1.88640008833054E+00 8.90609997150312E-01 2.14330335677730E+00 12 | 2.75548088368540E+00 5.71330052925753E+00 3.20324916833237E+01 9.46016736348796E+00 2.85588729825036E+01 13 | -------------------------------------------------------------------------------- /test/reference_results/01_FR/input.dat: -------------------------------------------------------------------------------- 1 | Maimai data courtesy Jeff McDonnell 2 | 1.0 ! stepsize (d) 3 | ST1: All data in mm/d 4 | ST2 5 | ST3 6 | * ! list directed format ok here 7 | year, month, day, hour, min, QC, P (mm/d), E (mm/d), Q_obs (mm/d) 8 | 1985 1 2 0 0 0 1.000000e-001 0.000000e+000 2.646000e-001 9 | 1985 1 3 0 0 0 4.200000e+000 0.000000e+000 4.426105e-001 10 | 1985 1 4 0 0 0 0.000000e+000 0.000000e+000 3.278842e-001 11 | 1985 1 5 0 0 0 1.320000e+001 0.000000e+000 5.415158e-001 12 | 1985 1 6 0 0 0 2.400000e+000 0.000000e+000 6.209053e-001 13 | 1985 1 7 0 0 0 1.430000e+001 0.000000e+000 1.255737e+000 14 | 1985 1 8 0 0 0 4.400000e+000 0.000000e+000 7.436842e-001 15 | 1985 1 9 0 0 0 1.700000e+000 0.000000e+000 4.998316e-001 16 | 1985 1 10 0 0 0 0.000000e+000 0.000000e+000 2.404421e-001 17 | 1985 1 11 0 0 0 7.360000e+001 0.000000e+000 2.727445e+001 18 | -------------------------------------------------------------------------------- /test/reference_results/02_UR/input.dat: -------------------------------------------------------------------------------- 1 | Maimai data courtesy Jeff McDonnell 2 | 1.0 ! stepsize (d) 3 | ST1: All data in mm/d 4 | ST2 5 | ST3 6 | * ! list directed format ok here 7 | year, month, day, hour, min, QC, P (mm/d), E (mm/d), Q_obs (mm/d) 8 | 1985 1 2 0 0 0 1.000000e-001 3.830020e+000 2.646000e-001 9 | 1985 1 3 0 0 0 4.200000e+000 3.830020e+000 4.426105e-001 10 | 1985 1 4 0 0 0 0.000000e+000 3.830020e+000 3.278842e-001 11 | 1985 1 5 0 0 0 1.320000e+001 3.830020e+000 5.415158e-001 12 | 1985 1 6 0 0 0 2.400000e+000 3.830020e+000 6.209053e-001 13 | 1985 1 7 0 0 0 1.430000e+001 3.830020e+000 1.255737e+000 14 | 1985 1 8 0 0 0 4.400000e+000 3.830020e+000 7.436842e-001 15 | 1985 1 9 0 0 0 1.700000e+000 3.830020e+000 4.998316e-001 16 | 1985 1 10 0 0 0 0.000000e+000 3.830020e+000 2.404421e-001 17 | 1985 1 11 0 0 0 7.360000e+001 3.830020e+000 2.727445e+001 18 | -------------------------------------------------------------------------------- /test/reference_results/03_UR_FR/input.dat: -------------------------------------------------------------------------------- 1 | Maimai data courtesy Jeff McDonnell 2 | 1.0 ! stepsize (d) 3 | ST1: All data in mm/d 4 | ST2 5 | ST3 6 | * ! list directed format ok here 7 | year, month, day, hour, min, QC, P (mm/d), E (mm/d), Q_obs (mm/d) 8 | 1985 1 2 0 0 0 1.000000e-001 3.830020e+000 2.646000e-001 9 | 1985 1 3 0 0 0 4.200000e+000 3.830020e+000 4.426105e-001 10 | 1985 1 4 0 0 0 0.000000e+000 3.830020e+000 3.278842e-001 11 | 1985 1 5 0 0 0 1.320000e+001 3.830020e+000 5.415158e-001 12 | 1985 1 6 0 0 0 2.400000e+000 3.830020e+000 6.209053e-001 13 | 1985 1 7 0 0 0 1.430000e+001 3.830020e+000 1.255737e+000 14 | 1985 1 8 0 0 0 4.400000e+000 3.830020e+000 7.436842e-001 15 | 1985 1 9 0 0 0 1.700000e+000 3.830020e+000 4.998316e-001 16 | 1985 1 10 0 0 0 0.000000e+000 3.830020e+000 2.404421e-001 17 | 1985 1 11 0 0 0 7.360000e+001 3.830020e+000 2.727445e+001 18 | -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/input.dat: -------------------------------------------------------------------------------- 1 | Maimai data courtesy Jeff McDonnell 2 | 1.0 ! stepsize (d) 3 | ST1: All data in mm/d 4 | ST2 5 | ST3 6 | * ! list directed format ok here 7 | year, month, day, hour, min, QC, P (mm/d), E (mm/d), Q_obs (mm/d) 8 | 1985 1 2 0 0 0 1.000000e-001 3.830020e+000 2.646000e-001 9 | 1985 1 3 0 0 0 4.200000e+000 3.830020e+000 4.426105e-001 10 | 1985 1 4 0 0 0 0.000000e+000 3.830020e+000 3.278842e-001 11 | 1985 1 5 0 0 0 1.320000e+001 3.830020e+000 5.415158e-001 12 | 1985 1 6 0 0 0 2.400000e+000 3.830020e+000 6.209053e-001 13 | 1985 1 7 0 0 0 1.430000e+001 3.830020e+000 1.255737e+000 14 | 1985 1 8 0 0 0 4.400000e+000 3.830020e+000 7.436842e-001 15 | 1985 1 9 0 0 0 1.700000e+000 3.830020e+000 4.998316e-001 16 | 1985 1 10 0 0 0 0.000000e+000 3.830020e+000 2.404421e-001 17 | 1985 1 11 0 0 0 7.360000e+001 3.830020e+000 2.727445e+001 18 | -------------------------------------------------------------------------------- /test/reference_results/07_FR_2dt/input.dat: -------------------------------------------------------------------------------- 1 | Maimai data courtesy Jeff McDonnell 2 | 2.0 ! stepsize (d) 3 | ST1: All data in mm/d 4 | ST2 5 | ST3 6 | * ! list directed format ok here 7 | year, month, day, hour, min, QC, P (mm/d), E (mm/d), Q_obs (mm/d) 8 | 1985 1 2 0 0 0 1.000000e-001 0.000000e+000 2.646000e-001 9 | 1985 1 3 0 0 0 4.200000e+000 0.000000e+000 4.426105e-001 10 | 1985 1 4 0 0 0 0.000000e+000 0.000000e+000 3.278842e-001 11 | 1985 1 5 0 0 0 1.320000e+001 0.000000e+000 5.415158e-001 12 | 1985 1 6 0 0 0 2.400000e+000 0.000000e+000 6.209053e-001 13 | 1985 1 7 0 0 0 1.430000e+001 0.000000e+000 1.255737e+000 14 | 1985 1 8 0 0 0 4.400000e+000 0.000000e+000 7.436842e-001 15 | 1985 1 9 0 0 0 1.700000e+000 0.000000e+000 4.998316e-001 16 | 1985 1 10 0 0 0 0.000000e+000 0.000000e+000 2.404421e-001 17 | 1985 1 11 0 0 0 7.360000e+001 0.000000e+000 2.727445e+001 18 | -------------------------------------------------------------------------------- /test/reference_results/08_UR_2dt/input.dat: -------------------------------------------------------------------------------- 1 | Maimai data courtesy Jeff McDonnell 2 | 2.0 ! stepsize (d) 3 | ST1: All data in mm/d 4 | ST2 5 | ST3 6 | * ! list directed format ok here 7 | year, month, day, hour, min, QC, P (mm/d), E (mm/d), Q_obs (mm/d) 8 | 1985 1 2 0 0 0 1.000000e-001 3.830020e+000 2.646000e-001 9 | 1985 1 3 0 0 0 4.200000e+000 3.830020e+000 4.426105e-001 10 | 1985 1 4 0 0 0 0.000000e+000 3.830020e+000 3.278842e-001 11 | 1985 1 5 0 0 0 1.320000e+001 3.830020e+000 5.415158e-001 12 | 1985 1 6 0 0 0 2.400000e+000 3.830020e+000 6.209053e-001 13 | 1985 1 7 0 0 0 1.430000e+001 3.830020e+000 1.255737e+000 14 | 1985 1 8 0 0 0 4.400000e+000 3.830020e+000 7.436842e-001 15 | 1985 1 9 0 0 0 1.700000e+000 3.830020e+000 4.998316e-001 16 | 1985 1 10 0 0 0 0.000000e+000 3.830020e+000 2.404421e-001 17 | 1985 1 11 0 0 0 7.360000e+001 3.830020e+000 2.727445e+001 18 | -------------------------------------------------------------------------------- /test/reference_results/04_UR_FR_SR/input.dat: -------------------------------------------------------------------------------- 1 | Maimai data courtesy Jeff McDonnell 2 | 1.0 ! stepsize (d) 3 | ST1: All data in mm/d 4 | ST2 5 | ST3 6 | * ! list directed format ok here 7 | year, month, day, hour, min, QC, P (mm/d), E (mm/d), Q_obs (mm/d) 8 | 1985 1 2 0 0 0 1.000000e-001 3.830020e+000 2.646000e-001 9 | 1985 1 3 0 0 0 4.200000e+000 3.830020e+000 4.426105e-001 10 | 1985 1 4 0 0 0 0.000000e+000 3.830020e+000 3.278842e-001 11 | 1985 1 5 0 0 0 1.320000e+001 3.830020e+000 5.415158e-001 12 | 1985 1 6 0 0 0 2.400000e+000 3.830020e+000 6.209053e-001 13 | 1985 1 7 0 0 0 1.430000e+001 3.830020e+000 1.255737e+000 14 | 1985 1 8 0 0 0 4.400000e+000 3.830020e+000 7.436842e-001 15 | 1985 1 9 0 0 0 1.700000e+000 3.830020e+000 4.998316e-001 16 | 1985 1 10 0 0 0 0.000000e+000 3.830020e+000 2.404421e-001 17 | 1985 1 11 0 0 0 7.360000e+001 3.830020e+000 2.727445e+001 18 | -------------------------------------------------------------------------------- /doc/installation.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 03/05/2021 2 | 3 | .. .. warning:: This guide is still work in progress. New pages are being written 4 | .. and existing ones modified. Once the guide will reach its final 5 | .. version, this box will disappear. 6 | 7 | .. _installation_label: 8 | 9 | Installation 10 | ============ 11 | 12 | SuperflexPy is implemented using Python 3 (version 3.7.3). It is not compatible 13 | with Python 2. 14 | 15 | SuperflexPy is available as a Python package at 16 | `PyPI repository `_ 17 | 18 | The simplest way to install SuperflexPy is to use the package installer for 19 | Python (pip). Open the operating system command prompt and run the command 20 | 21 | .. code-block:: bash 22 | 23 | pip install superflexpy 24 | 25 | To upgrade to a newer SuperflexPy version (when available), run the following command 26 | 27 | .. code-block:: bash 28 | 29 | pip install --upgrade superflexpy 30 | 31 | Dependencies 32 | ------------ 33 | 34 | SuperflexPy requires the following Python packages 35 | 36 | - `Numpy `_ 37 | - `Numba `_ 38 | 39 | All dependencies are available through pip and will be installed automatically 40 | when installing SuperflexPy. 41 | 42 | Note that Numba is required only if the modeler wishes to use the Numba 43 | optimized implementation of the numerical solvers. GPU acceleration (CUDA) is 44 | currently not supported but will be explored in future versions. 45 | -------------------------------------------------------------------------------- /doc/sfpy_in_literature.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 09/08/2022 2 | 3 | .. _sfpy_lit: 4 | 5 | SuperflexPy in the scientific literature 6 | ======================================== 7 | 8 | This page lists the scientific publications presenting SuperflexPy or using it 9 | in specific applications. 10 | 11 | .. tip:: 12 | If you use SuperflexPy for your publication, please `open an issue `_ in the GitHub 13 | repository so we will add it to this page. 14 | 15 | Previous publications on FLEX and Superflex 16 | ------------------------------------------- 17 | 18 | - Fenicia, F., Savenije, H. H. G.,Matgen, P., and Pfister, L.: **Understanding catchment behavior through stepwise model concept improvement**, Water Resources Research, 44, W01402, https://doi.org/10.1029/2006WR005563, 2008. 19 | - Fenicia, F., Kavetski D., and Savenije H. H. G.: **Elements of a flexible approach for conceptual hydrological modeling: 1. Motivation and theoretical development**, Water Resources Research, 47(11), W11510, https://doi.org/10.1029/2010wr010174, 2011 20 | - Kavetski, D., and Fenicia F.: **Elements of a flexible approach for conceptual hydrological modeling: 2. Application and experimental insights**, Water Resources Research, 47(11), W11511, https://doi.org/10.1029/2011wr010748, 2011 21 | 22 | Publications on SuperflexPy 23 | --------------------------- 24 | 25 | - Dal Molin, M., Kavetski, D., and Fenicia, F.: **SuperflexPy 1.3.0: an open** 26 | **source framework for building, testing and improving conceptual** 27 | **hydrological models**, Geosci. Model Dev., https://doi.org/10.5194/gmd-14-7047-2021, 2021. 28 | 29 | Publications using SuperflexPy 30 | ------------------------------ 31 | 32 | - Jansen, K. F., Teuling, A.J., Craig, J. R., Dal Molin, M., Knoben, W. J. M., 33 | Parajka, J., Vis, M., and Melsen, L. A.: **Mimicry of a conceptual** 34 | **hydrological model (HBV): what's in a name?**, Water Resources Research, 57, 35 | e2020WR029143. https://doi.org/10.1029/2020WR029143, 2020. 36 | -------------------------------------------------------------------------------- /doc/testing.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 04/05/2021 2 | 3 | .. _tests: 4 | 5 | Automated testing 6 | ================= 7 | 8 | Current testing of SuperflexPy consists of validating its numerical results 9 | against the original implementation of 10 | `Superflex `_. This testing is done for 11 | selected model configurations and selected sets of parameters and inputs. 12 | 13 | This testing strategy implicitly checks auxiliary methods, including setting 14 | parameters and states, retrieving the internal fluxes of the model, setting 15 | inputs and getting outputs, etc.. 16 | 17 | The testing code is contained in folder :code:`test` and uses the Python module 18 | :code:`unittest`. The folder contains :code:`reference_results` 19 | and :code:`unittest` containing the scripts that run the tests. 20 | 21 | Current testing covers: 22 | 23 | - Specific elements (reservoirs and lag functions) that 24 | are implemented in Superflex (e.g. :code:`01_FR.py`, :code:`02_UR.py`); 25 | - Multiple elements in a unit (e.g. 26 | :code:`03_UR_FR.py`, :code:`04_UR_FR_SR.py`); 27 | - Multiple units in a node (e.g. :code:`05_2HRUs.py`); 28 | - Multiple nodes inside a network (e.g. 29 | :code:`06_3Cats_2HRUs.py`); 30 | - Auxiliary methods, which are tested implicitly, i.e. assuming that 31 | errors in the auxiliary methods propagate to the results. 32 | 33 | Current testing does not cover: 34 | 35 | - Elements for which numerical results are not available (e.g. some components 36 | of GR4J); 37 | - Usage of the Explicit Euler solver; 38 | - Edge cases (e.g. extreme values of parameters and states) 39 | 40 | Users contributing SuperflexPy extensions should provide reference 41 | results and the code that tests them (including input data and model parameter 42 | values). 43 | 44 | As the SuperflexPy framework continues to develop, additional facilities for 45 | unit-testing and integrated-testing will be employed. 46 | 47 | Automation 48 | ---------- 49 | 50 | Any push of new code to any branch on the github repository will trigger 51 | automatic testing based on the scripts contained in the folder 52 | :code:`test/unittest`. 53 | -------------------------------------------------------------------------------- /doc/customize_components_code.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from superflexpy.framework.node import Node 4 | 5 | 6 | class RoutedNone(Node): 7 | """ 8 | Node class with parameters 't_internal' and 't_external' that implements 9 | internal and external routing using a triangular lag (symmentric) with 10 | base t_internal and t_external respectively. Settng the value lower to 1 11 | means no lag. 12 | """ 13 | 14 | def _internal_routing(self, flux): 15 | t_internal = self.get_parameters(names=[self._prefix_local_parameters + "t_internal"]) 16 | flux_out = [] 17 | 18 | for f in flux: 19 | flux_out.append(self._route(f, t_internal)) 20 | 21 | return flux_out 22 | 23 | def external_routing(self, flux): 24 | t_external = self.get_parameters(names=[self._prefix_local_parameters + "t_external"]) 25 | flux_out = [] 26 | 27 | for f in flux: 28 | flux_out.append(self._route(f, t_external)) 29 | 30 | return flux_out 31 | 32 | def _route(self, flux, time): 33 | state = np.zeros(int(np.ceil(time))) 34 | weight = self._calculate_weight(time) 35 | 36 | out = [] 37 | for value in flux: 38 | state = state + weight * value 39 | out.append(state[0]) 40 | state[0] = 0 41 | state = np.roll(state, shift=-1) 42 | 43 | return np.array(out) 44 | 45 | def _calculate_weight(self, time): 46 | weight = [] 47 | 48 | array_length = np.ceil(time) 49 | 50 | for i in range(int(array_length)): 51 | weight.append(self._calculate_lag_area(i + 1, time) - self._calculate_lag_area(i, time)) 52 | 53 | return weight 54 | 55 | @staticmethod 56 | def _calculate_lag_area(portion, time): 57 | half_time = time / 2 58 | 59 | if portion <= 0: 60 | value = 0 61 | elif portion < half_time: 62 | value = 2 * (portion / time) ** 2 63 | elif portion < time: 64 | value = 1 - 2 * ((time - portion) / time) ** 2 65 | else: 66 | value = 1 67 | 68 | return value 69 | -------------------------------------------------------------------------------- /superflexpy/implementation/models/m4_sf_2011.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | 25 | This file implements the model M4 presented in Kavetsi and Fenicia, 2011. 26 | 27 | Reference 28 | --------- 29 | 30 | Kavetski, D., and F. Fenicia (2011), Elements of a flexible approach 31 | for conceptual hydrological modeling: 2. Application and experimental insights, 32 | Water Resour. Res., 47, W11511, doi:10.1029/2011WR010748 33 | """ 34 | 35 | from superflexpy.framework.unit import Unit 36 | from superflexpy.implementation.elements.hbv import PowerReservoir, UnsaturatedReservoir 37 | from superflexpy.implementation.numerical_approximators.implicit_euler import ( 38 | ImplicitEulerPython, 39 | ) 40 | from superflexpy.implementation.root_finders.pegasus import PegasusPython 41 | 42 | root_finder = PegasusPython() 43 | numeric_approximator = ImplicitEulerPython(root_finder=root_finder) 44 | 45 | ur = UnsaturatedReservoir( 46 | parameters={"Smax": 50.0, "Ce": 1.0, "m": 0.01, "beta": 2.0}, 47 | states={"S0": 25.0}, 48 | approximation=numeric_approximator, 49 | id="UR", 50 | ) 51 | 52 | fr = PowerReservoir( 53 | parameters={"k": 0.1, "alpha": 1.0}, states={"S0": 10.0}, approximation=numeric_approximator, id="FR" 54 | ) 55 | 56 | model = Unit(layers=[[ur], [fr]], id="M4") 57 | -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/Results.csv: -------------------------------------------------------------------------------- 1 | # Q_tot, Q_H1, E_FR_H1, S_FR_H1, Q_H2, E_UR_H2, S_UR_H2, S_FR_H2, S_SR_H2 2 | 1.276566925472585057e-05,3.159780226522707953e-05,0.000000000000000000e+00,9.996840219773421576e-02,2.109139143916991476e-07,5.258974893186536548e+00,4.838015249948993457e+00,9.029568143400985066e-04,2.106689136215304358e-03 3 | 1.266726459154998430e-01,3.166701113934160539e-01,0.000000000000000000e+00,3.983298290804318409e+00,7.668930222361160562e-06,5.130691213399449779e+00,3.818677108437596335e+00,2.749578163005263545e-02,6.415312350222930615e-02 4 | 1.065474297827361805e-01,2.663570722380119715e-01,0.000000000000000000e+00,3.716941218566306659e+00,7.668145885635599773e-06,3.202714842730908007e+00,6.159622657066883278e-01,2.749452815505013317e-02,6.414670883134616919e-02 5 | 1.981036826683929997e+00,4.951976392398618643e+00,0.000000000000000000e+00,1.196496482616768731e+01,4.104495408040214244e-04,5.443911796302973727e+00,7.591173987917855470e+00,2.614080929775984830e-01,6.106991759538503706e-01 6 | 1.483389933158973051e+00,3.707744781785232480e+00,0.000000000000000000e+00,1.065722004438245385e+01,4.867007414670093310e-04,5.242400307174300167e+00,4.680046041928307865e+00,2.816055581455917389e-01,6.587426488596379581e-01 7 | 3.786313981468475642e+00,9.457787016280562398e+00,0.000000000000000000e+00,1.549943302810189394e+01,5.331958260418389467e-03,5.566199717157565452e+00,1.177879208311717996e+01,7.669701824120410683e-01,1.803100307986333251e+00 8 | 2.617508628982714747e+00,6.532500080672547504e+00,0.000000000000000000e+00,1.336693294742934945e+01,7.514327856159554175e-03,5.532314801708615448e+00,1.023875149990803024e+01,8.819824189585497853e-01,2.088299525084197583e+00 9 | 1.620239975627732365e+00,4.038812792135322738e+00,0.000000000000000000e+00,1.102812015529402778e+01,7.858097956005493170e-03,5.386421012745326919e+00,6.473141181737718242e+00,8.980954643987495434e-01,2.143517687112975523e+00 10 | 9.126216427681178578e-01,2.270004410544121498e+00,0.000000000000000000e+00,8.758115744749906284e+00,7.699797584115572295e-03,4.586741093407180614e+00,1.886400088330537628e+00,8.906099971503117496e-01,2.143303356777297886e+00 11 | 2.235949870695818831e+01,5.176552544186736071e+01,0.000000000000000000e+00,3.059259030288254877e+01,2.755480883685404336e+00,5.713300529257533178e+00,3.203249168332367702e+01,9.460167363487958170e+00,2.855887298250357631e+01 12 | -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/SuperflexRes.dat: -------------------------------------------------------------------------------- 1 | Data modelled by SF_ISO 2 | C1Wv%Qstream U1F1Wv%Qstrm U1F1Wv%Eact U1F1Wv%Sf[1] U2F1Wv%Qstrm U2F1Wv%Eact U2F1Wv%Su[1] U2F1Wv%Sf[1] U2F1Wv%Ss[1] 3 | 1.27656692547259E-05 3.15978022652271E-05 0.00000000000000E+00 9.99684021977342E-02 2.10913914391699E-07 5.25897489318654E+00 4.83801524994899E+00 9.02956814340099E-04 2.10668913621530E-03 4 | 1.26672645915500E-01 3.16670111393416E-01 0.00000000000000E+00 3.98329829080432E+00 7.66893022236116E-06 5.13069121339945E+00 3.81867710843760E+00 2.74957816300526E-02 6.41531235022293E-02 5 | 1.06547429782736E-01 2.66357072238012E-01 0.00000000000000E+00 3.71694121856631E+00 7.66814588563560E-06 3.20271484273091E+00 6.15962265706688E-01 2.74945281550501E-02 6.41467088313462E-02 6 | 1.98103682668393E+00 4.95197639239862E+00 0.00000000000000E+00 1.19649648261677E+01 4.10449540804021E-04 5.44391179630297E+00 7.59117398791786E+00 2.61408092977598E-01 6.10699175953850E-01 7 | 1.48338993315897E+00 3.70774478178523E+00 0.00000000000000E+00 1.06572200443825E+01 4.86700741467009E-04 5.24240030717430E+00 4.68004604192831E+00 2.81605558145592E-01 6.58742648859638E-01 8 | 3.78631398146848E+00 9.45778701628056E+00 0.00000000000000E+00 1.54994330281019E+01 5.33195826041839E-03 5.56619971715757E+00 1.17787920831172E+01 7.66970182412041E-01 1.80310030798633E+00 9 | 2.61750862898271E+00 6.53250008067255E+00 0.00000000000000E+00 1.33669329474293E+01 7.51432785615955E-03 5.53231480170862E+00 1.02387514999080E+01 8.81982418958550E-01 2.08829952508420E+00 10 | 1.62023997562773E+00 4.03881279213532E+00 0.00000000000000E+00 1.10281201552940E+01 7.85809795600549E-03 5.38642101274533E+00 6.47314118173772E+00 8.98095464398750E-01 2.14351768711298E+00 11 | 9.12621642768118E-01 2.27000441054412E+00 0.00000000000000E+00 8.75811574474991E+00 7.69979758411557E-03 4.58674109340718E+00 1.88640008833054E+00 8.90609997150312E-01 2.14330335677730E+00 12 | 2.23594987069582E+01 5.17655254418674E+01 0.00000000000000E+00 3.05925903028825E+01 2.75548088368540E+00 5.71330052925753E+00 3.20324916833237E+01 9.46016736348796E+00 2.85588729825036E+01 13 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # http://www.sphinx-doc.org/en/master/config 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | 16 | sys.path.insert(0, os.path.abspath("../")) 17 | 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = "SuperflexPy" 22 | copyright = "2021, Marco Dal Molin, Dmitri Kavetski, Fabrizio Fenicia" 23 | author = "Marco Dal Molin, Dmitri Kavetski, Fabrizio Fenicia" 24 | 25 | # The full version, including alpha/beta/rc tags 26 | release = "1.3.0" 27 | 28 | 29 | # -- General configuration --------------------------------------------------- 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | extensions = [ 35 | "sphinx.ext.autodoc", 36 | "sphinx.ext.napoleon", 37 | "sphinx.ext.viewcode", 38 | ] 39 | 40 | napoleon_numpy_docstring = True 41 | autodoc_member_order = "bysource" 42 | 43 | # Add any paths that contain templates here, relative to this directory. 44 | templates_path = ["_templates"] 45 | 46 | # List of patterns, relative to source directory, that match files and 47 | # directories to ignore when looking for source files. 48 | # This pattern also affects html_static_path and html_extra_path. 49 | exclude_patterns = [] 50 | master_doc = "index" 51 | 52 | # -- Options for HTML output ------------------------------------------------- 53 | 54 | # The theme to use for HTML and HTML Help pages. See the documentation for 55 | # a list of builtin themes. 56 | # 57 | html_theme = "sphinx_rtd_theme" 58 | html_theme_options = {"logo_only": True} 59 | html_logo = os.path.join(os.path.abspath(os.path.dirname(__file__)), "pics", "logo_inverted_2.PNG") 60 | 61 | # Add any paths that contain custom static files (such as style sheets) here, 62 | # relative to this directory. They are copied after the builtin static files, 63 | # so a file named "default.css" will overwrite the builtin "default.css". 64 | html_static_path = ["_static"] 65 | -------------------------------------------------------------------------------- /doc/interfaces_code.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import spotpy 3 | 4 | from superflexpy.framework.unit import Unit 5 | from superflexpy.implementation.elements.hbv import PowerReservoir 6 | from superflexpy.implementation.numerical_approximators.implicit_euler import ( 7 | ImplicitEulerPython, 8 | ) 9 | from superflexpy.implementation.root_finders.pegasus import PegasusPython 10 | 11 | root_finder = PegasusPython() 12 | num_app = ImplicitEulerPython(root_finder=root_finder) 13 | 14 | reservoir_1 = PowerReservoir(parameters={"k": 0.1, "alpha": 2.0}, states={"S0": 10.0}, approximation=num_app, id="FR1") 15 | reservoir_2 = PowerReservoir(parameters={"k": 0.5, "alpha": 1.0}, states={"S0": 10.0}, approximation=num_app, id="FR2") 16 | 17 | hyd_mod = Unit(layers=[[reservoir_1], [reservoir_2]], id="model") 18 | 19 | 20 | class spotpy_model(object): 21 | def __init__(self, model, inputs, dt, observations, parameters, parameter_names, output_index): 22 | self._model = model 23 | self._model.set_input(inputs) 24 | self._model.set_timestep(dt) 25 | 26 | self._parameters = parameters 27 | self._parameter_names = parameter_names 28 | self._observarions = observations 29 | self._output_index = output_index 30 | 31 | def parameters(self): 32 | return spotpy.parameter.generate(self._parameters) 33 | 34 | def simulation(self, parameters): 35 | named_parameters = {} 36 | for p_name, p in zip(self._parameter_names, parameters): 37 | named_parameters[p_name] = p 38 | 39 | self._model.set_parameters(named_parameters) 40 | self._model.reset_states() 41 | output = self._model.get_output() 42 | 43 | return output[self._output_index] 44 | 45 | def evaluation(self): 46 | return self._observarions 47 | 48 | def objectivefunction(self, simulation, evaluation): 49 | obj_fun = spotpy.objectivefunctions.nashsutcliffe(evaluation=evaluation, simulation=simulation) 50 | 51 | return obj_fun 52 | 53 | 54 | P = np.array([0.1, 0.0, 1.5]) 55 | Q_obs = np.array([5.0, 3.2, 4.5]) 56 | 57 | 58 | spotpy_hyd_mod = spotpy_model( 59 | model=hyd_mod, 60 | inputs=[P], 61 | dt=1.0, 62 | observations=Q_obs, 63 | parameters=[ 64 | spotpy.parameter.Uniform("model_FR1_k", 1e-4, 1e-1), 65 | spotpy.parameter.Uniform("model_FR2_k", 1e-3, 1.0), 66 | ], 67 | parameter_names=["model_FR1_k", "model_FR2_k"], 68 | output_index=0, 69 | ) 70 | 71 | 72 | sampler = spotpy.algorithms.sceua(spotpy_hyd_mod, dbname="calibration", dbformat="csv") 73 | sampler.sample(repetitions=5000) 74 | -------------------------------------------------------------------------------- /superflexpy/implementation/models/hymod.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | 25 | This file implements a version of the model Hymod 26 | """ 27 | 28 | from superflexpy.framework.unit import Unit 29 | from superflexpy.implementation.elements.hymod import LinearReservoir, UpperZone 30 | from superflexpy.implementation.elements.structure_elements import ( 31 | Junction, 32 | Splitter, 33 | Transparent, 34 | ) 35 | from superflexpy.implementation.numerical_approximators.implicit_euler import ( 36 | ImplicitEulerPython, 37 | ) 38 | from superflexpy.implementation.root_finders.pegasus import PegasusPython 39 | 40 | root_finder = PegasusPython() # Use the default parameters 41 | numerical_approximation = ImplicitEulerPython(root_finder) 42 | 43 | upper_zone = UpperZone( 44 | parameters={"Smax": 50.0, "m": 0.01, "beta": 2.0}, 45 | states={"S0": 10.0}, 46 | approximation=numerical_approximation, 47 | id="uz", 48 | ) 49 | 50 | splitter = Splitter(weight=[[0.6], [0.4]], direction=[[0], [0]], id="spl") 51 | 52 | channel_routing_1 = LinearReservoir( 53 | parameters={"k": 0.1}, states={"S0": 10.0}, approximation=numerical_approximation, id="cr1" 54 | ) 55 | 56 | channel_routing_2 = LinearReservoir( 57 | parameters={"k": 0.1}, states={"S0": 10.0}, approximation=numerical_approximation, id="cr2" 58 | ) 59 | 60 | channel_routing_3 = LinearReservoir( 61 | parameters={"k": 0.1}, states={"S0": 10.0}, approximation=numerical_approximation, id="cr3" 62 | ) 63 | 64 | lower_zone = LinearReservoir(parameters={"k": 0.1}, states={"S0": 10.0}, approximation=numerical_approximation, id="lz") 65 | 66 | transparent_1 = Transparent(id="tr1") 67 | 68 | transparent_2 = Transparent(id="tr2") 69 | 70 | junction = Junction(direction=[[0, 0]], id="jun") # First output 71 | 72 | model = Unit( 73 | layers=[ 74 | [upper_zone], 75 | [splitter], 76 | [channel_routing_1, lower_zone], 77 | [channel_routing_2, transparent_1], 78 | [channel_routing_3, transparent_2], 79 | [junction], 80 | ], 81 | id="model", 82 | ) 83 | -------------------------------------------------------------------------------- /test/reference_results/06_3Cats_2HRUs/input.dat: -------------------------------------------------------------------------------- 1 | Maimai data courtesy Jeff McDonnell 2 | 1.0 ! stepsize (d) 3 | ST1: All data in mm/d 4 | ST2 5 | ST3 6 | * ! list directed format ok here 7 | Year, Month, Day, Hour, Min, P_C1, P_C2, P_C3, E_C1, E_C2, E_C3, Q_C1, QC_Q_C1, Q_C2, QC_Q_C2, Q_C3, QC_Q_C3, 8 | 1981 1 1 0 0 2.50000 2.56000 3.81000 0.59700 0.65600 0.64500 1.38891 0 1.44086 0 1.43339 0 9 | 1981 1 2 0 0 8.02000 4.86000 5.39000 0.35900 0.12500 0.08000 1.44721 0 1.34096 0 1.11329 0 10 | 1981 1 3 0 0 10.48000 8.37000 9.43000 0.66200 0.80700 0.60900 3.71258 0 5.50120 0 1.96873 0 11 | 1981 1 4 0 0 19.42000 24.47000 27.28000 0.24200 0.21200 0.13600 7.55982 0 11.28273 0 11.68680 0 12 | 1981 1 5 0 0 1.49000 4.36000 6.31000 0.26400 0.13200 0.13900 4.24939 0 4.11050 0 4.44464 0 13 | 1981 1 6 0 0 6.53000 7.75000 11.03000 0.00000 0.00000 0.00700 3.18157 0 2.83220 0 2.64144 0 14 | 1981 1 7 0 0 1.63000 5.23000 7.14000 0.00000 0.00000 0.25200 2.59718 0 2.24096 0 2.06458 0 15 | 1981 1 8 0 0 0.31000 0.79000 1.08000 0.00000 0.00000 0.00000 2.15247 0 1.87579 0 1.70221 0 16 | 1981 1 9 0 0 0.26000 0.75000 0.69000 0.00000 0.07400 0.22900 1.98105 0 1.86998 0 1.44663 0 17 | 1981 1 10 0 0 1.95000 1.37000 1.15000 0.00000 0.00000 0.18100 1.92873 0 1.67512 0 1.67596 0 18 | -------------------------------------------------------------------------------- /doc/examples.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 04/05/2021 2 | 3 | .. _examples: 4 | 5 | Examples 6 | ======== 7 | 8 | The following examples are available as Jupyter notebooks. All examples can be either 9 | visualized on GitHub or run in a sandbox environment. 10 | 11 | - Run a simple model `visualize `_ - `run `_ 12 | - Calibrate a model `visualize `_ - `run `_ 13 | - Initialize a single element model `visualize `_ - `run `_ 14 | - Initialize a single unit model: `visualize `_ - `run `_ 15 | - Initialize a simple node model: `visualize `_ - `run `_ 16 | - Initialize a complete (network) model: `visualize `_ - `run `_ 17 | - Create a new reservoir: `visualize `_ - `run `_ 18 | - Replicate GR4J: `visualize `_ - `run `_ 19 | - Replicate Hymod: `visualize `_ - `run `_ 20 | - Replicate M02 in Dal Molin et al., HESS, 2020: `visualize `_ - `run `_ 21 | - Replicate M4 in Kavetski and Fenicia, WRR, 2011: `visualize `_ - `run `_ 22 | - Modify M4 in Kavetski and Fenicia, WRR, 2011: `visualize `_ - `run `_ 23 | -------------------------------------------------------------------------------- /superflexpy/implementation/models/gr4j.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | 25 | This file implements a version of the model GR4J 26 | """ 27 | 28 | from superflexpy.framework.unit import Unit 29 | from superflexpy.implementation.elements.gr4j import ( 30 | FluxAggregator, 31 | InterceptionFilter, 32 | ProductionStore, 33 | RoutingStore, 34 | UnitHydrograph1, 35 | UnitHydrograph2, 36 | ) 37 | from superflexpy.implementation.elements.structure_elements import ( 38 | Junction, 39 | Splitter, 40 | Transparent, 41 | ) 42 | from superflexpy.implementation.numerical_approximators.implicit_euler import ( 43 | ImplicitEulerPython, 44 | ) 45 | from superflexpy.implementation.root_finders.pegasus import PegasusPython 46 | 47 | x1, x2, x3, x4 = (50.0, 0.1, 20.0, 3.5) 48 | 49 | root_finder = PegasusPython() # Use the default parameters 50 | numerical_approximation = ImplicitEulerPython(root_finder) 51 | 52 | interception_filter = InterceptionFilter(id="ir") 53 | 54 | production_store = ProductionStore( 55 | parameters={"x1": x1, "alpha": 2.0, "beta": 5.0, "ni": 4 / 9}, 56 | states={"S0": 10.0}, 57 | approximation=numerical_approximation, 58 | id="ps", 59 | ) 60 | 61 | splitter = Splitter(weight=[[0.9], [0.1]], direction=[[0], [0]], id="spl") 62 | 63 | unit_hydrograph_1 = UnitHydrograph1(parameters={"lag-time": x4}, states={"lag": None}, id="uh1") 64 | 65 | unit_hydrograph_2 = UnitHydrograph2(parameters={"lag-time": 2 * x4}, states={"lag": None}, id="uh2") 66 | 67 | routing_store = RoutingStore( 68 | parameters={"x2": x2, "x3": x3, "gamma": 5.0, "omega": 3.5}, 69 | states={"S0": 10.0}, 70 | approximation=numerical_approximation, 71 | id="rs", 72 | ) 73 | 74 | transparent = Transparent(id="tr") 75 | 76 | junction = Junction( 77 | direction=[[0, None], [1, None], [None, 0]], id="jun" # First output # Second output # Third output 78 | ) 79 | 80 | flux_aggregator = FluxAggregator(id="fa") 81 | 82 | model = Unit( 83 | layers=[ 84 | [interception_filter], 85 | [production_store], 86 | [splitter], 87 | [unit_hydrograph_1, unit_hydrograph_2], 88 | [routing_store, transparent], 89 | [junction], 90 | [flux_aggregator], 91 | ], 92 | id="model", 93 | ) 94 | -------------------------------------------------------------------------------- /doc/customize_components.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 04/05/2021 2 | 3 | .. .. warning:: This guide is still work in progress. New pages are being written 4 | .. and existing ones modified. Once the guide will reach its final 5 | .. version, this box will disappear. 6 | 7 | .. _customize_components: 8 | 9 | Expand SuperflexPy: Build customized components 10 | =============================================== 11 | 12 | .. _routing_node: 13 | 14 | Adding routing to a node 15 | ------------------------ 16 | 17 | Nodes in SuperflexPy have the capability to apply a lag to the fluxes simulated 18 | by the units. Such lags can represent routing delays in the fluxes as they 19 | propagate through the catchment ("internal" routing), or routing delays associated with the river 20 | network ("external" routing). Both types of routing can be implemented within 21 | a SuperflexPy node. 22 | 23 | The default implementation of the node (:code:`Node` class in 24 | :code:`superflexpy.framework.node`) does not provide the routing functionality. 25 | The methods :code:`_internal_routing` and :code:`external_routing` exist but are 26 | set to simply return the incoming fluxes without any transformation. 27 | 28 | To support routing within a node, we need to create a customized node that implements 29 | the methods :code:`_internal_routing` and :code:`external_routing` 30 | for given lag functions. The object-oriented design of 31 | SuperflexPy simplifies this operation, because the new node class inherits all 32 | the methods from the original class, and has to overwrite only the two methods 33 | that are responsible for the routing. 34 | 35 | In this example, we illustrate an implementation of routing with a lag function 36 | in the shape of an isosceles triangle with base :code:`t_internal` and 37 | :code:`t_external`, for internal and external routing respectively. This new 38 | implementation is similar to the implementation of the :ref:`build_lag`. 39 | 40 | The first step is to import the :code:`Node` component from SuperflexPy and 41 | define the class :code:`RoutedNode` 42 | 43 | .. literalinclude:: customize_components_code.py 44 | :language: python 45 | :lines: 1, 4, 5 46 | :linenos: 47 | 48 | We then need to implement the methods :code:`_internal_routing` and 49 | :code:`external_routing`. Both methods receive as input a list of fluxes, 50 | and return as output the fluxes (in the same order of the inputs) with the 51 | delay applied. 52 | 53 | .. literalinclude:: customize_components_code.py 54 | :language: python 55 | :lines: 13-31 56 | :linenos: 57 | 58 | In this simple example, the two routing mechanisms are handled using the same 59 | lag functional form. Hence, the methods :code:`_internal_routing` and :code:`external_routing` 60 | take advantage of the method :code:`_route` 61 | (line 7 and 17). 62 | 63 | The method :code:`_route` is implemented as follows 64 | 65 | .. literalinclude:: customize_components_code.py 66 | :language: python 67 | :lines: 33-73 68 | :linenos: 69 | 70 | Note that the code in this block is similar to the code implemented in 71 | :ref:`build_lag`. The methods in this last code block are "support" methods that 72 | make the code more organized and easier to maintain. The same numerical results 73 | can be obtained by moving the functionality of these methods directly into 74 | :code:`_internal_routing` and :code:`external_routing`, though the resulting code would be less modular. 75 | -------------------------------------------------------------------------------- /superflexpy/utils/root_finder.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | 25 | This file contains the implementation of the base class for the root finder in 26 | case of elements governed by ODEs 27 | """ 28 | 29 | 30 | class RootFinder: 31 | """ 32 | This is the abstract class for the creation of a RootFinder. It defines how 33 | the solver of the differential equation must be implemented. 34 | """ 35 | 36 | architecture = None 37 | """ 38 | Implementation required to increase the performance (e.g. numba) 39 | """ 40 | 41 | def __init__(self, tol_F=1e-8, tol_x=1e-8, iter_max=10): 42 | """ 43 | The constructor of the subclass must accept the parameters of the 44 | solver. 45 | 46 | Parameters 47 | ---------- 48 | tol_F : float 49 | Tolerance on the y axis (distance from 0) that stops the solver 50 | tol_x : float 51 | Tolerance on the x axis (distance between two roots) that stops 52 | the solver 53 | iter_max : int 54 | Maximum number of iteration of the solver. After this value it 55 | raises a runtime error 56 | """ 57 | 58 | self._tol_F = tol_F 59 | self._tol_x = tol_x 60 | self._iter_max = iter_max 61 | self._name = "Solver" 62 | 63 | def get_settings(self): 64 | """ 65 | This method returns the settings of the root finder. 66 | 67 | Returns 68 | ------- 69 | float 70 | Function tollerance (tol_F) 71 | float 72 | X tollerance (tol_x) 73 | int 74 | Maximum number of iterations (iter_max) 75 | """ 76 | 77 | return ( 78 | self._tol_F, 79 | self._tol_x, 80 | self._iter_max, 81 | ) 82 | 83 | def __repr__(self): 84 | str = "Module: superflexPy\nClass: {}\n".format(self._name) 85 | str += "Parameters:\n" 86 | str += "\ttol_F = {}\n".format(self._tol_F) 87 | str += "\ttol_x = {}\n".format(self._tol_x) 88 | str += "\titer_max = {}".format(self._iter_max) 89 | 90 | return str 91 | 92 | def solve(self, *args, **kwargs): 93 | """ 94 | To be implemented by any child class. This method finds the root of the 95 | numerical approximation of the differential equation. It can operate 96 | over the whole time series. 97 | """ 98 | 99 | raise NotImplementedError("The method solve must be implemented") 100 | -------------------------------------------------------------------------------- /doc/share_models.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 04/05/2021 2 | 3 | Sharing model configurations 4 | ============================ 5 | 6 | A key goal of SuperflexPy is to facilitate collaboration between research 7 | groups, and to help compare and improve modelling solutions. To this end, users 8 | can share model configurations that can be imported and run by other users. Note 9 | that models built with SuperflexPy are Python objects that, once initialized, 10 | can be imported into other scripts. 11 | 12 | A user who wishes to share their model configuration with the community can 13 | create a Python script (with a descriptive name) that initializes the model 14 | (without running it) and "upload" it to the GitHub repository in the folder 15 | :code:`superflexpy/implementation/models/`. This "upload" requires the following steps: (1) 16 | fork the `SuperflexPy `_ 17 | repository, (2) add the script to the local fork of the repository, and (3) 18 | make a pull request to the original repository (see :ref:`contribute` for 19 | further details). The contributed code will be checked by the repository maintainers. Assuming all checks 20 | are passed the newly incorporated code will be incorporated in the following release of SuperflexPy 21 | and thus made available to other SuperflexPy users. 22 | 23 | The user will maintain authorship on the contributed code, which will be 24 | released with the same :ref:`license` as SuperflexPy. It is good practice to 25 | include unit tests to enable users to ensure the new code is operating as expected (see :ref:`tests`). 26 | 27 | Practical example with M4 28 | ------------------------- 29 | 30 | We illustrate of how to distribute SuperflexPy models to colleagues using as an 31 | example the model :ref:`M4_example`. 32 | 33 | First, we create the file :code:`m4_sf_2011.py` that contains the code to 34 | initialize the model 35 | 36 | .. literalinclude:: share_models_code.py 37 | :language: python 38 | :lines: 1-29 39 | :linenos: 40 | 41 | Then we incorporate the file :code:`m4_sf_2011.py` into the SuperflexPy repository in the folder 42 | :code:`superflexpy/implementation/models/` following the steps illustrated 43 | in the previous section (fork, change, and pull request). 44 | 45 | Once the next release of SuperflexPy is available, the M4 model implementation 46 | will be available in the updated installed package. 47 | General users can then use this new model in their own application, by importing it as shown below. 48 | 49 | .. literalinclude:: share_models_code.py 50 | :language: python 51 | :lines: 31-37 52 | :linenos: 53 | 54 | Sharing models "privately" with other users 55 | ------------------------------------------- 56 | 57 | Model configurations can be shared "privately" between research groups without 58 | waiting for a new release of the framework. 59 | 60 | This can be done by creating a :code:`my_new_model.py` file that initializes the 61 | model and then sharing the file "privately" with other users. 62 | 63 | The recipients of the new file can then save it on their machines and use 64 | local importing. Assuming that the script that the recipients use to run the 65 | model is in the same folder as the file initializing the model, the new model can be used as follows 66 | 67 | .. literalinclude:: share_models_code.py 68 | :language: python 69 | :lines: 39, 32, 32-37 70 | :linenos: 71 | 72 | Note the local import in line 1. 73 | 74 | As we believe in the `F.A.I.R. `_ 75 | principles, we encourage modelers to share their models with the whole 76 | community, using the procedure detailed earlier. 77 | 78 | Dumping objects with Pickle 79 | --------------------------- 80 | 81 | Python offers the module 82 | `Pickle `_ to serialize objects 83 | to binary files. This approach enables the distribution of binary files, but 84 | has the disadvantage of lacking transparency in the model structure. 85 | -------------------------------------------------------------------------------- /doc/reference.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 20/07/2021 2 | 3 | .. .. warning:: This guide is still work in progress. New pages are being written 4 | .. and existing ones modified. Once the guide will reach its final 5 | .. version, this box will disappear. 6 | 7 | Reference 8 | ========= 9 | 10 | This reference provides details of the classes within SuperflexPy. This page is 11 | limited to the core framework (i.e. content of :code:`superflexpy/framework/` 12 | and :code:`superflexpy/utils/`), in order to provide a clear reference for the 13 | classes that should be customized to extend SuperflexPy. Particular 14 | implementations of components (i.e. the content of 15 | :code:`superflexpy/implementation/`) are not included. 16 | 17 | The following diagram follows the standards of 18 | `UML `_ and shows the organization 19 | of the classes composing the framework. All the classes in the diagram can be 20 | extended through inheritance to create customized components. 21 | 22 | .. image:: pics/reference/class_uml.png 23 | :align: center 24 | 25 | superflexpy.framework.element 26 | ----------------------------- 27 | 28 | .. autoclass:: superflexpy.framework.element.BaseElement 29 | :members: 30 | :undoc-members: 31 | :private-members: 32 | :show-inheritance: 33 | :special-members: __init__ 34 | 35 | .. autoclass:: superflexpy.framework.element.ParameterizedElement 36 | :members: 37 | :undoc-members: 38 | :private-members: 39 | :special-members: __init__ 40 | :show-inheritance: 41 | 42 | .. autoclass:: superflexpy.framework.element.StateElement 43 | :members: 44 | :undoc-members: 45 | :private-members: 46 | :special-members: __init__ 47 | :show-inheritance: 48 | 49 | .. autoclass:: superflexpy.framework.element.StateParameterizedElement 50 | :members: 51 | :undoc-members: 52 | :private-members: 53 | :special-members: __init__ 54 | :show-inheritance: 55 | 56 | .. autoclass:: superflexpy.framework.element.ODEsElement 57 | :members: 58 | :undoc-members: 59 | :private-members: 60 | :special-members: __init__ 61 | :show-inheritance: 62 | 63 | .. autoclass:: superflexpy.framework.element.LagElement 64 | :members: 65 | :undoc-members: 66 | :private-members: 67 | :special-members: __init__ 68 | :show-inheritance: 69 | 70 | superflexpy.utils.generic_component 71 | ----------------------------------- 72 | 73 | .. autoclass:: superflexpy.utils.generic_component.GenericComponent 74 | :members: 75 | :undoc-members: 76 | :private-members: 77 | :special-members: __init__ 78 | :show-inheritance: 79 | 80 | superflexpy.framework.unit 81 | -------------------------- 82 | 83 | .. autoclass:: superflexpy.framework.unit.Unit 84 | :members: 85 | :undoc-members: 86 | :private-members: 87 | :special-members: __init__ 88 | :show-inheritance: 89 | 90 | superflexpy.framework.node 91 | -------------------------- 92 | 93 | .. autoclass:: superflexpy.framework.node.Node 94 | :members: 95 | :undoc-members: 96 | :private-members: 97 | :special-members: __init__ 98 | :show-inheritance: 99 | 100 | superflexpy.framework.network 101 | ----------------------------- 102 | 103 | .. autoclass:: superflexpy.framework.network.Network 104 | :members: 105 | :undoc-members: 106 | :private-members: 107 | :special-members: __init__ 108 | :show-inheritance: 109 | 110 | superflexpy.utils.root_finder 111 | ----------------------------- 112 | 113 | .. autoclass:: superflexpy.utils.root_finder.RootFinder 114 | :members: 115 | :undoc-members: 116 | :private-members: 117 | :special-members: __init__ 118 | :show-inheritance: 119 | 120 | superflexpy.utils.numerical_approximator 121 | ---------------------------------------- 122 | 123 | .. autoclass:: superflexpy.utils.numerical_approximator.NumericalApproximator 124 | :members: 125 | :special-members: __init__ 126 | :show-inheritance: 127 | -------------------------------------------------------------------------------- /doc/changelog.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 29/11/2021 2 | 3 | Change log 4 | ========== 5 | 6 | Version 1.3.1 7 | ------------- 8 | 9 | Minor changes 10 | ............. 11 | 12 | - Added the classifier :code:`Topic :: Scientific/Engineering :: Hydrology` 13 | 14 | Version 1.3.0 15 | ------------- 16 | 17 | Major changes to existing components 18 | .................................... 19 | 20 | - :code:`ODEsElements` can now return the derivative of the fluxes together with 21 | the fluxes. This enables the usage of numerical solvers that use the 22 | derivatives (e.g., Newton methods). 23 | - Folder structure improved. The numerical approximators and the root finders 24 | have been moved from the folder :code:`implementation/computation` to 25 | :code:`implementation/numerical_approximators` and 26 | :code:`implementation/root_finders`, respectively. Names of the files have 27 | been slightly modified to be coherent with this new folder organization. 28 | 29 | New code 30 | ........ 31 | 32 | - Implemented a new numerical approximator implementing Runge Kutta 4 33 | - Implemented a new root finder implementing a Newton-bisection method 34 | - Implemented a new root finder implementing a trivial algorithm to solve 35 | explicit algebraic equations. 36 | 37 | Version 1.2.1 38 | ------------- 39 | 40 | Minor changes 41 | ............. 42 | 43 | - The network attribute :code:`topography` has been changed to :code:`topology`. 44 | 45 | Version 1.2.0 46 | ------------- 47 | 48 | Major changes to existing components 49 | .................................... 50 | 51 | - The abbreviation of "differential equation" changes, in the code, from 52 | :code:`dif_eq` to :code:`diff_eq`. This change regards variables names, both 53 | in the methods arguments and implementation. 54 | 55 | - The class :code:`FastReservoir` has been changed to :code:`PowerReservoir`. No 56 | changes in the functionality of the class. 57 | 58 | Minor changes 59 | ............. 60 | 61 | - Testing improved. 62 | 63 | Version 1.1.0 64 | ------------- 65 | 66 | Major changes to existing components 67 | .................................... 68 | 69 | - Form this version, SuperflexPy is released under license LGPL. For details, 70 | read :ref:`license` 71 | 72 | Minor changes to existing components 73 | .................................... 74 | 75 | - Bug fix on the solution of the differential equations of the reservoirs. The 76 | calculation of the maximum storage was not correct. 77 | 78 | Version 1.0.0 79 | ------------- 80 | 81 | Version 1.0.0 represents the first mature release of SuperflexPy. Many aspects 82 | have changed since earlier 0.x releases both in terms of code organization 83 | and conceptualization of the framework. **Models built with versions 0.x are** 84 | **not compatible with this version and with the following releases**. 85 | 86 | Major changes to existing components 87 | .................................... 88 | 89 | - New numerical solver structure for elements controlled by ordinary 90 | differential equations (ODEs). A new component, the 91 | :code:`NumericaApproximator` is introduced; its task it to get the fluxes from 92 | the elements and construct an approximation of the ODEs. In the previous 93 | release of the framework the approximation was hard coded in the element 94 | implementation. 95 | 96 | - :code:`ODEsElement` have now to implement the methods :code:`_fluxes` and 97 | :code:`_fluxes_python` instead of :code:`_differential_equation` 98 | 99 | - Added the possibility for nodes and units to have local states and parameters. 100 | To this end, some internal functionalities for finding the element given the 101 | :code:`id` have been changed to account for the presence of states and 102 | parameters at a level higher then the elements. 103 | 104 | Minor changes to existing components 105 | .................................... 106 | 107 | - Added implicit or explicit check at initialization of units, nodes, and 108 | network that the components that they contain are of the right type (e.g. a 109 | node must contain units) 110 | 111 | - Minor changes to :code:`RootFinder` to accommodate the new numerical 112 | implementation. 113 | 114 | - Added Numba implementation of GR4J elements 115 | 116 | New code 117 | ........ 118 | 119 | - Added :code:`hymod` elements 120 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. .. warning:: This guide is still work in progress. New pages are being written 2 | .. and existing ones modified. Once the guide will reach its final 3 | .. version, this box will disappear. 4 | 5 | .. image:: pics/logo_transparent_2.png 6 | :align: center 7 | 8 | =========== 9 | SuperflexPy 10 | =========== 11 | 12 | SuperflexPy is an open-source Python framework for constructing conceptual 13 | hydrological models for lumped and semi-distributed applications. 14 | 15 | SuperflexPy builds on our 10 year experience with the development and 16 | application of `Superflex `_, including 17 | collaborations with colleagues at the Eawag (Switzerland), TU-Delft 18 | (Netherlands), LIST (Luxembourg), University of Adelaide (Australia), and 19 | others. The SuperflexPy framework offers a brand new implementation of 20 | Superflex, allowing the modeler to build fully customized, spatially-distributed 21 | hydrological models. 22 | 23 | Thanks to its object-oriented architecture, SuperflexPy can be easily 24 | extended to meet your modelling requirements, including the creation of new 25 | components with customized internal structure, in just a few lines of Python 26 | code. 27 | 28 | Constructing a hydrological model is straightforward with SuperflexPy: 29 | 30 | - inputs and outputs are handled directly by the modeler using common Python 31 | libraries (e.g. Numpy or Pandas). The modeller can use hence data files of 32 | their own design, without the need to pre- and/or post- process 33 | data into text formats prescribed by the framework itself; 34 | 35 | - the framework components are declared and initialized through a Python script; 36 | 37 | - the framework components are implemented as classes with built-in functionalities for 38 | handling parameters and states, routing fluxes, and solving the model 39 | equations (e.g. describing reservoirs, lag functions, etc.); 40 | 41 | - the numerical implementation is separated from the conceptual model, allowing 42 | the use of different numerical methods for solving the model equations; 43 | 44 | - the framework can be run at multiple levels of complexity, from a 45 | single-bucket model to a model that represents an entire river network; 46 | 47 | - the framework is available as an open source Python package from 48 | `Github `_; 49 | 50 | - the framework can be easily interfaced with other Python modules for 51 | calibration and uncertainty analysis. 52 | 53 | Team 54 | ---- 55 | 56 | SuperflexPy is developed and maintained by researchers in the 57 | `Hydrological Modelling Group 58 | `_ 59 | at `Eawag `_, with the support of external collaborators. 60 | 61 | The core team consists of: 62 | 63 | - `Dr. Marco Dal Molin `_ (implementation and design) 64 | 65 | - `Dr. Fabrizio Fenicia `_ 66 | (design and supervision) 67 | 68 | - `Prof. Dmitri Kavetski `_ 69 | (design and supervision) 70 | 71 | Stay in touch 72 | ------------- 73 | 74 | If you wish to receive emails about ongoing SuperflexPy developments\, 75 | please `subscribe `_ to our mailing list. 76 | 77 | .. note:: Using SuperflexPy requires a general knowledge of Python and Numpy. 78 | Other Python libraries may be needed for pre- and post- processing of 79 | the data. 80 | 81 | In line with the Python terminology, we will use the word **define** 82 | when referring to the definition of a class, and **initialize** when 83 | referring to the creation of an instance of a class, i.e. an object. 84 | 85 | .. toctree:: 86 | :maxdepth: 1 87 | :hidden: 88 | 89 | installation 90 | contribute 91 | introduction 92 | components 93 | numerical_solver 94 | demo 95 | elements_list 96 | build_element 97 | customize_components 98 | popular_models 99 | case_studies 100 | sfpy_in_literature 101 | share_models 102 | interfaces 103 | examples 104 | testing 105 | license 106 | reference 107 | changelog 108 | -------------------------------------------------------------------------------- /superflexpy/implementation/root_finders/explicit.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | 25 | This file contains the implementation of a trivial solver to use when the 26 | algebraic equation to solve is explicit and, therefore does not require 27 | iteration (e.g., with Explicit Euler or Runge Kutta). 28 | """ 29 | 30 | 31 | import numba as nb 32 | 33 | from ...utils.root_finder import RootFinder 34 | 35 | 36 | class ExplicitPython(RootFinder): 37 | """ 38 | This class defined a root finder to be used when the algebraic equation is 39 | explicit. 40 | """ 41 | 42 | def __init__(self): 43 | """ 44 | This is the initializer of the ExplicitRootFinderPython class. As the 45 | root finder it not iterative, no parameters defining the convergence are 46 | needed. 47 | """ 48 | 49 | super().__init__(tol_F=None, tol_x=None, iter_max=None) 50 | 51 | self._name = "ExplicitRootFinderPython" 52 | self.architecture = "python" 53 | self._error_message = "module : superflexPy, solver : {},".format(self._name) 54 | self._error_message += " Error message : " 55 | 56 | def solve(self, diff_eq, fluxes, S0, dt, ind, args): 57 | """ 58 | This method calculated the root of the input function. 59 | 60 | Parameters 61 | ---------- 62 | diff_eq : function 63 | Function be solved. The function must accept the following inputs: 64 | - fluxes : function used to calculate the fluxes given parameters 65 | and state 66 | - S : proposed root. If None, the function must initialize the root 67 | - S0 : state at the beginning of the time step 68 | - dt : time step 69 | - kwargs : other parameters needed by diff_eq 70 | It must return three float values: 71 | - Value of the function given the root and the kwargs 72 | - Lower x boundary for the search 73 | - Upper x boundary for the search 74 | fluxes : function 75 | Function to be passed to diff_eq. See specificatio in 76 | superflexpy.utils.numerical_approximator 77 | S0 : float 78 | state at the beginning of the time step 79 | dt : float 80 | time step 81 | kwargs : dict(str: float) 82 | parameters needed by diff_eq 83 | 84 | Returns 85 | ------- 86 | float 87 | Root of the function 88 | """ 89 | 90 | return -diff_eq(fluxes=fluxes, S=0, S0=S0, dt=dt, args=args, ind=ind)[0] 91 | 92 | 93 | class ExplicitNumba(RootFinder): 94 | """ 95 | This class defined a root finder to be used when the algebraic equation is 96 | explicit. 97 | """ 98 | 99 | def __init__(self): 100 | """ 101 | This is the initializer of the ExplicitRootFinderNumba class. As the 102 | root finder it not iterative, no parameters defining the convergence are 103 | needed. 104 | """ 105 | 106 | super().__init__(tol_F=None, tol_x=None, iter_max=None) 107 | 108 | self._name = "ExplicitRootFinderPython" 109 | self.architecture = "python" 110 | self._error_message = "module : superflexPy, solver : {},".format(self._name) 111 | self._error_message += " Error message : " 112 | 113 | @staticmethod 114 | @nb.jit(nopython=True) 115 | def solve(diff_eq, fluxes, S0, dt, ind, args, tol_F, tol_x, iter_max): 116 | return -diff_eq(fluxes=fluxes, S=0, S0=S0, dt=dt, args=args, ind=ind)[0] 117 | -------------------------------------------------------------------------------- /doc/contribute.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 22/07/2021 2 | 3 | .. .. warning:: This guide is still work in progress. New pages are being written 4 | .. and existing ones modified. Once the guide will reach its final 5 | .. version, this box will disappear. 6 | 7 | .. _contribute: 8 | 9 | Software organization and contribution 10 | ====================================== 11 | 12 | .. image:: pics/contribute/schematic_with_logo.png 13 | :align: center 14 | 15 | The SuperflexPy framework comprises the following components: 16 | 17 | - **Source code**: Latest version of all the code necessary to use the 18 | framework. The source code would normally be accessed only by advanced 19 | users, e.g. to understand the internal organization of the framework, to install 20 | manually the latest version, to extend the framework with new 21 | functionality, etc. 22 | - **Packaged release**: Latest stable version of the framework available for 23 | users. 24 | - **Documentation**: Detailed explanation of the framework. 25 | - **Examples**: Introduction to SuperflexPy for a new user, providing working 26 | models and demonstrating potential applications. 27 | - **Scientific references**: Publications that present and/or use 28 | the framework in scientific contexts. 29 | 30 | The source code, documentation, and examples are part of the official repository 31 | of SuperflexPy hosted on `GitHub `_. 32 | A user who wishes to read the source code and/or modify any aspect of 33 | SuperflexPy (source code, documentation, and examples) can do it using GitHub. 34 | 35 | New releases of the software are available from the official Python Package 36 | Index (PyPI), where SuperflexPy has a 37 | `dedicated page `_. 38 | 39 | The documentation builds automatically from the 40 | `source folder `_ on 41 | GitHub and is published online in 42 | `Read the Docs `_. 43 | 44 | Examples are available on GitHub as Jupyter notebooks. These examples can be 45 | visualized statically or run in a sandbox environment (Binder). Refer to :ref:`examples` for 46 | a list of the available examples. 47 | 48 | The scientific publication introducing SuperflexPy has been published in 49 | *Geoscientific Model Development* (`link `_). 50 | 51 | Contributions 52 | ------------- 53 | 54 | Contributions to the framework can be made in the following ways: 55 | 56 | - Submit issues on bugs, desired features, etc; 57 | - Solve open issues; 58 | - Extend the documentation with new demos and examples; 59 | - Extend and/or modify the framework; 60 | - Use and cite the framework in your publications. 61 | 62 | Code contribution by external users will be mainly additive (i.e., adding new 63 | components, as illustrated in :ref:`build_element` and :ref:`customize_components`) 64 | and should include also appropriate testing (:ref:`tests`). 65 | 66 | Contributors will maintain authorship of the contributed code and are invited 67 | to include, in all files, their contact information to facilitate future 68 | collaboration. The authors and maintainers of SuperflexPy will undertake a basic 69 | inspection of the contributed code to identify any quality issues. 70 | 71 | The typical workflow that should be followed when contributing to a GitHub 72 | project is described 73 | `here `_. 74 | 75 | In summary, 76 | the following steps should be followed: 77 | 78 | 1. Fork the SuperflexPy repository to the user GitHub account; 79 | 2. Clone the fork on the user computer; 80 | 3. Modify the code, commit the changes, and push them to the GitHub fork of 81 | SuperflexPy; 82 | 4. Make a pull request on GitHub to the SuperflexPy repository. 83 | 84 | Branching scheme of the GitHub repository 85 | ......................................... 86 | 87 | Updates to SuperflexPy are made directly in the branch :code:`master`, which 88 | is the most up-to-date branch. The branch :code:`release` is used only 89 | for the staging of new software releases and, therefore, code should not be 90 | pushed directly to it. 91 | 92 | When a code update is merged from :code:`master` to :code:`release`, a 93 | new version of the package is automatically released on PyPI. Remember to update 94 | the version number in the :code:`setup.py` file to avoid conflicts. 95 | 96 | Developers are free to create new branches, but pull requests must be directed to 97 | :code:`master` and not to :code:`release`. 98 | 99 | Documentation and examples are generated from the :code:`master` 100 | branch. 101 | -------------------------------------------------------------------------------- /doc/interfaces.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 04/05/2021 2 | 3 | Interfacing SuperflexPy with other frameworks 4 | ============================================= 5 | 6 | SuperflexPy does not integrate tools for calibration or uncertainty analysis. In 7 | this page we show an example on how a model built using SuperflexPy can be 8 | interfaced with other tools to perform this task. 9 | 10 | SuperflexPy + SPOTPY 11 | -------------------- 12 | 13 | .. note:: This example is for illustration purposes only, and as such does not 14 | represent a specific recommendation of SPOTPY or of any specific 15 | calibration algorithm. 16 | 17 | `SPOTPY `_ is a Python framework for 18 | calibration, uncertainty, and sensitivity analysis. 19 | 20 | A model can be interfaced with SPOTPY by defining a class that wraps the model 21 | and implements the following methods: 22 | 23 | - :code:`__init__`: initializes the class, defining some attributes; 24 | - :code:`parameters`: returns the parameters considered in the analysis (note 25 | that they may not be all the parameters used by the SuperflexPy model but 26 | only the ones that we want to vary in the analysis); 27 | - :code:`simulation`: returns the output of the simulation; 28 | - :code:`evaluation`: returns the observed output; 29 | - :code:`objectivefunction`: defines the objective function to use to evaluate 30 | the simulation results. 31 | 32 | Method :code:`__init__` 33 | ....................... 34 | 35 | .. literalinclude:: interfaces_code.py 36 | :language: python 37 | :lines: 5, 7, 29-40 38 | :linenos: 39 | 40 | The class :code:`spotpy_model` is initialized defining the SuperflexPy :code:`model` that is used. 41 | The :code:`model`, which can be any SuperflexPy component (from element to 42 | network), must be defined before; the :code:`spotpy_model` class sets only the :code:`inputs` 43 | and the :code:`dt`. 44 | 45 | Other variables necessary to initialize the class :code:`spotpy_model` are: 46 | 47 | - :code:`parameters` and :code:`parameters_names`, which define the parameters 48 | considered in the calibration. The first variable is a list of :code:`spotpy.parameter` 49 | objects, the second variable is a list of the names of the SuperflexPy parameters; 50 | - :code:`observations`, which is an array of observed output values; 51 | - :code:`output_index`, which is the index of the output flux to be considered 52 | when evaluating the SuperflexPy simulation. This specification is necessary in 53 | the case of multiple output fluxes. 54 | 55 | Method :code:`parameters` 56 | ......................... 57 | 58 | .. literalinclude:: interfaces_code.py 59 | :language: python 60 | :lines: 44-45 61 | :linenos: 62 | 63 | The method :code:`parameters` generates a new parameter set using the SPOTPY functionalities. 64 | 65 | Method :code:`simulation` 66 | ......................... 67 | 68 | .. literalinclude:: interfaces_code.py 69 | :language: python 70 | :lines: 49-59 71 | :linenos: 72 | 73 | The method :code:`simulation` sets the parameters (lines 3-7), resets the states to their initial 74 | value (line 8), runs the SuperflexPy model (line 9), and returns the output 75 | flux for the evaluation of the objective function (line 11). 76 | 77 | Method :code:`evaluation` 78 | ......................... 79 | 80 | .. literalinclude:: interfaces_code.py 81 | :language: python 82 | :lines: 63-64 83 | :linenos: 84 | 85 | The method :code:`evaluation` returns the observed flux, used for the evaluation of the objective function. 86 | 87 | Method :code:`objectivefunction` 88 | ................................ 89 | 90 | .. literalinclude:: interfaces_code.py 91 | :language: python 92 | :lines: 68-73 93 | :linenos: 94 | 95 | The method :code:`objectivefunction` defines the objective function used to measure the model fit to the observed data. In this 96 | case, the Nash-Sutcliffe efficiency is used. 97 | 98 | Example of use 99 | .............. 100 | 101 | We now show how to employ the implementation above to calibrate a lumped model 102 | composed of 2 reservoirs. 103 | 104 | First, we initialize the SuperflexPy model, as follows 105 | (see :ref:`demo` for more details on how to set-up a model). 106 | 107 | .. literalinclude:: interfaces_code.py 108 | :language: python 109 | :lines: 1-4, 9-24 110 | :linenos: 111 | 112 | Then, we initialize an instance of the :code:`spotpy_model` class 113 | 114 | .. literalinclude:: interfaces_code.py 115 | :language: python 116 | :lines: 81-92 117 | :linenos: 118 | 119 | The arrays :code:`P` and :code:`Q_obs` in lines 3 and 5 contain time series of precipitation (input) 120 | and observed streamflow (output). In this example, lines 6-10 indicate the two parameters that we calibrate 121 | (:code:`model_FR1_k` and :code:`model_FR2_k`) together with their range of 122 | variability. 123 | 124 | We can now call the SPOTPY method to calibrate the model. Here, the SCE algorithm option is used. 125 | 126 | .. literalinclude:: interfaces_code.py 127 | :language: python 128 | :lines: 96-97 129 | :linenos: 130 | -------------------------------------------------------------------------------- /test/unittest/01_FR.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | import sys 27 | import unittest 28 | from os.path import abspath, dirname, join 29 | 30 | import numpy as np 31 | import pandas as pd 32 | 33 | # Package path is 2 levels above this file 34 | package_path = join(abspath(dirname(__file__)), "..", "..") 35 | sys.path.insert(0, package_path) 36 | 37 | from superflexpy.implementation.elements.hbv import PowerReservoir 38 | from superflexpy.implementation.numerical_approximators.implicit_euler import ( 39 | ImplicitEulerNumba, 40 | ImplicitEulerPython, 41 | ) 42 | from superflexpy.implementation.root_finders.pegasus import PegasusNumba, PegasusPython 43 | 44 | 45 | class TestFR(unittest.TestCase): 46 | """ 47 | This class tests the functionality of the reservoir FR alone. 48 | We compare the results with superflex in two scenarios: 49 | - start and stop to check that it saves the intermediate states 50 | - 2 rounds to check that it re-sets the states to the initial value 51 | """ 52 | 53 | def _init_model(self, solver): 54 | if solver == "numba": 55 | solver = PegasusNumba() 56 | num_app = ImplicitEulerNumba(root_finder=solver) 57 | elif solver == "python": 58 | solver = PegasusPython() 59 | num_app = ImplicitEulerPython(root_finder=solver) 60 | 61 | fr = PowerReservoir(parameters={"k": 0.01, "alpha": 2.5}, states={"S0": 0.0}, approximation=num_app, id="FR") 62 | 63 | fr.set_timestep(1.0) 64 | self._model = fr 65 | 66 | def _read_inputs(self): 67 | data = pd.read_csv( 68 | "{}/test/reference_results/01_FR/input.dat".format(package_path), 69 | header=6, 70 | sep="\s+|,\s+|,", 71 | engine="python", 72 | ) 73 | self._precipitation = data.iloc[:, 6].values 74 | self._pet = data.iloc[:, 7].values 75 | 76 | def _read_outputs(self): 77 | self._superflex_output = pd.read_csv("{}/test/reference_results/01_FR/Results.csv".format(package_path)) 78 | 79 | def _test_fr_start_stop(self, solver): 80 | self._init_model(solver=solver) 81 | self._read_outputs() 82 | self._read_inputs() 83 | 84 | # First half of time series 85 | self._model.set_input([self._precipitation[:5]]) 86 | out = self._model.get_output() 87 | 88 | msg = "Fail in the first half" 89 | 90 | self.assertTrue(np.allclose(out, self._superflex_output.iloc[:5, 0]), msg=msg) 91 | self.assertTrue(np.allclose(self._model.state_array[:, 0], self._superflex_output.iloc[:5, 1]), msg=msg) 92 | 93 | # Second half of time series 94 | self._model.set_input([self._precipitation[5:]]) 95 | out = self._model.get_output() 96 | 97 | msg = "Fail in the second half" 98 | 99 | self.assertTrue(np.allclose(out, self._superflex_output.iloc[5:, 0]), msg=msg) 100 | self.assertTrue(np.allclose(self._model.state_array[:, 0], self._superflex_output.iloc[5:, 1]), msg=msg) 101 | 102 | def test_fr_start_stop_python(self): 103 | self._test_fr_start_stop(solver="python") 104 | 105 | def test_fr_start_stop_numba(self): 106 | self._test_fr_start_stop(solver="numba") 107 | 108 | def _test_2_rounds(self, solver): 109 | self._init_model(solver=solver) 110 | self._read_outputs() 111 | self._read_inputs() 112 | 113 | # First half of time series 114 | self._model.set_input([self._precipitation]) 115 | out = self._model.get_output() 116 | 117 | msg = "Fail in the first round" 118 | 119 | self.assertTrue(np.allclose(out, self._superflex_output.iloc[:, 0]), msg=msg) 120 | self.assertTrue(np.allclose(self._model.state_array[:, 0], self._superflex_output.iloc[:, 1]), msg=msg) 121 | 122 | # Second half of time series 123 | self._model.reset_states() 124 | out = self._model.get_output() 125 | 126 | msg = "Fail in the second round" 127 | 128 | self.assertTrue(np.allclose(out, self._superflex_output.iloc[:, 0]), msg=msg) 129 | self.assertTrue(np.allclose(self._model.state_array[:, 0], self._superflex_output.iloc[:, 1]), msg=msg) 130 | 131 | def test_2_rounds_python(self): 132 | self._test_2_rounds(solver="python") 133 | 134 | def test_2_rounds_numba(self): 135 | self._test_2_rounds(solver="numba") 136 | 137 | 138 | # if __name__ == "__main__": 139 | unittest.main() 140 | # test = TestFR() 141 | # test.test_2_rounds_python() 142 | -------------------------------------------------------------------------------- /test/unittest/07_FR_2dt.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2020 Marco Dal Molin et al. 3 | 4 | This file is part of SuperflexPy. 5 | 6 | SuperflexPy is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SuperflexPy is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with SuperflexPy. If not, see . 18 | 19 | This file is part of the SuperflexPy modelling framework. For details about it, 20 | visit the page https://superflexpy.readthedocs.io 21 | 22 | CODED BY: Marco Dal Molin 23 | DESIGNED BY: Marco Dal Molin, Fabrizio Fenicia, Dmitri Kavetski 24 | """ 25 | 26 | import sys 27 | import unittest 28 | from os.path import abspath, dirname, join 29 | 30 | import numpy as np 31 | import pandas as pd 32 | 33 | # Package path is 2 levels above this file 34 | package_path = join(abspath(dirname(__file__)), "..", "..") 35 | sys.path.insert(0, package_path) 36 | 37 | from superflexpy.implementation.elements.hbv import PowerReservoir 38 | from superflexpy.implementation.numerical_approximators.implicit_euler import ( 39 | ImplicitEulerNumba, 40 | ImplicitEulerPython, 41 | ) 42 | from superflexpy.implementation.root_finders.pegasus import PegasusNumba, PegasusPython 43 | 44 | 45 | class TestFR(unittest.TestCase): 46 | """ 47 | This class tests the functionality of the reservoir FR alone. 48 | We compare the results with superflex in two scenarios: 49 | - start and stop to check that it saves the intermediate states 50 | - 2 rounds to check that it re-sets the states to the initial value 51 | """ 52 | 53 | def _init_model(self, solver): 54 | if solver == "numba": 55 | solver = PegasusNumba() 56 | num_app = ImplicitEulerNumba(root_finder=solver) 57 | elif solver == "python": 58 | solver = PegasusPython() 59 | num_app = ImplicitEulerPython(root_finder=solver) 60 | 61 | fr = PowerReservoir(parameters={"k": 0.01, "alpha": 2.5}, states={"S0": 0.0}, approximation=num_app, id="FR") 62 | 63 | fr.set_timestep(2.0) 64 | self._model = fr 65 | 66 | def _read_inputs(self): 67 | data = pd.read_csv( 68 | "{}/test/reference_results/07_FR_2dt/input.dat".format(package_path), 69 | header=6, 70 | sep="\s+|,\s+|,", 71 | engine="python", 72 | ) 73 | self._precipitation = data.iloc[:, 6].values 74 | self._pet = data.iloc[:, 7].values 75 | 76 | def _read_outputs(self): 77 | self._superflex_output = pd.read_csv("{}/test/reference_results/07_FR_2dt/Results.csv".format(package_path)) 78 | 79 | def _test_fr_start_stop(self, solver): 80 | self._init_model(solver=solver) 81 | self._read_outputs() 82 | self._read_inputs() 83 | 84 | # First half of time series 85 | self._model.set_input([self._precipitation[:5]]) 86 | out = self._model.get_output() 87 | 88 | msg = "Fail in the first half" 89 | 90 | self.assertTrue(np.allclose(out, self._superflex_output.iloc[:5, 0]), msg=msg) 91 | self.assertTrue(np.allclose(self._model.state_array[:, 0], self._superflex_output.iloc[:5, 1]), msg=msg) 92 | 93 | # Second half of time series 94 | self._model.set_input([self._precipitation[5:]]) 95 | out = self._model.get_output() 96 | 97 | msg = "Fail in the second half" 98 | 99 | self.assertTrue(np.allclose(out, self._superflex_output.iloc[5:, 0]), msg=msg) 100 | self.assertTrue(np.allclose(self._model.state_array[:, 0], self._superflex_output.iloc[5:, 1]), msg=msg) 101 | 102 | def test_fr_start_stop_python(self): 103 | self._test_fr_start_stop(solver="python") 104 | 105 | def test_fr_start_stop_numba(self): 106 | self._test_fr_start_stop(solver="numba") 107 | 108 | def _test_2_rounds(self, solver): 109 | self._init_model(solver=solver) 110 | self._read_outputs() 111 | self._read_inputs() 112 | 113 | # First half of time series 114 | self._model.set_input([self._precipitation]) 115 | out = self._model.get_output() 116 | 117 | msg = "Fail in the first round" 118 | 119 | self.assertTrue(np.allclose(out, self._superflex_output.iloc[:, 0]), msg=msg) 120 | self.assertTrue(np.allclose(self._model.state_array[:, 0], self._superflex_output.iloc[:, 1]), msg=msg) 121 | 122 | # Second half of time series 123 | self._model.reset_states() 124 | out = self._model.get_output() 125 | 126 | msg = "Fail in the second round" 127 | 128 | self.assertTrue(np.allclose(out, self._superflex_output.iloc[:, 0]), msg=msg) 129 | self.assertTrue(np.allclose(self._model.state_array[:, 0], self._superflex_output.iloc[:, 1]), msg=msg) 130 | 131 | def test_2_rounds_python(self): 132 | self._test_2_rounds(solver="python") 133 | 134 | def test_2_rounds_numba(self): 135 | self._test_2_rounds(solver="numba") 136 | 137 | 138 | # if __name__ == "__main__": 139 | unittest.main() 140 | # test = TestFR() 141 | # test.test_2_rounds_python() 142 | -------------------------------------------------------------------------------- /test/reference_results/01_FR/M01_main.dat: -------------------------------------------------------------------------------- 1 | FLEX_MAIN_CONFIGURATION_FILE_V1.05 2 | ! Description: FLEX-SPAM model configuration file 3 | !======== 4 | 01 ! index describing model configuration (for ease of reference/documentation) 5 | "M01" ! nametag describing model configuration (eg, "stdFLEX/powerAS", etc) 6 | !======== 7 | FLEX NUMERICS 8 | 1 ! numerical solver for interception reservoir (0=odeint, 1=fixed-spm-implicit, 2=bounded EE, -1=simple-threshold, -2=algebraic-statique) 9 | 3 ! numerical solver for simple reservoirs (0=odeint, 3=fixed-liebre-implicit, 2=bounded EE) 10 | 1 ! numerical solver for UR zone (0=odeint, 1=fixed-spm-implicit, 2=bounded EE) 11 | !======== 12 | FLEX DISTRIBUTION 13 | 1 ! number of HRUs 14 | 1 ! number of catchments 15 | 0 ! number of tracers 16 | 1 ! number of layers (dead storages) 17 | !======== 18 | HRU CHARACTERISTICS FILE NAME 19 | "*/flexConfig_Areas.dat" 20 | !======== 21 | UNITS FILE NAME 22 | "*/flexConfig_ML01.dat" 23 | !======== 24 | UNITS PRESENCE MATRIX 25 | FC_01(Lumped) ! ID 26 | .true. ! 27 | !======== 28 | INPUTS DESCRIPTION 29 | 2 ! precipitation input (1=lumped,2=perSubcatchment(ID),3=perFied) 30 | 0 ! tracer input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 31 | 2 ! etp input (1=lumped,2=perSubcatchment(ID),3=perFied) 32 | 0 ! temperature input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 33 | !======== 34 | DRAINAGE DISTANCES 35 | riverScaleInc riverScaleOut riverSlopeInc riverSlopeOut 36 | 1.0 1.0 1.0 1.0 37 | !======== 38 | DEPENDENCIES 39 | DrainsInto 40 | 0 41 | !======== 42 | RIVER ROUTING CONVOLUTION INFORMATION 43 | "none",.false.,-1,1 ! convolution function "symTri","genTri","kiedKeid","none", for symTri only tS and tR are needed; couple scales (if true relative scaleInc and scaleOut is preserved) smoothing options; maximum number of convolution states 44 | !======== 45 | ACTIVE_PARAMETER_INFO ! (parameters visible to BATEA) 46 | parName parDef parLo parHi parScal parSD parTran parFit linkTo Comment 47 | "Cmlt_P, - " 1.0 0.9 1.1 10.0 -9999.9 0 F 0 (cannot be dead) Rainfall multiplication factor 48 | "Cmlt_E, - " 1.0 0.2 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor for evaporation 49 | "CmltSmax_IR, - " 1.0 1.e-1 3.0 10.0 -9999.9 1 F 0 (cannot be dead) Intercaption multiplication factor 50 | "CmltSmax_UR, - " 1.0 1.e-1 500.0 10.0 -9999.9 1 F 0 (cannot be dead) SuMax multiplication factor 51 | "CmltBetaQq_UR, -" 1.0 1.e-2 10.0 10.0 -9999.9 1 F 0 (cannot be dead) BetaQq multiplication factor 52 | "Cmlt_P_WR, - " 1.0 1.e-1 3.0 10.0 -9999.9 0 F 0 (cannot be dead) Multiplication factor to wCorr in snow reservoir 53 | "CmltK_Qm_WR, - " 1.0 1.e-1 10.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qm in snow reservoir 54 | "CmltK_Qq_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qq in slow reservoir 55 | "CmltK_Qb_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qb in slow reservoir 56 | !======== 57 | MORTO_PARAMETER_INFO ! (parameters that dont exist for this configuration) 58 | "tFall_IL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 59 | "K_IL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 60 | "tFall_OL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 61 | "K_OL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 62 | "tStart_IL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 63 | "tRise_IL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 64 | "betaM_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 65 | "betaS_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 66 | "tStart_OL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 67 | "tRise_OL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 68 | "betaM_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 69 | "betaS_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 70 | !======== 71 | -------------------------------------------------------------------------------- /test/reference_results/02_UR/M01_main.dat: -------------------------------------------------------------------------------- 1 | FLEX_MAIN_CONFIGURATION_FILE_V1.05 2 | ! Description: FLEX-SPAM model configuration file 3 | !======== 4 | 01 ! index describing model configuration (for ease of reference/documentation) 5 | "M01" ! nametag describing model configuration (eg, "stdFLEX/powerAS", etc) 6 | !======== 7 | FLEX NUMERICS 8 | 1 ! numerical solver for interception reservoir (0=odeint, 1=fixed-spm-implicit, 2=bounded EE, -1=simple-threshold, -2=algebraic-statique) 9 | 3 ! numerical solver for simple reservoirs (0=odeint, 3=fixed-liebre-implicit, 2=bounded EE) 10 | 1 ! numerical solver for UR zone (0=odeint, 1=fixed-spm-implicit, 2=bounded EE) 11 | !======== 12 | FLEX DISTRIBUTION 13 | 1 ! number of HRUs 14 | 1 ! number of catchments 15 | 0 ! number of tracers 16 | 1 ! number of layers (dead storages) 17 | !======== 18 | HRU CHARACTERISTICS FILE NAME 19 | "*/flexConfig_Areas.dat" 20 | !======== 21 | UNITS FILE NAME 22 | "*/flexConfig_ML01.dat" 23 | !======== 24 | UNITS PRESENCE MATRIX 25 | FC_01(Lumped) ! ID 26 | .true. ! 27 | !======== 28 | INPUTS DESCRIPTION 29 | 2 ! precipitation input (1=lumped,2=perSubcatchment(ID),3=perFied) 30 | 0 ! tracer input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 31 | 2 ! etp input (1=lumped,2=perSubcatchment(ID),3=perFied) 32 | 0 ! temperature input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 33 | !======== 34 | DRAINAGE DISTANCES 35 | riverScaleInc riverScaleOut riverSlopeInc riverSlopeOut 36 | 1.0 1.0 1.0 1.0 37 | !======== 38 | DEPENDENCIES 39 | DrainsInto 40 | 0 41 | !======== 42 | RIVER ROUTING CONVOLUTION INFORMATION 43 | "none",.false.,-1,1 ! convolution function "symTri","genTri","kiedKeid","none", for symTri only tS and tR are needed; couple scales (if true relative scaleInc and scaleOut is preserved) smoothing options; maximum number of convolution states 44 | !======== 45 | ACTIVE_PARAMETER_INFO ! (parameters visible to BATEA) 46 | parName parDef parLo parHi parScal parSD parTran parFit linkTo Comment 47 | "Cmlt_P, - " 1.0 0.9 1.1 10.0 -9999.9 0 F 0 (cannot be dead) Rainfall multiplication factor 48 | "Cmlt_E, - " 1.0 0.2 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor for evaporation 49 | "CmltSmax_IR, - " 1.0 1.e-1 3.0 10.0 -9999.9 1 F 0 (cannot be dead) Intercaption multiplication factor 50 | "CmltSmax_UR, - " 1.0 1.e-1 500.0 10.0 -9999.9 1 F 0 (cannot be dead) SuMax multiplication factor 51 | "CmltBetaQq_UR, -" 1.0 1.e-2 10.0 10.0 -9999.9 1 F 0 (cannot be dead) BetaQq multiplication factor 52 | "Cmlt_P_WR, - " 1.0 1.e-1 3.0 10.0 -9999.9 0 F 0 (cannot be dead) Multiplication factor to wCorr in snow reservoir 53 | "CmltK_Qm_WR, - " 1.0 1.e-1 10.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qm in snow reservoir 54 | "CmltK_Qq_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qq in slow reservoir 55 | "CmltK_Qb_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qb in slow reservoir 56 | !======== 57 | MORTO_PARAMETER_INFO ! (parameters that dont exist for this configuration) 58 | "tFall_IL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 59 | "K_IL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 60 | "tFall_OL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 61 | "K_OL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 62 | "tStart_IL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 63 | "tRise_IL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 64 | "betaM_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 65 | "betaS_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 66 | "tStart_OL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 67 | "tRise_OL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 68 | "betaM_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 69 | "betaS_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 70 | !======== 71 | -------------------------------------------------------------------------------- /test/reference_results/03_UR_FR/M01_main.dat: -------------------------------------------------------------------------------- 1 | FLEX_MAIN_CONFIGURATION_FILE_V1.05 2 | ! Description: FLEX-SPAM model configuration file 3 | !======== 4 | 01 ! index describing model configuration (for ease of reference/documentation) 5 | "M01" ! nametag describing model configuration (eg, "stdFLEX/powerAS", etc) 6 | !======== 7 | FLEX NUMERICS 8 | 1 ! numerical solver for interception reservoir (0=odeint, 1=fixed-spm-implicit, 2=bounded EE, -1=simple-threshold, -2=algebraic-statique) 9 | 3 ! numerical solver for simple reservoirs (0=odeint, 3=fixed-liebre-implicit, 2=bounded EE) 10 | 1 ! numerical solver for UR zone (0=odeint, 1=fixed-spm-implicit, 2=bounded EE) 11 | !======== 12 | FLEX DISTRIBUTION 13 | 1 ! number of HRUs 14 | 1 ! number of catchments 15 | 0 ! number of tracers 16 | 1 ! number of layers (dead storages) 17 | !======== 18 | HRU CHARACTERISTICS FILE NAME 19 | "*/flexConfig_Areas.dat" 20 | !======== 21 | UNITS FILE NAME 22 | "*/flexConfig_ML01.dat" 23 | !======== 24 | UNITS PRESENCE MATRIX 25 | FC_01(Lumped) ! ID 26 | .true. ! 27 | !======== 28 | INPUTS DESCRIPTION 29 | 2 ! precipitation input (1=lumped,2=perSubcatchment(ID),3=perFied) 30 | 0 ! tracer input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 31 | 2 ! etp input (1=lumped,2=perSubcatchment(ID),3=perFied) 32 | 0 ! temperature input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 33 | !======== 34 | DRAINAGE DISTANCES 35 | riverScaleInc riverScaleOut riverSlopeInc riverSlopeOut 36 | 1.0 1.0 1.0 1.0 37 | !======== 38 | DEPENDENCIES 39 | DrainsInto 40 | 0 41 | !======== 42 | RIVER ROUTING CONVOLUTION INFORMATION 43 | "none",.false.,-1,1 ! convolution function "symTri","genTri","kiedKeid","none", for symTri only tS and tR are needed; couple scales (if true relative scaleInc and scaleOut is preserved) smoothing options; maximum number of convolution states 44 | !======== 45 | ACTIVE_PARAMETER_INFO ! (parameters visible to BATEA) 46 | parName parDef parLo parHi parScal parSD parTran parFit linkTo Comment 47 | "Cmlt_P, - " 1.0 0.9 1.1 10.0 -9999.9 0 F 0 (cannot be dead) Rainfall multiplication factor 48 | "Cmlt_E, - " 1.0 0.2 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor for evaporation 49 | "CmltSmax_IR, - " 1.0 1.e-1 3.0 10.0 -9999.9 1 F 0 (cannot be dead) Intercaption multiplication factor 50 | "CmltSmax_UR, - " 1.0 1.e-1 500.0 10.0 -9999.9 1 F 0 (cannot be dead) SuMax multiplication factor 51 | "CmltBetaQq_UR, -" 1.0 1.e-2 10.0 10.0 -9999.9 1 F 0 (cannot be dead) BetaQq multiplication factor 52 | "Cmlt_P_WR, - " 1.0 1.e-1 3.0 10.0 -9999.9 0 F 0 (cannot be dead) Multiplication factor to wCorr in snow reservoir 53 | "CmltK_Qm_WR, - " 1.0 1.e-1 10.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qm in snow reservoir 54 | "CmltK_Qq_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qq in slow reservoir 55 | "CmltK_Qb_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qb in slow reservoir 56 | !======== 57 | MORTO_PARAMETER_INFO ! (parameters that dont exist for this configuration) 58 | "tFall_IL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 59 | "K_IL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 60 | "tFall_OL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 61 | "K_OL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 62 | "tStart_IL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 63 | "tRise_IL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 64 | "betaM_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 65 | "betaS_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 66 | "tStart_OL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 67 | "tRise_OL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 68 | "betaM_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 69 | "betaS_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 70 | !======== 71 | -------------------------------------------------------------------------------- /test/reference_results/07_FR_2dt/M01_main.dat: -------------------------------------------------------------------------------- 1 | FLEX_MAIN_CONFIGURATION_FILE_V1.05 2 | ! Description: FLEX-SPAM model configuration file 3 | !======== 4 | 01 ! index describing model configuration (for ease of reference/documentation) 5 | "M01" ! nametag describing model configuration (eg, "stdFLEX/powerAS", etc) 6 | !======== 7 | FLEX NUMERICS 8 | 1 ! numerical solver for interception reservoir (0=odeint, 1=fixed-spm-implicit, 2=bounded EE, -1=simple-threshold, -2=algebraic-statique) 9 | 3 ! numerical solver for simple reservoirs (0=odeint, 3=fixed-liebre-implicit, 2=bounded EE) 10 | 1 ! numerical solver for UR zone (0=odeint, 1=fixed-spm-implicit, 2=bounded EE) 11 | !======== 12 | FLEX DISTRIBUTION 13 | 1 ! number of HRUs 14 | 1 ! number of catchments 15 | 0 ! number of tracers 16 | 1 ! number of layers (dead storages) 17 | !======== 18 | HRU CHARACTERISTICS FILE NAME 19 | "*/flexConfig_Areas.dat" 20 | !======== 21 | UNITS FILE NAME 22 | "*/flexConfig_ML01.dat" 23 | !======== 24 | UNITS PRESENCE MATRIX 25 | FC_01(Lumped) ! ID 26 | .true. ! 27 | !======== 28 | INPUTS DESCRIPTION 29 | 2 ! precipitation input (1=lumped,2=perSubcatchment(ID),3=perFied) 30 | 0 ! tracer input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 31 | 2 ! etp input (1=lumped,2=perSubcatchment(ID),3=perFied) 32 | 0 ! temperature input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 33 | !======== 34 | DRAINAGE DISTANCES 35 | riverScaleInc riverScaleOut riverSlopeInc riverSlopeOut 36 | 1.0 1.0 1.0 1.0 37 | !======== 38 | DEPENDENCIES 39 | DrainsInto 40 | 0 41 | !======== 42 | RIVER ROUTING CONVOLUTION INFORMATION 43 | "none",.false.,-1,1 ! convolution function "symTri","genTri","kiedKeid","none", for symTri only tS and tR are needed; couple scales (if true relative scaleInc and scaleOut is preserved) smoothing options; maximum number of convolution states 44 | !======== 45 | ACTIVE_PARAMETER_INFO ! (parameters visible to BATEA) 46 | parName parDef parLo parHi parScal parSD parTran parFit linkTo Comment 47 | "Cmlt_P, - " 1.0 0.9 1.1 10.0 -9999.9 0 F 0 (cannot be dead) Rainfall multiplication factor 48 | "Cmlt_E, - " 1.0 0.2 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor for evaporation 49 | "CmltSmax_IR, - " 1.0 1.e-1 3.0 10.0 -9999.9 1 F 0 (cannot be dead) Intercaption multiplication factor 50 | "CmltSmax_UR, - " 1.0 1.e-1 500.0 10.0 -9999.9 1 F 0 (cannot be dead) SuMax multiplication factor 51 | "CmltBetaQq_UR, -" 1.0 1.e-2 10.0 10.0 -9999.9 1 F 0 (cannot be dead) BetaQq multiplication factor 52 | "Cmlt_P_WR, - " 1.0 1.e-1 3.0 10.0 -9999.9 0 F 0 (cannot be dead) Multiplication factor to wCorr in snow reservoir 53 | "CmltK_Qm_WR, - " 1.0 1.e-1 10.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qm in snow reservoir 54 | "CmltK_Qq_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qq in slow reservoir 55 | "CmltK_Qb_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qb in slow reservoir 56 | !======== 57 | MORTO_PARAMETER_INFO ! (parameters that dont exist for this configuration) 58 | "tFall_IL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 59 | "K_IL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 60 | "tFall_OL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 61 | "K_OL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 62 | "tStart_IL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 63 | "tRise_IL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 64 | "betaM_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 65 | "betaS_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 66 | "tStart_OL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 67 | "tRise_OL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 68 | "betaM_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 69 | "betaS_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 70 | !======== 71 | -------------------------------------------------------------------------------- /test/reference_results/08_UR_2dt/M01_main.dat: -------------------------------------------------------------------------------- 1 | FLEX_MAIN_CONFIGURATION_FILE_V1.05 2 | ! Description: FLEX-SPAM model configuration file 3 | !======== 4 | 01 ! index describing model configuration (for ease of reference/documentation) 5 | "M01" ! nametag describing model configuration (eg, "stdFLEX/powerAS", etc) 6 | !======== 7 | FLEX NUMERICS 8 | 1 ! numerical solver for interception reservoir (0=odeint, 1=fixed-spm-implicit, 2=bounded EE, -1=simple-threshold, -2=algebraic-statique) 9 | 3 ! numerical solver for simple reservoirs (0=odeint, 3=fixed-liebre-implicit, 2=bounded EE) 10 | 1 ! numerical solver for UR zone (0=odeint, 1=fixed-spm-implicit, 2=bounded EE) 11 | !======== 12 | FLEX DISTRIBUTION 13 | 1 ! number of HRUs 14 | 1 ! number of catchments 15 | 0 ! number of tracers 16 | 1 ! number of layers (dead storages) 17 | !======== 18 | HRU CHARACTERISTICS FILE NAME 19 | "*/flexConfig_Areas.dat" 20 | !======== 21 | UNITS FILE NAME 22 | "*/flexConfig_ML01.dat" 23 | !======== 24 | UNITS PRESENCE MATRIX 25 | FC_01(Lumped) ! ID 26 | .true. ! 27 | !======== 28 | INPUTS DESCRIPTION 29 | 2 ! precipitation input (1=lumped,2=perSubcatchment(ID),3=perFied) 30 | 0 ! tracer input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 31 | 2 ! etp input (1=lumped,2=perSubcatchment(ID),3=perFied) 32 | 0 ! temperature input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 33 | !======== 34 | DRAINAGE DISTANCES 35 | riverScaleInc riverScaleOut riverSlopeInc riverSlopeOut 36 | 1.0 1.0 1.0 1.0 37 | !======== 38 | DEPENDENCIES 39 | DrainsInto 40 | 0 41 | !======== 42 | RIVER ROUTING CONVOLUTION INFORMATION 43 | "none",.false.,-1,1 ! convolution function "symTri","genTri","kiedKeid","none", for symTri only tS and tR are needed; couple scales (if true relative scaleInc and scaleOut is preserved) smoothing options; maximum number of convolution states 44 | !======== 45 | ACTIVE_PARAMETER_INFO ! (parameters visible to BATEA) 46 | parName parDef parLo parHi parScal parSD parTran parFit linkTo Comment 47 | "Cmlt_P, - " 1.0 0.9 1.1 10.0 -9999.9 0 F 0 (cannot be dead) Rainfall multiplication factor 48 | "Cmlt_E, - " 1.0 0.2 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor for evaporation 49 | "CmltSmax_IR, - " 1.0 1.e-1 3.0 10.0 -9999.9 1 F 0 (cannot be dead) Intercaption multiplication factor 50 | "CmltSmax_UR, - " 1.0 1.e-1 500.0 10.0 -9999.9 1 F 0 (cannot be dead) SuMax multiplication factor 51 | "CmltBetaQq_UR, -" 1.0 1.e-2 10.0 10.0 -9999.9 1 F 0 (cannot be dead) BetaQq multiplication factor 52 | "Cmlt_P_WR, - " 1.0 1.e-1 3.0 10.0 -9999.9 0 F 0 (cannot be dead) Multiplication factor to wCorr in snow reservoir 53 | "CmltK_Qm_WR, - " 1.0 1.e-1 10.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qm in snow reservoir 54 | "CmltK_Qq_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qq in slow reservoir 55 | "CmltK_Qb_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qb in slow reservoir 56 | !======== 57 | MORTO_PARAMETER_INFO ! (parameters that dont exist for this configuration) 58 | "tFall_IL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 59 | "K_IL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 60 | "tFall_OL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 61 | "K_OL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 62 | "tStart_IL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 63 | "tRise_IL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 64 | "betaM_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 65 | "betaS_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 66 | "tStart_OL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 67 | "tRise_OL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 68 | "betaM_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 69 | "betaS_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 70 | !======== 71 | -------------------------------------------------------------------------------- /test/reference_results/04_UR_FR_SR/M01_main.dat: -------------------------------------------------------------------------------- 1 | FLEX_MAIN_CONFIGURATION_FILE_V1.05 2 | ! Description: FLEX-SPAM model configuration file 3 | !======== 4 | 01 ! index describing model configuration (for ease of reference/documentation) 5 | "M01" ! nametag describing model configuration (eg, "stdFLEX/powerAS", etc) 6 | !======== 7 | FLEX NUMERICS 8 | 1 ! numerical solver for interception reservoir (0=odeint, 1=fixed-spm-implicit, 2=bounded EE, -1=simple-threshold, -2=algebraic-statique) 9 | 3 ! numerical solver for simple reservoirs (0=odeint, 3=fixed-liebre-implicit, 2=bounded EE) 10 | 1 ! numerical solver for UR zone (0=odeint, 1=fixed-spm-implicit, 2=bounded EE) 11 | !======== 12 | FLEX DISTRIBUTION 13 | 1 ! number of HRUs 14 | 1 ! number of catchments 15 | 0 ! number of tracers 16 | 1 ! number of layers (dead storages) 17 | !======== 18 | HRU CHARACTERISTICS FILE NAME 19 | "*/flexConfig_Areas.dat" 20 | !======== 21 | UNITS FILE NAME 22 | "*/flexConfig_ML01.dat" 23 | !======== 24 | UNITS PRESENCE MATRIX 25 | FC_01(Lumped) ! ID 26 | .true. ! 27 | !======== 28 | INPUTS DESCRIPTION 29 | 2 ! precipitation input (1=lumped,2=perSubcatchment(ID),3=perFied) 30 | 0 ! tracer input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 31 | 2 ! etp input (1=lumped,2=perSubcatchment(ID),3=perFied) 32 | 0 ! temperature input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 33 | !======== 34 | DRAINAGE DISTANCES 35 | riverScaleInc riverScaleOut riverSlopeInc riverSlopeOut 36 | 1.0 1.0 1.0 1.0 37 | !======== 38 | DEPENDENCIES 39 | DrainsInto 40 | 0 41 | !======== 42 | RIVER ROUTING CONVOLUTION INFORMATION 43 | "none",.false.,-1,1 ! convolution function "symTri","genTri","kiedKeid","none", for symTri only tS and tR are needed; couple scales (if true relative scaleInc and scaleOut is preserved) smoothing options; maximum number of convolution states 44 | !======== 45 | ACTIVE_PARAMETER_INFO ! (parameters visible to BATEA) 46 | parName parDef parLo parHi parScal parSD parTran parFit linkTo Comment 47 | "Cmlt_P, - " 1.0 0.9 1.1 10.0 -9999.9 0 F 0 (cannot be dead) Rainfall multiplication factor 48 | "Cmlt_E, - " 1.0 0.2 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor for evaporation 49 | "CmltSmax_IR, - " 1.0 1.e-1 3.0 10.0 -9999.9 1 F 0 (cannot be dead) Intercaption multiplication factor 50 | "CmltSmax_UR, - " 1.0 1.e-1 500.0 10.0 -9999.9 1 F 0 (cannot be dead) SuMax multiplication factor 51 | "CmltBetaQq_UR, -" 1.0 1.e-2 10.0 10.0 -9999.9 1 F 0 (cannot be dead) BetaQq multiplication factor 52 | "Cmlt_P_WR, - " 1.0 1.e-1 3.0 10.0 -9999.9 0 F 0 (cannot be dead) Multiplication factor to wCorr in snow reservoir 53 | "CmltK_Qm_WR, - " 1.0 1.e-1 10.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qm in snow reservoir 54 | "CmltK_Qq_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qq in slow reservoir 55 | "CmltK_Qb_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qb in slow reservoir 56 | !======== 57 | MORTO_PARAMETER_INFO ! (parameters that dont exist for this configuration) 58 | "tFall_IL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 59 | "K_IL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 60 | "tFall_OL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 61 | "K_OL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 62 | "tStart_IL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 63 | "tRise_IL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 64 | "betaM_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 65 | "betaS_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 66 | "tStart_OL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 67 | "tRise_OL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 68 | "betaM_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 69 | "betaS_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 70 | !======== 71 | -------------------------------------------------------------------------------- /test/reference_results/05_2HRUs/M01_main.dat: -------------------------------------------------------------------------------- 1 | FLEX_MAIN_CONFIGURATION_FILE_V1.05 2 | ! Description: FLEX-SPAM model configuration file 3 | !======== 4 | 01 ! index describing model configuration (for ease of reference/documentation) 5 | "M01" ! nametag describing model configuration (eg, "stdFLEX/powerAS", etc) 6 | !======== 7 | FLEX NUMERICS 8 | 1 ! numerical solver for interception reservoir (0=odeint, 1=fixed-spm-implicit, 2=bounded EE, -1=simple-threshold, -2=algebraic-statique) 9 | 3 ! numerical solver for simple reservoirs (0=odeint, 3=fixed-liebre-implicit, 2=bounded EE) 10 | 1 ! numerical solver for UR zone (0=odeint, 1=fixed-spm-implicit, 2=bounded EE) 11 | !======== 12 | FLEX DISTRIBUTION 13 | 2 ! number of HRUs 14 | 1 ! number of catchments 15 | 0 ! number of tracers 16 | 1 ! number of layers (dead storages) 17 | !======== 18 | HRU CHARACTERISTICS FILE NAME 19 | "*/flexConfig_Areas.dat" 20 | !======== 21 | UNITS FILE NAME 22 | "*/flexConfig_HRU1.dat" 23 | "*/flexConfig_HRU2.dat" 24 | !======== 25 | UNITS PRESENCE MATRIX 26 | FC_01(Cons) FC_01(NotCons) ! ID 27 | .true. .true. ! 28 | !======== 29 | INPUTS DESCRIPTION 30 | 2 ! precipitation input (1=lumped,2=perSubcatchment(ID),3=perFied) 31 | 0 ! tracer input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 32 | 2 ! etp input (1=lumped,2=perSubcatchment(ID),3=perFied) 33 | 0 ! temperature input (0=absent,1=lumped,2=perSubcatchment(ID),3=perFied) 34 | !======== 35 | DRAINAGE DISTANCES 36 | riverScaleInc riverScaleOut riverSlopeInc riverSlopeOut 37 | 1.0 1.0 1.0 1.0 38 | !======== 39 | DEPENDENCIES 40 | DrainsInto 41 | 0 42 | !======== 43 | RIVER ROUTING CONVOLUTION INFORMATION 44 | "none",.false.,-1,1 ! convolution function "symTri","genTri","kiedKeid","none", for symTri only tS and tR are needed; couple scales (if true relative scaleInc and scaleOut is preserved) smoothing options; maximum number of convolution states 45 | !======== 46 | ACTIVE_PARAMETER_INFO ! (parameters visible to BATEA) 47 | parName parDef parLo parHi parScal parSD parTran parFit linkTo Comment 48 | "Cmlt_P, - " 1.0 0.9 1.1 10.0 -9999.9 0 F 0 (cannot be dead) Rainfall multiplication factor 49 | "Cmlt_E, - " 1.0 0.2 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor for evaporation 50 | "CmltSmax_IR, - " 1.0 1.e-1 3.0 10.0 -9999.9 1 F 0 (cannot be dead) Intercaption multiplication factor 51 | "CmltSmax_UR, - " 1.0 1.e-1 500.0 10.0 -9999.9 1 F 0 (cannot be dead) SuMax multiplication factor 52 | "CmltBetaQq_UR, -" 1.0 1.e-2 10.0 10.0 -9999.9 1 F 0 (cannot be dead) BetaQq multiplication factor 53 | "Cmlt_P_WR, - " 1.0 1.e-1 3.0 10.0 -9999.9 0 F 0 (cannot be dead) Multiplication factor to wCorr in snow reservoir 54 | "CmltK_Qm_WR, - " 1.0 1.e-1 10.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qm in snow reservoir 55 | "CmltK_Qq_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qq in slow reservoir 56 | "CmltK_Qb_SR, - " 1.0 1.e-1 5.0 10.0 -9999.9 1 F 0 (cannot be dead) Multiplication factor to K_Qb in slow reservoir 57 | !======== 58 | MORTO_PARAMETER_INFO ! (parameters that dont exist for this configuration) 59 | "tFall_IL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 60 | "K_IL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 61 | "tFall_OL, t " 0.5 0.5 20.0 10.0 -9999.9 0 T 0 Time base for river routing - TFall 62 | "K_OL, 1/t " 0.0 1.e-2 4.0 10.0 -9999.9 0 F 0 k for linear nash cascade ("kiedKeid") (uses TRise as nRes) 63 | "tStart_IL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 64 | "tRise_IL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 65 | "betaM_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 66 | "betaS_IL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 67 | "tStart_OL, t " 0.0 0.0 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TStart 68 | "tRise_OL, t " 1.0 0.5 10.0 10.0 -9999.9 0 F 0 Time base for river routing - TRise 69 | "betaM_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power slope 70 | "betaS_OL, - " 1.0 0.1 1.0 10.0 -9999.9 0 F 0 Power storage (kiedKeid) or length/slope (convolution) 71 | !======== 72 | -------------------------------------------------------------------------------- /doc/model_thur_hess2020.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import sys 3 | 4 | REPO_FOLDER = pathlib.Path(__file__).absolute().parents[2] 5 | sys.path.insert(0, str(REPO_FOLDER)) 6 | from superflexpy.framework.network import Network 7 | from superflexpy.framework.node import Node 8 | from superflexpy.framework.unit import Unit 9 | from superflexpy.implementation.elements.structure_elements import ( 10 | Junction, 11 | Splitter, 12 | Transparent, 13 | ) 14 | from superflexpy.implementation.elements.thur_model_hess import ( 15 | HalfTriangularLag, 16 | PowerReservoir, 17 | SnowReservoir, 18 | UnsaturatedReservoir, 19 | ) 20 | from superflexpy.implementation.numerical_approximators.implicit_euler import ( 21 | ImplicitEulerPython, 22 | ) 23 | from superflexpy.implementation.root_finders.pegasus import PegasusPython 24 | 25 | solver = PegasusPython() 26 | approximator = ImplicitEulerPython(root_finder=solver) 27 | 28 | # Fluxes in the order P, T, PET 29 | upper_splitter = Splitter( 30 | direction=[ 31 | [0, 1, None], # P and T go to the snow reservoir 32 | [2, None, None], # PET goes to the transparent element 33 | ], 34 | weight=[[1.0, 1.0, 0.0], [0.0, 0.0, 1.0]], 35 | id="upper-splitter", 36 | ) 37 | 38 | snow = SnowReservoir( 39 | parameters={"t0": 0.0, "k": 0.01, "m": 2.0}, states={"S0": 0.0}, approximation=approximator, id="snow" 40 | ) 41 | 42 | upper_transparent = Transparent(id="upper-transparent") 43 | 44 | upper_junction = Junction(direction=[[0, None], [None, 0]], id="upper-junction") 45 | 46 | unsaturated = UnsaturatedReservoir( 47 | parameters={"Smax": 50.0, "Ce": 1.0, "m": 0.01, "beta": 2.0}, 48 | states={"S0": 10.0}, 49 | approximation=approximator, 50 | id="unsaturated", 51 | ) 52 | 53 | lower_splitter = Splitter( 54 | direction=[[0], [0]], 55 | weight=[[0.3], [0.7]], # Portion to slow reservoir # Portion to fast reservoir 56 | id="lower-splitter", 57 | ) 58 | 59 | lag_fun = HalfTriangularLag(parameters={"lag-time": 2.0}, states={"lag": None}, id="lag-fun") 60 | 61 | fast = PowerReservoir(parameters={"k": 0.01, "alpha": 3.0}, states={"S0": 0.0}, approximation=approximator, id="fast") 62 | 63 | slow = PowerReservoir(parameters={"k": 1e-4, "alpha": 1.0}, states={"S0": 0.0}, approximation=approximator, id="slow") 64 | 65 | lower_transparent = Transparent(id="lower-transparent") 66 | 67 | lower_junction = Junction(direction=[[0, 0]], id="lower-junction") 68 | 69 | consolidated = Unit( 70 | layers=[ 71 | [upper_splitter], 72 | [snow, upper_transparent], 73 | [upper_junction], 74 | [unsaturated], 75 | [lower_splitter], 76 | [slow, lag_fun], 77 | [lower_transparent, fast], 78 | [lower_junction], 79 | ], 80 | id="consolidated", 81 | ) 82 | 83 | unconsolidated = Unit( 84 | layers=[ 85 | [upper_splitter], 86 | [snow, upper_transparent], 87 | [upper_junction], 88 | [unsaturated], 89 | [lower_splitter], 90 | [slow, lag_fun], 91 | [lower_transparent, fast], 92 | [lower_junction], 93 | ], 94 | id="unconsolidated", 95 | ) 96 | 97 | andelfingen = Node(units=[consolidated, unconsolidated], weights=[0.24, 0.76], area=403.3, id="andelfingen") 98 | 99 | appenzell = Node(units=[consolidated, unconsolidated], weights=[0.92, 0.08], area=74.4, id="appenzell") 100 | 101 | frauenfeld = Node(units=[consolidated, unconsolidated], weights=[0.49, 0.51], area=134.4, id="frauenfeld") 102 | 103 | halden = Node(units=[consolidated, unconsolidated], weights=[0.34, 0.66], area=314.3, id="halden") 104 | 105 | herisau = Node(units=[consolidated, unconsolidated], weights=[0.88, 0.12], area=16.7, id="herisau") 106 | 107 | jonschwil = Node(units=[consolidated, unconsolidated], weights=[0.9, 0.1], area=401.6, id="jonschwil") 108 | 109 | mogelsberg = Node(units=[consolidated, unconsolidated], weights=[0.92, 0.08], area=88.1, id="mogelsberg") 110 | 111 | mosnang = Node(units=[consolidated], weights=[1.0], area=3.1, id="mosnang") 112 | 113 | stgallen = Node(units=[consolidated, unconsolidated], weights=[0.87, 0.13], area=186.6, id="stgallen") 114 | 115 | waengi = Node(units=[consolidated, unconsolidated], weights=[0.63, 0.37], area=78.9, id="waengi") 116 | 117 | thur_catchment = Network( 118 | nodes=[ 119 | andelfingen, 120 | appenzell, 121 | frauenfeld, 122 | halden, 123 | herisau, 124 | jonschwil, 125 | mogelsberg, 126 | mosnang, 127 | stgallen, 128 | waengi, 129 | ], 130 | topology={ 131 | "andelfingen": None, 132 | "appenzell": "stgallen", 133 | "frauenfeld": "andelfingen", 134 | "halden": "andelfingen", 135 | "herisau": "halden", 136 | "jonschwil": "halden", 137 | "mogelsberg": "jonschwil", 138 | "mosnang": "jonschwil", 139 | "stgallen": "halden", 140 | "waengi": "frauenfeld", 141 | }, 142 | ) 143 | 144 | thur_catchment.set_timestep(1.0) 145 | 146 | catchments = [ 147 | andelfingen, 148 | appenzell, 149 | frauenfeld, 150 | halden, 151 | herisau, 152 | jonschwil, 153 | mogelsberg, 154 | mosnang, 155 | stgallen, 156 | waengi, 157 | ] 158 | 159 | catchments_names = [ 160 | "andelfingen", 161 | "appenzell", 162 | "frauenfeld", 163 | "halden", 164 | "herisau", 165 | "jonschwil", 166 | "mogelsberg", 167 | "mosnang", 168 | "stgallen", 169 | "waengi", 170 | ] 171 | 172 | df = {} 173 | 174 | for cat, cat_name in zip(catchments, catchments_names): 175 | cat.set_input( 176 | [ 177 | df["P_{}".format(cat_name)].values, 178 | df["T_{}".format(cat_name)].values, 179 | df["PET_{}".format(cat_name)].values, 180 | ] 181 | ) 182 | 183 | thur_catchment.set_timestep(1.0) 184 | 185 | output = thur_catchment.get_output() 186 | -------------------------------------------------------------------------------- /doc/case_studies.rst: -------------------------------------------------------------------------------- 1 | .. note:: Last update 04/05/2021 2 | 3 | .. .. warning:: This guide is still work in progress. New pages are being written 4 | .. and existing ones modified. Once the guide will reach its final 5 | .. version, this box will disappear. 6 | 7 | .. _case_studies: 8 | 9 | Case studies 10 | ============ 11 | 12 | This page describes the model configurations used in research publications based 13 | on Superflex and SuperflexPy. 14 | 15 | .. _thur_case_study: 16 | 17 | Dal Molin et al., 2020, HESS 18 | ---------------------------- 19 | 20 | This section describes the implementation of the semi-distributed hydrological 21 | model M02 presented in the article: 22 | 23 | Dal Molin, M., Schirmer, M., Zappa, M., and Fenicia, F.: **Understanding** 24 | **dominant controls on streamflow spatial variability to set up a** 25 | **semi-distributed hydrological model: the case study of the Thur** 26 | **catchment**, Hydrol. Earth Syst. Sci., 24, 1319–1345, 27 | https://doi.org/10.5194/hess-24-1319-2020, 2020. 28 | 29 | In this application, the Thur catchment is discretized into 10 subcatchments and 2 30 | hydrological response units (HRUs). Please refer to the article for the details; 31 | here we only show the SuperflexPy code needed to reproduce the model from the 32 | publication. 33 | 34 | Model structure 35 | ............... 36 | 37 | The two HRUs are represented using the same model structure, shown in the 38 | figure below. 39 | 40 | .. image:: pics/case_studies/model_structure_thur.png 41 | :align: center 42 | 43 | This model structure is similar to :ref:`hymod`; its implementation using 44 | SuperflexPy is presented next. 45 | 46 | .. image:: pics/case_studies/ThurHESS2020.png 47 | :align: center 48 | 49 | This model structure includes a snow model, and hence requires time series of 50 | temperature as an input in addition to precipitation and PET. 51 | Inputs are assigned to the element in the first layer of the unit and the 52 | model structure then propagates these inputs through all the elements until they 53 | reach the element (snow reservoir) where they are actually needed. Consequently, all the elements 54 | upstream of the snow reservoir have to be able to handle (i.e. to input and output) that input. 55 | 56 | In this model, the choice of temperature as input is convenient because 57 | temperature is required by the element appearing first in the model structure. 58 | 59 | In other cases, an alternative solution would have been to design the snow 60 | reservoir such that the temperature is one of its state variables. This solution 61 | would be preferable if the snow reservoir is not the first element of the 62 | structure, given that temperature is not an input commonly used by other 63 | elements. 64 | 65 | The discretization of the Thur catchment into units (HRUs) and nodes 66 | (subcatchments) is represented in the figure below. 67 | 68 | .. image:: pics/case_studies/ThurSchemeNodes.png 69 | :align: center 70 | 71 | Initializing the elements 72 | ......................... 73 | 74 | All elements required for this model structure are already available in 75 | SuperflexPy. Therefore they just need to be imported. 76 | 77 | .. literalinclude:: model_thur_hess2020.py 78 | :language: python 79 | :lines: 5-6, 10, 11 80 | :linenos: 81 | 82 | Elements are then initialized, defining the initial state and parameter values. 83 | 84 | .. literalinclude:: model_thur_hess2020.py 85 | :language: python 86 | :lines: 13-15, 17-96 87 | :linenos: 88 | 89 | Initializing the HRUs structure 90 | ............................... 91 | 92 | We now define the two units that represent the HRUs. 93 | 94 | .. literalinclude:: model_thur_hess2020.py 95 | :language: python 96 | :lines: 98-124 97 | :linenos: 98 | 99 | Initializing the catchments 100 | ........................... 101 | 102 | We now assign the units (HRUs) to the nodes (catchments). 103 | 104 | .. literalinclude:: model_thur_hess2020.py 105 | :language: python 106 | :lines: 126-194 107 | :linenos: 108 | 109 | Note that all nodes incorporate the information about their :code:`area`, which 110 | is used by the network to calculate their contribution to the total outflow. 111 | 112 | There is no requirement for a node to contain all units. For example, the unit 113 | :code:`unconsolidated` is not present in the Mosnang subcatchment. Hence, as 114 | shown in line 50, the node :code:`mosnang` is defined to contain only the unit 115 | :code:`consolidated`. 116 | 117 | Initializing the network 118 | ........................ 119 | 120 | The last step consists in creating the network that connects all the nodes 121 | previously initialized. 122 | 123 | .. literalinclude:: model_thur_hess2020.py 124 | :language: python 125 | :lines: 196-221 126 | :linenos: 127 | 128 | Running the model 129 | ................. 130 | 131 | Before the model can be run, we need to set the input fluxes and the time step size. 132 | 133 | The input fluxes are assigned to the individual nodes (catchments). 134 | Here, the data is available as a Pandas DataFrame, with columns names :code:`P_name_of_the_catchment`, 135 | :code:`T_name_of_the_catchment`, and :code:`PET_name_of_the_catchment`. 136 | 137 | The inputs can be set using a :code:`for` loop 138 | 139 | .. literalinclude:: model_thur_hess2020.py 140 | :language: python 141 | :lines: 253-258 142 | :linenos: 143 | 144 | The model time step size is set next. This can be done directly at the 145 | network level, which automatically sets the time step size to all lower-level 146 | model components. 147 | 148 | .. literalinclude:: model_thur_hess2020.py 149 | :language: python 150 | :lines: 260 151 | :linenos: 152 | 153 | We can now run the model and access its output (see :ref:`demo_network` for details). 154 | 155 | .. literalinclude:: model_thur_hess2020.py 156 | :language: python 157 | :lines: 262 158 | :linenos: 159 | --------------------------------------------------------------------------------