Commit 0cedfa7c authored by Thibault Hallouin's avatar Thibault Hallouin
Browse files

add intervals-based metrics (CR, AW, AWN, AWI, WS, WSS)

1 merge request!3release v0.1.0
Pipeline #43737 failed with stage
in 1 minute and 50 seconds
Showing with 833 additions and 3 deletions
+833 -3
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "quantiles.hpp" #include "quantiles.hpp"
#include "contingency.hpp" #include "contingency.hpp"
#include "ranks.hpp" #include "ranks.hpp"
#include "intervals.hpp"
namespace evalhyd namespace evalhyd
...@@ -31,6 +32,7 @@ namespace evalhyd ...@@ -31,6 +32,7 @@ namespace evalhyd
const XD4& q_prd; const XD4& q_prd;
// members for optional input data // members for optional input data
const XD2& _q_thr; const XD2& _q_thr;
const xt::xtensor<double, 1>& _c_lvl;
xtl::xoptional<const std::string, bool> _events; xtl::xoptional<const std::string, bool> _events;
XB4 t_msk; XB4 t_msk;
const std::vector<xt::xkeep_slice<int>>& b_exp; const std::vector<xt::xkeep_slice<int>>& b_exp;
...@@ -45,6 +47,7 @@ namespace evalhyd ...@@ -45,6 +47,7 @@ namespace evalhyd
std::size_t n_msk; std::size_t n_msk;
std::size_t n_mbr; std::size_t n_mbr;
std::size_t n_thr; std::size_t n_thr;
std::size_t n_itv;
std::size_t n_exp; std::size_t n_exp;
// members for computational elements // members for computational elements
...@@ -64,6 +67,11 @@ namespace evalhyd ...@@ -64,6 +67,11 @@ namespace evalhyd
// > Ranks-based // > Ranks-based
xtl::xoptional<xt::xtensor<double, 3>, bool> r_k; xtl::xoptional<xt::xtensor<double, 3>, bool> r_k;
xtl::xoptional<xt::xtensor<double, 5>, bool> o_j; xtl::xoptional<xt::xtensor<double, 5>, bool> o_j;
// > Intervals-based
xtl::xoptional<xt::xtensor<double, 5>, bool> itv_bnds;
xtl::xoptional<xt::xtensor<double, 4>, bool> obs_in_itv;
xtl::xoptional<xt::xtensor<double, 4>, bool> itv_width;
xtl::xoptional<xt::xtensor<double, 6>, bool> clim_bnds;
// members for intermediate evaluation metrics // members for intermediate evaluation metrics
// (i.e. before the reduction along the temporal axis) // (i.e. before the reduction along the temporal axis)
...@@ -77,6 +85,8 @@ namespace evalhyd ...@@ -77,6 +85,8 @@ namespace evalhyd
xtl::xoptional<xt::xtensor<double, 5>, bool> pofd; xtl::xoptional<xt::xtensor<double, 5>, bool> pofd;
xtl::xoptional<xt::xtensor<double, 5>, bool> far; xtl::xoptional<xt::xtensor<double, 5>, bool> far;
xtl::xoptional<xt::xtensor<double, 5>, bool> csi; xtl::xoptional<xt::xtensor<double, 5>, bool> csi;
// > Intervals-based
xtl::xoptional<xt::xtensor<double, 4>, bool> ws;
// members for evaluation metrics // members for evaluation metrics
// > Brier-based // > Brier-based
...@@ -97,6 +107,13 @@ namespace evalhyd ...@@ -97,6 +107,13 @@ namespace evalhyd
xtl::xoptional<xt::xtensor<double, 5>, bool> RANK_DIAG; xtl::xoptional<xt::xtensor<double, 5>, bool> RANK_DIAG;
xtl::xoptional<xt::xtensor<double, 4>, bool> DS; xtl::xoptional<xt::xtensor<double, 4>, bool> DS;
xtl::xoptional<xt::xtensor<double, 4>, bool> AS; xtl::xoptional<xt::xtensor<double, 4>, bool> AS;
// > Intervals-based
xtl::xoptional<xt::xtensor<double, 5>, bool> CR;
xtl::xoptional<xt::xtensor<double, 5>, bool> AW;
xtl::xoptional<xt::xtensor<double, 5>, bool> AWN;
xtl::xoptional<xt::xtensor<double, 5>, bool> AWI;
xtl::xoptional<xt::xtensor<double, 5>, bool> WS;
xtl::xoptional<xt::xtensor<double, 5>, bool> WSS;
// methods to get optional parameters // methods to get optional parameters
auto get_q_thr() auto get_q_thr()
...@@ -113,6 +130,20 @@ namespace evalhyd ...@@ -113,6 +130,20 @@ namespace evalhyd
} }
} }
auto get_c_lvl()
{
if (_c_lvl.size() < 1)
{
throw std::runtime_error(
"interval-based metric requested, "
"but *c_lvl* not provided"
);
}
else{
return _c_lvl;
}
}
bool is_high_flow_event() bool is_high_flow_event()
{ {
if (_events.has_value()) if (_events.has_value())
...@@ -276,6 +307,53 @@ namespace evalhyd ...@@ -276,6 +307,53 @@ namespace evalhyd
return o_j.value(); return o_j.value();
}; };
xt::xtensor<double, 5> get_itv_bnds()
{
if (!itv_bnds.has_value())
{
itv_bnds = elements::calc_itv_bnds(
q_prd, get_c_lvl(),
n_sit, n_ldt, n_itv, n_tim
);
}
return itv_bnds.value();
};
xt::xtensor<double, 4> get_obs_in_itv()
{
if (!obs_in_itv.has_value())
{
obs_in_itv = elements::calc_obs_in_itv(
q_obs, get_itv_bnds()
);
}
return obs_in_itv.value();
};
xt::xtensor<double, 4> get_itv_width()
{
if (!itv_width.has_value())
{
itv_width = elements::calc_itv_width(
get_itv_bnds()
);
}
return itv_width.value();
};
xt::xtensor<double, 6> get_clim_bnds()
{
if (!clim_bnds.has_value())
{
clim_bnds = elements::calc_clim_bnds(
q_obs, get_c_lvl(), t_msk, b_exp,
n_sit, n_ldt, n_itv, n_msk, n_exp
);
}
return clim_bnds.value();
};
// methods to compute intermediate metrics // methods to compute intermediate metrics
xt::xtensor<double, 4> get_bs() xt::xtensor<double, 4> get_bs()
{ {
...@@ -354,17 +432,30 @@ namespace evalhyd ...@@ -354,17 +432,30 @@ namespace evalhyd
return csi.value(); return csi.value();
}; };
xt::xtensor<double, 4> get_ws()
{
if (!ws.has_value())
{
ws = intermediate::calc_ws(
q_obs, get_c_lvl(), get_itv_bnds()
);
}
return ws.value();
};
public: public:
// constructor method // constructor method
Evaluator(const XD2& obs, Evaluator(const XD2& obs,
const XD4& prd, const XD4& prd,
const XD2& thr, const XD2& thr,
const xt::xtensor<double, 1>& lvl,
xtl::xoptional<const std::string&, bool> events, xtl::xoptional<const std::string&, bool> events,
const XB4& msk, const XB4& msk,
const std::vector<xt::xkeep_slice<int>>& exp, const std::vector<xt::xkeep_slice<int>>& exp,
const long int seed) : const long int seed) :
q_obs{obs}, q_prd{prd}, q_obs{obs}, q_prd{prd},
_q_thr{thr}, _events{events}, t_msk(msk), b_exp(exp), _q_thr{thr}, _c_lvl{lvl}, _events{events},
t_msk(msk), b_exp(exp),
random_seed{seed} random_seed{seed}
{ {
// initialise a mask if none provided // initialise a mask if none provided
...@@ -384,6 +475,7 @@ namespace evalhyd ...@@ -384,6 +475,7 @@ namespace evalhyd
n_tim = q_prd.shape(3); n_tim = q_prd.shape(3);
n_msk = t_msk.shape(2); n_msk = t_msk.shape(2);
n_thr = _q_thr.shape(1); n_thr = _q_thr.shape(1);
n_itv = _c_lvl.size();
n_exp = b_exp.size(); n_exp = b_exp.size();
// drop time steps where observations and/or predictions are NaN // drop time steps where observations and/or predictions are NaN
...@@ -583,6 +675,77 @@ namespace evalhyd ...@@ -583,6 +675,77 @@ namespace evalhyd
} }
return AS.value(); return AS.value();
}; };
xt::xtensor<double, 5> get_CR()
{
if (!CR.has_value())
{
CR = metrics::calc_CR(
get_obs_in_itv(), t_msk, b_exp,
n_sit, n_ldt, n_itv, n_msk, n_exp
);
}
return CR.value();
};
xt::xtensor<double, 5> get_AW()
{
if (!AW.has_value())
{
AW = metrics::calc_AW(
get_itv_width(), t_msk, b_exp,
n_sit, n_ldt, n_itv, n_msk, n_exp
);
}
return AW.value();
};
xt::xtensor<double, 5> get_AWN()
{
if (!AWN.has_value())
{
AWN = metrics::calc_AWN(
q_obs, get_AW(), t_msk, b_exp,
n_sit, n_msk, n_exp
);
}
return AWN.value();
};
xt::xtensor<double, 5> get_AWI()
{
if (!AWI.has_value())
{
AWI = metrics::calc_AWI(
get_AW(), get_clim_bnds()
);
}
return AWI.value();
};
xt::xtensor<double, 5> get_WS()
{
if (!WS.has_value())
{
WS = metrics::calc_WS(
get_ws(), t_msk, b_exp,
n_sit, n_ldt, n_itv, n_msk, n_exp
);
}
return WS.value();
};
xt::xtensor<double, 5> get_WSS()
{
if (!WSS.has_value())
{
WSS = metrics::calc_WSS(
q_obs, get_c_lvl(), get_clim_bnds(), get_WS(),
n_sit, n_ldt, n_itv, n_msk, n_exp
);
}
return WSS.value();
};
}; };
} }
} }
......
This diff is collapsed.
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <xtensor/xexpression.hpp> #include <xtensor/xexpression.hpp>
#include <xtensor/xtensor.hpp> #include <xtensor/xtensor.hpp>
#include <xtensor/xarray.hpp> #include <xtensor/xarray.hpp>
#include <xtensor/xadapt.hpp>
#include "detail/utils.hpp" #include "detail/utils.hpp"
#include "detail/masks.hpp" #include "detail/masks.hpp"
...@@ -73,6 +74,9 @@ namespace evalhyd ...@@ -73,6 +74,9 @@ namespace evalhyd
/// occurring when streamflow goes below threshold). It must be /// occurring when streamflow goes below threshold). It must be
/// provided if *q_thr* is provided. /// provided if *q_thr* is provided.
/// ///
/// c_lvl: ``std::vector<double>``, optional
/// Confidence interval(s).
///
/// t_msk: ``XB4``, optional /// t_msk: ``XB4``, optional
/// Mask(s) used to generate temporal subsets of the whole streamflow /// Mask(s) used to generate temporal subsets of the whole streamflow
/// time series (where True/False is used for the time steps to /// time series (where True/False is used for the time steps to
...@@ -162,6 +166,7 @@ namespace evalhyd ...@@ -162,6 +166,7 @@ namespace evalhyd
const xt::xexpression<XD2>& q_thr = XD2({}), const xt::xexpression<XD2>& q_thr = XD2({}),
xtl::xoptional<const std::string, bool> events = xtl::xoptional<const std::string, bool> events =
xtl::missing<const std::string>(), xtl::missing<const std::string>(),
const std::vector<double>& c_lvl = {},
const xt::xexpression<XB4>& t_msk = XB4({}), const xt::xexpression<XB4>& t_msk = XB4({}),
const xt::xtensor<std::array<char, 32>, 2>& m_cdt = {}, const xt::xtensor<std::array<char, 32>, 2>& m_cdt = {},
xtl::xoptional<const std::unordered_map<std::string, int>, bool> bootstrap = xtl::xoptional<const std::unordered_map<std::string, int>, bool> bootstrap =
...@@ -198,13 +203,17 @@ namespace evalhyd ...@@ -198,13 +203,17 @@ namespace evalhyd
const XB4& t_msk_ = t_msk.derived_cast(); const XB4& t_msk_ = t_msk.derived_cast();
// adapt vector to tensor
const xt::xtensor<double, 1> c_lvl_ = xt::adapt(c_lvl);
// check that the metrics to be computed are valid // check that the metrics to be computed are valid
utils::check_metrics( utils::check_metrics(
metrics, metrics,
{"BS", "BSS", "BS_CRD", "BS_LBD", {"BS", "BSS", "BS_CRD", "BS_LBD",
"QS", "CRPS", "QS", "CRPS",
"POD", "POFD", "FAR", "CSI", "ROCSS", "POD", "POFD", "FAR", "CSI", "ROCSS",
"RANK_DIAG", "DS", "AS"} "RANK_DIAG", "DS", "AS",
"CR", "AW", "AWN", "AWI", "WS", "WSS"}
); );
// check optional parameters // check optional parameters
...@@ -371,7 +380,7 @@ namespace evalhyd ...@@ -371,7 +380,7 @@ namespace evalhyd
// instantiate determinist evaluator // instantiate determinist evaluator
probabilist::Evaluator<XD2, XD4, XB4> evaluator( probabilist::Evaluator<XD2, XD4, XB4> evaluator(
q_obs_, q_prd_, q_thr_, events, q_obs_, q_prd_, q_thr_, c_lvl_, events,
t_msk_.size() > 0 ? t_msk_: (m_cdt.size() > 0 ? c_msk : t_msk_), t_msk_.size() > 0 ? t_msk_: (m_cdt.size() > 0 ? c_msk : t_msk_),
b_exp, b_exp,
random_seed random_seed
...@@ -466,6 +475,42 @@ namespace evalhyd ...@@ -466,6 +475,42 @@ namespace evalhyd
uncertainty::summarise(evaluator.get_AS(), summary) uncertainty::summarise(evaluator.get_AS(), summary)
); );
} }
else if ( metric == "CR" )
{
r.emplace_back(
uncertainty::summarise(evaluator.get_CR(), summary)
);
}
else if ( metric == "AW" )
{
r.emplace_back(
uncertainty::summarise(evaluator.get_AW(), summary)
);
}
else if ( metric == "AWN" )
{
r.emplace_back(
uncertainty::summarise(evaluator.get_AWN(), summary)
);
}
else if ( metric == "AWI" )
{
r.emplace_back(
uncertainty::summarise(evaluator.get_AWI(), summary)
);
}
else if ( metric == "WS" )
{
r.emplace_back(
uncertainty::summarise(evaluator.get_WS(), summary)
);
}
else if ( metric == "WSS" )
{
r.emplace_back(
uncertainty::summarise(evaluator.get_WSS(), summary)
);
}
} }
return r; return r;
......
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