From 548fc1f98cec909dad7a23d131313e3d9b614b83 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 17 Dec 2024 15:42:34 +0100 Subject: [PATCH] New hydro remix : change the algorithm due to new specifications --- src/solver/simulation/hydro-remix-new.cpp | 102 ++++++--- .../solver/simulation/test-hydro-remix.cpp | 201 +++++++++++++----- 2 files changed, 220 insertions(+), 83 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 7c78b20703..4a6cd7d3bf 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -11,13 +12,14 @@ int find_min_index(const std::vector& G_plus_H, const std::vector& new_H, const std::vector& tried_creux, const std::vector& P_max, + const std::vector& filter_hours_remix, double top) { double min_val = top; int min_idx = -1; for (int i = 0; i < G_plus_H.size(); ++i) { - if (new_D[i] > 0 && new_H[i] < P_max[i] && tried_creux[i] == 0) + if (new_D[i] > 0 && new_H[i] < P_max[i] && tried_creux[i] == 0 && filter_hours_remix[i]) { if (G_plus_H[i] < min_val) { @@ -33,6 +35,7 @@ int find_max_index(const std::vector& G_plus_H, const std::vector& new_H, const std::vector& tried_pic, const std::vector& P_min, + const std::vector& filter_hours_remix, double ref_value, double eps) { @@ -40,7 +43,8 @@ int find_max_index(const std::vector& G_plus_H, int max_idx = -1; for (int i = 0; i < G_plus_H.size(); ++i) { - if (new_H[i] > P_min[i] && G_plus_H[i] >= ref_value + eps && tried_pic[i] == 0) + if (new_H[i] > P_min[i] && G_plus_H[i] >= ref_value + eps && tried_pic[i] == 0 + && filter_hours_remix[i]) { if (G_plus_H[i] > max_val) { @@ -59,7 +63,11 @@ static void checkInputCorrectness(const std::vector& G, const std::vector& P_min, double initial_level, double capa, - const std::vector& inflows) + const std::vector& inflows, + const std::vector& overflow, + const std::vector& pump, + const std::vector& S, + const std::vector& DTG_MRG) { std::string msg_prefix = "Remix hydro input : "; @@ -74,7 +82,12 @@ static void checkInputCorrectness(const std::vector& G, D.size(), P_max.size(), P_min.size(), - inflows.size()}; + inflows.size(), + overflow.size(), + pump.size(), + S.size(), + DTG_MRG.size()}; + if (std::ranges::adjacent_find(sizes, std::not_equal_to()) != sizes.end()) { throw std::invalid_argument(msg_prefix + "arrays of different sizes"); @@ -104,17 +117,38 @@ static void checkInputCorrectness(const std::vector& G, } } -std::pair, std::vector> new_remix_hydro( - const std::vector& G, - const std::vector& H, - const std::vector& D, - const std::vector& P_max, - const std::vector& P_min, - double initial_level, - double capa, - const std::vector& inflows) +struct RemixHydroOutput +{ + std::vector new_H; + std::vector new_D; + std::vector levels; +}; + +RemixHydroOutput new_remix_hydro(const std::vector& G, + const std::vector& H, + const std::vector& D, + const std::vector& P_max, + const std::vector& P_min, + double initial_level, + double capa, + const std::vector& inflows, + const std::vector& overflow, + const std::vector& pump, + const std::vector& S, + const std::vector& DTG_MRG) { - checkInputCorrectness(G, H, D, P_max, P_min, initial_level, capa, inflows); + checkInputCorrectness(G, + H, + D, + P_max, + P_min, + initial_level, + capa, + inflows, + overflow, + pump, + S, + DTG_MRG); std::vector new_H = H; std::vector new_D = D; @@ -124,14 +158,23 @@ std::pair, std::vector> new_remix_hydro( double top = *std::max_element(G.begin(), G.end()) + *std::max_element(H.begin(), H.end()) + *std::max_element(D.begin(), D.end()) + 1; + std::vector filter_hours_remix(G.size(), false); + for (unsigned int h = 0; h < filter_hours_remix.size(); h++) + { + if (S[h] + DTG_MRG[h] == 0. && H[h] + D[h] > 0.) + { + filter_hours_remix[h] = true; + } + } + std::vector G_plus_H(G.size()); std::transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), std::plus<>()); - std::vector level(G.size()); - level[0] = initial_level + inflows[0] - new_H[0]; - for (size_t i = 1; i < level.size(); ++i) + std::vector levels(G.size()); + levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - new_H[0]; + for (size_t i = 1; i < levels.size(); ++i) { - level[i] = level[i - 1] + inflows[i] - new_H[i]; + levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - new_H[i]; } while (loop-- > 0) @@ -141,7 +184,13 @@ std::pair, std::vector> new_remix_hydro( while (true) { - int idx_creux = find_min_index(G_plus_H, new_D, new_H, tried_creux, P_max, top); + int idx_creux = find_min_index(G_plus_H, + new_D, + new_H, + tried_creux, + P_max, + filter_hours_remix, + top); if (idx_creux == -1) { break; @@ -154,6 +203,7 @@ std::pair, std::vector> new_remix_hydro( new_H, tried_pic, P_min, + filter_hours_remix, G_plus_H[idx_creux], eps); if (idx_pic == -1) @@ -161,8 +211,9 @@ std::pair, std::vector> new_remix_hydro( break; } - std::vector intermediate_level(level.begin() + std::min(idx_creux, idx_pic), - level.begin() + std::vector intermediate_level(levels.begin() + + std::min(idx_creux, idx_pic), + levels.begin() + std::max(idx_creux, idx_pic)); double max_pic = std::min(new_H[idx_pic] - P_min[idx_pic], @@ -204,14 +255,13 @@ std::pair, std::vector> new_remix_hydro( } std::transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), std::plus<>()); - level[0] = initial_level + inflows[0] - new_H[0]; - for (size_t i = 1; i < level.size(); ++i) + levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - new_H[0]; + for (size_t i = 1; i < levels.size(); ++i) { - level[i] = level[i - 1] + inflows[i] - new_H[i]; + levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - new_H[i]; } } - - return {new_H, new_D}; + return {new_H, new_D, levels}; } } // End namespace Antares::Solver::Simulation diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 431cbe86a7..4e553e9e61 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -10,103 +10,109 @@ namespace Antares::Solver::Simulation { -std::pair, std::vector> new_remix_hydro( - const std::vector& G, - const std::vector& H, - const std::vector& D, - const std::vector& P_max, - const std::vector& P_min, - double initial_level, - double capa, - const std::vector& inflow); -} +// gp : instead of this, we should make a header asociated to hydro-remix-new.cpp +// ==> hydro-remix-new.h +struct RemixHydroOutput +{ + std::vector new_H; + std::vector new_D; + std::vector levels; +}; + +RemixHydroOutput new_remix_hydro(const std::vector& G, + const std::vector& H, + const std::vector& D, + const std::vector& P_max, + const std::vector& P_min, + double initial_level, + double capa, + const std::vector& inflow, + const std::vector& overflow, + const std::vector& pump, + const std::vector& S, + const std::vector& DTG_MRG); + +} // namespace Antares::Solver::Simulation using namespace Antares::Solver::Simulation; -BOOST_AUTO_TEST_CASE(dummy_unit_test___will_be_removed) -{ - std::vector G = {1.0, 2.0, 3.0, 4.0, 5.0}; - std::vector H = {2.0, 3.0, 4.0, 5.0, 6.0}; - std::vector D = {1.0, 1.5, 2.0, 2.5, 3.0}; - std::vector P_max = {10.0, 10.0, 10.0, 10.0, 10.0}; - std::vector P_min = {0.0, 0.0, 0.0, 0.0, 0.0}; - double initial_level = 5.0; - double capa = 20.0; - std::vector inflow = {3.0, 3.0, 3.0, 3.0, 3.0}; - - auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflow); - - BOOST_CHECK(true); -} - BOOST_AUTO_TEST_CASE(input_arrays_of_different_sizes__exception_raised) { - std::vector G, D, P_max, P_min, inflows; + std::vector G, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; std::vector H = {0., 0.}; double initial_level = 0.; double capa = 0.; - BOOST_CHECK_EXCEPTION(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows), - std::invalid_argument, - checkMessage("Remix hydro input : arrays of different sizes")); + BOOST_CHECK_EXCEPTION( + new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : arrays of different sizes")); } BOOST_AUTO_TEST_CASE(input_init_level_exceeds_capacity__exception_raised) { - std::vector G, D, P_max, P_min, inflows; + std::vector G, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; std::vector H = {0., 0.}; double initial_level = 2.; double capa = 1.; - BOOST_CHECK_EXCEPTION(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows), - std::invalid_argument, - checkMessage("Remix hydro input : initial level > reservoir capacity")); + BOOST_CHECK_EXCEPTION( + new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : initial level > reservoir capacity")); } BOOST_AUTO_TEST_CASE(all_input_arrays_of_size_0__exception_raised) { - std::vector G, H, D, P_max, P_min, inflows; + std::vector G, H, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; double initial_level = 0.; double capa = 1.; - BOOST_CHECK_EXCEPTION(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows), - std::invalid_argument, - checkMessage("Remix hydro input : all arrays of sizes 0")); + BOOST_CHECK_EXCEPTION( + new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : all arrays of sizes 0")); } BOOST_AUTO_TEST_CASE(H_not_smaller_than_pmax__exception_raised) { std::vector G(5, 0.), D(5, 0.), P_min(5, 0.), inflows(5, 0.); + std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); std::vector H = {1., 2., 3., 4., 5.}; std::vector P_max = {2., 2., 2., 4., 5.}; double initial_level = 0.; double capa = 1.; - BOOST_CHECK_EXCEPTION(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows), - std::invalid_argument, - checkMessage("Remix hydro input : H not smaller than Pmax everywhere")); + BOOST_CHECK_EXCEPTION( + new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : H not smaller than Pmax everywhere")); } BOOST_AUTO_TEST_CASE(H_not_greater_than_pmin__exception_raised) { std::vector G(5, 0.), D(5, 0.), P_max(5, 1000.), inflows(5, 0.); + std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); std::vector H = {1., 2., 3., 4., 5.}; std::vector P_min = {0., 0., 4., 0., 0.}; double initial_level = 0.; double capa = 1.; - BOOST_CHECK_EXCEPTION(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows), - std::invalid_argument, - checkMessage("Remix hydro input : H not greater than Pmin everywhere")); + BOOST_CHECK_EXCEPTION( + new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : H not greater than Pmin everywhere")); } BOOST_AUTO_TEST_CASE(input_is_acceptable__no_exception_raised) { std::vector G = {0.}, H = {0.}, D = {0.}, P_max = {0.}, P_min = {0.}, inflows = {0.}; + std::vector ovf = {0.}, pump = {0.}, S = {0.}, DTG_MRG = {0.}; double initial_level = 0.; double capa = 1.; - BOOST_CHECK_NO_THROW(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows)); + BOOST_CHECK_NO_THROW( + new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG)); } BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20mwh) @@ -119,8 +125,20 @@ BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20 double initial_level = 500.; double capa = 1000.; std::vector inflows(5, 0.); - - auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + + auto [new_H, new_D, _] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + initial_level, + capa, + inflows, + ovf, + pump, + S, + DTG_MRG); std::vector expected_H = {20., 20., 20., 20., 20.}; // D such as G + H + D remains constant at each hour @@ -139,8 +157,20 @@ BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) double initial_level = 500.; double capa = 1000.; std::vector inflows(5, 0.); - - auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + + auto [new_H, new_D, _] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + initial_level, + capa, + inflows, + ovf, + pump, + S, + DTG_MRG); std::vector expected_H = {20., 20., 20., 20., 20.}; // D such as G + H + D remains constant at each hour @@ -159,8 +189,20 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20 double initial_level = 500.; double capa = 1000.; std::vector inflows(5, 0.); - - auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + + auto [new_H, new_D, _] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + initial_level, + capa, + inflows, + ovf, + pump, + S, + DTG_MRG); std::vector expected_H = {20., 20., 20., 20., 20.}; // D such as G + H + D remains constant at each hour @@ -182,12 +224,24 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) double initial_level = 500.; double capa = 1000.; std::vector inflows(5, 0.); + std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); // 1. Algorithm tends to flatten G + H, so it would require H to increase. // Proof : std::vector P_max(5., std::numeric_limits::max()); - auto [new_H1, new_D1] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + auto [new_H1, new_D1, L] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + initial_level, + capa, + inflows, + ovf, + pump, + S, + DTG_MRG); std::vector expected_H1 = {0., 0., 13.33, 33.33, 53.33}; BOOST_TEST(new_H1 == expected_H1, boost::test_tools::per_element()); @@ -195,7 +249,18 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) // 2. But H is limited by P_max. So Algo does nothing in the end. // Proof : P_max = {20., 20., 20., 20., 20.}; - auto [new_H2, new_D2] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + auto [new_H2, new_D2, _] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + initial_level, + capa, + inflows, + ovf, + pump, + S, + DTG_MRG); std::vector expected_H2 = {20., 20., 20., 20., 20.}; std::vector expected_D2 = {50., 50., 50., 50., 50.}; @@ -216,16 +281,39 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) double initial_level = 500.; double capa = 1000.; std::vector inflows(5, 0.); + std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); // 1. Algorithm tends to flatten G + H, so it would require H to increase. std::vector P_min(5, 0.); - auto [new_H1, new_D1] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + auto [new_H1, new_D1, L] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + initial_level, + capa, + inflows, + ovf, + pump, + S, + DTG_MRG); std::vector expected_H1 = {0., 0., 13.33, 33.33, 53.33}; BOOST_TEST(new_H1 == expected_H1, boost::test_tools::per_element()); // 2. But H is low bounded by P_min. So Algo does nothing in the end. P_min = {20., 20., 20., 20., 20.}; - auto [new_H2, new_D2] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + auto [new_H2, new_D2, _] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + initial_level, + capa, + inflows, + ovf, + pump, + S, + DTG_MRG); std::vector expected_H2 = {20., 20., 20., 20., 20.}; std::vector expected_D2 = {50., 50., 50., 50., 50.}; @@ -237,6 +325,5 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) // ================================ // - Remix hydro algorithm seems symmetrical (if we have input vectors and corresponding output // vectors, run the algo on reversed vectors gives reversed output result vectors) -// - How to test influence of Pmin ? // - After running remix hydro algo, sum(H), sum(H + D) must remain the same. -// - influence of D : low values of G + H are searched where D > 0 (not where D >= 0) +// - influence of D : low values of G + H are searched where D > 0 (not where D == 0)