pyfloodrisk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyfloodrisk-0.1.0/LICENSE +21 -0
- pyfloodrisk-0.1.0/PKG-INFO +75 -0
- pyfloodrisk-0.1.0/README.md +54 -0
- pyfloodrisk-0.1.0/pyproject.toml +42 -0
- pyfloodrisk-0.1.0/setup.cfg +4 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/__init__.py +28 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/calibration_robust.py +191 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/CS_418005/Areal_CS_AllStats.csv +892 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/CS_418005/Areal_CS_Increments.csv +892 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/CS_418005/CS_AllStats.csv +721 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/CS_418005/CS_Increments.csv +721 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/CS_421026/Areal_ECsouth_AllStats.csv +892 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/CS_421026/Areal_ECsouth_Increments.csv +892 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/CS_421026/ECsouth_AllStats.csv +745 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/CS_421026/ECsouth_Increments.csv +721 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/GR4H_climatedata/GR4H_climatedata_418005_hr.csv +52585 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/GR4H_climatedata/GR4H_climatedata_421026_hr.csv +57635 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/__init__.py +0 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/hrs_station_details.csv +479 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp01.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp02.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp03.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp04.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp05.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp06.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp07.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp08.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp09.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/data/storms/421026_1in2000_12hr_tp10.csv +121 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/demo_data.py +88 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/design_flood.py +187 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/design_storm.py +231 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/gr4h/GR4H_calibrate.py +128 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/gr4h/GR4H_model.py +416 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/gr4h/__init__.py +10 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk/hydroevents.py +401 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk.egg-info/PKG-INFO +75 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk.egg-info/SOURCES.txt +41 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk.egg-info/dependency_links.txt +1 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk.egg-info/requires.txt +10 -0
- pyfloodrisk-0.1.0/src/pyfloodrisk.egg-info/top_level.txt +1 -0
- pyfloodrisk-0.1.0/tests/test_demo_data.py +42 -0
- pyfloodrisk-0.1.0/tests/test_design_storm.py +42 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ze Jiang, Caleb Dykman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyfloodrisk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Flood Risk Assessment Workflow for GR4H-Based Design Flood Analysis
|
|
5
|
+
Author-email: Ze Jiang <ze.jiang@unsw.edu.au>, Caleb Dykman <caleb.dykman@unsw.edu.au>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/crdykman/pyfloodrisk
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: numpy>=1.24
|
|
12
|
+
Requires-Dist: pandas>=2.0
|
|
13
|
+
Requires-Dist: scipy>=1.10
|
|
14
|
+
Requires-Dist: numba>=0.57
|
|
15
|
+
Requires-Dist: spotpy>=1.5
|
|
16
|
+
Requires-Dist: seaborn>=0.12
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# pyfloodrisk
|
|
23
|
+
|
|
24
|
+
Flood Risk Assessment Workflow for GR4H-Based Design Flood Analysis.
|
|
25
|
+
|
|
26
|
+
`pyfloodrisk` is a Python port of an R-based design flood workflow built
|
|
27
|
+
around the GR4H hourly rainfall-runoff model. It covers the full pipeline
|
|
28
|
+
from streamflow calibration through to design flood simulation:
|
|
29
|
+
|
|
30
|
+
- **GR4H** — hourly production/routing rainfall-runoff model
|
|
31
|
+
(`pyfloodrisk.gr4h`).
|
|
32
|
+
- **Calibration** — DREAM-based calibration against observed streamflow,
|
|
33
|
+
plus an optional robust re-calibration step that re-ranks the
|
|
34
|
+
behavioural posterior against design storm events
|
|
35
|
+
(`calibration`, `behavioural_posterior`, `robust_calibration`).
|
|
36
|
+
- **Event delineation** — baseflow separation and hydrologic event
|
|
37
|
+
extraction (peaks-over-threshold or local maxima), used to derive
|
|
38
|
+
antecedent model states ahead of each event (`hydro_event_pipeline`,
|
|
39
|
+
`extract_initial_states`).
|
|
40
|
+
- **Design storms** — builds design storms from temporal-pattern
|
|
41
|
+
increment files (`build_design_storm`).
|
|
42
|
+
- **Design flood simulation** — runs GR4H forward across design storm
|
|
43
|
+
patterns and antecedent states to produce a design flood ensemble
|
|
44
|
+
(`simulate_design_flood`, `run_demo_workflow`).
|
|
45
|
+
|
|
46
|
+
A small bundled demo dataset (climate data and design storm increments
|
|
47
|
+
for two stations) lets the whole workflow run end-to-end without any
|
|
48
|
+
external data.
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install -e .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For running the test suite:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install -e ".[dev]"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quickstart
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from pyfloodrisk import run_demo_workflow
|
|
66
|
+
|
|
67
|
+
results = run_demo_workflow(station="421026")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Development
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# pyfloodrisk
|
|
2
|
+
|
|
3
|
+
Flood Risk Assessment Workflow for GR4H-Based Design Flood Analysis.
|
|
4
|
+
|
|
5
|
+
`pyfloodrisk` is a Python port of an R-based design flood workflow built
|
|
6
|
+
around the GR4H hourly rainfall-runoff model. It covers the full pipeline
|
|
7
|
+
from streamflow calibration through to design flood simulation:
|
|
8
|
+
|
|
9
|
+
- **GR4H** — hourly production/routing rainfall-runoff model
|
|
10
|
+
(`pyfloodrisk.gr4h`).
|
|
11
|
+
- **Calibration** — DREAM-based calibration against observed streamflow,
|
|
12
|
+
plus an optional robust re-calibration step that re-ranks the
|
|
13
|
+
behavioural posterior against design storm events
|
|
14
|
+
(`calibration`, `behavioural_posterior`, `robust_calibration`).
|
|
15
|
+
- **Event delineation** — baseflow separation and hydrologic event
|
|
16
|
+
extraction (peaks-over-threshold or local maxima), used to derive
|
|
17
|
+
antecedent model states ahead of each event (`hydro_event_pipeline`,
|
|
18
|
+
`extract_initial_states`).
|
|
19
|
+
- **Design storms** — builds design storms from temporal-pattern
|
|
20
|
+
increment files (`build_design_storm`).
|
|
21
|
+
- **Design flood simulation** — runs GR4H forward across design storm
|
|
22
|
+
patterns and antecedent states to produce a design flood ensemble
|
|
23
|
+
(`simulate_design_flood`, `run_demo_workflow`).
|
|
24
|
+
|
|
25
|
+
A small bundled demo dataset (climate data and design storm increments
|
|
26
|
+
for two stations) lets the whole workflow run end-to-end without any
|
|
27
|
+
external data.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For running the test suite:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install -e ".[dev]"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quickstart
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from pyfloodrisk import run_demo_workflow
|
|
45
|
+
|
|
46
|
+
results = run_demo_workflow(station="421026")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Development
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pyfloodrisk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Flood Risk Assessment Workflow for GR4H-Based Design Flood Analysis"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Ze Jiang", email = "ze.jiang@unsw.edu.au" },
|
|
13
|
+
{ name = "Caleb Dykman", email = "caleb.dykman@unsw.edu.au" },
|
|
14
|
+
]
|
|
15
|
+
requires-python = ">=3.10"
|
|
16
|
+
dependencies = [
|
|
17
|
+
"numpy>=1.24",
|
|
18
|
+
"pandas>=2.0",
|
|
19
|
+
"scipy>=1.10",
|
|
20
|
+
"numba>=0.57",
|
|
21
|
+
"spotpy>=1.5",
|
|
22
|
+
"seaborn>=0.12",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
dev = ["pytest>=7", "pytest-cov"]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Repository = "https://github.com/crdykman/pyfloodrisk"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["src"]
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.package-dir]
|
|
35
|
+
"" = "src"
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.package-data]
|
|
38
|
+
"pyfloodrisk.data" = ["**/*"]
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
testpaths = ["tests"]
|
|
42
|
+
pythonpath = ["src"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Flood Risk Assessment: GR4H-Based Design Flood Analysis."""
|
|
2
|
+
|
|
3
|
+
from .calibration_robust import behavioural_posterior, calibration, robust_calibration
|
|
4
|
+
from .demo_data import (
|
|
5
|
+
catchment_data,
|
|
6
|
+
demo_paths,
|
|
7
|
+
list_demo_stations,
|
|
8
|
+
load_demo_station_data,
|
|
9
|
+
)
|
|
10
|
+
from .design_flood import run_demo_workflow, simulate_design_flood
|
|
11
|
+
from .design_storm import build_design_storm
|
|
12
|
+
from .hydroevents import extract_initial_states, hydro_event_pipeline
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|
|
15
|
+
__all__ = [
|
|
16
|
+
"behavioural_posterior",
|
|
17
|
+
"build_design_storm",
|
|
18
|
+
"calibration",
|
|
19
|
+
"catchment_data",
|
|
20
|
+
"demo_paths",
|
|
21
|
+
"extract_initial_states",
|
|
22
|
+
"hydro_event_pipeline",
|
|
23
|
+
"list_demo_stations",
|
|
24
|
+
"load_demo_station_data",
|
|
25
|
+
"robust_calibration",
|
|
26
|
+
"run_demo_workflow",
|
|
27
|
+
"simulate_design_flood",
|
|
28
|
+
]
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""DREAM-based calibration and robust (multi-event) re-calibration of GR4H."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import seaborn as sns
|
|
6
|
+
import spotpy
|
|
7
|
+
|
|
8
|
+
from .gr4h.GR4H_model import GR4H
|
|
9
|
+
from .gr4h.GR4H_calibrate import spot_setup
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def calibration(area, data, nsamples, eventsidx=None, save_output=True):
|
|
13
|
+
"""Calibrate GR4H against observed streamflow using DREAM.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
area : float
|
|
18
|
+
Catchment area in km2.
|
|
19
|
+
data : str or Path
|
|
20
|
+
Path to a climate CSV with ``prec``, ``pet``, and ``qt`` columns.
|
|
21
|
+
nsamples : int
|
|
22
|
+
Maximum number of DREAM function evaluations (repetitions).
|
|
23
|
+
eventsidx : array_like, optional
|
|
24
|
+
Indices to restrict the objective function to specific events.
|
|
25
|
+
If None, all data after the warm-up period is used.
|
|
26
|
+
save_output : bool, optional
|
|
27
|
+
If True (default), save the DREAM chain history to
|
|
28
|
+
``dream_calibration_results.npy``.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
Structured array of DREAM chain results (parameters, likelihood,
|
|
33
|
+
and chain id per sample), as returned by ``spotpy``'s
|
|
34
|
+
``sampler.getdata()``.
|
|
35
|
+
"""
|
|
36
|
+
spotsetup = spot_setup(
|
|
37
|
+
data,
|
|
38
|
+
area,
|
|
39
|
+
obj_func=spotpy.objectivefunctions.nashsutcliffe,
|
|
40
|
+
ps0=1.0,
|
|
41
|
+
rs0=0.5,
|
|
42
|
+
warmup=365,
|
|
43
|
+
events=eventsidx,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
sampler = spotpy.algorithms.dream(
|
|
47
|
+
spotsetup,
|
|
48
|
+
dbname="DREAM_GR4H",
|
|
49
|
+
dbformat="ram",
|
|
50
|
+
save_threshold=0.0,
|
|
51
|
+
save_sim=False,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# DREAM sampling settings
|
|
55
|
+
rep = nsamples # maximum number of function evaluations allowed
|
|
56
|
+
nChains = max(nsamples // 1000, 10)
|
|
57
|
+
nCr = 3
|
|
58
|
+
delta = 3
|
|
59
|
+
c = 0.1
|
|
60
|
+
eps = 10e-6
|
|
61
|
+
convergence_limit = 1.01
|
|
62
|
+
runs_after_convergence = 100
|
|
63
|
+
acceptance_test_option = 1
|
|
64
|
+
|
|
65
|
+
sampler.sample(
|
|
66
|
+
rep,
|
|
67
|
+
nChains,
|
|
68
|
+
nCr,
|
|
69
|
+
delta,
|
|
70
|
+
c,
|
|
71
|
+
eps,
|
|
72
|
+
convergence_limit,
|
|
73
|
+
runs_after_convergence,
|
|
74
|
+
acceptance_test_option,
|
|
75
|
+
)
|
|
76
|
+
results = sampler.getdata()
|
|
77
|
+
if save_output:
|
|
78
|
+
np.save("dream_calibration_results.npy", results)
|
|
79
|
+
|
|
80
|
+
return results
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def behavioural_posterior(results, Cb=0.6, n=100):
|
|
84
|
+
"""Select the behavioural posterior from a DREAM calibration run.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
results : structured ndarray
|
|
89
|
+
Output of :func:`calibration`.
|
|
90
|
+
Cb : float, optional
|
|
91
|
+
Minimum likelihood (``like1``) threshold for a sample to be
|
|
92
|
+
considered behavioural. Default 0.6.
|
|
93
|
+
n : int, optional
|
|
94
|
+
Number of top-likelihood samples to consider before applying the
|
|
95
|
+
``Cb`` threshold. Default 100.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
Structured ndarray subset of ``results``, sorted by descending
|
|
100
|
+
likelihood and filtered to ``like1 >= Cb``.
|
|
101
|
+
"""
|
|
102
|
+
topn = np.sort(results, order="like1")[-n:][::-1]
|
|
103
|
+
bpost = topn[topn["like1"] >= Cb]
|
|
104
|
+
return bpost
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def robust_calibration(
|
|
108
|
+
posterior,
|
|
109
|
+
area,
|
|
110
|
+
events,
|
|
111
|
+
ps=[0.5, 0.6, 0.7, 0.8, 0.9],
|
|
112
|
+
rs=[0.5, 0.6, 0.7, 0.8, 0.9],
|
|
113
|
+
topn=20,
|
|
114
|
+
save_output=False,
|
|
115
|
+
):
|
|
116
|
+
"""Re-rank a behavioural posterior by robustness against design events.
|
|
117
|
+
|
|
118
|
+
For every posterior parameter set and every combination of initial
|
|
119
|
+
production/routing state (``ps``/``rs``), simulates each design event
|
|
120
|
+
and scores parameter sets by how consistently they reproduce a
|
|
121
|
+
plausible peak-flow distribution (estimated via KDE) across events of
|
|
122
|
+
the same frequency.
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
posterior : structured ndarray
|
|
127
|
+
Behavioural posterior from :func:`behavioural_posterior`.
|
|
128
|
+
area : float
|
|
129
|
+
Catchment area in km2.
|
|
130
|
+
events : dict
|
|
131
|
+
Nested mapping ``{duration: {frequency: [forcings, ...]}}``, where
|
|
132
|
+
each ``forcings`` is a DataFrame accepted by ``GR4H.run``.
|
|
133
|
+
ps, rs : list of float, optional
|
|
134
|
+
Candidate initial production/routing storage fractions to test.
|
|
135
|
+
topn : int, optional
|
|
136
|
+
Number of most robust parameter sets to keep. Default 20.
|
|
137
|
+
save_output : bool, optional
|
|
138
|
+
If True, save the retained parameter sets to
|
|
139
|
+
``robust_models_{duration}hr.npy``.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
Structured ndarray subset of ``posterior`` containing the ``topn``
|
|
144
|
+
most robust parameter sets for the (first) duration in ``events``.
|
|
145
|
+
"""
|
|
146
|
+
durs = events.keys()
|
|
147
|
+
for d in durs:
|
|
148
|
+
df_likelihood = pd.DataFrame()
|
|
149
|
+
frqs = events[d].keys()
|
|
150
|
+
for f in frqs:
|
|
151
|
+
sims_event_max = pd.DataFrame()
|
|
152
|
+
nevents = len(events[d][f])
|
|
153
|
+
nsimspfd = nevents * len(ps) * len(rs)
|
|
154
|
+
for j in range(len(posterior)):
|
|
155
|
+
for m in ps:
|
|
156
|
+
for n in rs:
|
|
157
|
+
parameters = {
|
|
158
|
+
"ps0": m, # Initial production storage (ps/X1)
|
|
159
|
+
"rs0": n, # Initial routing storage (rs/X3)
|
|
160
|
+
"x1": posterior[j][1], # Max production capacity (mm)
|
|
161
|
+
"x2": posterior[j][2], # Water exchange coeff. (mm)
|
|
162
|
+
"x3": posterior[j][3], # Routing max capacity (mm)
|
|
163
|
+
"x4": posterior[j][4], # Unit hydrograph base (hrs)
|
|
164
|
+
}
|
|
165
|
+
# Create a model
|
|
166
|
+
model = GR4H(area=area, params=parameters)
|
|
167
|
+
for i in range(nevents):
|
|
168
|
+
# Run model
|
|
169
|
+
sim = model.run(events[d][f][i])
|
|
170
|
+
col = f"Param-{i}_ps0-{m}_rs0-{n}_event-{i}_1in{f}_dur-{d}"
|
|
171
|
+
sims_event_max[col] = [sim.qt.max()]
|
|
172
|
+
|
|
173
|
+
# Robustness: score peak flows against a KDE of their distribution
|
|
174
|
+
x, y = (
|
|
175
|
+
sns.kdeplot(sims_event_max.values[0], cut=10, clip=(0, None))
|
|
176
|
+
.get_lines()[0]
|
|
177
|
+
.get_data()
|
|
178
|
+
)
|
|
179
|
+
likelihood = np.zeros(len(posterior))
|
|
180
|
+
for i in range(len(posterior)):
|
|
181
|
+
window = sims_event_max.values[0, i * nsimspfd:(i + 1) * nsimspfd]
|
|
182
|
+
likelihood[i] = np.sum(np.interp(window, x, np.log10(y)))
|
|
183
|
+
df_likelihood[f"Likelihood_1in{f}"] = likelihood
|
|
184
|
+
|
|
185
|
+
df_likelihood["Likelihood_total"] = df_likelihood.sum(axis=1)
|
|
186
|
+
robust_models_idx = df_likelihood.nlargest(topn, "Likelihood_total").index
|
|
187
|
+
robust_models = posterior[robust_models_idx]
|
|
188
|
+
if save_output:
|
|
189
|
+
np.save(f"robust_models_{d}hr.npy", robust_models)
|
|
190
|
+
|
|
191
|
+
return robust_models
|