diff --git a/include/evalhyd/determinist.hpp b/include/evalhyd/determinist.hpp index 0cb6e7b369f75d4f5e52ef22609eb1f7dd54c56c..8a716a9f8c995f93a4225c2d66723efb3ef2a549 100644 --- a/include/evalhyd/determinist.hpp +++ b/include/evalhyd/determinist.hpp @@ -12,83 +12,81 @@ namespace eh = evalhyd; namespace evalhyd { - namespace determinist { - /// Function allowing the evaluation of streamflow simulations using a - /// range of relevant metrics. - /// - /// \param [in] metrics: - /// Vector of strings for the metric(s) to be computed. - /// \param [in] q_obs: - /// 2D array of streamflow observations. - /// shape: (1+, time) - /// \param [in] q_sim: - /// 2D array of streamflow simulations. - /// shape: (1+, time) - /// \return - /// Vector of 1D array of metrics for each time series. - template <class A> - std::vector<A> evaluate( - const std::vector<std::string>& metrics, - const xt::xexpression<A>& q_obs, - const xt::xexpression<A>& q_sim - ) + /// Function allowing the evaluation of streamflow simulations using a + /// range of relevant metrics. + /// + /// \param [in] metrics: + /// Vector of strings for the metric(s) to be computed. + /// \param [in] q_obs: + /// 2D array of streamflow observations. + /// shape: (1+, time) + /// \param [in] q_sim: + /// 2D array of streamflow simulations. + /// shape: (1+, time) + /// \return + /// Vector of 1D array of metrics for each time series. + template <class A> + std::vector<A> evald( + const std::vector<std::string>& metrics, + const xt::xexpression<A>& q_obs, + const xt::xexpression<A>& q_sim + ) + { + const A& obs = q_obs.derived_cast(); + const A& sim = q_sim.derived_cast(); + + // check that the metrics to be computed are valid + utils::check_metrics( + metrics, + {"NSE"} + ); + + // instantiate determinist evaluator + eh::determinist::Evaluator<A> evaluator(obs, sim); + + // declare maps for memoisation purposes + std::unordered_map<std::string, std::vector<std::string>> elt; + std::unordered_map<std::string, std::vector<std::string>> dep; + + // register potentially recurring computation elt across metrics + // TODO + + // register nested metrics (i.e. metric dependent on another metric) + // TODO + + // determine required elt/dep to be pre-computed + std::vector<std::string> req_elt; + std::vector<std::string> req_dep; + + eh::utils::find_requirements(metrics, elt, dep, req_elt, req_dep); + + // pre-compute required elt + for ( const auto& element : req_elt ) { - const A& obs = q_obs.derived_cast(); - const A& sim = q_sim.derived_cast(); - - // check that the metrics to be computed are valid - utils::check_metrics( - metrics, - {"NSE"} - ); - - // instantiate determinist evaluator - eh::determinist::Evaluator<A> evaluator(obs, sim); - - // declare maps for memoisation purposes - std::unordered_map<std::string, std::vector<std::string>> elt; - std::unordered_map<std::string, std::vector<std::string>> dep; - - // register potentially recurring computation elt across metrics // TODO + } - // register nested metrics (i.e. metric dependent on another metric) + // pre-compute required dep + for ( const auto& dependency : req_dep ) + { // TODO + } - // determine required elt/dep to be pre-computed - std::vector<std::string> req_elt; - std::vector<std::string> req_dep; - - eh::utils::find_requirements(metrics, elt, dep, req_elt, req_dep); - - // pre-compute required elt - for ( const auto& element : req_elt ) - { - // TODO - } - - // pre-compute required dep - for ( const auto& dependency : req_dep ) - { - // TODO - } - - // retrieve or compute requested metrics - std::vector<A> r; + // retrieve or compute requested metrics + std::vector<A> r; - for ( const auto& metric : metrics ) + for ( const auto& metric : metrics ) + { + if ( metric == "NSE" ) { - if ( metric == "NSE" ) - { - if (std::find(req_dep.begin(), req_dep.end(), metric) - == req_dep.end()) - evaluator.calc_NSE(); - r.emplace_back(evaluator.NSE); - } + if (std::find(req_dep.begin(), req_dep.end(), metric) + == req_dep.end()) + evaluator.calc_NSE(); + r.emplace_back(evaluator.NSE); } - - return r; } + + return r; } } diff --git a/include/evalhyd/probabilist.hpp b/include/evalhyd/probabilist.hpp index fe59365a21ceedf4ebe74d9ed1c56e93eaf36cba..6db5fb34648acd0384b9b0b10911fe1c851b80b8 100644 --- a/include/evalhyd/probabilist.hpp +++ b/include/evalhyd/probabilist.hpp @@ -14,143 +14,140 @@ namespace eh = evalhyd; namespace evalhyd { - namespace probabilist + /// Function allowing the evaluation of streamflow forecasts using a + /// range of relevant metrics. + /// + /// \param [in] metrics: + /// Vector of strings for the metric(s) to be computed. + /// \param [in] q_obs: + /// 2D array of streamflow observations. + /// shape: (1, time) + /// \param [in] q_frc: + /// 2D array of streamflow forecasts. + /// shape: (members, time) + /// \param [in] q_thr: + /// 1D array of streamflow exceedance threshold(s). + /// shape: (thresholds,) + /// \return + /// Vector of 2D array of metrics for each threshold. + std::vector<xt::xtensor<double, 2>> evalp( + const std::vector<std::string>& metrics, + const xt::xtensor<double, 2>& q_obs, + const xt::xtensor<double, 2>& q_frc, + const xt::xtensor<double, 1>& q_thr = {} + ) { - /// Function allowing the evaluation of streamflow forecasts using a - /// range of relevant metrics. - /// - /// \param [in] metrics: - /// Vector of strings for the metric(s) to be computed. - /// \param [in] q_obs: - /// 2D array of streamflow observations. - /// shape: (1, time) - /// \param [in] q_frc: - /// 2D array of streamflow forecasts. - /// shape: (members, time) - /// \param [in] q_thr: - /// 1D array of streamflow exceedance threshold(s). - /// shape: (thresholds,) - /// \return - /// Vector of 2D array of metrics for each threshold. - std::vector<xt::xtensor<double, 2>> evaluate( - const std::vector<std::string>& metrics, - const xt::xtensor<double, 2>& q_obs, - const xt::xtensor<double, 2>& q_frc, - const xt::xtensor<double, 1>& q_thr = {} - ) + // check that the metrics to be computed are valid + eh::utils::check_metrics( + metrics, + {"BS", "BSS", "BS_CRD", "BS_LBD", "QS", "CRPS"} + ); + + // check that optional parameters are given as arguments + eh::utils::check_optionals(metrics, q_thr); + + // instantiate probabilist evaluator + eh::probabilist::Evaluator evaluator(q_obs, q_frc, q_thr); + + // declare maps for memoisation purposes + std::unordered_map<std::string, std::vector<std::string>> elt; + std::unordered_map<std::string, std::vector<std::string>> dep; + + // register potentially recurring computation elements across metrics + elt["bs"] = {"o_k", "y_k"}; + elt["bss"] = {"o_k", "bar_o"}; + elt["BS_CRD"] = {"o_k", "bar_o", "y_k"}; + elt["BS_LBD"] = {"o_k", "y_k"}; + elt["qs"] = {"q_qnt"}; + + // register nested metrics (i.e. metric dependent on another metric) + dep["BS"] = {"bs"}; + dep["BSS"] = {"bs", "bss"}; + dep["QS"] = {"qs"}; + dep["CRPS"] = {"qs", "crps"}; + + // determine required elt/dep to be pre-computed + std::vector<std::string> req_elt; + std::vector<std::string> req_dep; + + eh::utils::find_requirements(metrics, elt, dep, req_elt, req_dep); + + // pre-compute required elt + for (const auto& element : req_elt) { - // check that the metrics to be computed are valid - eh::utils::check_metrics( - metrics, - {"BS", "BSS", "BS_CRD", "BS_LBD", "QS", "CRPS"} - ); - - // check that optional parameters are given as arguments - eh::utils::check_optionals(metrics, q_thr); - - // instantiate probabilist evaluator - eh::probabilist::Evaluator evaluator(q_obs, q_frc, q_thr); - - // declare maps for memoisation purposes - std::unordered_map<std::string, std::vector<std::string>> elt; - std::unordered_map<std::string, std::vector<std::string>> dep; - - // register potentially recurring computation elements across metrics - elt["bs"] = {"o_k", "y_k"}; - elt["bss"] = {"o_k", "bar_o"}; - elt["BS_CRD"] = {"o_k", "bar_o", "y_k"}; - elt["BS_LBD"] = {"o_k", "y_k"}; - elt["qs"] = {"q_qnt"}; - - // register nested metrics (i.e. metric dependent on another metric) - dep["BS"] = {"bs"}; - dep["BSS"] = {"bs", "bss"}; - dep["QS"] = {"qs"}; - dep["CRPS"] = {"qs", "crps"}; - - // determine required elt/dep to be pre-computed - std::vector<std::string> req_elt; - std::vector<std::string> req_dep; - - eh::utils::find_requirements(metrics, elt, dep, req_elt, req_dep); - - // pre-compute required elt - for (const auto& element : req_elt) + if ( element == "o_k" ) + evaluator.calc_o_k(); + else if ( element == "bar_o" ) + evaluator.calc_bar_o(); + else if ( element == "y_k" ) + evaluator.calc_y_k(); + else if ( element == "q_qnt" ) + evaluator.calc_q_qnt(); + } + + // pre-compute required dep + for (const auto& dependency : req_dep) + { + if ( dependency == "bs" ) + evaluator.calc_bs(); + else if ( dependency == "bss" ) + evaluator.calc_bss(); + else if ( dependency == "qs" ) + evaluator.calc_qs(); + else if ( dependency == "crps" ) + evaluator.calc_crps(); + } + + // retrieve or compute requested metrics + std::vector<xt::xtensor<double, 2>> r; + + for (const auto& metric : metrics) + { + if ( metric == "BS" ) { - if ( element == "o_k" ) - evaluator.calc_o_k(); - else if ( element == "bar_o" ) - evaluator.calc_bar_o(); - else if ( element == "y_k" ) - evaluator.calc_y_k(); - else if ( element == "q_qnt" ) - evaluator.calc_q_qnt(); + if (std::find(req_dep.begin(), req_dep.end(), metric) + == req_dep.end()) + evaluator.calc_BS(); + r.emplace_back(evaluator.BS); } - - // pre-compute required dep - for (const auto& dependency : req_dep) + else if ( metric == "BSS" ) { - if ( dependency == "bs" ) - evaluator.calc_bs(); - else if ( dependency == "bss" ) - evaluator.calc_bss(); - else if ( dependency == "qs" ) - evaluator.calc_qs(); - else if ( dependency == "crps" ) - evaluator.calc_crps(); + if (std::find(req_dep.begin(), req_dep.end(), metric) + == req_dep.end()) + evaluator.calc_BSS(); + r.emplace_back(evaluator.BSS); } - - // retrieve or compute requested metrics - std::vector<xt::xtensor<double, 2>> r; - - for (const auto& metric : metrics) + else if ( metric == "BS_CRD" ) { - if ( metric == "BS" ) - { - if (std::find(req_dep.begin(), req_dep.end(), metric) - == req_dep.end()) - evaluator.calc_BS(); - r.emplace_back(evaluator.BS); - } - else if ( metric == "BSS" ) - { - if (std::find(req_dep.begin(), req_dep.end(), metric) - == req_dep.end()) - evaluator.calc_BSS(); - r.emplace_back(evaluator.BSS); - } - else if ( metric == "BS_CRD" ) - { - if (std::find(req_dep.begin(), req_dep.end(), metric) - == req_dep.end()) - evaluator.calc_BS_CRD(); - r.emplace_back(evaluator.BS_CRD); - } - else if ( metric == "BS_LBD" ) - { - if (std::find(req_dep.begin(), req_dep.end(), metric) - == req_dep.end()) - evaluator.calc_BS_LBD(); - r.emplace_back(evaluator.BS_LBD); - } - else if ( metric == "QS" ) - { - if (std::find(req_dep.begin(), req_dep.end(), metric) - == req_dep.end()) - evaluator.calc_QS(); - r.emplace_back(evaluator.QS); - } - else if ( metric == "CRPS" ) - { - if (std::find(req_dep.begin(), req_dep.end(), metric) - == req_dep.end()) - evaluator.calc_CRPS(); - r.emplace_back(evaluator.CRPS); - } + if (std::find(req_dep.begin(), req_dep.end(), metric) + == req_dep.end()) + evaluator.calc_BS_CRD(); + r.emplace_back(evaluator.BS_CRD); + } + else if ( metric == "BS_LBD" ) + { + if (std::find(req_dep.begin(), req_dep.end(), metric) + == req_dep.end()) + evaluator.calc_BS_LBD(); + r.emplace_back(evaluator.BS_LBD); + } + else if ( metric == "QS" ) + { + if (std::find(req_dep.begin(), req_dep.end(), metric) + == req_dep.end()) + evaluator.calc_QS(); + r.emplace_back(evaluator.QS); + } + else if ( metric == "CRPS" ) + { + if (std::find(req_dep.begin(), req_dep.end(), metric) + == req_dep.end()) + evaluator.calc_CRPS(); + r.emplace_back(evaluator.CRPS); } - - return r; } + + return r; } } diff --git a/tests/test_determinist.cpp b/tests/test_determinist.cpp index 6a7c90a5ea1966c0378183035811b350d532a80a..0d8fe65477f055f3a7565b793a7c007ab8f6307b 100644 --- a/tests/test_determinist.cpp +++ b/tests/test_determinist.cpp @@ -28,12 +28,12 @@ TEST(DeterministTests, TestNSE) { // compute scores (both with 2D and 1D tensors) std::vector<xt::xtensor<double, 2>> metrics_2d = - evalhyd::determinist::evaluate<xt::xtensor<double, 2>>( + evalhyd::evald<xt::xtensor<double, 2>>( {"NSE"}, observed_2d, forecast_2d ); std::vector<xt::xtensor<double, 1>> metrics_1d = - evalhyd::determinist::evaluate<xt::xtensor<double, 1>>( + evalhyd::evald<xt::xtensor<double, 1>>( {"NSE"}, observed_1d, forecast_1d ); diff --git a/tests/test_probabilist.cpp b/tests/test_probabilist.cpp index 8cb117467d8ee9e6cde87cb989bb7426180606c5..911c653c18a71873c1cbc4381b421184bc25fe69 100644 --- a/tests/test_probabilist.cpp +++ b/tests/test_probabilist.cpp @@ -23,7 +23,7 @@ TEST(ProbabilistTests, TestBrier) { xt::xtensor<double, 1> thresholds = {690, 534, 445}; std::vector<xt::xtensor<double, 2>> metrics = - evalhyd::probabilist::evaluate( + evalhyd::evalp( {"BS", "BSS", "BS_CRD", "BS_LBD"}, xt::transpose(observed), xt::transpose(forecast), thresholds