Commit 02c22fc5 authored by Thibault Hallouin's avatar Thibault Hallouin
Browse files

update to new evalhyd API

The new API of `evalhyd` is centred around two `evaluate` functions,
one for deterministic evaluation and one for probabilistic evaluation.
The probabilitist side of things is not header-only anymore, and so
additional C++ source files needed to be pointed to in *setup.py*.
The example notebooks are also updated to reflect those changes.
No related merge requests found
Showing with 378 additions and 47 deletions
+378 -47
Subproject commit 2d7ac593980dcd6ee8352ad9e713e4874741772b Subproject commit d4371768981123eb42f638cede8f22b1a4e0f75e
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
import numpy import numpy
import evalhyd import evalhyd.determinist as ehd
``` ```
%% Cell type:markdown id: tags:
### Calculate Nash-Sutcliffe efficiency on 1D arrays
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
sim = numpy.array(
[5.3, 4.2, 5.7, 2.3]
)
obs = numpy.array( obs = numpy.array(
[4.7, 4.3, 5.5, 2.7] [4.7, 4.3, 5.5, 2.7]
) )
print(evalhyd.nse(sim, obs)) sim = numpy.array(
[5.3, 4.2, 5.7, 2.3]
)
print(obs.shape, sim.shape)
``` ```
%% Output %% Output
[0.86298077] (4,) (4,)
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
sim = numpy.array( ehd.evaluate(['nse'], obs, sim)
[[5.3, 5.3, 5.3],
[4.2, 4.2, 4.2],
[5.7, 5.7, 5.7],
[2.3, 2.3, 2.3]]
)
obs = numpy.array(
[[4.7],
[4.3],
[5.5],
[2.7]]
)
print(sim.shape, obs.shape)
print(evalhyd.nse(sim, obs, axis=0))
``` ```
%% Output %% Output
(4, 3) (4, 1) [array([0.86298077])]
[[0.86298077 0.86298077 0.86298077]]
%% Cell type:markdown id: tags:
### Calculate Nash-Sutcliffe efficiency on 2D arrays
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
sim = numpy.array(
[[5.3, 4.2, 5.7, 2.3],
[5.3, 4.2, 5.7, 2.3],
[5.3, 4.2, 5.7, 2.3]]
)
obs = numpy.array( obs = numpy.array(
[[4.7, 4.3, 5.5, 2.7]] [[4.7, 4.3, 5.5, 2.7]]
) )
print(sim.shape, obs.shape) sim = numpy.array(
print(evalhyd.nse(sim, obs, axis=1)) [[5.3, 4.2, 5.7, 2.3],
[4.3, 4.2, 4.7, 4.3],
[5.3, 5.2, 5.7, 2.3]]
)
print(obs.shape, sim.shape)
```
%% Output
(1, 4) (3, 4)
%% Cell type:code id: tags:
``` python
ehd.evaluate(['nse'], obs, sim)
``` ```
%% Output %% Output
(3, 4) (1, 4) [array([[0.86298077],\n [0.18990385],\n [0.67067308]])]
[[0.86298077]
[0.86298077]
[0.86298077]]
......
%% Cell type:code id: tags:
``` python
import numpy
import evalhyd.probabilist as ehp
```
%% Cell type:markdown id: tags:
### Calculate Brier score and Brier skill score at once
%% Cell type:code id: tags:
``` python
# streamflow observations
obs = numpy.array(
[[4.7, 4.3, 5.5, 2.7, 4.1]]
)
# streamflow forecasts (3 members)
frc = numpy.array(
[[5.3, 4.2, 5.7, 2.3, 3.1],
[4.3, 4.2, 4.7, 4.3, 3.3],
[5.3, 5.2, 5.7, 2.3, 3.9]]
)
# streamflow thresholds (2)
thr = [4., 5.]
print(obs.shape, frc.shape)
```
%% Output
(1, 5) (3, 5)
%% Cell type:code id: tags:
``` python
bs, bss = ehp.evaluate(['bs', 'bss'], obs, frc, thr)
```
%% Cell type:code id: tags:
``` python
print("Brier score", numpy.squeeze(bs))
```
%% Output
Brier score [0.22222222 0.13333333]
%% Cell type:code id: tags:
``` python
print("Brier skill score", numpy.squeeze(bss))
```
%% Output
Brier skill score [-0.38888889 0.16666667]
%% Cell type:markdown id: tags:
### Calculate decompositions of Brier score
%% Cell type:code id: tags:
``` python
bs_crd, bs_lbd = ehp.evaluate(['bs_crd', 'bs_lbd'], obs, frc, [4., 5.])
```
%% Cell type:code id: tags:
``` python
# calibration-refinement decomposition
rel, res, unc = bs_crd.T
print("reliability", rel)
print("resolution", res)
print("uncertainty", unc)
```
%% Output
reliability [0.22222222 0.03333333]
resolution [0.16 0.06]
uncertainty [0.16 0.16]
%% Cell type:code id: tags:
``` python
# bs = rel - res + unc?
numpy.allclose(numpy.squeeze(bs), rel - res + unc)
```
%% Output
True
%% Cell type:code id: tags:
``` python
# likelihood-based decomposition
t2b, dis, shr = bs_lbd.T
print("type 2 bias", t2b)
print("discrimination", dis)
print("sharpness", shr)
```
%% Output
type 2 bias [0.07222222 0.07222222]
discrimination [0.02777778 0.02777778]
sharpness [0.17777778 0.08888889]
%% Cell type:code id: tags:
``` python
# bs = t2b - dis + shr?
numpy.allclose(numpy.squeeze(bs), t2b - dis + shr)
```
%% Output
True
...@@ -40,7 +40,10 @@ class get_numpy_include(object): ...@@ -40,7 +40,10 @@ class get_numpy_include(object):
ext_modules = [ ext_modules = [
Extension( Extension(
'evalhyd', 'evalhyd',
['src/evalhyd-python.cpp'], ['src/evalhyd-python.cpp',
'deps/evalhyd/include/evalhyd/probabilistic/evaluator_brier.cpp',
'deps/evalhyd/include/evalhyd/probabilistic/evaluator_elements.cpp',
'deps/evalhyd/include/evalhyd/probabilistic/evaluator_utils.cpp'],
include_dirs=[ include_dirs=[
# Path to pybind11 headers # Path to pybind11 headers
get_pybind_include(), get_pybind_include(),
...@@ -106,13 +109,14 @@ class BuildExt(build_ext): ...@@ -106,13 +109,14 @@ class BuildExt(build_ext):
ext.extra_compile_args = opts ext.extra_compile_args = opts
build_ext.build_extensions(self) build_ext.build_extensions(self)
setup( setup(
name='evalhyd-python', name='evalhyd-python',
version=__version__, version=__version__,
author='Thibault Hallouin', author='Thibault Hallouin',
author_email='thibault.hallouin@inrae.fr', author_email='thibault.hallouin@inrae.fr',
url='https://gitlab.irstea.fr/thibault.hallouin/evalhyd-python', url='https://gitlab.irstea.fr/evalhyd/evalhyd-python',
description='EvalHyd in Python', description='Python bindings for EvalHyd',
long_description='An evaluator for hydrological simulations/forecasts.', long_description='An evaluator for hydrological simulations/forecasts.',
ext_modules=ext_modules, ext_modules=ext_modules,
install_requires=['pybind11>=2.0.1', 'numpy'], install_requires=['pybind11>=2.0.1', 'numpy'],
......
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#define FORCE_IMPORT_ARRAY #define FORCE_IMPORT_ARRAY
#include <xtensor-python/pytensor.hpp> #include <xtensor-python/pytensor.hpp>
#include "evalhyd/nse.hpp" #include "evalhyd/determinist.hpp"
#include "evalhyd/probabilist.hpp"
namespace py = pybind11; namespace py = pybind11;
// Python Module and Docstrings namespace ehd = evalhyd::determinist;
namespace ehp = evalhyd::probabilist;
// Python Module and Docstrings
PYBIND11_MODULE(evalhyd, m) PYBIND11_MODULE(evalhyd, m)
{ {
xt::import_numpy(); xt::import_numpy();
m.doc() = "evaluator for hydrological simulations/forecasts"; m.doc() = "evaluator for hydrological simulations/forecasts";
m.def("nse", evalhyd::nse<xt::pytensor<double, 1>>, "Return the Nash-Sutcliffe Efficiency (NSE) [1D arrays]", // Submodule for deterministic evaluation of streamflow simulations
py::arg("sim"), py::arg("obs"), py::arg("axis") = 0); py::module_ md = m.def_submodule("determinist", "deterministic streamflow evaluation");
m.def("nse", evalhyd::nse<xt::pytensor<double, 2>>, "Return the Nash-Sutcliffe Efficiency (NSE) [2D arrays]",
py::arg("sim"), py::arg("obs"), py::arg("axis") = 0); md.def(
"evaluate", ehd::evaluate<xt::pytensor<double, 1>>,
"Deterministic streamflow evaluation [1D arrays]",
py::arg("metrics"), py::arg("q_obs"), py::arg("q_sim")
);
md.def(
"evaluate", ehd::evaluate<xt::pytensor<double, 2>>,
"Deterministic streamflow evaluation [2D arrays]",
py::arg("metrics"), py::arg("q_obs"), py::arg("q_sim")
);
// Submodule for probabilistic evaluation of streamflow forecasts
py::module_ mp = m.def_submodule("probabilist", "probabilistic streamflow evaluation");
mp.def(
"evaluate", ehp::evaluate,
"Probabilist streamflow evaluation",
py::arg("metrics"), py::arg("q_obs"), py::arg("q_frc"), py::arg("q_thr")
);
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment