Commit ced03451 authored by Thibault Hallouin's avatar Thibault Hallouin
Browse files

remove default values from function signatures

since those default values were only used to check whether these
parameters were provided or not, they are turned into optional
parameters
1 merge request!3release v0.1.0
Pipeline #42968 passed with stage
in 2 minutes and 6 seconds
Showing with 112 additions and 64 deletions
+112 -64
......@@ -52,6 +52,13 @@ namespace evalhyd
"number of samples missing for bootstrap"
);
}
auto n_samples = bootstrap.find("n_samples")->second;
if (n_samples < 1)
{
throw std::runtime_error(
"number of samples must be greater than zero"
);
}
// check len_sample
if (bootstrap.find("len_sample") == bootstrap.end())
{
......@@ -59,6 +66,13 @@ namespace evalhyd
"length of sample missing for bootstrap"
);
}
auto len_sample = bootstrap.find("len_sample")->second;
if (len_sample < 1)
{
throw std::runtime_error(
"length of sample must be greater than zero"
);
}
// check summary
if (bootstrap.find("summary") == bootstrap.end())
{
......@@ -66,9 +80,9 @@ namespace evalhyd
"summary missing for bootstrap"
);
}
auto s = bootstrap.find("summary")->second;
auto summary = bootstrap.find("summary")->second;
// TODO: change upper bound when mean+stddev and quantiles implemented
if ((s < 0) || (s > 0))
if ((summary < 0) || (summary > 0))
{
throw std::runtime_error(
"invalid value for bootstrap summary"
......
......@@ -4,6 +4,7 @@
#include <unordered_map>
#include <vector>
#include <xtl/xoptional.hpp>
#include <xtensor/xexpression.hpp>
#include <xtensor/xtensor.hpp>
#include <xtensor/xarray.hpp>
......@@ -58,18 +59,17 @@ namespace evalhyd
///
/// exponent: ``double``, optional
/// The value of the exponent n to use when the *transform* is the
/// power function. If not provided (or set to default value 1),
/// the streamflow observations and predictions remain untransformed.
/// power function. If not provided, the streamflow observations
/// and predictions remain untransformed.
///
/// epsilon: ``double``, optional
/// The value of the small constant ε to add to both the streamflow
/// observations and predictions prior to the calculation of the
/// *metrics* when the *transform* is the reciprocal function, the
/// natural logarithm, or the power function with a negative exponent
/// (since none are defined for 0). If not provided (or set to default
/// value -9), one hundredth of the mean of the streamflow
/// observations is used as value for epsilon, as recommended by
/// `Pushpalatha et al. (2012)
/// (since none are defined for 0). If not provided, one hundredth of
/// the mean of the streamflow observations is used as value for
/// epsilon, as recommended by `Pushpalatha et al. (2012)
/// <https://doi.org/10.1016/j.jhydrol.2011.11.055>`_.
///
/// t_msk: ``XB2``, optional
......@@ -159,13 +159,16 @@ namespace evalhyd
const xt::xexpression<XD2>& q_obs,
const xt::xexpression<XD2>& q_prd,
const std::vector<std::string>& metrics,
const std::string& transform = "none",
double exponent = 1,
double epsilon = -9,
xtl::xoptional<const std::string, bool> transform =
xtl::missing<const std::string>(),
xtl::xoptional<double, bool> exponent =
xtl::missing<double>(),
xtl::xoptional<double, bool> epsilon =
xtl::missing<double>(),
const xt::xexpression<XB2>& t_msk = XB2({}),
const xt::xtensor<std::array<char, 32>, 1>& m_cdt = {},
const std::unordered_map<std::string, int>& bootstrap =
{{"n_samples", -9}, {"len_sample", -9}, {"summary", 0}},
xtl::xoptional<const std::unordered_map<std::string, int>> bootstrap =
xtl::missing<const std::unordered_map<std::string, int>>(),
const std::vector<std::string>& dts = {}
)
{
......@@ -196,7 +199,10 @@ namespace evalhyd
);
// check that optional parameters are valid
utils::check_bootstrap(bootstrap);
if (bootstrap.has_value())
{
utils::check_bootstrap(bootstrap.value());
}
// check that data dimensions are compatible
// > time
......@@ -277,68 +283,90 @@ namespace evalhyd
// apply streamflow transformation if requested
auto q_transform = [&](const XD2& q)
{
if ( transform == "none" || (transform == "pow" && exponent == 1))
{
return q;
}
else if ( transform == "sqrt" )
{
return XD2(xt::sqrt(q));
}
else if ( transform == "inv" )
if (transform.has_value())
{
if ( epsilon == -9 )
if ( transform.value() == "sqrt" )
{
// determine an epsilon value to avoid zero divide
epsilon = xt::mean(q_obs_)() * 0.01;
return XD2(xt::sqrt(q));
}
return XD2(1. / (q + epsilon));
}
else if ( transform == "log" )
{
if ( epsilon == -9 )
else if ( transform.value() == "inv" )
{
// determine an epsilon value to avoid log zero
epsilon = xt::mean(q_obs_)() * 0.01;
}
if ( !epsilon.has_value() )
{
// determine an epsilon value to avoid zero divide
epsilon = xt::mean(q_obs_)() * 0.01;
}
return XD2(xt::log(q + epsilon));
}
else if ( transform == "pow" )
{
if ( exponent < 0 )
return XD2(1. / (q + epsilon.value()));
}
else if ( transform.value() == "log" )
{
if ( epsilon == -9 )
if ( !epsilon.has_value() )
{
// determine an epsilon value to avoid zero divide
// determine an epsilon value to avoid log zero
epsilon = xt::mean(q_obs_)() * 0.01;
}
return XD2(xt::pow(q + epsilon, exponent));
return XD2(xt::log(q + epsilon.value()));
}
else if ( transform.value() == "pow" )
{
if ( exponent.has_value() )
{
if ( exponent.value() == 1)
{
return q;
}
else if ( exponent.value() < 0 )
{
if ( !epsilon.has_value() )
{
// determine an epsilon value to avoid zero divide
epsilon = xt::mean(q_obs_)() * 0.01;
}
return XD2(xt::pow(q + epsilon.value(),
exponent.value()));
}
else
{
return XD2(xt::pow(q, exponent.value()));
}
}
else
{
throw std::runtime_error(
"missing exponent for power transformation"
);
}
}
else
{
return XD2(xt::pow(q, exponent));
throw std::runtime_error(
"invalid streamflow transformation: "
+ transform.value()
);
}
}
else
{
throw std::runtime_error(
"invalid streamflow transformation: " + transform
);
return q;
}
};
const XD2 obs = q_transform(q_obs_);
const XD2 prd = q_transform(q_prd_);
const XD2& obs = q_transform(q_obs_);
const XD2& prd = q_transform(q_prd_);
// generate bootstrap experiment if requested
std::vector<xt::xkeep_slice<int>> exp;
auto n_samples = bootstrap.find("n_samples")->second;
auto len_sample = bootstrap.find("len_sample")->second;
if ((n_samples != -9) && (len_sample != -9))
int summary;
if (bootstrap.has_value())
{
auto n_samples = bootstrap.value().find("n_samples")->second;
auto len_sample = bootstrap.value().find("len_sample")->second;
summary = bootstrap.value().find("summary")->second;
if (dts.empty())
{
throw std::runtime_error(
......@@ -354,6 +382,7 @@ namespace evalhyd
{
// if no bootstrap requested, generate one sample
// containing all the time indices once
summary = 0;
xt::xtensor<int, 1> all = xt::arange(n_tim);
exp.push_back(xt::keep(all));
}
......@@ -364,8 +393,6 @@ namespace evalhyd
// retrieve or compute requested metrics
std::vector<xt::xarray<double>> r;
auto summary = bootstrap.find("summary")->second;
for ( const auto& metric : metrics )
{
if ( metric == "RMSE" )
......
......@@ -4,6 +4,7 @@
#include <unordered_map>
#include <vector>
#include <xtl/xoptional.hpp>
#include <xtensor/xexpression.hpp>
#include <xtensor/xtensor.hpp>
#include <xtensor/xarray.hpp>
......@@ -144,8 +145,8 @@ namespace evalhyd
const xt::xexpression<XD2>& q_thr = XD2({}),
const xt::xexpression<XB4>& t_msk = XB4({}),
const xt::xtensor<std::array<char, 32>, 2>& m_cdt = {},
const std::unordered_map<std::string, int>& bootstrap =
{{"n_samples", -9}, {"len_sample", -9}, {"summary", 0}},
xtl::xoptional<const std::unordered_map<std::string, int>> bootstrap =
xtl::missing<const std::unordered_map<std::string, int>>(),
const std::vector<std::string>& dts = {}
)
{
......@@ -184,7 +185,10 @@ namespace evalhyd
// check that optional parameters are given as arguments
utils::evalp::check_optionals(metrics, q_thr_);
utils::check_bootstrap(bootstrap);
if (bootstrap.has_value())
{
utils::check_bootstrap(bootstrap.value());
}
// check that data dimensions are compatible
// > time
......@@ -266,8 +270,8 @@ namespace evalhyd
std::size_t n_thr = q_thr_.shape(1);
std::size_t n_msk = t_msk_.size() > 0 ? t_msk_.shape(2) :
(m_cdt.size() > 0 ? m_cdt.shape(1) : 1);
std::size_t n_exp = bootstrap.find("n_samples")->second == -9 ? 1:
bootstrap.find("n_samples")->second;
std::size_t n_exp = !bootstrap.has_value() ? 1:
bootstrap.value().find("n_samples")->second;
// register metrics number of dimensions
std::unordered_map<std::string, std::vector<std::size_t>> dim;
......@@ -308,10 +312,14 @@ namespace evalhyd
// generate bootstrap experiment if requested
std::vector<xt::xkeep_slice<int>> b_exp;
auto n_samples = bootstrap.find("n_samples")->second;
auto len_sample = bootstrap.find("len_sample")->second;
if ((n_samples != -9) && (len_sample != -9))
int summary;
if (bootstrap.has_value())
{
auto n_samples = bootstrap.value().find("n_samples")->second;
auto len_sample = bootstrap.value().find("len_sample")->second;
summary = bootstrap.value().find("summary")->second;
if (dts.empty())
{
throw std::runtime_error(
......@@ -325,6 +333,7 @@ namespace evalhyd
{
// if no bootstrap requested, generate one sample
// containing all the time indices once
summary = 0;
xt::xtensor<int, 1> all = xt::arange(n_tim);
b_exp.push_back(xt::keep(all));
}
......@@ -336,8 +345,6 @@ namespace evalhyd
r.emplace_back(xt::zeros<double>(dim[metric]));
}
auto summary = bootstrap.find("summary")->second;
// compute variables one site at a time to minimise memory imprint
for (std::size_t s = 0; s < n_sit; s++)
{
......
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