diff --git a/include/evalhyd/detail/determinist/errors.hpp b/include/evalhyd/detail/determinist/errors.hpp
index 4fb1ff894f36d73ba69291e5199e1cc7ae1bfc4a..f6e12354f9d45d05ebf34a2bef08793750fd50e1 100644
--- a/include/evalhyd/detail/determinist/errors.hpp
+++ b/include/evalhyd/detail/determinist/errors.hpp
@@ -121,7 +121,7 @@ namespace evalhyd
                 return mean_prd;
             }
 
-            /// Compute the quadratic error between observations and predictions.
+            /// Compute the error between observations and predictions.
             ///
             /// \param q_obs
             ///     Streamflow observations.
@@ -130,15 +130,45 @@ namespace evalhyd
             ///     Streamflow predictions.
             ///     shape: (series, time)
             /// \return
-            ///     Quadratic errors between observations and predictions.
+            ///     Errors between observations and predictions.
             ///     shape: (series, time)
             template <class XD2>
-            inline xt::xtensor<double, 2> calc_quad_err(
+            inline xt::xtensor<double, 2> calc_err(
                     const XD2& q_obs,
                     const XD2& q_prd
             )
             {
-                return xt::square(q_obs - q_prd);
+                return q_obs - q_prd;
+            }
+
+            /// Compute the absolute error between observations and predictions.
+            ///
+            /// \param err
+            ///     Errors between observations and predictions.
+            ///     shape: (series, time)
+            /// \return
+            ///     Quadratic errors between observations and predictions.
+            ///     shape: (series, time)
+            inline xt::xtensor<double, 2> calc_abs_err(
+                    const xt::xtensor<double, 2>& err
+            )
+            {
+                return xt::abs(err);
+            }
+
+            /// Compute the quadratic error between observations and predictions.
+            ///
+            /// \param err
+            ///     Errors between observations and predictions.
+            ///     shape: (series, time)
+            /// \return
+            ///     Quadratic errors between observations and predictions.
+            ///     shape: (series, time)
+            inline xt::xtensor<double, 2> calc_quad_err(
+                    const xt::xtensor<double, 2>& err
+            )
+            {
+                return xt::square(err);
             }
 
             /// Compute the quadratic error between observations and mean observation.
@@ -252,7 +282,101 @@ namespace evalhyd
 
         namespace metrics
         {
-            /// Compute the root-mean-square error (RMSE).
+            /// Compute the mean absolute error (MAE).
+            ///
+            /// \param abs_err
+            ///     Absolute errors between observations and predictions.
+            ///     shape: (series, time)
+            /// \param t_msk
+            ///     Temporal subsets of the whole record.
+            ///     shape: (series, subsets, time)
+            /// \param b_exp
+            ///     Boostrap samples.
+            ///     shape: (samples, time slice)
+            /// \param n_srs
+            ///     Number of prediction series.
+            /// \param n_msk
+            ///     Number of temporal subsets.
+            /// \param n_exp
+            ///     Number of bootstrap samples.
+            /// \return
+            ///     Mean absolute errors.
+            ///     shape: (series, subsets, samples)
+            inline xt::xtensor<double, 3> calc_MAE(
+                    const xt::xtensor<double, 2>& abs_err,
+                    const xt::xtensor<bool, 3>& t_msk,
+                    const std::vector<xt::xkeep_slice<int>>& b_exp,
+                    std::size_t n_srs,
+                    std::size_t n_msk,
+                    std::size_t n_exp
+            )
+            {
+                // compute RMSE
+                xt::xtensor<double, 3> MAE =
+                        xt::zeros<double>({n_srs, n_msk, n_exp});
+
+                for (std::size_t m = 0; m < n_msk; m++)
+                {
+                    // apply the mask
+                    // (using NaN workaround until reducers work on masked_view)
+                    auto abs_err_masked = xt::where(xt::view(t_msk, xt::all(), m),
+                                                     abs_err, NAN);
+
+                    // compute variable one sample at a time
+                    for (std::size_t e = 0; e < n_exp; e++)
+                    {
+                        auto err = xt::view(abs_err_masked, xt::all(), b_exp[e]);
+                        xt::view(MAE, xt::all(), m, e) = xt::nanmean(err, -1);
+                    }
+                }
+
+                return MAE;
+            }
+
+            /// Compute the mean absolute relative error (MARE).
+            ///
+            /// \param MAE
+            ///     Mean absolute errors.
+            ///     shape: (series, subsets, samples)
+            /// \param mean_obs
+            ///     Mean observed streamflow.
+            ///     shape: (subsets, samples, series, 1)
+            /// \param n_srs
+            ///     Number of prediction series.
+            /// \param n_msk
+            ///     Number of temporal subsets.
+            /// \param n_exp
+            ///     Number of bootstrap samples.
+            /// \return
+            ///     Mean absolute relative errors.
+            ///     shape: (series, subsets, samples)
+            inline xt::xtensor<double, 3> calc_MARE(
+                    const xt::xtensor<double, 3>& MAE,
+                    const xt::xtensor<double, 4>& mean_obs,
+                    std::size_t n_srs,
+                    std::size_t n_msk,
+                    std::size_t n_exp
+            )
+            {
+                // compute RMSE
+                xt::xtensor<double, 3> MARE =
+                        xt::zeros<double>({n_srs, n_msk, n_exp});
+
+                for (std::size_t m = 0; m < n_msk; m++)
+                {
+                    // compute variable one sample at a time
+                    for (std::size_t e = 0; e < n_exp; e++)
+                    {
+                        xt::view(MARE, xt::all(), m, e) =
+                                xt::view(MAE, xt::all(), m, e)
+                                / xt::view(mean_obs, m, e, xt::all(), 0);
+                    }
+                }
+
+                return MARE;
+            }
+
+            /// Compute the mean square error (MSE).
             ///
             /// \param quad_err
             ///     Quadratic errors between observations and predictions.
@@ -270,9 +394,9 @@ namespace evalhyd
             /// \param n_exp
             ///     Number of bootstrap samples.
             /// \return
-            ///     Root-mean-square errors.
+            ///     Mean square errors.
             ///     shape: (series, subsets, samples)
-            inline xt::xtensor<double, 3> calc_RMSE(
+            inline xt::xtensor<double, 3> calc_MSE(
                     const xt::xtensor<double, 2>& quad_err,
                     const xt::xtensor<bool, 3>& t_msk,
                     const std::vector<xt::xkeep_slice<int>>& b_exp,
@@ -282,7 +406,7 @@ namespace evalhyd
             )
             {
                 // compute RMSE
-                xt::xtensor<double, 3> RMSE =
+                xt::xtensor<double, 3> MSE =
                         xt::zeros<double>({n_srs, n_msk, n_exp});
 
                 for (std::size_t m = 0; m < n_msk; m++)
@@ -296,10 +420,28 @@ namespace evalhyd
                     for (std::size_t e = 0; e < n_exp; e++)
                     {
                         auto err2 = xt::view(quad_err_masked, xt::all(), b_exp[e]);
-                        xt::view(RMSE, xt::all(), m, e) = xt::sqrt(xt::nanmean(err2, -1));
+                        xt::view(MSE, xt::all(), m, e) = xt::nanmean(err2, -1);
                     }
                 }
 
+                return MSE;
+            }
+
+            /// Compute the root mean square error (RMSE).
+            ///
+            /// \param MSE
+            ///     Mean square errors.
+            ///     shape: (series, subsets, samples)
+            /// \return
+            ///     Root mean square errors.
+            ///     shape: (series, subsets, samples)
+            inline xt::xtensor<double, 3> calc_RMSE(
+                    const xt::xtensor<double, 3>& MSE
+            )
+            {
+                // compute RMSE
+                auto RMSE = xt::sqrt(MSE);
+
                 return RMSE;
             }
         }
diff --git a/include/evalhyd/detail/determinist/evaluator.hpp b/include/evalhyd/detail/determinist/evaluator.hpp
index f7e58bd52bdc42ed59d9673d8601942b1c234e94..a5d5a3e0abc5d13334fc430cb2f373f4937c9228 100644
--- a/include/evalhyd/detail/determinist/evaluator.hpp
+++ b/include/evalhyd/detail/determinist/evaluator.hpp
@@ -39,6 +39,8 @@ namespace evalhyd
             // members for computational elements
             xtl::xoptional<xt::xtensor<double, 4>, bool> mean_obs;
             xtl::xoptional<xt::xtensor<double, 4>, bool> mean_prd;
+            xtl::xoptional<xt::xtensor<double, 2>, bool> err;
+            xtl::xoptional<xt::xtensor<double, 2>, bool> abs_err;
             xtl::xoptional<xt::xtensor<double, 2>, bool> quad_err;
             xtl::xoptional<xt::xtensor<double, 4>, bool> quad_obs;
             xtl::xoptional<xt::xtensor<double, 4>, bool> quad_prd;
@@ -48,6 +50,9 @@ namespace evalhyd
             xtl::xoptional<xt::xtensor<double, 3>, bool> bias;
 
             // members for evaluation metrics
+            xtl::xoptional<xt::xtensor<double, 3>, bool> MAE;
+            xtl::xoptional<xt::xtensor<double, 3>, bool> MARE;
+            xtl::xoptional<xt::xtensor<double, 3>, bool> MSE;
             xtl::xoptional<xt::xtensor<double, 3>, bool> RMSE;
             xtl::xoptional<xt::xtensor<double, 3>, bool> NSE;
             xtl::xoptional<xt::xtensor<double, 3>, bool> KGE;
@@ -78,12 +83,34 @@ namespace evalhyd
                 return mean_prd.value();
             };
 
+            xt::xtensor<double, 2> get_err()
+            {
+                if (!err.has_value())
+                {
+                    err = elements::calc_err(
+                            q_obs, q_prd
+                    );
+                }
+                return err.value();
+            };
+
+            xt::xtensor<double, 2> get_abs_err()
+            {
+                if (!abs_err.has_value())
+                {
+                    abs_err = elements::calc_abs_err(
+                            get_err()
+                    );
+                }
+                return abs_err.value();
+            };
+
             xt::xtensor<double, 2> get_quad_err()
             {
                 if (!quad_err.has_value())
                 {
                     quad_err = elements::calc_quad_err(
-                            q_obs, q_prd
+                            get_err()
                     );
                 }
                 return quad_err.value();
@@ -196,12 +223,45 @@ namespace evalhyd
             };
 
             // methods to compute metrics
+            xt::xtensor<double, 3> get_MAE()
+            {
+                if (!MAE.has_value())
+                {
+                    MAE = metrics::calc_MAE(
+                            get_abs_err(), t_msk, b_exp, n_srs, n_msk, n_exp
+                    );
+                }
+                return MAE.value();
+            };
+
+            xt::xtensor<double, 3> get_MARE()
+            {
+                if (!MARE.has_value())
+                {
+                    MARE = metrics::calc_MARE(
+                            get_MAE(), get_mean_obs(), n_srs, n_msk, n_exp
+                    );
+                }
+                return MARE.value();
+            };
+
+            xt::xtensor<double, 3> get_MSE()
+            {
+                if (!MSE.has_value())
+                {
+                    MSE = metrics::calc_MSE(
+                            get_quad_err(), t_msk, b_exp, n_srs, n_msk, n_exp
+                    );
+                }
+                return MSE.value();
+            };            
+            
             xt::xtensor<double, 3> get_RMSE()
             {
                 if (!RMSE.has_value())
                 {
                     RMSE = metrics::calc_RMSE(
-                            get_quad_err(), t_msk, b_exp, n_srs, n_msk, n_exp
+                            get_MSE()
                     );
                 }
                 return RMSE.value();
diff --git a/include/evalhyd/evald.hpp b/include/evalhyd/evald.hpp
index 810df0ad4bfc94834d7a399848da829ac53eeea9..ef858dfcfe97d058e7351155dd711f152a9f3d1b 100644
--- a/include/evalhyd/evald.hpp
+++ b/include/evalhyd/evald.hpp
@@ -208,7 +208,8 @@ namespace evalhyd
         // check that the metrics to be computed are valid
         utils::check_metrics(
                 metrics,
-                {"RMSE", "NSE", "KGE", "KGE_D", "KGEPRIME", "KGEPRIME_D"}
+                {"MAE", "MARE", "MSE", "RMSE",
+                 "NSE", "KGE", "KGE_D", "KGEPRIME", "KGEPRIME_D"}
         );
 
         // check that optional parameters are valid
@@ -434,6 +435,24 @@ namespace evalhyd
 
         for ( const auto& metric : metrics )
         {
+            if ( metric == "MAE" )
+            {
+                r.emplace_back(
+                        uncertainty::summarise_d(evaluator.get_MAE(), summary)
+                );
+            }
+            if ( metric == "MARE" )
+            {
+                r.emplace_back(
+                        uncertainty::summarise_d(evaluator.get_MARE(), summary)
+                );
+            }
+            if ( metric == "MSE" )
+            {
+                r.emplace_back(
+                        uncertainty::summarise_d(evaluator.get_MSE(), summary)
+                );
+            }
             if ( metric == "RMSE" )
             {
                 r.emplace_back(
diff --git a/tests/test_determinist.cpp b/tests/test_determinist.cpp
index 78f07d8169b05b743a099168eab49ffbad619eb1..41df12857ebd3a5f36ac569c7562b5c4a03c1a2b 100644
--- a/tests/test_determinist.cpp
+++ b/tests/test_determinist.cpp
@@ -15,6 +15,7 @@
 #include <xtensor/xmath.hpp>
 #include <xtensor/xsort.hpp>
 #include <xtensor/xcsv.hpp>
+#include <xtensor/xio.hpp>
 
 #include "evalhyd/evald.hpp"
 
@@ -26,7 +27,8 @@ using namespace xt::placeholders;  // required for `_` to work
 
 
 std::vector<std::string> all_metrics_d = {
-        "RMSE", "NSE", "KGE", "KGE_D", "KGEPRIME", "KGEPRIME_D"
+        "MAE", "MARE", "MSE", "RMSE",
+        "NSE", "KGE", "KGE_D", "KGEPRIME", "KGEPRIME_D"
 };
 
 std::tuple<xt::xtensor<double, 2>, xt::xtensor<double, 2>> load_data_d()
@@ -60,13 +62,37 @@ TEST(DeterministTests, TestMetrics)
             );
 
     // check results on all metrics
+    xt::xtensor<double, 3> mae =
+            {{{ 265.192926}},
+             {{ 265.681672}},
+             {{ 265.70418 }},
+             {{ 265.70418 }},
+             {{ 265.836013}}};
+    EXPECT_TRUE(xt::allclose(metrics[0], mae));
+
+    xt::xtensor<double, 3> mare =
+            {{{ 0.211088}},
+             {{ 0.211477}},
+             {{ 0.211495}},
+             {{ 0.211495}},
+             {{ 0.2116  }}};
+    EXPECT_TRUE(xt::allclose(metrics[1], mare));
+
+    xt::xtensor<double, 3> mse =
+            {{{ 603782.26045 }},
+             {{ 603540.170418}},
+             {{ 604973.176849}},
+             {{ 605519.106109}},
+             {{ 606241.115756}}};
+    EXPECT_TRUE(xt::allclose(metrics[2], mse));
+
     xt::xtensor<double, 3> rmse =
             {{{777.034272}},
              {{776.878479}},
              {{777.800217}},
              {{778.151082}},
              {{778.61487 }}};
-    EXPECT_TRUE(xt::allclose(metrics[0], rmse));
+    EXPECT_TRUE(xt::allclose(metrics[3], rmse));
 
     xt::xtensor<double, 3> nse =
             {{{0.718912}},
@@ -74,7 +100,7 @@ TEST(DeterministTests, TestMetrics)
              {{0.718358}},
              {{0.718104}},
              {{0.717767}}};
-    EXPECT_TRUE(xt::allclose(metrics[1], nse));
+    EXPECT_TRUE(xt::allclose(metrics[4], nse));
 
     xt::xtensor<double, 3> kge =
             {{{0.748088}},
@@ -82,7 +108,7 @@ TEST(DeterministTests, TestMetrics)
              {{0.744111}},
              {{0.743011}},
              {{0.741768}}};
-    EXPECT_TRUE(xt::allclose(metrics[2], kge));
+    EXPECT_TRUE(xt::allclose(metrics[5], kge));
 
     xt::xtensor<double, 4> kge_d =
             {{{{ 0.907125,  1.224429,  1.066824}}},
@@ -90,7 +116,7 @@ TEST(DeterministTests, TestMetrics)
              {{{ 0.90805 ,  1.228409,  1.069668}}},
              {{{ 0.908256,  1.229451,  1.070558}}},
              {{{ 0.908474,  1.230672,  1.071395}}}};
-    EXPECT_TRUE(xt::allclose(metrics[3], kge_d));
+    EXPECT_TRUE(xt::allclose(metrics[6], kge_d));
 
     xt::xtensor<double, 3> kgeprime =
             {{{0.813141}},
@@ -98,7 +124,7 @@ TEST(DeterministTests, TestMetrics)
              {{0.812032}},
              {{0.811787}},
              {{0.811387}}};
-    EXPECT_TRUE(xt::allclose(metrics[4], kgeprime));
+    EXPECT_TRUE(xt::allclose(metrics[7], kgeprime));
 
     xt::xtensor<double, 4> kgeprime_d =
             {{{{ 0.907125,  1.147733,  1.066824}}},
@@ -106,7 +132,7 @@ TEST(DeterministTests, TestMetrics)
              {{{ 0.90805 ,  1.148403,  1.069668}}},
              {{{ 0.908256,  1.148421,  1.070558}}},
              {{{ 0.908474,  1.148663,  1.071395}}}};
-    EXPECT_TRUE(xt::allclose(metrics[5], kgeprime_d));
+    EXPECT_TRUE(xt::allclose(metrics[8], kgeprime_d));
 }
 
 TEST(DeterministTests, TestTransform)