An error occurred while loading the file. Please try again.
-
Pierre-Antoine Rouby authoredab1b7a26
// Copyright (c) 2023, INRAE.
// Distributed under the terms of the GPL-3 Licence.
// The full licence is in the file LICENCE, distributed with this software.
#ifndef EVALHYD_PROBABILIST_INTERVALS_HPP
#define EVALHYD_PROBABILIST_INTERVALS_HPP
#include <limits>
#include <xtensor/xtensor.hpp>
#include <xtensor/xview.hpp>
#include <xtensor/xindex_view.hpp>
#include <xtensor/xsort.hpp>
namespace evalhyd
{
namespace probabilist
{
namespace elements
{
/// Compute the bounds of the predictive intervals by computing
/// the quantiles of the predictive distribution corresponding
/// to the confidence intervals.
///
/// \param q_prd
/// Streamflow predictions.
/// shape: (sites, lead times, members, time)
/// \param c_lvl
/// Confidence levels for the predictive intervals.
/// shape: (intervals,)
/// \param n_sit
/// Number of sites.
/// \param n_ldt
/// Number of lead times.
/// \param n_itv
/// Number of predictive intervals.
/// \param n_tim
/// Number of time steps.
/// \return
/// Bounds of the predictive intervals.
/// shape: (sites, lead times, intervals, bounds, time)
template <class XD4>
inline xt::xtensor<double, 5> calc_itv_bnds(
const XD4& q_prd,
const xt::xtensor<double, 1>& c_lvl,
const xt::xtensor<double, 1>& q_lvl,
std::size_t n_sit,
std::size_t n_ldt,
std::size_t n_itv,
std::size_t n_tim
)
{
xt::xtensor<double, 5> itv_bnds =
xt::zeros<double>({n_sit, n_ldt, n_itv, std::size_t {2}, n_tim});
// determine quantiles forming the predictive intervals
// from the confidence levels
xt::xtensor<double, 2> quantiles =
xt::zeros<double>({n_itv, std::size_t {2}});
xt::col(quantiles, 0) = 0.5 - c_lvl / 200.;
xt::col(quantiles, 1) = 0.5 + c_lvl / 200.;
// get or compute predictive interval bounds from quantiles
if (q_lvl.size() > 0)
{
for (std::size_t i = 0; i < n_itv; i++)
{
auto a = xt::broadcast(xt::view(quantiles, i), std::vector<std::size_t>({q_lvl.size(), 2}));
auto b = xt::broadcast(q_lvl, std::vector<std::size_t>({2, q_lvl.size()}));
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
auto res = xt::where(xt::equal(a, xt::transpose(b)));
if (res.size() != 2)
{
throw std::runtime_error(
"interval-based metric requested, "
"but *c_lvl* not matching *q_lvl"
);
} else
{
xt::view(itv_bnds, xt::all(), xt::all(), i, 0, xt::all()) =
xt::view(q_prd, xt::all(), xt::all(), std::min(res[0][1], res[1][1]), xt::all());
xt::view(itv_bnds, xt::all(), xt::all(), i, 1, xt::all()) =
xt::view(q_prd, xt::all(), xt::all(), std::max(res[0][1], res[1][1]), xt::all());
}
}
}
else
{
for (std::size_t i = 0; i < n_itv; i++)
{
auto q = xt::quantile(q_prd, xt::view(quantiles, i), 2);
xt::view(itv_bnds, xt::all(), xt::all(), i, 0, xt::all()) =
xt::view(q, 0);
xt::view(itv_bnds, xt::all(), xt::all(), i, 1, xt::all()) =
xt::view(q, 1);
}
}
return itv_bnds;
}
/// Determine whether the observations are inside the predictive
/// intervals for each time step.
///
/// \param q_obs
/// Streamflow predictions.
/// shape: (sites, time)
/// \param itv_bnds
/// Bounds of the predictive intervals.
/// shape: (sites, lead times, intervals, bounds, time)
/// \return
/// Boolean-like tensor evaluating to true where observations
/// are inside the predictive intervals.
/// shape: (sites, lead times, intervals, time)
template <class XD2>
inline xt::xtensor<double, 4> calc_obs_in_itv(
const XD2& q_obs,
const xt::xtensor<double, 5>& itv_bnds
)
{
// notations below follow Gneiting and Raftery (2007), sect 6.2
// https://doi.org/10.1198/016214506000001437
auto x = xt::view(q_obs, xt::all(), xt::newaxis(), xt::newaxis(), xt::all());
auto l = xt::view(itv_bnds, xt::all(), xt::all(), xt::all(), 0, xt::all());
auto u = xt::view(itv_bnds, xt::all(), xt::all(), xt::all(), 1, xt::all());
return ((x >= l) && (x <= u));
}
/// Compute the width of the predictive intervals for each time step.
///
/// \param itv_bnds
/// Bounds of the predictive intervals.
/// shape: (sites, lead times, intervals, bounds, time)
/// \return
/// Interval scores for each time step.
/// shape: (sites, lead times, intervals, time)
inline xt::xtensor<double, 4> calc_itv_width(