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 @@
#include "quantiles.hpp"
#include "contingency.hpp"
#include "ranks.hpp"
#include "intervals.hpp"
namespace evalhyd
......@@ -31,6 +32,7 @@ namespace evalhyd
const XD4& q_prd;
// members for optional input data
const XD2& _q_thr;
const xt::xtensor<double, 1>& _c_lvl;
xtl::xoptional<const std::string, bool> _events;
XB4 t_msk;
const std::vector<xt::xkeep_slice<int>>& b_exp;
......@@ -45,6 +47,7 @@ namespace evalhyd
std::size_t n_msk;
std::size_t n_mbr;
std::size_t n_thr;
std::size_t n_itv;
std::size_t n_exp;
// members for computational elements
......@@ -64,6 +67,11 @@ namespace evalhyd
// > Ranks-based
xtl::xoptional<xt::xtensor<double, 3>, bool> r_k;
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
// (i.e. before the reduction along the temporal axis)
......@@ -77,6 +85,8 @@ namespace evalhyd
xtl::xoptional<xt::xtensor<double, 5>, bool> pofd;
xtl::xoptional<xt::xtensor<double, 5>, bool> far;
xtl::xoptional<xt::xtensor<double, 5>, bool> csi;
// > Intervals-based
xtl::xoptional<xt::xtensor<double, 4>, bool> ws;
// members for evaluation metrics
// > Brier-based
......@@ -97,6 +107,13 @@ namespace evalhyd
xtl::xoptional<xt::xtensor<double, 5>, bool> RANK_DIAG;
xtl::xoptional<xt::xtensor<double, 4>, bool> DS;
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
auto get_q_thr()
......@@ -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()
{
if (_events.has_value())
......@@ -276,6 +307,53 @@ namespace evalhyd
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
xt::xtensor<double, 4> get_bs()
{
......@@ -354,17 +432,30 @@ namespace evalhyd
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:
// constructor method
Evaluator(const XD2& obs,
const XD4& prd,
const XD2& thr,
const xt::xtensor<double, 1>& lvl,
xtl::xoptional<const std::string&, bool> events,
const XB4& msk,
const std::vector<xt::xkeep_slice<int>>& exp,
const long int seed) :
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}
{
// initialise a mask if none provided
......@@ -384,6 +475,7 @@ namespace evalhyd
n_tim = q_prd.shape(3);
n_msk = t_msk.shape(2);
n_thr = _q_thr.shape(1);
n_itv = _c_lvl.size();
n_exp = b_exp.size();
// drop time steps where observations and/or predictions are NaN
......@@ -583,6 +675,77 @@ namespace evalhyd
}
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 @@
#include <xtensor/xexpression.hpp>
#include <xtensor/xtensor.hpp>
#include <xtensor/xarray.hpp>
#include <xtensor/xadapt.hpp>
#include "detail/utils.hpp"
#include "detail/masks.hpp"
......@@ -73,6 +74,9 @@ namespace evalhyd
/// occurring when streamflow goes below threshold). It must be
/// provided if *q_thr* is provided.
///
/// c_lvl: ``std::vector<double>``, optional
/// Confidence interval(s).
///
/// t_msk: ``XB4``, optional
/// Mask(s) used to generate temporal subsets of the whole streamflow
/// time series (where True/False is used for the time steps to
......@@ -162,6 +166,7 @@ namespace evalhyd
const xt::xexpression<XD2>& q_thr = XD2({}),
xtl::xoptional<const std::string, bool> events =
xtl::missing<const std::string>(),
const std::vector<double>& c_lvl = {},
const xt::xexpression<XB4>& t_msk = XB4({}),
const xt::xtensor<std::array<char, 32>, 2>& m_cdt = {},
xtl::xoptional<const std::unordered_map<std::string, int>, bool> bootstrap =
......@@ -198,13 +203,17 @@ namespace evalhyd
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
utils::check_metrics(
metrics,
{"BS", "BSS", "BS_CRD", "BS_LBD",
"QS", "CRPS",
"POD", "POFD", "FAR", "CSI", "ROCSS",
"RANK_DIAG", "DS", "AS"}
"RANK_DIAG", "DS", "AS",
"CR", "AW", "AWN", "AWI", "WS", "WSS"}
);
// check optional parameters
......@@ -371,7 +380,7 @@ namespace evalhyd
// instantiate determinist 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_),
b_exp,
random_seed
......@@ -466,6 +475,42 @@ namespace evalhyd
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;
......
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