From 6871e989cef6eb726e70aac1c7ac9ebfe6082954 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 12 Dec 2024 17:58:13 +0100 Subject: [PATCH 01/44] New hydro remix : setting unit tests environment --- src/solver/simulation/hydro-remix-new.cpp | 171 ++++++++++++++++++ .../src/solver/simulation/CMakeLists.txt | 121 ++++++++----- .../solver/simulation/test-hydro-remix.cpp | 46 +++++ 3 files changed, 289 insertions(+), 49 deletions(-) create mode 100644 src/solver/simulation/hydro-remix-new.cpp create mode 100644 src/tests/src/solver/simulation/test-hydro-remix.cpp diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp new file mode 100644 index 0000000000..e44edd813b --- /dev/null +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace Antares::Solver::Simulation +{ + +bool new_remix_hydro() +{ + return true; +} + +int find_min_index(const vector& G_plus_H, + const vector& new_D, + const vector& new_H, + const vector& tried_creux, + const vector& P_max, + double top) +{ + double min_val = top; + int min_idx = -1; + for (size_t i = 0; i < G_plus_H.size(); ++i) + { + if (new_D[i] > 0 && new_H[i] < P_max[i] && tried_creux[i] == 0) + { + if (G_plus_H[i] < min_val) + { + min_val = G_plus_H[i]; + min_idx = i; + } + } + } + return min_idx; +} + +int find_max_index(const vector& G_plus_H, + const vector& new_H, + const vector& tried_pic, + const vector& P_min, + double ref_value, + double eps) +{ + double max_val = 0; + int max_idx = -1; + for (size_t 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 (G_plus_H[i] > max_val) + { + max_val = G_plus_H[i]; + max_idx = i; + } + } + } + return max_idx; +} + +pair, vector> new_remix_hydro(const vector& G, + const vector& H, + const vector& D, + const vector& P_max, + const vector& P_min, + double initial_level, + double capa, + const vector& inflow) +{ + vector new_H = H; + vector new_D = D; + + int loop = 1000; + double eps = 1e-2; + double top = *max_element(G.begin(), G.end()) + *max_element(H.begin(), H.end()) + + *max_element(D.begin(), D.end()) + 1; + + vector G_plus_H(G.size()); + transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), plus<>()); + + vector level(G.size()); + level[0] = initial_level + inflow[0] - new_H[0]; + for (size_t i = 1; i < level.size(); ++i) + { + level[i] = level[i - 1] + inflow[i] - new_H[i]; + } + + while (loop-- > 0) + { + vector tried_creux(G.size(), 0); + double delta = 0; + + while (true) + { + int idx_creux = find_min_index(G_plus_H, new_D, new_H, tried_creux, P_max, top); + if (idx_creux == -1) + { + break; + } + + vector tried_pic(G.size(), 0); + while (true) + { + int idx_pic = find_max_index(G_plus_H, + new_H, + tried_pic, + P_min, + G_plus_H[idx_creux], + eps); + if (idx_pic == -1) + { + break; + } + + vector intermediate_level(level.begin() + min(idx_creux, idx_pic), + level.begin() + max(idx_creux, idx_pic)); + + double max_pic = min(new_H[idx_pic] - P_min[idx_pic], + capa + - *max_element(intermediate_level.begin(), + intermediate_level.end())); + double max_creux = min( + {P_max[idx_creux] - new_H[idx_creux], + new_D[idx_creux], + *min_element(intermediate_level.begin(), intermediate_level.end())}); + double dif_pic_creux = max(G_plus_H[idx_pic] - G_plus_H[idx_creux], 0.0); + + delta = max(min({max_pic, max_creux, dif_pic_creux / 2.0}), 0.0); + + if (delta > 0) + { + new_H[idx_pic] -= delta; + new_H[idx_creux] += delta; + new_D[idx_pic] = H[idx_pic] + D[idx_pic] - new_H[idx_pic]; + new_D[idx_creux] = H[idx_creux] + D[idx_creux] - new_H[idx_creux]; + break; + } + else + { + tried_pic[idx_pic] = 1; + } + } + + if (delta > 0) + { + break; + } + tried_creux[idx_creux] = 1; + } + + if (delta == 0) + { + break; + } + + transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), plus<>()); + level[0] = initial_level + inflow[0] - new_H[0]; + for (size_t i = 1; i < level.size(); ++i) + { + level[i] = level[i - 1] + inflow[i] - new_H[i]; + } + } + + return {new_H, new_D}; +} + +} // End namespace Antares::Solver::Simulation diff --git a/src/tests/src/solver/simulation/CMakeLists.txt b/src/tests/src/solver/simulation/CMakeLists.txt index 294005454b..10ef79b619 100644 --- a/src/tests/src/solver/simulation/CMakeLists.txt +++ b/src/tests/src/solver/simulation/CMakeLists.txt @@ -4,27 +4,27 @@ set(src_solver_hydro "${CMAKE_SOURCE_DIR}/solver/hydro") set(src_libs_antares_study "${CMAKE_SOURCE_DIR}/libs/antares/study") set(SRC_TS_NUMBERS - # For confort in IDE, but not necessary - ${src_solver_simulation}/include/antares/solver/simulation/timeseries-numbers.h - - # Necessary cpp files - ${src_solver_simulation}/timeseries-numbers.cpp - ${src_solver_simulation}/include/antares/solver/simulation/ITimeSeriesNumbersWriter.h) + # For confort in IDE, but not necessary + ${src_solver_simulation}/include/antares/solver/simulation/timeseries-numbers.h + + # Necessary cpp files + ${src_solver_simulation}/timeseries-numbers.cpp + ${src_solver_simulation}/include/antares/solver/simulation/ITimeSeriesNumbersWriter.h) add_executable(tests-ts-numbers tests-ts-numbers.cpp ${SRC_TS_NUMBERS}) target_include_directories(tests-ts-numbers - PRIVATE - "${src_solver_simulation}" - "${src_libs_antares_study}" + PRIVATE + "${src_solver_simulation}" + "${src_libs_antares_study}" ) target_link_libraries(tests-ts-numbers - PRIVATE - Antares::utils - Boost::unit_test_framework - model_antares - antares-solver-simulation - antares-solver-ts-generator + PRIVATE + Antares::utils + Boost::unit_test_framework + model_antares + antares-solver-simulation + antares-solver-ts-generator ) # Storing tests-ts-numbers under the folder Unit-tests in the IDE @@ -38,23 +38,23 @@ set_property(TEST ts-numbers PROPERTY LABELS unit) # Tests on area's store-timeseries-number # =================================== set(SRC_STORE_TS - test-store-timeseries-number.cpp - ) + test-store-timeseries-number.cpp +) add_executable(test-store-timeseries-number ${SRC_STORE_TS}) target_link_libraries(test-store-timeseries-number - PRIVATE - Boost::unit_test_framework + PRIVATE + Boost::unit_test_framework test_utils_unit - antares-solver-simulation - Antares::study - Antares::result_writer - ) + antares-solver-simulation + Antares::study + Antares::result_writer +) # Linux -if(UNIX AND NOT APPLE) - target_link_libraries(test-store-timeseries-number PRIVATE stdc++fs) -endif() +if (UNIX AND NOT APPLE) + target_link_libraries(test-store-timeseries-number PRIVATE stdc++fs) +endif () set_target_properties(test-store-timeseries-number PROPERTIES FOLDER Unit-tests) @@ -66,22 +66,22 @@ set_property(TEST store-timeseries-number PROPERTY LABELS unit) # Tests on time series # =================================== set(SRC_STORE_TS - test-time_series.cpp - ) + test-time_series.cpp +) add_executable(test-time_series ${SRC_STORE_TS}) target_link_libraries(test-time_series - PRIVATE - Boost::unit_test_framework + PRIVATE + Boost::unit_test_framework test_utils_unit - antares-solver-simulation - Antares::study - ) + antares-solver-simulation + Antares::study +) # Linux -if(UNIX AND NOT APPLE) - target_link_libraries(test-time_series PRIVATE stdc++fs) -endif() +if (UNIX AND NOT APPLE) + target_link_libraries(test-time_series PRIVATE stdc++fs) +endif () set_target_properties(test-time_series PROPERTIES FOLDER Unit-tests) @@ -97,26 +97,49 @@ set_property(TEST time_series PROPERTY LABELS unit) add_executable(test-hydro_final test-hydro-final-reservoir-level-functions.cpp) target_include_directories(test-hydro_final - PRIVATE - "${src_solver_simulation}" - "${src_libs_antares_study}" - "${src_solver_hydro}" + PRIVATE + "${src_solver_simulation}" + "${src_libs_antares_study}" + "${src_solver_hydro}" ) target_link_libraries(test-hydro_final - PRIVATE - Boost::unit_test_framework - Antares::study - antares-solver-simulation - Antares::array + PRIVATE + Boost::unit_test_framework + Antares::study + antares-solver-simulation + Antares::array ) # Linux -if(UNIX AND NOT APPLE) - target_link_libraries(test-hydro_final PRIVATE stdc++fs) -endif() +if (UNIX AND NOT APPLE) + target_link_libraries(test-hydro_final PRIVATE stdc++fs) +endif () set_target_properties(test-hydro_final PROPERTIES FOLDER Unit-tests) add_test(NAME hydro_final COMMAND test-hydro_final) -set_property(TEST hydro_final PROPERTY LABELS unit) \ No newline at end of file +set_property(TEST hydro_final PROPERTY LABELS unit) + + +# =================================== +# Tests on hydro remix algorithm +# =================================== +add_executable(test-hydro-remix + test-hydro-remix.cpp + ${src_solver_simulation}/hydro-remix-new.cpp +) + +target_link_libraries(test-hydro-remix + PRIVATE + Boost::unit_test_framework +) + +# gp : do we need this ? +if (UNIX AND NOT APPLE) + target_link_libraries(test-hydro_final PRIVATE stdc++fs) +endif () + +set_target_properties(test-hydro-remix PROPERTIES FOLDER Unit-tests) +add_test(NAME hydro_remix COMMAND test-hydro-remix) +set_property(TEST hydro_remix PROPERTY LABELS unit) \ No newline at end of file diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp new file mode 100644 index 0000000000..4ca8773c4a --- /dev/null +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -0,0 +1,46 @@ +#define BOOST_TEST_MODULE hydro remix + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +namespace Antares::Solver::Simulation +{ +bool new_remix_hydro(); +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); +} // namespace Antares::Solver::Simulation + +using namespace Antares::Solver::Simulation; +using namespace std; + +BOOST_AUTO_TEST_CASE(my_first_unit_test) +{ + BOOST_CHECK(new_remix_hydro()); +} + +BOOST_AUTO_TEST_CASE(my_second_unit_test) +{ + vector G = {1.0, 2.0, 3.0, 4.0, 5.0}; + vector H = {2.0, 3.0, 4.0, 5.0, 6.0}; + vector D = {1.0, 1.5, 2.0, 2.5, 3.0}; + vector P_max = {10.0, 10.0, 10.0, 10.0, 10.0}; + vector P_min = {0.0, 0.0, 0.0, 0.0, 0.0}; + double initial_level = 5.0; + double capa = 20.0; + vector inflow = {3.0, 3.0, 3.0, 3.0, 3.0}; + + // Call the function + auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflow); + + BOOST_CHECK(true); +} From 33a96eadf060fb8287cfe3950429ac64e525a6ae Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 12 Dec 2024 18:10:39 +0100 Subject: [PATCH 02/44] New hydro remix : some cleaning --- src/solver/simulation/hydro-remix-new.cpp | 82 ++++++++----------- .../solver/simulation/test-hydro-remix.cpp | 22 ++--- 2 files changed, 43 insertions(+), 61 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index e44edd813b..76e9e9f90c 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -1,26 +1,14 @@ #include -#include -#include -#include -#include -#include #include -using namespace std; - namespace Antares::Solver::Simulation { -bool new_remix_hydro() -{ - return true; -} - -int find_min_index(const vector& G_plus_H, - const vector& new_D, - const vector& new_H, - const vector& tried_creux, - const vector& P_max, +int find_min_index(const std::vector& G_plus_H, + const std::vector& new_D, + const std::vector& new_H, + const std::vector& tried_creux, + const std::vector& P_max, double top) { double min_val = top; @@ -39,10 +27,10 @@ int find_min_index(const vector& G_plus_H, return min_idx; } -int find_max_index(const vector& G_plus_H, - const vector& new_H, - const vector& tried_pic, - const vector& P_min, +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, double ref_value, double eps) { @@ -62,27 +50,28 @@ int find_max_index(const vector& G_plus_H, return max_idx; } -pair, vector> new_remix_hydro(const vector& G, - const vector& H, - const vector& D, - const vector& P_max, - const vector& P_min, - double initial_level, - double capa, - const vector& inflow) +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) { - vector new_H = H; - vector new_D = D; + std::vector new_H = H; + std::vector new_D = D; int loop = 1000; double eps = 1e-2; double top = *max_element(G.begin(), G.end()) + *max_element(H.begin(), H.end()) + *max_element(D.begin(), D.end()) + 1; - vector G_plus_H(G.size()); - transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), plus<>()); + std::vector G_plus_H(G.size()); + transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), std::plus<>()); - vector level(G.size()); + std::vector level(G.size()); level[0] = initial_level + inflow[0] - new_H[0]; for (size_t i = 1; i < level.size(); ++i) { @@ -91,7 +80,7 @@ pair, vector> new_remix_hydro(const vector& G, while (loop-- > 0) { - vector tried_creux(G.size(), 0); + std::vector tried_creux(G.size(), 0); double delta = 0; while (true) @@ -102,7 +91,7 @@ pair, vector> new_remix_hydro(const vector& G, break; } - vector tried_pic(G.size(), 0); + std::vector tried_pic(G.size(), 0); while (true) { int idx_pic = find_max_index(G_plus_H, @@ -116,20 +105,21 @@ pair, vector> new_remix_hydro(const vector& G, break; } - vector intermediate_level(level.begin() + min(idx_creux, idx_pic), - level.begin() + max(idx_creux, idx_pic)); + std::vector intermediate_level(level.begin() + std::min(idx_creux, idx_pic), + level.begin() + + std::max(idx_creux, idx_pic)); - double max_pic = min(new_H[idx_pic] - P_min[idx_pic], - capa - - *max_element(intermediate_level.begin(), - intermediate_level.end())); - double max_creux = min( + double max_pic = std::min(new_H[idx_pic] - P_min[idx_pic], + capa + - *max_element(intermediate_level.begin(), + intermediate_level.end())); + double max_creux = std::min( {P_max[idx_creux] - new_H[idx_creux], new_D[idx_creux], *min_element(intermediate_level.begin(), intermediate_level.end())}); - double dif_pic_creux = max(G_plus_H[idx_pic] - G_plus_H[idx_creux], 0.0); + double dif_pic_creux = std::max(G_plus_H[idx_pic] - G_plus_H[idx_creux], 0.0); - delta = max(min({max_pic, max_creux, dif_pic_creux / 2.0}), 0.0); + delta = std::max(std::min({max_pic, max_creux, dif_pic_creux / 2.0}), 0.0); if (delta > 0) { @@ -157,7 +147,7 @@ pair, vector> new_remix_hydro(const vector& G, break; } - transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), plus<>()); + transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), std::plus<>()); level[0] = initial_level + inflow[0] - new_H[0]; for (size_t i = 1; i < level.size(); ++i) { diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 4ca8773c4a..3f90756f0d 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -8,7 +8,6 @@ namespace Antares::Solver::Simulation { -bool new_remix_hydro(); std::pair, std::vector> new_remix_hydro( const std::vector& G, const std::vector& H, @@ -18,28 +17,21 @@ std::pair, std::vector> new_remix_hydro( double initial_level, double capa, const std::vector& inflow); -} // namespace Antares::Solver::Simulation +} using namespace Antares::Solver::Simulation; -using namespace std; BOOST_AUTO_TEST_CASE(my_first_unit_test) { - BOOST_CHECK(new_remix_hydro()); -} - -BOOST_AUTO_TEST_CASE(my_second_unit_test) -{ - vector G = {1.0, 2.0, 3.0, 4.0, 5.0}; - vector H = {2.0, 3.0, 4.0, 5.0, 6.0}; - vector D = {1.0, 1.5, 2.0, 2.5, 3.0}; - vector P_max = {10.0, 10.0, 10.0, 10.0, 10.0}; - vector P_min = {0.0, 0.0, 0.0, 0.0, 0.0}; + 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; - vector inflow = {3.0, 3.0, 3.0, 3.0, 3.0}; + std::vector inflow = {3.0, 3.0, 3.0, 3.0, 3.0}; - // Call the function auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflow); BOOST_CHECK(true); From e40b32f6173f4e52c1890ec9a2856d20f70924b7 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Fri, 13 Dec 2024 17:23:17 +0100 Subject: [PATCH 03/44] New hydro remix : unit tests on input data --- src/solver/simulation/hydro-remix-new.cpp | 67 +++++++++++++++---- .../src/solver/simulation/CMakeLists.txt | 1 + .../solver/simulation/test-hydro-remix.cpp | 47 ++++++++++++- 3 files changed, 100 insertions(+), 15 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 76e9e9f90c..80c7530b73 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include namespace Antares::Solver::Simulation @@ -13,7 +15,7 @@ int find_min_index(const std::vector& G_plus_H, { double min_val = top; int min_idx = -1; - for (size_t i = 0; i < G_plus_H.size(); ++i) + 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) { @@ -36,7 +38,7 @@ int find_max_index(const std::vector& G_plus_H, { double max_val = 0; int max_idx = -1; - for (size_t i = 0; i < G_plus_H.size(); ++i) + 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) { @@ -50,6 +52,41 @@ int find_max_index(const std::vector& G_plus_H, return max_idx; } +static void checkInputCorrectness(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) +{ + std::string msg_prefix = "Remix hydro input : "; + + // Initial level smaller than capacity + if (initial_level > capa) + { + throw std::invalid_argument(msg_prefix + "initial level > reservoir capacity"); + } + // Arrays sizes must be identical + std::vector sizes = {G.size(), + H.size(), + D.size(), + P_max.size(), + P_min.size(), + inflows.size()}; + if (std::ranges::adjacent_find(sizes, std::not_equal_to()) != sizes.end()) + { + throw std::invalid_argument(msg_prefix + "arrays of different sizes"); + } + + // Arrays are of size 0 + if (!G.size()) + { + throw std::invalid_argument(msg_prefix + "all arrays of sizes 0"); + } +} + std::pair, std::vector> new_remix_hydro( const std::vector& G, const std::vector& H, @@ -58,24 +95,26 @@ std::pair, std::vector> new_remix_hydro( const std::vector& P_min, double initial_level, double capa, - const std::vector& inflow) + const std::vector& inflows) { + checkInputCorrectness(G, H, D, P_max, P_min, initial_level, capa, inflows); + std::vector new_H = H; std::vector new_D = D; int loop = 1000; double eps = 1e-2; - double top = *max_element(G.begin(), G.end()) + *max_element(H.begin(), H.end()) - + *max_element(D.begin(), D.end()) + 1; + 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 G_plus_H(G.size()); - transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), std::plus<>()); + std::transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), std::plus<>()); std::vector level(G.size()); - level[0] = initial_level + inflow[0] - new_H[0]; + level[0] = initial_level + inflows[0] - new_H[0]; for (size_t i = 1; i < level.size(); ++i) { - level[i] = level[i - 1] + inflow[i] - new_H[i]; + level[i] = level[i - 1] + inflows[i] - new_H[i]; } while (loop-- > 0) @@ -111,12 +150,12 @@ std::pair, std::vector> new_remix_hydro( double max_pic = std::min(new_H[idx_pic] - P_min[idx_pic], capa - - *max_element(intermediate_level.begin(), - intermediate_level.end())); + - *std::max_element(intermediate_level.begin(), + intermediate_level.end())); double max_creux = std::min( {P_max[idx_creux] - new_H[idx_creux], new_D[idx_creux], - *min_element(intermediate_level.begin(), intermediate_level.end())}); + *std::min_element(intermediate_level.begin(), intermediate_level.end())}); double dif_pic_creux = std::max(G_plus_H[idx_pic] - G_plus_H[idx_creux], 0.0); delta = std::max(std::min({max_pic, max_creux, dif_pic_creux / 2.0}), 0.0); @@ -147,11 +186,11 @@ std::pair, std::vector> new_remix_hydro( break; } - transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), std::plus<>()); - level[0] = initial_level + inflow[0] - new_H[0]; + 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) { - level[i] = level[i - 1] + inflow[i] - new_H[i]; + level[i] = level[i - 1] + inflows[i] - new_H[i]; } } diff --git a/src/tests/src/solver/simulation/CMakeLists.txt b/src/tests/src/solver/simulation/CMakeLists.txt index 10ef79b619..be2285170d 100644 --- a/src/tests/src/solver/simulation/CMakeLists.txt +++ b/src/tests/src/solver/simulation/CMakeLists.txt @@ -133,6 +133,7 @@ add_executable(test-hydro-remix target_link_libraries(test-hydro-remix PRIVATE Boost::unit_test_framework + test_utils_unit ) # gp : do we need this ? diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 3f90756f0d..e846113bf3 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -2,6 +2,7 @@ #define WIN32_LEAN_AND_MEAN +#include #include #include @@ -21,7 +22,7 @@ std::pair, std::vector> new_remix_hydro( using namespace Antares::Solver::Simulation; -BOOST_AUTO_TEST_CASE(my_first_unit_test) +BOOST_AUTO_TEST_CASE(first_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}; @@ -36,3 +37,47 @@ BOOST_AUTO_TEST_CASE(my_first_unit_test) 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 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_AUTO_TEST_CASE(input_init_level_exceeds_capacity__exception_raised) +{ + std::vector G, D, P_max, P_min, inflows; + 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_AUTO_TEST_CASE(all_input_arrays_of_size_0__exception_raised) +{ + std::vector G, H, D, P_max, P_min, inflows; + 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_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.}; + 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)); +} From 34f0ed7b2d4816900d751a204a7ac1f81fdcf50e Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Fri, 13 Dec 2024 18:01:25 +0100 Subject: [PATCH 04/44] New hydro remix : add unit test > pmax is supposed to limit hydro generation --- .../solver/simulation/test-hydro-remix.cpp | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index e846113bf3..2d12aaaaa0 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -22,7 +22,7 @@ std::pair, std::vector> new_remix_hydro( using namespace Antares::Solver::Simulation; -BOOST_AUTO_TEST_CASE(first_dummy_unit_test___will_be_removed) +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}; @@ -81,3 +81,24 @@ BOOST_AUTO_TEST_CASE(input_is_acceptable__no_exception_raised) BOOST_CHECK_NO_THROW(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows)); } + +BOOST_AUTO_TEST_CASE(hydro_prod_very_changing__smoothing_required___smoothing_limited_by_pmax) +{ + double pmax = 10.; + std::vector G(5, 100.); + std::vector H = {0., 20., 40.0, 60.0, 80.0}; + std::vector D = {80.0, 60., 40., 20., 0.}; + std::vector P_max(5, pmax); + std::vector P_min(5, 0.); + double initial_level = 200.; + double capa = 400.; + std::vector inflows(5, 0.); + + auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + + BOOST_CHECK(new_H[0] < pmax); + BOOST_CHECK(new_H[1] < pmax); + BOOST_CHECK(new_H[2] < pmax); + BOOST_CHECK(new_H[3] < pmax); + BOOST_CHECK(new_H[4] < pmax); +} From cba01ee621bdaf091ecfdaf2d08ae169406d2c16 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Mon, 16 Dec 2024 14:39:41 +0100 Subject: [PATCH 05/44] New hydro remix : adding tests on Pmax respect --- .../solver/simulation/test-hydro-remix.cpp | 94 ++++++++++++++++--- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 2d12aaaaa0..d29577e627 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -2,6 +2,7 @@ #define WIN32_LEAN_AND_MEAN +#include #include #include @@ -82,23 +83,94 @@ BOOST_AUTO_TEST_CASE(input_is_acceptable__no_exception_raised) BOOST_CHECK_NO_THROW(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows)); } -BOOST_AUTO_TEST_CASE(hydro_prod_very_changing__smoothing_required___smoothing_limited_by_pmax) +BOOST_AUTO_TEST_CASE(hydro_increases_but_pmax_only_10mwh___10mwh_are_moved_from_last_to_first_hour) { - double pmax = 10.; std::vector G(5, 100.); - std::vector H = {0., 20., 40.0, 60.0, 80.0}; + std::vector H = {0., 20., 40., 60., 80.}; std::vector D = {80.0, 60., 40., 20., 0.}; - std::vector P_max(5, pmax); + std::vector P_max(5, 10.); std::vector P_min(5, 0.); - double initial_level = 200.; - double capa = 400.; + 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); - BOOST_CHECK(new_H[0] < pmax); - BOOST_CHECK(new_H[1] < pmax); - BOOST_CHECK(new_H[2] < pmax); - BOOST_CHECK(new_H[3] < pmax); - BOOST_CHECK(new_H[4] < pmax); + std::vector expected_H = {10., 20., 40., 60., 70.}; + std::vector expected_D = {70., 60., 40., 20., 10.}; + BOOST_CHECK(new_H == expected_H); + BOOST_CHECK(new_D == expected_D); } + +BOOST_AUTO_TEST_CASE(hydro_increases_but_pmax_only_20mwh___20mwh_are_moved_from_last_to_first_hour) +{ + std::vector G(5, 100.); + std::vector H = {0., 20., 40., 60., 80.}; + std::vector D = {80.0, 60., 40., 20., 0.}; + std::vector P_max(5, 20.); + std::vector P_min(5, 0.); + 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 expected_H = {20., 20., 40., 60., 60.}; + BOOST_CHECK(new_H == expected_H); +} + +BOOST_AUTO_TEST_CASE(hydro_increases_but_pmax_only_30mwh___30mwh_are_moved_from_last_to_first_hour) +{ + std::vector G(5, 100.); + std::vector H = {0., 20., 40., 60., 80.}; + std::vector D = {80.0, 60., 40., 20., 0.}; + std::vector P_max(5, 30.); + std::vector P_min(5, 0.); + 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 expected_H = {30., 30., 40., 50., 50.}; + BOOST_CHECK(new_H == expected_H); +} + +BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___final_hydro_is_flat_and_limited_by_pmax) +{ + std::vector G(5, 100.); + std::vector H = {0., 20., 40., 60., 80.}; + std::vector D = {80.0, 60., 40., 20., 0.}; + std::vector P_max(5, 40.); + std::vector P_min(5, 0.); + 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 expected_H = {40., 40., 40., 40., 40.}; + BOOST_CHECK(new_H == expected_H); +} + +BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_50mwh___final_hydro_is_flat_and_limited_by_pmax) +{ + std::vector G(5, 100.); + std::vector H = {0., 20., 40., 60., 80.}; + std::vector D = {80.0, 60., 40., 20., 0.}; + std::vector P_max(5, 50.); + std::vector P_min(5, 0.); + 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 expected_H = {40., 40., 40., 40., 40.}; + BOOST_CHECK(new_H == expected_H); +} + +// Comment for further tests : +// - Remix hydro algorithm seems symetrical (if we have input vectors and corresponding output +// vectors, run the algo on reversed vectors gives reversed output result vectors) +// - After running remix hydro algo, sum(H), sum(H + D) must remain the same. From 9f41dc1faaa845ef6a35584c8dd19e39bdc17cc4 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Mon, 16 Dec 2024 17:13:52 +0100 Subject: [PATCH 06/44] New hydro remix : Hydro must respect condition H <= Pmax in input of algo + consequences --- src/solver/simulation/hydro-remix-new.cpp | 17 ++++ .../solver/simulation/test-hydro-remix.cpp | 95 ++++++++++--------- 2 files changed, 65 insertions(+), 47 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 80c7530b73..7c78b20703 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -85,6 +85,23 @@ static void checkInputCorrectness(const std::vector& G, { throw std::invalid_argument(msg_prefix + "all arrays of sizes 0"); } + + // Hydro production < Pmax + for (int h = 0; h < H.size(); h++) + { + if (H[h] > P_max[h]) + { + throw std::invalid_argument(msg_prefix + "H not smaller than Pmax everywhere"); + } + } + + for (int h = 0; h < H.size(); h++) + { + if (H[h] < P_min[h]) + { + throw std::invalid_argument(msg_prefix + "H not greater than Pmin everywhere"); + } + } } std::pair, std::vector> new_remix_hydro( diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index d29577e627..0ebb2075db 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -74,103 +74,104 @@ BOOST_AUTO_TEST_CASE(all_input_arrays_of_size_0__exception_raised) checkMessage("Remix hydro input : all arrays of sizes 0")); } -BOOST_AUTO_TEST_CASE(input_is_acceptable__no_exception_raised) +BOOST_AUTO_TEST_CASE(H_not_smaller_than_pmax__exception_raised) { - std::vector G = {0.}, H = {0.}, D = {0.}, P_max = {0.}, P_min = {0.}, inflows = {0.}; + std::vector G(5, 0.), D(5, 0.), P_min(5, 0.), inflows(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_NO_THROW(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows)); + 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_AUTO_TEST_CASE(hydro_increases_but_pmax_only_10mwh___10mwh_are_moved_from_last_to_first_hour) +BOOST_AUTO_TEST_CASE(H_not_greater_than_pmin__exception_raised) { - std::vector G(5, 100.); - std::vector H = {0., 20., 40., 60., 80.}; - std::vector D = {80.0, 60., 40., 20., 0.}; - std::vector P_max(5, 10.); - std::vector P_min(5, 0.); - 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 G(5, 0.), D(5, 0.), P_max(5, 1000.), inflows(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.; - std::vector expected_H = {10., 20., 40., 60., 70.}; - std::vector expected_D = {70., 60., 40., 20., 10.}; - BOOST_CHECK(new_H == expected_H); - BOOST_CHECK(new_D == expected_D); + 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_AUTO_TEST_CASE(hydro_increases_but_pmax_only_20mwh___20mwh_are_moved_from_last_to_first_hour) +BOOST_AUTO_TEST_CASE(input_is_acceptable__no_exception_raised) { - std::vector G(5, 100.); - std::vector H = {0., 20., 40., 60., 80.}; - std::vector D = {80.0, 60., 40., 20., 0.}; - std::vector P_max(5, 20.); - std::vector P_min(5, 0.); - 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 G = {0.}, H = {0.}, D = {0.}, P_max = {0.}, P_min = {0.}, inflows = {0.}; + double initial_level = 0.; + double capa = 1.; - std::vector expected_H = {20., 20., 40., 60., 60.}; - BOOST_CHECK(new_H == expected_H); + BOOST_CHECK_NO_THROW(new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows)); } -BOOST_AUTO_TEST_CASE(hydro_increases_but_pmax_only_30mwh___30mwh_are_moved_from_last_to_first_hour) +BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20mwh) { + std::vector P_max(5, 40.); + std::vector P_min(5, 0.); std::vector G(5, 100.); - std::vector H = {0., 20., 40., 60., 80.}; + std::vector H = {0., 10., 20., 30., 40.}; // H <= Pmax everywhere std::vector D = {80.0, 60., 40., 20., 0.}; - std::vector P_max(5, 30.); - std::vector P_min(5, 0.); 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 expected_H = {30., 30., 40., 50., 50.}; + std::vector expected_H = {20., 20., 20., 20., 20.}; + // D such as G + H + D remains constant at each hour + std::vector expected_D = {60., 50., 40., 30., 20.}; BOOST_CHECK(new_H == expected_H); + BOOST_CHECK(new_D == expected_D); } -BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___final_hydro_is_flat_and_limited_by_pmax) +BOOST_AUTO_TEST_CASE(Pmax_does_not_influence_results_when_greater_than_40mwh) { + std::vector P_max(5, 50.); + std::vector P_min(5, 0.); std::vector G(5, 100.); - std::vector H = {0., 20., 40., 60., 80.}; + std::vector H = {0., 10., 20., 30., 40.}; // H <= Pmax everywhere std::vector D = {80.0, 60., 40., 20., 0.}; - std::vector P_max(5, 40.); - std::vector P_min(5, 0.); 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 expected_H = {40., 40., 40., 40., 40.}; + std::vector expected_H = {20., 20., 20., 20., 20.}; + // D such as G + H + D remains constant at each hour + std::vector expected_D = {60., 50., 40., 30., 20.}; BOOST_CHECK(new_H == expected_H); + BOOST_CHECK(new_D == expected_D); } -BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_50mwh___final_hydro_is_flat_and_limited_by_pmax) +BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20mwh) { - std::vector G(5, 100.); - std::vector H = {0., 20., 40., 60., 80.}; - std::vector D = {80.0, 60., 40., 20., 0.}; - std::vector P_max(5, 50.); + std::vector P_max(5, 40.); std::vector P_min(5, 0.); + std::vector G(5, 100.); + std::vector H = {40., 30., 20., 10., 0.}; // H <= Pmax everywhere + // std::vector D = {80.0, 60., 40., 20., 0.}; + std::vector D = {0., 20., 40., 60., 80.}; 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 expected_H = {40., 40., 40., 40., 40.}; + std::vector expected_H = {20., 20., 20., 20., 20.}; + // D such as G + H + D remains constant at each hour + std::vector expected_D = {20., 30., 40., 50., 60.}; BOOST_CHECK(new_H == expected_H); + BOOST_CHECK(new_D == expected_D); } // Comment for further tests : // - Remix hydro algorithm seems symetrical (if we have input vectors and corresponding output // vectors, run the algo on reversed vectors gives reversed output result vectors) // - 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) From a52aa7b813dcd218393025b1d0ec87ab7689c8a2 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Mon, 16 Dec 2024 18:20:17 +0100 Subject: [PATCH 07/44] New hydro remix : adding a test on influence of Pmax --- .../solver/simulation/test-hydro-remix.cpp | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 0ebb2075db..f3737b4df9 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20 BOOST_CHECK(new_D == expected_D); } -BOOST_AUTO_TEST_CASE(Pmax_does_not_influence_results_when_greater_than_40mwh) +BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) { std::vector P_max(5, 50.); std::vector P_min(5, 0.); @@ -155,7 +155,6 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20 std::vector P_min(5, 0.); std::vector G(5, 100.); std::vector H = {40., 30., 20., 10., 0.}; // H <= Pmax everywhere - // std::vector D = {80.0, 60., 40., 20., 0.}; std::vector D = {0., 20., 40., 60., 80.}; double initial_level = 500.; double capa = 1000.; @@ -170,8 +169,36 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20 BOOST_CHECK(new_D == expected_D); } -// Comment for further tests : -// - Remix hydro algorithm seems symetrical (if we have input vectors and corresponding output +BOOST_AUTO_TEST_CASE(influence_of_pmax) +{ + std::vector P_max(5, 20.); + std::vector P_min(5, 0.); + + // G decreases + std::vector G = {100., 80., 60., 40., 20.}; + + // H is flat and must respect H <= Pmax everywhere + std::vector H = {20., 20., 20., 20., 20.}; // H <= Pmax everywhere + std::vector D = {50., 50., 50., 50., 50.}; + double initial_level = 500.; + double capa = 1000.; + std::vector inflows(5, 0.); + + // What we expect to happen : + // Algorithm tends to flatten G + H, so it would require to increase H. + // But H is limited by P_max. So Algo does nothing in the end. + auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + + std::vector expected_H = {20., 20., 20., 20., 20.}; + std::vector expected_D = {50., 50., 50., 50., 50.}; + BOOST_CHECK(new_H == expected_H); + BOOST_CHECK(new_D == expected_D); +} + +// Ideas for building further tests : +// ================================ +// - 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) From 52b04e0a4f12b3f2ef5b316d4da61071e6f34af6 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Mon, 16 Dec 2024 18:36:33 +0100 Subject: [PATCH 08/44] New hydro remix : adding a test on influence of Pmin --- .../solver/simulation/test-hydro-remix.cpp | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index f3737b4df9..22870da2a5 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20 std::vector P_max(5, 40.); std::vector P_min(5, 0.); std::vector G(5, 100.); - std::vector H = {0., 10., 20., 30., 40.}; // H <= Pmax everywhere + std::vector H = {0., 10., 20., 30., 40.}; // we have Pmin <= H <= Pmax std::vector D = {80.0, 60., 40., 20., 0.}; double initial_level = 500.; double capa = 1000.; @@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) std::vector P_max(5, 50.); std::vector P_min(5, 0.); std::vector G(5, 100.); - std::vector H = {0., 10., 20., 30., 40.}; // H <= Pmax everywhere + std::vector H = {0., 10., 20., 30., 40.}; std::vector D = {80.0, 60., 40., 20., 0.}; double initial_level = 500.; double capa = 1000.; @@ -154,7 +154,7 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20 std::vector P_max(5, 40.); std::vector P_min(5, 0.); std::vector G(5, 100.); - std::vector H = {40., 30., 20., 10., 0.}; // H <= Pmax everywhere + std::vector H = {40., 30., 20., 10., 0.}; std::vector D = {0., 20., 40., 60., 80.}; double initial_level = 500.; double capa = 1000.; @@ -178,14 +178,14 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax) std::vector G = {100., 80., 60., 40., 20.}; // H is flat and must respect H <= Pmax everywhere - std::vector H = {20., 20., 20., 20., 20.}; // H <= Pmax everywhere + std::vector H = {20., 20., 20., 20., 20.}; std::vector D = {50., 50., 50., 50., 50.}; double initial_level = 500.; double capa = 1000.; std::vector inflows(5, 0.); // What we expect to happen : - // Algorithm tends to flatten G + H, so it would require to increase H. + // Algorithm tends to flatten G + H, so it would require H to increase. // But H is limited by P_max. So Algo does nothing in the end. auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); @@ -195,6 +195,32 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax) BOOST_CHECK(new_D == expected_D); } +BOOST_AUTO_TEST_CASE(influence_of_pmin) +{ + std::vector P_max(5, std::numeric_limits::max()); + std::vector P_min(5, 20.); + + // G decreases + std::vector G = {100., 80., 60., 40., 20.}; + + // H is flat and must respect Pmin <= H <= Pmax everywhere + std::vector H = {20., 20., 20., 20., 20.}; + std::vector D = {50., 50., 50., 50., 50.}; + double initial_level = 500.; + double capa = 1000.; + std::vector inflows(5, 0.); + + // What we expect to happen : + // Algorithm tends to flatten G + H, so it would require H to decrease. + // But H is low bounded by P_min. So Algo does nothing in the end. + auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + + std::vector expected_H = {20., 20., 20., 20., 20.}; + std::vector expected_D = {50., 50., 50., 50., 50.}; + BOOST_CHECK(new_H == expected_H); + BOOST_CHECK(new_D == expected_D); +} + // Ideas for building further tests : // ================================ // - Remix hydro algorithm seems symmetrical (if we have input vectors and corresponding output From 56ab22dfa8f7224550f637827f2fcf05b84bf46a Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 17 Dec 2024 11:48:42 +0100 Subject: [PATCH 09/44] New hydro remix : Pmin & Pmax unit tests enhancement --- .../solver/simulation/test-hydro-remix.cpp | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 22870da2a5..431cbe86a7 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -169,9 +169,8 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20 BOOST_CHECK(new_D == expected_D); } -BOOST_AUTO_TEST_CASE(influence_of_pmax) +BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) { - std::vector P_max(5, 20.); std::vector P_min(5, 0.); // G decreases @@ -184,21 +183,29 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax) double capa = 1000.; std::vector inflows(5, 0.); - // What we expect to happen : - // Algorithm tends to flatten G + H, so it would require H to increase. - // But H is limited by P_max. So Algo does nothing in the end. - auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + // 1. Algorithm tends to flatten G + H, so it would require H to increase. + // Proof : + std::vector P_max(5., std::numeric_limits::max()); - std::vector expected_H = {20., 20., 20., 20., 20.}; - std::vector expected_D = {50., 50., 50., 50., 50.}; - BOOST_CHECK(new_H == expected_H); - BOOST_CHECK(new_D == expected_D); + auto [new_H1, new_D1] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); + + 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 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); + + std::vector expected_H2 = {20., 20., 20., 20., 20.}; + std::vector expected_D2 = {50., 50., 50., 50., 50.}; + BOOST_CHECK(new_H2 == expected_H2); + BOOST_CHECK(new_D2 == expected_D2); } -BOOST_AUTO_TEST_CASE(influence_of_pmin) +BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) { std::vector P_max(5, std::numeric_limits::max()); - std::vector P_min(5, 20.); // G decreases std::vector G = {100., 80., 60., 40., 20.}; @@ -210,15 +217,20 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin) double capa = 1000.; std::vector inflows(5, 0.); - // What we expect to happen : - // Algorithm tends to flatten G + H, so it would require H to decrease. - // But H is low bounded by P_min. So Algo does nothing in the end. - auto [new_H, new_D] = new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows); - - std::vector expected_H = {20., 20., 20., 20., 20.}; - std::vector expected_D = {50., 50., 50., 50., 50.}; - BOOST_CHECK(new_H == expected_H); - BOOST_CHECK(new_D == expected_D); + // 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); + 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); + + std::vector expected_H2 = {20., 20., 20., 20., 20.}; + std::vector expected_D2 = {50., 50., 50., 50., 50.}; + BOOST_CHECK(new_H2 == expected_H2); + BOOST_CHECK(new_D2 == expected_D2); } // Ideas for building further tests : From 548fc1f98cec909dad7a23d131313e3d9b614b83 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 17 Dec 2024 15:42:34 +0100 Subject: [PATCH 10/44] 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) From f3708e21d8111648c49bf37cc5d34d458e0cf56c Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 17 Dec 2024 18:10:13 +0100 Subject: [PATCH 11/44] New hydro remix : adding 2 unit tests on levels computation --- src/solver/simulation/hydro-remix-new.cpp | 2 +- .../solver/simulation/test-hydro-remix.cpp | 73 ++++++++++++++++++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 4a6cd7d3bf..081cfb6663 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -107,7 +107,7 @@ static void checkInputCorrectness(const std::vector& G, throw std::invalid_argument(msg_prefix + "H not smaller than Pmax everywhere"); } } - + // Hydro production > Pmin for (int h = 0; h < H.size(); h++) { if (H[h] < P_min[h]) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 4e553e9e61..eda4954719 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(input_is_acceptable__no_exception_raised) 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) +BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh) { std::vector P_max(5, 40.); std::vector P_min(5, 0.); @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) BOOST_CHECK(new_D == expected_D); } -BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_smoothed_to_mean_H_20mwh) +BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh) { std::vector P_max(5, 40.); std::vector P_min(5, 0.); @@ -321,9 +321,78 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) BOOST_CHECK(new_D2 == expected_D2); } +BOOST_AUTO_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed) +{ + // Not important + std::vector P_max(5, 25.), P_min(5, 0.), G(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + std::vector D(5, 10.); + double capa = 1000.; + + // Used for level computations + double initial_level = 500.; + std::vector ovf(5, 25.), H(5, 20.); // Cause levels to lower + std::vector inflows(5, 15.), pump(5, 10.); // Cause levels to raise + + auto [new_H, new_D, levels] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + initial_level, + capa, + inflows, + ovf, + pump, + S, + DTG_MRG); + + std::vector expected_levels = {480., 460., 440., 420., 400.}; + BOOST_TEST(levels == expected_levels, boost::test_tools::per_element()); +} + +BOOST_AUTO_TEST_CASE(what_if_levels_are_up_bounded_by_capacity) +{ + // Not important + std::vector P_max(5, 25.), P_min(5, 0.), G(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + std::vector D(5, 10.); + + // Used for level computations + double initial_level = 500.; + double capacity = 550.; + std::vector ovf(5, 15.), H(5, 10.); // Cause levels to lower + std::vector inflows(5, 25.), pump(5, 20.); // Cause levels to raise + + auto [new_H, new_D, levels] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + initial_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + // Bad ! Levels not limited by capacity. + std::vector expected_levels = {520., 540., 560., 580., 600.}; + BOOST_TEST(levels == expected_levels, boost::test_tools::per_element()); +} + // Ideas for building further tests : // ================================ // - 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) // - 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) + +// Possible simplifications / clarifications of the algorithm itself : +// - remove french from variable names +// - the algo is flat, it's C (not C++), it should be divided in a small number of steps +// - max_pic is a up hydro production margin (H_up_mrg) +// - max_creux is a down hydro production margin (H_down_mrg) +// - an iter updates new_H : it's its main job. So new_D could be updated from new_H at the +// end of an iteration, separately. +// - they are 3 while loops. 2 loops should be enough (the iteration loop and +// another one simply updating new_H and new_D) From 4c8d40757daea5cc20537f9061252da93f36b0d3 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Wed, 18 Dec 2024 11:35:55 +0100 Subject: [PATCH 12/44] New hydro remix : improve comparison between 2 std::vector --- src/solver/simulation/hydro-remix-new.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 081cfb6663..ccb85ece18 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -56,6 +55,13 @@ int find_max_index(const std::vector& G_plus_H, return max_idx; } +static bool isLessThan(const std::vector& a, const std::vector& b) +{ + std::vector a_minus_b; + std::ranges::transform(a, b, std::back_inserter(a_minus_b), std::minus()); + return std::ranges::all_of(a_minus_b, [](double d) { return d <= 0.; }); +} + static void checkInputCorrectness(const std::vector& G, const std::vector& H, const std::vector& D, @@ -100,20 +106,14 @@ static void checkInputCorrectness(const std::vector& G, } // Hydro production < Pmax - for (int h = 0; h < H.size(); h++) + if (!isLessThan(H, P_max)) { - if (H[h] > P_max[h]) - { - throw std::invalid_argument(msg_prefix + "H not smaller than Pmax everywhere"); - } + throw std::invalid_argument(msg_prefix + "H not smaller than Pmax everywhere"); } // Hydro production > Pmin - for (int h = 0; h < H.size(); h++) + if (!isLessThan(P_min, H)) { - if (H[h] < P_min[h]) - { - throw std::invalid_argument(msg_prefix + "H not greater than Pmin everywhere"); - } + throw std::invalid_argument(msg_prefix + "H not greater than Pmin everywhere"); } } From 88dd5ae9b4d74e8ad0d8cc754e00ba15c3f1f77e Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Wed, 18 Dec 2024 11:52:17 +0100 Subject: [PATCH 13/44] New hydro remix : make a test rightfully fail --- src/tests/src/solver/simulation/test-hydro-remix.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index eda4954719..c226fc5281 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -378,6 +378,8 @@ BOOST_AUTO_TEST_CASE(what_if_levels_are_up_bounded_by_capacity) // Bad ! Levels not limited by capacity. std::vector expected_levels = {520., 540., 560., 580., 600.}; BOOST_TEST(levels == expected_levels, boost::test_tools::per_element()); + + BOOST_CHECK(std::ranges::all_of(levels, [&capacity](double e) { return e <= capacity; })); } // Ideas for building further tests : From d3a24ef005f1bd3795a9cb7bf65b77301654cdfb Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Wed, 18 Dec 2024 15:00:52 +0100 Subject: [PATCH 14/44] New hydro remix : adding unit tests on levels computed from input data --- src/solver/simulation/hydro-remix-new.cpp | 42 ++++++-- .../solver/simulation/test-hydro-remix.cpp | 100 +++++++++--------- 2 files changed, 84 insertions(+), 58 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index ccb85ece18..96de0ab226 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -59,16 +59,27 @@ static bool isLessThan(const std::vector& a, const std::vector& { std::vector a_minus_b; std::ranges::transform(a, b, std::back_inserter(a_minus_b), std::minus()); - return std::ranges::all_of(a_minus_b, [](double d) { return d <= 0.; }); + return std::ranges::all_of(a_minus_b, [](const double& e) { return e <= 0.; }); +} + +static bool isLessThan(const std::vector& v, const double c) +{ + return std::ranges::all_of(v, [&c](const double& e) { return e <= c; }); +} + +static bool isGreaterThan(const std::vector& v, const double c) +{ + return std::ranges::all_of(v, [&c](const double& e) { return e >= c; }); } static void checkInputCorrectness(const std::vector& G, const std::vector& H, const std::vector& D, + const std::vector& levels, const std::vector& P_max, const std::vector& P_min, double initial_level, - double capa, + double capacity, const std::vector& inflows, const std::vector& overflow, const std::vector& pump, @@ -78,7 +89,7 @@ static void checkInputCorrectness(const std::vector& G, std::string msg_prefix = "Remix hydro input : "; // Initial level smaller than capacity - if (initial_level > capa) + if (initial_level > capacity) { throw std::invalid_argument(msg_prefix + "initial level > reservoir capacity"); } @@ -86,6 +97,7 @@ static void checkInputCorrectness(const std::vector& G, std::vector sizes = {G.size(), H.size(), D.size(), + levels.size(), P_max.size(), P_min.size(), inflows.size(), @@ -115,6 +127,12 @@ static void checkInputCorrectness(const std::vector& G, { throw std::invalid_argument(msg_prefix + "H not greater than Pmin everywhere"); } + + if (!isLessThan(levels, capacity) || !isGreaterThan(levels, 0.)) + { + throw std::invalid_argument(msg_prefix + + "levels computed from input don't respect constraints"); + } } struct RemixHydroOutput @@ -137,9 +155,20 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, const std::vector& S, const std::vector& DTG_MRG) { + std::vector levels(G.size()); + if (levels.size()) + { + levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - H[0]; + for (size_t i = 1; i < levels.size(); ++i) + { + levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - H[i]; + } + } + checkInputCorrectness(G, H, D, + levels, P_max, P_min, initial_level, @@ -170,13 +199,6 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, std::vector G_plus_H(G.size()); std::transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), std::plus<>()); - 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) - { - levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - new_H[i]; - } - while (loop-- > 0) { std::vector tried_creux(G.size(), 0); diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index c226fc5281..46ac1c1d1e 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -24,7 +24,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, const std::vector& D, const std::vector& P_max, const std::vector& P_min, - double initial_level, + double init_level, double capa, const std::vector& inflow, const std::vector& overflow, @@ -36,15 +36,15 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, using namespace Antares::Solver::Simulation; -BOOST_AUTO_TEST_CASE(input_arrays_of_different_sizes__exception_raised) +BOOST_AUTO_TEST_CASE(input_vectors_of_different_sizes__exception_raised) { std::vector G, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; std::vector H = {0., 0.}; - double initial_level = 0.; + double init_level = 0.; double capa = 0.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : arrays of different sizes")); } @@ -53,11 +53,11 @@ BOOST_AUTO_TEST_CASE(input_init_level_exceeds_capacity__exception_raised) { std::vector G, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; std::vector H = {0., 0.}; - double initial_level = 2.; + double init_level = 2.; double capa = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : initial level > reservoir capacity")); } @@ -65,11 +65,11 @@ BOOST_AUTO_TEST_CASE(input_init_level_exceeds_capacity__exception_raised) BOOST_AUTO_TEST_CASE(all_input_arrays_of_size_0__exception_raised) { std::vector G, H, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; - double initial_level = 0.; + double init_level = 0.; double capa = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : all arrays of sizes 0")); } @@ -80,11 +80,11 @@ BOOST_AUTO_TEST_CASE(H_not_smaller_than_pmax__exception_raised) 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 init_level = 0.; double capa = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : H not smaller than Pmax everywhere")); } @@ -95,11 +95,11 @@ BOOST_AUTO_TEST_CASE(H_not_greater_than_pmin__exception_raised) 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 init_level = 0.; double capa = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : H not greater than Pmin everywhere")); } @@ -108,11 +108,11 @@ 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 init_level = 0.; double capa = 1.; BOOST_CHECK_NO_THROW( - new_remix_hydro(G, H, D, P_max, P_min, initial_level, capa, inflows, ovf, pump, S, DTG_MRG)); + new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG)); } BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh) @@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 std::vector G(5, 100.); std::vector H = {0., 10., 20., 30., 40.}; // we have Pmin <= H <= Pmax std::vector D = {80.0, 60., 40., 20., 0.}; - double initial_level = 500.; + double init_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.); @@ -132,7 +132,7 @@ BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 D, P_max, P_min, - initial_level, + init_level, capa, inflows, ovf, @@ -154,7 +154,7 @@ BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) std::vector G(5, 100.); std::vector H = {0., 10., 20., 30., 40.}; std::vector D = {80.0, 60., 40., 20., 0.}; - double initial_level = 500.; + double init_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.); @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) D, P_max, P_min, - initial_level, + init_level, capa, inflows, ovf, @@ -186,7 +186,7 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 std::vector G(5, 100.); std::vector H = {40., 30., 20., 10., 0.}; std::vector D = {0., 20., 40., 60., 80.}; - double initial_level = 500.; + double init_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.); @@ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 D, P_max, P_min, - initial_level, + init_level, capa, inflows, ovf, @@ -221,7 +221,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) // H is flat and must respect H <= Pmax everywhere std::vector H = {20., 20., 20., 20., 20.}; std::vector D = {50., 50., 50., 50., 50.}; - double initial_level = 500.; + double init_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.); @@ -235,7 +235,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) D, P_max, P_min, - initial_level, + init_level, capa, inflows, ovf, @@ -254,7 +254,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) D, P_max, P_min, - initial_level, + init_level, capa, inflows, ovf, @@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) // H is flat and must respect Pmin <= H <= Pmax everywhere std::vector H = {20., 20., 20., 20., 20.}; std::vector D = {50., 50., 50., 50., 50.}; - double initial_level = 500.; + double init_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.); @@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) D, P_max, P_min, - initial_level, + init_level, capa, inflows, ovf, @@ -307,7 +307,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) D, P_max, P_min, - initial_level, + init_level, capa, inflows, ovf, @@ -323,13 +323,13 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) BOOST_AUTO_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed) { - // Not important + // Not important for testing levels std::vector P_max(5, 25.), P_min(5, 0.), G(5, 0.), S(5, 0.), DTG_MRG(5, 0.); std::vector D(5, 10.); double capa = 1000.; // Used for level computations - double initial_level = 500.; + double init_level = 500.; std::vector ovf(5, 25.), H(5, 20.); // Cause levels to lower std::vector inflows(5, 15.), pump(5, 10.); // Cause levels to raise @@ -338,7 +338,7 @@ BOOST_AUTO_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed D, P_max, P_min, - initial_level, + init_level, capa, inflows, ovf, @@ -350,36 +350,40 @@ BOOST_AUTO_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed BOOST_TEST(levels == expected_levels, boost::test_tools::per_element()); } -BOOST_AUTO_TEST_CASE(what_if_levels_are_up_bounded_by_capacity) +BOOST_AUTO_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised) { - // Not important + // Not important for testing levels std::vector P_max(5, 25.), P_min(5, 0.), G(5, 0.), S(5, 0.), DTG_MRG(5, 0.); std::vector D(5, 10.); // Used for level computations - double initial_level = 500.; + double init_level = 500.; double capacity = 550.; std::vector ovf(5, 15.), H(5, 10.); // Cause levels to lower std::vector inflows(5, 25.), pump(5, 20.); // Cause levels to raise - auto [new_H, new_D, levels] = new_remix_hydro(G, - H, - D, - P_max, - P_min, - initial_level, - capacity, - inflows, - ovf, - pump, - S, - DTG_MRG); + BOOST_CHECK_EXCEPTION( + new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : levels computed from input don't respect constraints")); +} - // Bad ! Levels not limited by capacity. - std::vector expected_levels = {520., 540., 560., 580., 600.}; - BOOST_TEST(levels == expected_levels, boost::test_tools::per_element()); +BOOST_AUTO_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised) +{ + // Not important for testing levels + std::vector P_max(5, 25.), P_min(5, 0.), G(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + std::vector D(5, 10.); + + // Used for level computations + double init_level = 50.; + double capacity = 100.; + std::vector ovf(5, 30.), H(5, 10.); // Cause levels to lower + std::vector inflows(5, 10.), pump(5, 10.); // Cause levels to raise - BOOST_CHECK(std::ranges::all_of(levels, [&capacity](double e) { return e <= capacity; })); + BOOST_CHECK_EXCEPTION( + new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : levels computed from input don't respect constraints")); } // Ideas for building further tests : From cd35bdb413e05813c9e6e1db5b57c594c7b42ee4 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 19 Dec 2024 13:24:19 +0100 Subject: [PATCH 15/44] New hydro remix : adding a failing test about of impact reservoir capacity on remix hydro algorithm --- src/solver/simulation/hydro-remix-new.cpp | 4 +- .../solver/simulation/test-hydro-remix.cpp | 116 +++++++++++++----- 2 files changed, 90 insertions(+), 30 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 96de0ab226..11b59b4585 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -131,7 +131,7 @@ static void checkInputCorrectness(const std::vector& G, if (!isLessThan(levels, capacity) || !isGreaterThan(levels, 0.)) { throw std::invalid_argument(msg_prefix - + "levels computed from input don't respect constraints"); + + "levels computed from input don't respect reservoir bounds"); } } @@ -183,7 +183,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, std::vector new_D = D; int loop = 1000; - double eps = 1e-2; + double eps = 1e-3; double top = *std::max_element(G.begin(), G.end()) + *std::max_element(H.begin(), H.end()) + *std::max_element(D.begin(), D.end()) + 1; diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 46ac1c1d1e..2273e59f26 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -25,7 +25,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, const std::vector& P_max, const std::vector& P_min, double init_level, - double capa, + double capacity, const std::vector& inflow, const std::vector& overflow, const std::vector& pump, @@ -41,10 +41,10 @@ BOOST_AUTO_TEST_CASE(input_vectors_of_different_sizes__exception_raised) std::vector G, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; std::vector H = {0., 0.}; double init_level = 0.; - double capa = 0.; + double capacity = 0.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : arrays of different sizes")); } @@ -54,10 +54,10 @@ BOOST_AUTO_TEST_CASE(input_init_level_exceeds_capacity__exception_raised) std::vector G, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; std::vector H = {0., 0.}; double init_level = 2.; - double capa = 1.; + double capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : initial level > reservoir capacity")); } @@ -66,10 +66,10 @@ BOOST_AUTO_TEST_CASE(all_input_arrays_of_size_0__exception_raised) { std::vector G, H, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; double init_level = 0.; - double capa = 1.; + double capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : all arrays of sizes 0")); } @@ -81,10 +81,10 @@ BOOST_AUTO_TEST_CASE(H_not_smaller_than_pmax__exception_raised) std::vector H = {1., 2., 3., 4., 5.}; std::vector P_max = {2., 2., 2., 4., 5.}; double init_level = 0.; - double capa = 1.; + double capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : H not smaller than Pmax everywhere")); } @@ -96,10 +96,10 @@ BOOST_AUTO_TEST_CASE(H_not_greater_than_pmin__exception_raised) std::vector H = {1., 2., 3., 4., 5.}; std::vector P_min = {0., 0., 4., 0., 0.}; double init_level = 0.; - double capa = 1.; + double capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : H not greater than Pmin everywhere")); } @@ -109,10 +109,10 @@ 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 init_level = 0.; - double capa = 1.; + double capacity = 1.; BOOST_CHECK_NO_THROW( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capa, inflows, ovf, pump, S, DTG_MRG)); + new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG)); } BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh) @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 std::vector H = {0., 10., 20., 30., 40.}; // we have Pmin <= H <= Pmax std::vector D = {80.0, 60., 40., 20., 0.}; double init_level = 500.; - double capa = 1000.; + double capacity = 1000.; std::vector inflows(5, 0.); std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); @@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 P_max, P_min, init_level, - capa, + capacity, inflows, ovf, pump, @@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) std::vector H = {0., 10., 20., 30., 40.}; std::vector D = {80.0, 60., 40., 20., 0.}; double init_level = 500.; - double capa = 1000.; + double capacity = 1000.; std::vector inflows(5, 0.); std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) P_max, P_min, init_level, - capa, + capacity, inflows, ovf, pump, @@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 std::vector H = {40., 30., 20., 10., 0.}; std::vector D = {0., 20., 40., 60., 80.}; double init_level = 500.; - double capa = 1000.; + double capacity = 1000.; std::vector inflows(5, 0.); std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); @@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 P_max, P_min, init_level, - capa, + capacity, inflows, ovf, pump, @@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) std::vector H = {20., 20., 20., 20., 20.}; std::vector D = {50., 50., 50., 50., 50.}; double init_level = 500.; - double capa = 1000.; + double capacity = 1000.; std::vector inflows(5, 0.); std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); @@ -236,7 +236,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) P_max, P_min, init_level, - capa, + capacity, inflows, ovf, pump, @@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) P_max, P_min, init_level, - capa, + capacity, inflows, ovf, pump, @@ -279,7 +279,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) std::vector H = {20., 20., 20., 20., 20.}; std::vector D = {50., 50., 50., 50., 50.}; double init_level = 500.; - double capa = 1000.; + double capacity = 1000.; std::vector inflows(5, 0.); std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); @@ -291,7 +291,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) P_max, P_min, init_level, - capa, + capacity, inflows, ovf, pump, @@ -308,7 +308,7 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) P_max, P_min, init_level, - capa, + capacity, inflows, ovf, pump, @@ -326,7 +326,7 @@ BOOST_AUTO_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed // Not important for testing levels std::vector P_max(5, 25.), P_min(5, 0.), G(5, 0.), S(5, 0.), DTG_MRG(5, 0.); std::vector D(5, 10.); - double capa = 1000.; + double capacity = 1000.; // Used for level computations double init_level = 500.; @@ -339,7 +339,7 @@ BOOST_AUTO_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed P_max, P_min, init_level, - capa, + capacity, inflows, ovf, pump, @@ -383,7 +383,66 @@ BOOST_AUTO_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised) BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, - checkMessage("Remix hydro input : levels computed from input don't respect constraints")); + checkMessage( + "Remix hydro input : levels computed from input don't respect reservoir bounds")); +} + +BOOST_AUTO_TEST_CASE(influence_of_reservoir_capacity_on_hydro_production, + *boost::unit_test::tolerance(0.001)) +{ + // Not important for this test + std::vector P_max(10, std::numeric_limits::max()); + std::vector P_min(10, 0.); + std::vector G(10, 0.), pump(10, 0.), ovf(10, 0.), S(10, 0.), DTG_MRG(10, 0.); + std::vector D(10, 20.); + + // H oscillates between 10 and 20 (new H will be flattened to 15 everywhere) + std::vector H = {10., 20., 10., 20., 10., 20., 10., 20., 10., 20.}; + // First inflows > H, then inflows < H. Consequence : levels first increase, then decrease. + std::vector inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; + double init_level = 100.; + // H and inflows result in : input_levels = {115, 120, 135, 140, 155, 140, 135, 120, 115, 100} + // Note sup(input_levels) = 155 + + // Case 1 : capacity unlimited + double capacity = std::numeric_limits::max(); + auto [new_H, new_D, L] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + std::vector expected_H(10, 15.); // H is flat and is 15. (means of initial H) + // Levels associated to new H are such as sup(L) = 150. < sup(input_levels) = 155 + std::vector expected_L = {110., 120., 130., 140., 150., 140., 130., 120., 110., 100.}; + BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); + BOOST_TEST(L == expected_L, boost::test_tools::per_element()); + + // Now, if we limit to capacity to sup(input_levels) = 155, we should have same H and L + // as previously + capacity = 155.; + auto [new_H2, new_D2, L2] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + BOOST_TEST(new_H2 == expected_H, boost::test_tools::per_element()); + BOOST_TEST(L2 == expected_L, boost::test_tools::per_element()); } // Ideas for building further tests : @@ -392,6 +451,7 @@ BOOST_AUTO_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised) // vectors, run the algo on reversed vectors gives reversed output result vectors) // - 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) +// - // Possible simplifications / clarifications of the algorithm itself : // - remove french from variable names From f7757b1013c3aceae300b9350811cfe867503cfd Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 19 Dec 2024 14:17:24 +0100 Subject: [PATCH 16/44] New hydro remix : change algorithm to try to fix a test failure --- src/solver/simulation/hydro-remix-new.cpp | 30 ++++++++++++------- .../solver/simulation/test-hydro-remix.cpp | 2 +- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 11b59b4585..789a0ff988 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -237,18 +237,28 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, + std::min(idx_creux, idx_pic), levels.begin() + std::max(idx_creux, idx_pic)); + double max_pic, max_creux; + if (idx_creux < idx_creux) + { + max_pic = capa; + max_creux = *std::min_element(intermediate_level.begin(), + intermediate_level.end()); + } + else + { + max_pic = capa + - *std::max_element(intermediate_level.begin(), + intermediate_level.end()); + max_creux = capa; + } + + max_pic = std::min(new_H[idx_pic] - P_min[idx_pic], max_pic); + max_creux = std::min( + {P_max[idx_creux] - new_H[idx_creux], new_D[idx_creux], max_creux}); - double max_pic = std::min(new_H[idx_pic] - P_min[idx_pic], - capa - - *std::max_element(intermediate_level.begin(), - intermediate_level.end())); - double max_creux = std::min( - {P_max[idx_creux] - new_H[idx_creux], - new_D[idx_creux], - *std::min_element(intermediate_level.begin(), intermediate_level.end())}); - double dif_pic_creux = std::max(G_plus_H[idx_pic] - G_plus_H[idx_creux], 0.0); + double dif_pic_creux = std::max(G_plus_H[idx_pic] - G_plus_H[idx_creux], 0.); - delta = std::max(std::min({max_pic, max_creux, dif_pic_creux / 2.0}), 0.0); + delta = std::max(std::min({max_pic, max_creux, dif_pic_creux / 2.}), 0.); if (delta > 0) { diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 2273e59f26..cbff0f49b9 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -456,7 +456,7 @@ BOOST_AUTO_TEST_CASE(influence_of_reservoir_capacity_on_hydro_production, // Possible simplifications / clarifications of the algorithm itself : // - remove french from variable names // - the algo is flat, it's C (not C++), it should be divided in a small number of steps -// - max_pic is a up hydro production margin (H_up_mrg) +// - max_pic is an up hydro production margin (H_up_mrg) // - max_creux is a down hydro production margin (H_down_mrg) // - an iter updates new_H : it's its main job. So new_D could be updated from new_H at the // end of an iteration, separately. From ea7e23f047623cab059e0782f837b17b47e684cd Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 19 Dec 2024 14:22:32 +0100 Subject: [PATCH 17/44] New hydro remix : oops, tiny fix --- src/tests/src/solver/simulation/test-hydro-remix.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index cbff0f49b9..4fbf8cef27 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -365,7 +365,8 @@ BOOST_AUTO_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised) BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, - checkMessage("Remix hydro input : levels computed from input don't respect constraints")); + checkMessage( + "Remix hydro input : levels computed from input don't respect reservoir bounds")); } BOOST_AUTO_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised) From 6ed6f62e3050035888c483a47db43600bc26d59d Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 19 Dec 2024 14:38:41 +0100 Subject: [PATCH 18/44] New hydro remix : fix the previous fix --- src/solver/simulation/hydro-remix-new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 789a0ff988..12a5c4d626 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -238,7 +238,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, levels.begin() + std::max(idx_creux, idx_pic)); double max_pic, max_creux; - if (idx_creux < idx_creux) + if (idx_creux < idx_pic) { max_pic = capa; max_creux = *std::min_element(intermediate_level.begin(), From adb89a75c068019a146d07c35e24d6008a2797bf Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 19 Dec 2024 16:09:08 +0100 Subject: [PATCH 19/44] New hydro remix : adding a unit test on getting a sub optimal solution for H --- .../solver/simulation/test-hydro-remix.cpp | 69 ++++++++++++++++++- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 4fbf8cef27..2ed37a3799 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -388,7 +388,7 @@ BOOST_AUTO_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised) "Remix hydro input : levels computed from input don't respect reservoir bounds")); } -BOOST_AUTO_TEST_CASE(influence_of_reservoir_capacity_on_hydro_production, +BOOST_AUTO_TEST_CASE(influence_of_capacity_on_hydro_prod___case_where_no_influence, *boost::unit_test::tolerance(0.001)) { // Not important for this test @@ -426,8 +426,9 @@ BOOST_AUTO_TEST_CASE(influence_of_reservoir_capacity_on_hydro_production, BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); - // Now, if we limit to capacity to sup(input_levels) = 155, we should have same H and L - // as previously + // Case 2 : now, if we lower capacity to sup(input_levels) = 155, we should + // have same computed H and L as previously : this value of capacity should + // not have an influence on H and levels as results of the algorithm. capacity = 155.; auto [new_H2, new_D2, L2] = new_remix_hydro(G, H, @@ -446,6 +447,68 @@ BOOST_AUTO_TEST_CASE(influence_of_reservoir_capacity_on_hydro_production, BOOST_TEST(L2 == expected_L, boost::test_tools::per_element()); } +BOOST_AUTO_TEST_CASE(lowering_capacity_too_much_leads_to_suboptimal_solution_for_GplusH, + *boost::unit_test::tolerance(0.001)) +{ + // Not important for this test + std::vector P_max(10, std::numeric_limits::max()); + std::vector P_min(10, 0.); + std::vector G(10, 0.), pump(10, 0.), ovf(10, 0.), S(10, 0.), DTG_MRG(10, 0.); + std::vector D(10, 20.); + + // H oscillates between 10 and 20 (new H will be flattened to 15 everywhere) + std::vector H = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; + // First inflows > H, then inflows < H. Consequence : levels first increase, then decrease. + std::vector inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; + double init_level = 100.; + // H and inflows result in : input_levels = {105, 120, 125, 140, 145, 140, 125, 120, 105, 100} + // Note sup(input_levels) = 145 + + // Case 1 : capacity unlimited + double capacity = std::numeric_limits::max(); + auto [new_H, new_D, L] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + std::vector expected_H(10, 15.); // H is flat and is 15. (means of initial H) + // Levels associated to new H are such as sup(L) = 150. > sup(input_levels) = 145 + std::vector expected_L = {110., 120., 130., 140., 150., 140., 130., 120., 110., 100.}; + BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); + BOOST_TEST(L == expected_L, boost::test_tools::per_element()); + + // Case 2 : now we lower capacity to sup(input_levels) = 145. + // This makes input acceptable for algo : levels computed from input have an + // up bound <= capacity + // But this time levels can not increase up to sup(L) = 150., as it would if capacity + // was infinite. So we expect to get an output H flat by interval, not on the whole domain. + capacity = 145.; + auto [new_H2, new_D2, L2] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + // new_H2 is flat by interval + std::vector expected_H2 = {16., 16., 16., 16., 16., 14., 14., 14., 14., 14.}; + BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); +} + // Ideas for building further tests : // ================================ // - Remix hydro algorithm seems symmetrical (if we have input vectors and corresponding output From 72f75e45bb746ab9c051a766b20b9b363ac62a97 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 19 Dec 2024 17:39:14 +0100 Subject: [PATCH 20/44] New hydro remix : adding a unit test about the effect of lowering initial level too low --- .../solver/simulation/test-hydro-remix.cpp | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 2ed37a3799..af6110dac4 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -447,7 +447,7 @@ BOOST_AUTO_TEST_CASE(influence_of_capacity_on_hydro_prod___case_where_no_influen BOOST_TEST(L2 == expected_L, boost::test_tools::per_element()); } -BOOST_AUTO_TEST_CASE(lowering_capacity_too_much_leads_to_suboptimal_solution_for_GplusH, +BOOST_AUTO_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_for_GplusH, *boost::unit_test::tolerance(0.001)) { // Not important for this test @@ -509,6 +509,69 @@ BOOST_AUTO_TEST_CASE(lowering_capacity_too_much_leads_to_suboptimal_solution_for BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); } +BOOST_AUTO_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution_for_GplusH, + *boost::unit_test::tolerance(0.001)) +{ + // Not important for this test + std::vector P_max(10, std::numeric_limits::max()); + std::vector P_min(10, 0.); + std::vector G(10, 0.), pump(10, 0.), ovf(10, 0.), S(10, 0.), DTG_MRG(10, 0.); + std::vector D(10, 20.); + + // H oscillates between 20 and 30 (new H will be flattened to 15 everywhere) + std::vector H = {20., 30., 20., 30., 20., 30., 20., 30., 20., 30.}; + // First inflows < H, then inflows > H. Consequence : levels first decrease, then increase. + std::vector inflows = {5., 5., 5., 5., 5., 45., 45., 45., 45., 45.}; + double capacity = std::numeric_limits::max(); + double init_level = 100.; + // H and inflows result in : input_levels = {85, 60, 45, 20, 5, 20, 45, 60, 85, 100} + // Note : inf(input_levels) = 5 + + // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) + // are acceptable by algorithm, and levels computed by algorithm (output) are optimal, that is + // computed from a optimal (that is flat) new_H. + auto [new_H, new_D, L] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + std::vector expected_H(10, 25.); // H is flat and is 25. (means of initial H) + // Levels associated to new H are such as inf(L) = 0. > inf(input_levels) = 5 + std::vector expected_L = {80., 60., 40., 20., 0., 20., 40., 60., 80., 100.}; + BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); + BOOST_TEST(L == expected_L, boost::test_tools::per_element()); + + // Case 2 : now we lower initial level. We know that input data are still acceptable + // for algorithm, and that algorithm will have take the levels lower bound (0.) + // into account. As the level change, the solution new_H will be suboptimal, that + // is flat by interval. + init_level = 95.; + auto [new_H2, new_D2, L2] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + // new_H2 is flat by interval + std::vector expected_H2 = {24., 24., 24., 24., 24., 26., 26., 26., 26., 26.}; + BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); +} + // Ideas for building further tests : // ================================ // - Remix hydro algorithm seems symmetrical (if we have input vectors and corresponding output From 08bbd702dbc8f570348d4aeef67ea3cbcd920fc6 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 19 Dec 2024 18:15:51 +0100 Subject: [PATCH 21/44] New hydro remix : adding test that case where initial level has no influence on algorithm --- .../solver/simulation/test-hydro-remix.cpp | 68 ++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index af6110dac4..4c8f1e42bc 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -388,7 +388,7 @@ BOOST_AUTO_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised) "Remix hydro input : levels computed from input don't respect reservoir bounds")); } -BOOST_AUTO_TEST_CASE(influence_of_capacity_on_hydro_prod___case_where_no_influence, +BOOST_AUTO_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influence, *boost::unit_test::tolerance(0.001)) { // Not important for this test @@ -518,7 +518,7 @@ BOOST_AUTO_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution std::vector G(10, 0.), pump(10, 0.), ovf(10, 0.), S(10, 0.), DTG_MRG(10, 0.); std::vector D(10, 20.); - // H oscillates between 20 and 30 (new H will be flattened to 15 everywhere) + // H oscillates between 20 and 30 (new H will be flattened to 25 everywhere) std::vector H = {20., 30., 20., 30., 20., 30., 20., 30., 20., 30.}; // First inflows < H, then inflows > H. Consequence : levels first decrease, then increase. std::vector inflows = {5., 5., 5., 5., 5., 45., 45., 45., 45., 45.}; @@ -550,7 +550,7 @@ BOOST_AUTO_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution BOOST_TEST(L == expected_L, boost::test_tools::per_element()); // Case 2 : now we lower initial level. We know that input data are still acceptable - // for algorithm, and that algorithm will have take the levels lower bound (0.) + // for algorithm, and that algorithm will have to take the levels lower bound (0.) // into account. As the level change, the solution new_H will be suboptimal, that // is flat by interval. init_level = 95.; @@ -572,6 +572,68 @@ BOOST_AUTO_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); } +BOOST_AUTO_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_influence, + *boost::unit_test::tolerance(0.001)) +{ + // Not important for this test + std::vector P_max(10, std::numeric_limits::max()); + std::vector P_min(10, 0.); + std::vector G(10, 0.), pump(10, 0.), ovf(10, 0.), S(10, 0.), DTG_MRG(10, 0.); + std::vector D(10, 20.); + + // H oscillates between 10 and 20 (new H will be flattened to 15 everywhere) + std::vector H = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; + // First inflows < H, then inflows > H. Consequence : levels first decrease, then increase. + std::vector inflows = {5., 5., 5., 5., 5., 25., 25., 25., 25., 25.}; + double capacity = std::numeric_limits::max(); + double init_level = 100.; + // H and inflows are such as inf(input_levels) = 45 + + // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) + // are acceptable by algorithm, and levels computed by algorithm (output) are optimal, that + // is computed from a optimal (that is flat) new_H. + auto [new_H, new_D, L] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + std::vector expected_H(10, 15.); // H is flat and is 15. (means of initial H) + // Levels associated to new H are such as inf(L) = 50 > inf(input_levels) = 45 + std::vector expected_L = {90., 80., 70., 60., 50., 60., 70., 80., 90., 100.}; + BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); + BOOST_TEST(L == expected_L, boost::test_tools::per_element()); + + // Case 2 : now we lower initial level down to 55. + // In this way, input data is still acceptable for algorithm + // and algorithm won't have to take the levels lower bound (0.) into account. + // The solution new_H will be optimal, that is flat by interval. + init_level = 55.; + auto [new_H2, new_D2, L2] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + // new_H2 is flat (and optimal) + std::vector expected_H2(10, 15.); + BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); +} + // Ideas for building further tests : // ================================ // - Remix hydro algorithm seems symmetrical (if we have input vectors and corresponding output From f0854dd2a742dd206196230b69281bc76edf54e3 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Fri, 20 Dec 2024 10:38:41 +0100 Subject: [PATCH 22/44] New hydro remix : creating a header for remix hydro algorithm --- src/solver/simulation/hydro-remix-new.cpp | 9 ++---- .../solver/simulation/hydro-remix-new.h | 29 +++++++++++++++++++ .../src/solver/simulation/CMakeLists.txt | 5 ++++ .../solver/simulation/test-hydro-remix.cpp | 26 +---------------- 4 files changed, 37 insertions(+), 32 deletions(-) create mode 100644 src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 12a5c4d626..141f3bcf4f 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -1,3 +1,5 @@ +#include "include/antares/solver/simulation/hydro-remix-new.h" + #include #include #include @@ -135,13 +137,6 @@ static void checkInputCorrectness(const std::vector& G, } } -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, diff --git a/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h b/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h new file mode 100644 index 0000000000..f621d90628 --- /dev/null +++ b/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h @@ -0,0 +1,29 @@ + +#pragma once + +#include + +namespace Antares::Solver::Simulation +{ + +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 init_level, + double capacity, + 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 diff --git a/src/tests/src/solver/simulation/CMakeLists.txt b/src/tests/src/solver/simulation/CMakeLists.txt index be2285170d..e62fbcd2fa 100644 --- a/src/tests/src/solver/simulation/CMakeLists.txt +++ b/src/tests/src/solver/simulation/CMakeLists.txt @@ -130,6 +130,11 @@ add_executable(test-hydro-remix ${src_solver_simulation}/hydro-remix-new.cpp ) +target_include_directories(test-hydro-remix + PRIVATE + ${src_solver_simulation} +) + target_link_libraries(test-hydro-remix PRIVATE Boost::unit_test_framework diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 4c8f1e42bc..640a62c1c8 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -8,31 +8,7 @@ #include -namespace Antares::Solver::Simulation -{ -// 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 init_level, - double capacity, - 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 +#include "include/antares/solver/simulation/hydro-remix-new.h" using namespace Antares::Solver::Simulation; From 4685abb8268bb506dcc932401d33dd1df5743ff2 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Fri, 20 Dec 2024 11:24:31 +0100 Subject: [PATCH 23/44] New hydro remix : define and use proper comparison operator when checking input data --- src/solver/simulation/hydro-remix-new.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 141f3bcf4f..4b6f8a97a0 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -57,19 +57,19 @@ int find_max_index(const std::vector& G_plus_H, return max_idx; } -static bool isLessThan(const std::vector& a, const std::vector& b) +static bool operator<=(const std::vector& a, const std::vector& b) { std::vector a_minus_b; std::ranges::transform(a, b, std::back_inserter(a_minus_b), std::minus()); return std::ranges::all_of(a_minus_b, [](const double& e) { return e <= 0.; }); } -static bool isLessThan(const std::vector& v, const double c) +static bool operator<=(const std::vector& v, const double c) { return std::ranges::all_of(v, [&c](const double& e) { return e <= c; }); } -static bool isGreaterThan(const std::vector& v, const double c) +static bool operator>=(const std::vector& v, const double c) { return std::ranges::all_of(v, [&c](const double& e) { return e >= c; }); } @@ -120,17 +120,18 @@ static void checkInputCorrectness(const std::vector& G, } // Hydro production < Pmax - if (!isLessThan(H, P_max)) + if (!(H <= P_max)) { throw std::invalid_argument(msg_prefix + "H not smaller than Pmax everywhere"); } + // Hydro production > Pmin - if (!isLessThan(P_min, H)) + if (!(P_min <= H)) { throw std::invalid_argument(msg_prefix + "H not greater than Pmin everywhere"); } - if (!isLessThan(levels, capacity) || !isGreaterThan(levels, 0.)) + if (!(levels <= capacity) || !(levels >= 0.)) { throw std::invalid_argument(msg_prefix + "levels computed from input don't respect reservoir bounds"); From 957cd5b8f23df88154cabfc3fd21effe74bf14ad Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Fri, 20 Dec 2024 11:36:20 +0100 Subject: [PATCH 24/44] [skip ci] New hydro remix : replace use of std::adjacent_find with use of std::all_of instead --- src/solver/simulation/hydro-remix-new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 4b6f8a97a0..cf76ccedbc 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -108,7 +108,7 @@ static void checkInputCorrectness(const std::vector& G, S.size(), DTG_MRG.size()}; - if (std::ranges::adjacent_find(sizes, std::not_equal_to()) != sizes.end()) + if (!std::ranges::all_of(sizes, [&sizes](const size_t s) { return s == sizes.front(); })) { throw std::invalid_argument(msg_prefix + "arrays of different sizes"); } From 6157f341d50c9f9ba00e891a3a8315714a4730cd Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Fri, 20 Dec 2024 12:26:58 +0100 Subject: [PATCH 25/44] [skip ci] New hydro remix : make code comment more clear --- .../solver/simulation/test-hydro-remix.cpp | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 640a62c1c8..cb78db4dd5 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influenc // H and inflows result in : input_levels = {115, 120, 135, 140, 155, 140, 135, 120, 115, 100} // Note sup(input_levels) = 155 - // Case 1 : capacity unlimited + // Case 1 : capacity unlimited (relaxed) ==> leads to optimal solution (H is flat) double capacity = std::numeric_limits::max(); auto [new_H, new_D, L] = new_remix_hydro(G, H, @@ -403,7 +403,7 @@ BOOST_AUTO_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influenc BOOST_TEST(L == expected_L, boost::test_tools::per_element()); // Case 2 : now, if we lower capacity to sup(input_levels) = 155, we should - // have same computed H and L as previously : this value of capacity should + // have H and L identical to previously : this value of capacity should // not have an influence on H and levels as results of the algorithm. capacity = 155.; auto [new_H2, new_D2, L2] = new_remix_hydro(G, @@ -437,10 +437,11 @@ BOOST_AUTO_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_for_ // First inflows > H, then inflows < H. Consequence : levels first increase, then decrease. std::vector inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; double init_level = 100.; - // H and inflows result in : input_levels = {105, 120, 125, 140, 145, 140, 125, 120, 105, 100} + // H and inflows lead to have : + // input_levels = {105, 120, 125, 140, 145, 140, 125, 120, 105,100} // Note sup(input_levels) = 145 - // Case 1 : capacity unlimited + // Case 1 : capacity unlimited (relaxed) ==> leads to optimal solution (H is flat) double capacity = std::numeric_limits::max(); auto [new_H, new_D, L] = new_remix_hydro(G, H, @@ -461,11 +462,12 @@ BOOST_AUTO_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_for_ BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); - // Case 2 : now we lower capacity to sup(input_levels) = 145. + // Case 2 : we lower capacity to sup(input_levels) = 145. // This makes input acceptable for algo : levels computed from input have an // up bound <= capacity // But this time levels can not increase up to sup(L) = 150., as it would if capacity - // was infinite. So we expect to get an output H flat by interval, not on the whole domain. + // was infinite. Therefore, solution found is suboptimal : we expect to get an + // output H flat by interval, not flat on the whole domain. capacity = 145.; auto [new_H2, new_D2, L2] = new_remix_hydro(G, H, @@ -504,8 +506,8 @@ BOOST_AUTO_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution // Note : inf(input_levels) = 5 // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) - // are acceptable by algorithm, and levels computed by algorithm (output) are optimal, that is - // computed from a optimal (that is flat) new_H. + // are acceptable for algorithm (input levels >= 0.), and running algorithm leads to optimal + // solution (new_H is flat) auto [new_H, new_D, L] = new_remix_hydro(G, H, D, @@ -525,10 +527,10 @@ BOOST_AUTO_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); - // Case 2 : now we lower initial level. We know that input data are still acceptable - // for algorithm, and that algorithm will have to take the levels lower bound (0.) - // into account. As the level change, the solution new_H will be suboptimal, that - // is flat by interval. + // Case 2 : we lower initial level. Input data are still acceptable + // for algorithm (despite the new init level), algorithm will have to take the levels lower + // bound (0.) into account. As the levels change, the solution new_H will be suboptimal, that is + // flat by interval (not flat on the whole domain). init_level = 95.; auto [new_H2, new_D2, L2] = new_remix_hydro(G, H, From 889b982f7cec39982f44a99599ffcb4ef9acf190 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Fri, 20 Dec 2024 15:35:25 +0100 Subject: [PATCH 26/44] New hydro remix : improve unit tests by use of a fixture --- .../solver/simulation/test-hydro-remix.cpp | 292 ++++++++---------- 1 file changed, 130 insertions(+), 162 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index cb78db4dd5..c8568ebbf5 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -12,12 +12,31 @@ using namespace Antares::Solver::Simulation; -BOOST_AUTO_TEST_CASE(input_vectors_of_different_sizes__exception_raised) +template +struct InputFixture { - std::vector G, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; - std::vector H = {0., 0.}; + InputFixture() + { + G.assign(size, 0.); + H.assign(size, 0.); + D.assign(size, 0.); + P_max.assign(size, std::numeric_limits::max()); + P_min.assign(size, 0.); + inflows.assign(size, 0.); + ovf.assign(size, 0.); + pump.assign(size, 0.); + S.assign(size, 0.); + DTG_MRG.assign(size, 0.); + } + + std::vector G, H, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; double init_level = 0.; - double capacity = 0.; + double capacity = std::numeric_limits::max(); +}; + +BOOST_FIXTURE_TEST_CASE(input_vectors_of_different_sizes__exception_raised, InputFixture<0>) +{ + H = {0., 0.}; BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), @@ -25,12 +44,11 @@ BOOST_AUTO_TEST_CASE(input_vectors_of_different_sizes__exception_raised) checkMessage("Remix hydro input : arrays of different sizes")); } -BOOST_AUTO_TEST_CASE(input_init_level_exceeds_capacity__exception_raised) +BOOST_FIXTURE_TEST_CASE(input_init_level_exceeds_capacity__exception_raised, InputFixture<0>) { - std::vector G, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; - std::vector H = {0., 0.}; - double init_level = 2.; - double capacity = 1.; + H = {0., 0.}; + init_level = 2.; + capacity = 1.; BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), @@ -38,11 +56,10 @@ BOOST_AUTO_TEST_CASE(input_init_level_exceeds_capacity__exception_raised) checkMessage("Remix hydro input : initial level > reservoir capacity")); } -BOOST_AUTO_TEST_CASE(all_input_arrays_of_size_0__exception_raised) +BOOST_FIXTURE_TEST_CASE(all_input_arrays_of_size_0__exception_raised, InputFixture<0>) { - std::vector G, H, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; - double init_level = 0.; - double capacity = 1.; + init_level = 0.; + capacity = 1.; BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), @@ -50,14 +67,12 @@ BOOST_AUTO_TEST_CASE(all_input_arrays_of_size_0__exception_raised) checkMessage("Remix hydro input : all arrays of sizes 0")); } -BOOST_AUTO_TEST_CASE(H_not_smaller_than_pmax__exception_raised) +BOOST_FIXTURE_TEST_CASE(H_not_smaller_than_pmax__exception_raised, InputFixture<5>) { - 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 init_level = 0.; - double capacity = 1.; + H = {1., 2., 3., 4., 5.}; + P_max = {2., 2., 2., 4., 5.}; + init_level = 0.; + capacity = 1.; BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), @@ -65,14 +80,12 @@ BOOST_AUTO_TEST_CASE(H_not_smaller_than_pmax__exception_raised) checkMessage("Remix hydro input : H not smaller than Pmax everywhere")); } -BOOST_AUTO_TEST_CASE(H_not_greater_than_pmin__exception_raised) +BOOST_FIXTURE_TEST_CASE(H_not_greater_than_pmin__exception_raised, InputFixture<5>) { - 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 init_level = 0.; - double capacity = 1.; + H = {1., 2., 3., 4., 5.}; + P_min = {0., 0., 4., 0., 0.}; + init_level = 0.; + capacity = 1.; BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), @@ -80,28 +93,24 @@ BOOST_AUTO_TEST_CASE(H_not_greater_than_pmin__exception_raised) checkMessage("Remix hydro input : H not greater than Pmin everywhere")); } -BOOST_AUTO_TEST_CASE(input_is_acceptable__no_exception_raised) +BOOST_FIXTURE_TEST_CASE(input_is_acceptable__no_exception_raised, InputFixture<1>) { - 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 init_level = 0.; - double capacity = 1.; + init_level = 0.; + capacity = 1.; BOOST_CHECK_NO_THROW( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG)); } -BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh) +BOOST_FIXTURE_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh, + InputFixture<5>) { - std::vector P_max(5, 40.); - std::vector P_min(5, 0.); - std::vector G(5, 100.); - std::vector H = {0., 10., 20., 30., 40.}; // we have Pmin <= H <= Pmax - std::vector D = {80.0, 60., 40., 20., 0.}; - double init_level = 500.; - double capacity = 1000.; - std::vector inflows(5, 0.); - std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + std::ranges::fill(P_max, 40.); + std::ranges::fill(G, 100.); + H = {0., 10., 20., 30., 40.}; // we have Pmin <= H <= Pmax + D = {80.0, 60., 40., 20., 0.}; + init_level = 500.; + capacity = 1000.; auto [new_H, new_D, _] = new_remix_hydro(G, H, @@ -117,23 +126,20 @@ BOOST_AUTO_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 DTG_MRG); std::vector expected_H = {20., 20., 20., 20., 20.}; - // D such as G + H + D remains constant at each hour + // D such as G + H + D remains flat std::vector expected_D = {60., 50., 40., 30., 20.}; BOOST_CHECK(new_H == expected_H); BOOST_CHECK(new_D == expected_D); } -BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) +BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, InputFixture<5>) { - std::vector P_max(5, 50.); - std::vector P_min(5, 0.); - std::vector G(5, 100.); - std::vector H = {0., 10., 20., 30., 40.}; - std::vector D = {80.0, 60., 40., 20., 0.}; - double init_level = 500.; - double capacity = 1000.; - std::vector inflows(5, 0.); - std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + std::ranges::fill(P_max, 50.); + std::ranges::fill(G, 100.); + H = {0., 10., 20., 30., 40.}; + D = {80.0, 60., 40., 20., 0.}; + init_level = 500.; + capacity = 1000.; auto [new_H, new_D, _] = new_remix_hydro(G, H, @@ -155,17 +161,15 @@ BOOST_AUTO_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh) BOOST_CHECK(new_D == expected_D); } -BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh) +BOOST_FIXTURE_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh, + InputFixture<5>) { - std::vector P_max(5, 40.); - std::vector P_min(5, 0.); - std::vector G(5, 100.); - std::vector H = {40., 30., 20., 10., 0.}; - std::vector D = {0., 20., 40., 60., 80.}; - double init_level = 500.; - double capacity = 1000.; - std::vector inflows(5, 0.); - std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + std::ranges::fill(P_max, 40.); + std::ranges::fill(G, 100.); + H = {40., 30., 20., 10., 0.}; + D = {0., 20., 40., 60., 80.}; + init_level = 500.; + capacity = 1000.; auto [new_H, new_D, _] = new_remix_hydro(G, H, @@ -187,25 +191,19 @@ BOOST_AUTO_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_2 BOOST_CHECK(new_D == expected_D); } -BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) +BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::tolerance(0.01)) { - std::vector P_min(5, 0.); - // G decreases - std::vector G = {100., 80., 60., 40., 20.}; + G = {100., 80., 60., 40., 20.}; // H is flat and must respect H <= Pmax everywhere - std::vector H = {20., 20., 20., 20., 20.}; - std::vector D = {50., 50., 50., 50., 50.}; - double init_level = 500.; - double capacity = 1000.; - std::vector inflows(5, 0.); - std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + H = {20., 20., 20., 20., 20.}; + D = {50., 50., 50., 50., 50.}; + init_level = 500.; + capacity = 1000.; // 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, L] = new_remix_hydro(G, H, D, @@ -244,23 +242,18 @@ BOOST_AUTO_TEST_CASE(influence_of_pmax, *boost::unit_test::tolerance(0.01)) BOOST_CHECK(new_D2 == expected_D2); } -BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) +BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::tolerance(0.01)) { - std::vector P_max(5, std::numeric_limits::max()); - // G decreases - std::vector G = {100., 80., 60., 40., 20.}; + G = {100., 80., 60., 40., 20.}; // H is flat and must respect Pmin <= H <= Pmax everywhere - std::vector H = {20., 20., 20., 20., 20.}; - std::vector D = {50., 50., 50., 50., 50.}; - double init_level = 500.; - double capacity = 1000.; - std::vector inflows(5, 0.); - std::vector ovf(5, 0.), pump(5, 0.), S(5, 0.), DTG_MRG(5, 0.); + H = {20., 20., 20., 20., 20.}; + D = {50., 50., 50., 50., 50.}; + init_level = 500.; + capacity = 1000.; // 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, L] = new_remix_hydro(G, H, D, @@ -297,17 +290,14 @@ BOOST_AUTO_TEST_CASE(influence_of_pmin, *boost::unit_test::tolerance(0.01)) BOOST_CHECK(new_D2 == expected_D2); } -BOOST_AUTO_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed) +BOOST_FIXTURE_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed, + InputFixture<5>) { - // Not important for testing levels - std::vector P_max(5, 25.), P_min(5, 0.), G(5, 0.), S(5, 0.), DTG_MRG(5, 0.); - std::vector D(5, 10.); - double capacity = 1000.; - - // Used for level computations - double init_level = 500.; - std::vector ovf(5, 25.), H(5, 20.); // Cause levels to lower - std::vector inflows(5, 15.), pump(5, 10.); // Cause levels to raise + init_level = 500.; + std::ranges::fill(ovf, 25.); // Cause levels to decrease + std::ranges::fill(H, 20.); // Cause levels to decrease + std::ranges::fill(inflows, 15.); // Cause levels to increase + std::ranges::fill(pump, 10.); // Cause levels to increase auto [new_H, new_D, levels] = new_remix_hydro(G, H, @@ -326,17 +316,14 @@ BOOST_AUTO_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed BOOST_TEST(levels == expected_levels, boost::test_tools::per_element()); } -BOOST_AUTO_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised) +BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised, InputFixture<5>) { - // Not important for testing levels - std::vector P_max(5, 25.), P_min(5, 0.), G(5, 0.), S(5, 0.), DTG_MRG(5, 0.); - std::vector D(5, 10.); - - // Used for level computations - double init_level = 500.; - double capacity = 550.; - std::vector ovf(5, 15.), H(5, 10.); // Cause levels to lower - std::vector inflows(5, 25.), pump(5, 20.); // Cause levels to raise + init_level = 500.; + capacity = 550.; + std::ranges::fill(ovf, 15); // Cause levels to decrease + std::ranges::fill(H, 10); // Cause levels to decrease + std::ranges::fill(inflows, 25); // Cause levels to increase + std::ranges::fill(pump, 20); // Cause levels to increase BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), @@ -345,17 +332,13 @@ BOOST_AUTO_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised) "Remix hydro input : levels computed from input don't respect reservoir bounds")); } -BOOST_AUTO_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised) +BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised, InputFixture<5>) { - // Not important for testing levels - std::vector P_max(5, 25.), P_min(5, 0.), G(5, 0.), S(5, 0.), DTG_MRG(5, 0.); - std::vector D(5, 10.); - - // Used for level computations - double init_level = 50.; - double capacity = 100.; - std::vector ovf(5, 30.), H(5, 10.); // Cause levels to lower - std::vector inflows(5, 10.), pump(5, 10.); // Cause levels to raise + init_level = 50.; + std::ranges::fill(ovf, 30); // Cause levels to decrease + std::ranges::fill(H, 10); // Cause levels to decrease + std::ranges::fill(inflows, 5); // Cause levels to increase + std::ranges::fill(pump, 10); // Cause levels to increase BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), @@ -364,25 +347,21 @@ BOOST_AUTO_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised) "Remix hydro input : levels computed from input don't respect reservoir bounds")); } -BOOST_AUTO_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influence, - *boost::unit_test::tolerance(0.001)) +BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influence, + InputFixture<10>, + *boost::unit_test::tolerance(0.001)) { - // Not important for this test - std::vector P_max(10, std::numeric_limits::max()); - std::vector P_min(10, 0.); - std::vector G(10, 0.), pump(10, 0.), ovf(10, 0.), S(10, 0.), DTG_MRG(10, 0.); - std::vector D(10, 20.); + std::ranges::fill(D, 20); // Not important for this test // H oscillates between 10 and 20 (new H will be flattened to 15 everywhere) - std::vector H = {10., 20., 10., 20., 10., 20., 10., 20., 10., 20.}; + H = {10., 20., 10., 20., 10., 20., 10., 20., 10., 20.}; // First inflows > H, then inflows < H. Consequence : levels first increase, then decrease. - std::vector inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; - double init_level = 100.; + inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; + init_level = 100.; // H and inflows result in : input_levels = {115, 120, 135, 140, 155, 140, 135, 120, 115, 100} // Note sup(input_levels) = 155 - // Case 1 : capacity unlimited (relaxed) ==> leads to optimal solution (H is flat) - double capacity = std::numeric_limits::max(); + // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (H is flat) auto [new_H, new_D, L] = new_remix_hydro(G, H, D, @@ -423,26 +402,22 @@ BOOST_AUTO_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influenc BOOST_TEST(L2 == expected_L, boost::test_tools::per_element()); } -BOOST_AUTO_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_for_GplusH, - *boost::unit_test::tolerance(0.001)) +BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_for_GplusH, + InputFixture<10>, + *boost::unit_test::tolerance(0.001)) { - // Not important for this test - std::vector P_max(10, std::numeric_limits::max()); - std::vector P_min(10, 0.); - std::vector G(10, 0.), pump(10, 0.), ovf(10, 0.), S(10, 0.), DTG_MRG(10, 0.); - std::vector D(10, 20.); + std::ranges::fill(D, 20); // Not important for this test // H oscillates between 10 and 20 (new H will be flattened to 15 everywhere) - std::vector H = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; + H = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; // First inflows > H, then inflows < H. Consequence : levels first increase, then decrease. - std::vector inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; - double init_level = 100.; + inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; + init_level = 100.; // H and inflows lead to have : // input_levels = {105, 120, 125, 140, 145, 140, 125, 120, 105,100} // Note sup(input_levels) = 145 - // Case 1 : capacity unlimited (relaxed) ==> leads to optimal solution (H is flat) - double capacity = std::numeric_limits::max(); + // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (H is flat) auto [new_H, new_D, L] = new_remix_hydro(G, H, D, @@ -487,21 +462,18 @@ BOOST_AUTO_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_for_ BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); } -BOOST_AUTO_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution_for_GplusH, - *boost::unit_test::tolerance(0.001)) +BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution_for_GplusH, + InputFixture<10>, + *boost::unit_test::tolerance(0.001)) { - // Not important for this test - std::vector P_max(10, std::numeric_limits::max()); - std::vector P_min(10, 0.); - std::vector G(10, 0.), pump(10, 0.), ovf(10, 0.), S(10, 0.), DTG_MRG(10, 0.); - std::vector D(10, 20.); + std::ranges::fill(D, 20); // Not important for this test // H oscillates between 20 and 30 (new H will be flattened to 25 everywhere) - std::vector H = {20., 30., 20., 30., 20., 30., 20., 30., 20., 30.}; + H = {20., 30., 20., 30., 20., 30., 20., 30., 20., 30.}; // First inflows < H, then inflows > H. Consequence : levels first decrease, then increase. - std::vector inflows = {5., 5., 5., 5., 5., 45., 45., 45., 45., 45.}; - double capacity = std::numeric_limits::max(); - double init_level = 100.; + inflows = {5., 5., 5., 5., 5., 45., 45., 45., 45., 45.}; + capacity = std::numeric_limits::max(); + init_level = 100.; // H and inflows result in : input_levels = {85, 60, 45, 20, 5, 20, 45, 60, 85, 100} // Note : inf(input_levels) = 5 @@ -550,21 +522,17 @@ BOOST_AUTO_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); } -BOOST_AUTO_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_influence, - *boost::unit_test::tolerance(0.001)) +BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_influence, + InputFixture<10>, + *boost::unit_test::tolerance(0.001)) { - // Not important for this test - std::vector P_max(10, std::numeric_limits::max()); - std::vector P_min(10, 0.); - std::vector G(10, 0.), pump(10, 0.), ovf(10, 0.), S(10, 0.), DTG_MRG(10, 0.); - std::vector D(10, 20.); + std::ranges::fill(D, 20); // Not important for this test // H oscillates between 10 and 20 (new H will be flattened to 15 everywhere) - std::vector H = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; + H = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; // First inflows < H, then inflows > H. Consequence : levels first decrease, then increase. - std::vector inflows = {5., 5., 5., 5., 5., 25., 25., 25., 25., 25.}; - double capacity = std::numeric_limits::max(); - double init_level = 100.; + inflows = {5., 5., 5., 5., 5., 25., 25., 25., 25., 25.}; + init_level = 100.; // H and inflows are such as inf(input_levels) = 45 // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) From da27cb9497937359d07ea1c6a1de45caaff0408f Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Fri, 27 Dec 2024 17:10:16 +0100 Subject: [PATCH 27/44] New hydro remix : adding test on invariance where S + DTG_MRG > 0 --- .../solver/simulation/test-hydro-remix.cpp | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index c8568ebbf5..5b60bc53a3 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -580,6 +580,64 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); } +BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, InputFixture<5>) +{ + std::ranges::fill(G, 100.); + H = {40., 30., 20., 10., 0.}; + D = {0., 20., 40., 60., 80.}; + init_level = 500.; + capacity = 1000.; + // At this stage, DTG_MRG is filled with zeros. Running the algorithm would flatten + // H to 20 everywhere : H = {20, 20, 20, 20, 20} + // But : + S[0] = 1.; + // Now, we expect no change for H at hour 0 + auto [new_H, __, _] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + std::vector expected_H = {40., 15., 15., 15., 15.}; + BOOST_CHECK(new_H == expected_H); +} + +BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, InputFixture<5>) +{ + std::ranges::fill(G, 100.); + H = {40., 30., 20., 10., 0.}; + D = {0., 20., 40., 60., 80.}; + init_level = 500.; + capacity = 1000.; + // At this stage, DTG_MRG is filled with zeros. Running the algorithm would flatten + // H to 20 everywhere : H = {20, 20, 20, 20, 20} + // But : + DTG_MRG[4] = 1.; + // Now, we expect no change for H at hour 4 + auto [new_H, new_D, L] = new_remix_hydro(G, + H, + D, + P_max, + P_min, + init_level, + capacity, + inflows, + ovf, + pump, + S, + DTG_MRG); + + std::vector expected_H = {25., 25., 25., 25., 0.}; + BOOST_CHECK(new_H == expected_H); +} + // Ideas for building further tests : // ================================ // - Remix hydro algorithm seems symmetrical (if we have input vectors and corresponding output From 91e0a0a57cadc462c495db004fb5818f029321bb Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Mon, 6 Jan 2025 14:13:06 +0100 Subject: [PATCH 28/44] New hydro remix : renaming algorithm input data --- src/solver/simulation/hydro-remix-new.cpp | 117 ++++++++++++---------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index cf76ccedbc..7392ce287d 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -12,7 +12,7 @@ int find_min_index(const std::vector& G_plus_H, const std::vector& new_D, const std::vector& new_H, const std::vector& tried_creux, - const std::vector& P_max, + const std::vector& HydroPmax, const std::vector& filter_hours_remix, double top) { @@ -20,7 +20,7 @@ int find_min_index(const std::vector& G_plus_H, 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 && filter_hours_remix[i]) + if (new_D[i] > 0 && new_H[i] < HydroPmax[i] && tried_creux[i] == 0 && filter_hours_remix[i]) { if (G_plus_H[i] < min_val) { @@ -35,7 +35,7 @@ int find_min_index(const std::vector& G_plus_H, 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& HydroPmin, const std::vector& filter_hours_remix, double ref_value, double eps) @@ -44,7 +44,7 @@ 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] > HydroPmin[i] && G_plus_H[i] >= ref_value + eps && tried_pic[i] == 0 && filter_hours_remix[i]) { if (G_plus_H[i] > max_val) @@ -74,18 +74,18 @@ static bool operator>=(const std::vector& v, const double c) return std::ranges::all_of(v, [&c](const double& e) { return e >= c; }); } -static void checkInputCorrectness(const std::vector& G, - const std::vector& H, - const std::vector& D, +static void checkInputCorrectness(const std::vector& ThermalGen, + const std::vector& HydroGen, + const std::vector& UnsupE, const std::vector& levels, - const std::vector& P_max, - const std::vector& P_min, + const std::vector& HydroPmax, + const std::vector& HydroPmin, double initial_level, double capacity, const std::vector& inflows, const std::vector& overflow, const std::vector& pump, - const std::vector& S, + const std::vector& Spillage, const std::vector& DTG_MRG) { std::string msg_prefix = "Remix hydro input : "; @@ -96,16 +96,16 @@ static void checkInputCorrectness(const std::vector& G, throw std::invalid_argument(msg_prefix + "initial level > reservoir capacity"); } // Arrays sizes must be identical - std::vector sizes = {G.size(), - H.size(), - D.size(), + std::vector sizes = {ThermalGen.size(), + HydroGen.size(), + UnsupE.size(), levels.size(), - P_max.size(), - P_min.size(), + HydroPmax.size(), + HydroPmin.size(), inflows.size(), overflow.size(), pump.size(), - S.size(), + Spillage.size(), DTG_MRG.size()}; if (!std::ranges::all_of(sizes, [&sizes](const size_t s) { return s == sizes.front(); })) @@ -114,21 +114,23 @@ static void checkInputCorrectness(const std::vector& G, } // Arrays are of size 0 - if (!G.size()) + if (!ThermalGen.size()) { throw std::invalid_argument(msg_prefix + "all arrays of sizes 0"); } // Hydro production < Pmax - if (!(H <= P_max)) + if (!(HydroGen <= HydroPmax)) { - throw std::invalid_argument(msg_prefix + "H not smaller than Pmax everywhere"); + throw std::invalid_argument(msg_prefix + + "Hydro generation not smaller than Pmax everywhere"); } // Hydro production > Pmin - if (!(P_min <= H)) + if (!(HydroPmin <= HydroGen)) { - throw std::invalid_argument(msg_prefix + "H not greater than Pmin everywhere"); + throw std::invalid_argument(msg_prefix + + "Hydro generation not greater than Pmin everywhere"); } if (!(levels <= capacity) || !(levels >= 0.)) @@ -138,66 +140,71 @@ static void checkInputCorrectness(const std::vector& G, } } -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, +RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, + const std::vector& HydroGen, + const std::vector& UnsupE, + const std::vector& HydroPmax, + const std::vector& HydroPmin, double initial_level, double capa, const std::vector& inflows, const std::vector& overflow, const std::vector& pump, - const std::vector& S, + const std::vector& Spillage, const std::vector& DTG_MRG) { - std::vector levels(G.size()); + std::vector levels(ThermalGen.size()); if (levels.size()) { - levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - H[0]; + levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - HydroGen[0]; for (size_t i = 1; i < levels.size(); ++i) { - levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - H[i]; + levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - HydroGen[i]; } } - checkInputCorrectness(G, - H, - D, + checkInputCorrectness(ThermalGen, + HydroGen, + UnsupE, levels, - P_max, - P_min, + HydroPmax, + HydroPmin, initial_level, capa, inflows, overflow, pump, - S, + Spillage, DTG_MRG); - std::vector new_H = H; - std::vector new_D = D; + std::vector new_H = HydroGen; + std::vector new_D = UnsupE; int loop = 1000; double eps = 1e-3; - double top = *std::max_element(G.begin(), G.end()) + *std::max_element(H.begin(), H.end()) - + *std::max_element(D.begin(), D.end()) + 1; + double top = *std::max_element(ThermalGen.begin(), ThermalGen.end()) + + *std::max_element(HydroGen.begin(), HydroGen.end()) + + *std::max_element(UnsupE.begin(), UnsupE.end()) + 1; - std::vector filter_hours_remix(G.size(), false); + std::vector filter_hours_remix(ThermalGen.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.) + if (Spillage[h] + DTG_MRG[h] == 0. && HydroGen[h] + UnsupE[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 G_plus_H(ThermalGen.size()); + std::transform(ThermalGen.begin(), + ThermalGen.end(), + new_H.begin(), + G_plus_H.begin(), + std::plus<>()); while (loop-- > 0) { - std::vector tried_creux(G.size(), 0); + std::vector tried_creux(ThermalGen.size(), 0); double delta = 0; while (true) @@ -206,7 +213,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, new_D, new_H, tried_creux, - P_max, + HydroPmax, filter_hours_remix, top); if (idx_creux == -1) @@ -214,13 +221,13 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, break; } - std::vector tried_pic(G.size(), 0); + std::vector tried_pic(ThermalGen.size(), 0); while (true) { int idx_pic = find_max_index(G_plus_H, new_H, tried_pic, - P_min, + HydroPmin, filter_hours_remix, G_plus_H[idx_creux], eps); @@ -248,9 +255,9 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, max_creux = capa; } - max_pic = std::min(new_H[idx_pic] - P_min[idx_pic], max_pic); + max_pic = std::min(new_H[idx_pic] - HydroPmin[idx_pic], max_pic); max_creux = std::min( - {P_max[idx_creux] - new_H[idx_creux], new_D[idx_creux], max_creux}); + {HydroPmax[idx_creux] - new_H[idx_creux], new_D[idx_creux], max_creux}); double dif_pic_creux = std::max(G_plus_H[idx_pic] - G_plus_H[idx_creux], 0.); @@ -260,8 +267,8 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, { new_H[idx_pic] -= delta; new_H[idx_creux] += delta; - new_D[idx_pic] = H[idx_pic] + D[idx_pic] - new_H[idx_pic]; - new_D[idx_creux] = H[idx_creux] + D[idx_creux] - new_H[idx_creux]; + new_D[idx_pic] = HydroGen[idx_pic] + UnsupE[idx_pic] - new_H[idx_pic]; + new_D[idx_creux] = HydroGen[idx_creux] + UnsupE[idx_creux] - new_H[idx_creux]; break; } else @@ -282,7 +289,11 @@ RemixHydroOutput new_remix_hydro(const std::vector& G, break; } - std::transform(G.begin(), G.end(), new_H.begin(), G_plus_H.begin(), std::plus<>()); + std::transform(ThermalGen.begin(), + ThermalGen.end(), + new_H.begin(), + G_plus_H.begin(), + std::plus<>()); levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - new_H[0]; for (size_t i = 1; i < levels.size(); ++i) { From c02210a0c8d8655ee4dc6a880a1ead06b3f3a491 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Mon, 6 Jan 2025 14:25:35 +0100 Subject: [PATCH 29/44] New hydro remix : renaming algorithm input data (part 2) --- src/solver/simulation/hydro-remix-new.cpp | 78 ++++++++++--------- .../solver/simulation/test-hydro-remix.cpp | 4 +- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 7392ce287d..5abcf36e3f 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -8,9 +8,9 @@ namespace Antares::Solver::Simulation { -int find_min_index(const std::vector& G_plus_H, - const std::vector& new_D, - const std::vector& new_H, +int find_min_index(const std::vector& Thermal_plus_Hydro, + const std::vector& OutUnsupE, + const std::vector& OutHydroGen, const std::vector& tried_creux, const std::vector& HydroPmax, const std::vector& filter_hours_remix, @@ -18,13 +18,14 @@ int find_min_index(const std::vector& G_plus_H, { double min_val = top; int min_idx = -1; - for (int i = 0; i < G_plus_H.size(); ++i) + for (int i = 0; i < Thermal_plus_Hydro.size(); ++i) { - if (new_D[i] > 0 && new_H[i] < HydroPmax[i] && tried_creux[i] == 0 && filter_hours_remix[i]) + if (OutUnsupE[i] > 0 && OutHydroGen[i] < HydroPmax[i] && tried_creux[i] == 0 + && filter_hours_remix[i]) { - if (G_plus_H[i] < min_val) + if (Thermal_plus_Hydro[i] < min_val) { - min_val = G_plus_H[i]; + min_val = Thermal_plus_Hydro[i]; min_idx = i; } } @@ -32,8 +33,8 @@ int find_min_index(const std::vector& G_plus_H, return min_idx; } -int find_max_index(const std::vector& G_plus_H, - const std::vector& new_H, +int find_max_index(const std::vector& Thermal_plus_Hydro, + const std::vector& OutHydroGen, const std::vector& tried_pic, const std::vector& HydroPmin, const std::vector& filter_hours_remix, @@ -42,14 +43,14 @@ int find_max_index(const std::vector& G_plus_H, { double max_val = 0; int max_idx = -1; - for (int i = 0; i < G_plus_H.size(); ++i) + for (int i = 0; i < Thermal_plus_Hydro.size(); ++i) { - if (new_H[i] > HydroPmin[i] && G_plus_H[i] >= ref_value + eps && tried_pic[i] == 0 - && filter_hours_remix[i]) + if (OutHydroGen[i] > HydroPmin[i] && Thermal_plus_Hydro[i] >= ref_value + eps + && tried_pic[i] == 0 && filter_hours_remix[i]) { - if (G_plus_H[i] > max_val) + if (Thermal_plus_Hydro[i] > max_val) { - max_val = G_plus_H[i]; + max_val = Thermal_plus_Hydro[i]; max_idx = i; } } @@ -177,8 +178,8 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, Spillage, DTG_MRG); - std::vector new_H = HydroGen; - std::vector new_D = UnsupE; + std::vector OutHydroGen = HydroGen; + std::vector OutUnsupE = UnsupE; int loop = 1000; double eps = 1e-3; @@ -195,11 +196,11 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, } } - std::vector G_plus_H(ThermalGen.size()); + std::vector Thermal_plus_Hydro(ThermalGen.size()); std::transform(ThermalGen.begin(), ThermalGen.end(), - new_H.begin(), - G_plus_H.begin(), + OutHydroGen.begin(), + Thermal_plus_Hydro.begin(), std::plus<>()); while (loop-- > 0) @@ -209,9 +210,9 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, while (true) { - int idx_creux = find_min_index(G_plus_H, - new_D, - new_H, + int idx_creux = find_min_index(Thermal_plus_Hydro, + OutUnsupE, + OutHydroGen, tried_creux, HydroPmax, filter_hours_remix, @@ -224,12 +225,12 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, std::vector tried_pic(ThermalGen.size(), 0); while (true) { - int idx_pic = find_max_index(G_plus_H, - new_H, + int idx_pic = find_max_index(Thermal_plus_Hydro, + OutHydroGen, tried_pic, HydroPmin, filter_hours_remix, - G_plus_H[idx_creux], + Thermal_plus_Hydro[idx_creux], eps); if (idx_pic == -1) { @@ -255,20 +256,23 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, max_creux = capa; } - max_pic = std::min(new_H[idx_pic] - HydroPmin[idx_pic], max_pic); + max_pic = std::min(OutHydroGen[idx_pic] - HydroPmin[idx_pic], max_pic); max_creux = std::min( - {HydroPmax[idx_creux] - new_H[idx_creux], new_D[idx_creux], max_creux}); + {HydroPmax[idx_creux] - OutHydroGen[idx_creux], OutUnsupE[idx_creux], max_creux}); - double dif_pic_creux = std::max(G_plus_H[idx_pic] - G_plus_H[idx_creux], 0.); + double dif_pic_creux = std::max(Thermal_plus_Hydro[idx_pic] + - Thermal_plus_Hydro[idx_creux], + 0.); delta = std::max(std::min({max_pic, max_creux, dif_pic_creux / 2.}), 0.); if (delta > 0) { - new_H[idx_pic] -= delta; - new_H[idx_creux] += delta; - new_D[idx_pic] = HydroGen[idx_pic] + UnsupE[idx_pic] - new_H[idx_pic]; - new_D[idx_creux] = HydroGen[idx_creux] + UnsupE[idx_creux] - new_H[idx_creux]; + OutHydroGen[idx_pic] -= delta; + OutHydroGen[idx_creux] += delta; + OutUnsupE[idx_pic] = HydroGen[idx_pic] + UnsupE[idx_pic] - OutHydroGen[idx_pic]; + OutUnsupE[idx_creux] = HydroGen[idx_creux] + UnsupE[idx_creux] + - OutHydroGen[idx_creux]; break; } else @@ -291,16 +295,16 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, std::transform(ThermalGen.begin(), ThermalGen.end(), - new_H.begin(), - G_plus_H.begin(), + OutHydroGen.begin(), + Thermal_plus_Hydro.begin(), std::plus<>()); - levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - new_H[0]; + levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - OutHydroGen[0]; for (size_t i = 1; i < levels.size(); ++i) { - levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - new_H[i]; + levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - OutHydroGen[i]; } } - return {new_H, new_D, levels}; + return {OutHydroGen, OutUnsupE, 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 5b60bc53a3..84e77be8df 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -77,7 +77,7 @@ BOOST_FIXTURE_TEST_CASE(H_not_smaller_than_pmax__exception_raised, InputFixture< BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, - checkMessage("Remix hydro input : H not smaller than Pmax everywhere")); + checkMessage("Remix hydro input : Hydro generation not smaller than Pmax everywhere")); } BOOST_FIXTURE_TEST_CASE(H_not_greater_than_pmin__exception_raised, InputFixture<5>) @@ -90,7 +90,7 @@ BOOST_FIXTURE_TEST_CASE(H_not_greater_than_pmin__exception_raised, InputFixture< BOOST_CHECK_EXCEPTION( new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), std::invalid_argument, - checkMessage("Remix hydro input : H not greater than Pmin everywhere")); + checkMessage("Remix hydro input : Hydro generation not greater than Pmin everywhere")); } BOOST_FIXTURE_TEST_CASE(input_is_acceptable__no_exception_raised, InputFixture<1>) From 7d71f04041cc20ebb5d31b6dcb36effc96557182 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Mon, 6 Jan 2025 14:45:08 +0100 Subject: [PATCH 30/44] New hydro remix : unit tests - renaming algorithm input data --- .../solver/simulation/test-hydro-remix.cpp | 561 ++++++++++-------- 1 file changed, 329 insertions(+), 232 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 84e77be8df..43864313fc 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -17,43 +17,64 @@ struct InputFixture { InputFixture() { - G.assign(size, 0.); - H.assign(size, 0.); - D.assign(size, 0.); - P_max.assign(size, std::numeric_limits::max()); - P_min.assign(size, 0.); + ThermalGen.assign(size, 0.); + HydroGen.assign(size, 0.); + UnsupE.assign(size, 0.); + HydroPmax.assign(size, std::numeric_limits::max()); + HydroPmin.assign(size, 0.); inflows.assign(size, 0.); ovf.assign(size, 0.); pump.assign(size, 0.); - S.assign(size, 0.); + Spillage.assign(size, 0.); DTG_MRG.assign(size, 0.); } - std::vector G, H, D, P_max, P_min, inflows, ovf, pump, S, DTG_MRG; + std::vector ThermalGen, HydroGen, UnsupE, HydroPmax, HydroPmin, inflows, ovf, pump, + Spillage, DTG_MRG; double init_level = 0.; double capacity = std::numeric_limits::max(); }; BOOST_FIXTURE_TEST_CASE(input_vectors_of_different_sizes__exception_raised, InputFixture<0>) { - H = {0., 0.}; + HydroGen = {0., 0.}; - BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), - std::invalid_argument, - checkMessage("Remix hydro input : arrays of different sizes")); + BOOST_CHECK_EXCEPTION(new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : arrays of different sizes")); } BOOST_FIXTURE_TEST_CASE(input_init_level_exceeds_capacity__exception_raised, InputFixture<0>) { - H = {0., 0.}; + HydroGen = {0., 0.}; init_level = 2.; capacity = 1.; - BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), - std::invalid_argument, - checkMessage("Remix hydro input : initial level > reservoir capacity")); + BOOST_CHECK_EXCEPTION(new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : initial level > reservoir capacity")); } BOOST_FIXTURE_TEST_CASE(all_input_arrays_of_size_0__exception_raised, InputFixture<0>) @@ -61,34 +82,66 @@ BOOST_FIXTURE_TEST_CASE(all_input_arrays_of_size_0__exception_raised, InputFixtu init_level = 0.; capacity = 1.; - BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), - std::invalid_argument, - checkMessage("Remix hydro input : all arrays of sizes 0")); + BOOST_CHECK_EXCEPTION(new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : all arrays of sizes 0")); } BOOST_FIXTURE_TEST_CASE(H_not_smaller_than_pmax__exception_raised, InputFixture<5>) { - H = {1., 2., 3., 4., 5.}; - P_max = {2., 2., 2., 4., 5.}; + HydroGen = {1., 2., 3., 4., 5.}; + HydroPmax = {2., 2., 2., 4., 5.}; init_level = 0.; capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : Hydro generation not smaller than Pmax everywhere")); } BOOST_FIXTURE_TEST_CASE(H_not_greater_than_pmin__exception_raised, InputFixture<5>) { - H = {1., 2., 3., 4., 5.}; - P_min = {0., 0., 4., 0., 0.}; + HydroGen = {1., 2., 3., 4., 5.}; + HydroPmin = {0., 0., 4., 0., 0.}; init_level = 0.; capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : Hydro generation not greater than Pmin everywhere")); } @@ -98,35 +151,45 @@ BOOST_FIXTURE_TEST_CASE(input_is_acceptable__no_exception_raised, InputFixture<1 init_level = 0.; capacity = 1.; - BOOST_CHECK_NO_THROW( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG)); + BOOST_CHECK_NO_THROW(new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG)); } BOOST_FIXTURE_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh, InputFixture<5>) { - std::ranges::fill(P_max, 40.); - std::ranges::fill(G, 100.); - H = {0., 10., 20., 30., 40.}; // we have Pmin <= H <= Pmax - D = {80.0, 60., 40., 20., 0.}; + std::ranges::fill(HydroPmax, 40.); + std::ranges::fill(ThermalGen, 100.); + HydroGen = {0., 10., 20., 30., 40.}; // we have Pmin <= HydroGen <= Pmax + UnsupE = {80.0, 60., 40., 20., 0.}; init_level = 500.; capacity = 1000.; - auto [new_H, new_D, _] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + auto [new_H, new_D, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); std::vector expected_H = {20., 20., 20., 20., 20.}; - // D such as G + H + D remains flat + // UnsupE such as ThermalGen + HydroGen + UnsupE remains flat std::vector expected_D = {60., 50., 40., 30., 20.}; BOOST_CHECK(new_H == expected_H); BOOST_CHECK(new_D == expected_D); @@ -134,28 +197,28 @@ BOOST_FIXTURE_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_ BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, InputFixture<5>) { - std::ranges::fill(P_max, 50.); - std::ranges::fill(G, 100.); - H = {0., 10., 20., 30., 40.}; - D = {80.0, 60., 40., 20., 0.}; + std::ranges::fill(HydroPmax, 50.); + std::ranges::fill(ThermalGen, 100.); + HydroGen = {0., 10., 20., 30., 40.}; + UnsupE = {80.0, 60., 40., 20., 0.}; init_level = 500.; capacity = 1000.; - auto [new_H, new_D, _] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + auto [new_H, new_D, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); std::vector expected_H = {20., 20., 20., 20., 20.}; - // D such as G + H + D remains constant at each hour + // UnsupE such as ThermalGen + HydroGen + UnsupE remains constant at each hour std::vector expected_D = {60., 50., 40., 30., 20.}; BOOST_CHECK(new_H == expected_H); BOOST_CHECK(new_D == expected_D); @@ -164,28 +227,28 @@ BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, In BOOST_FIXTURE_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh, InputFixture<5>) { - std::ranges::fill(P_max, 40.); - std::ranges::fill(G, 100.); - H = {40., 30., 20., 10., 0.}; - D = {0., 20., 40., 60., 80.}; + std::ranges::fill(HydroPmax, 40.); + std::ranges::fill(ThermalGen, 100.); + HydroGen = {40., 30., 20., 10., 0.}; + UnsupE = {0., 20., 40., 60., 80.}; init_level = 500.; capacity = 1000.; - auto [new_H, new_D, _] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + auto [new_H, new_D, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); std::vector expected_H = {20., 20., 20., 20., 20.}; - // D such as G + H + D remains constant at each hour + // UnsupE such as ThermalGen + HydroGen + UnsupE remains constant at each hour std::vector expected_D = {20., 30., 40., 50., 60.}; BOOST_CHECK(new_H == expected_H); BOOST_CHECK(new_D == expected_D); @@ -193,47 +256,47 @@ BOOST_FIXTURE_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::tolerance(0.01)) { - // G decreases - G = {100., 80., 60., 40., 20.}; + // ThermalGen decreases + ThermalGen = {100., 80., 60., 40., 20.}; - // H is flat and must respect H <= Pmax everywhere - H = {20., 20., 20., 20., 20.}; - D = {50., 50., 50., 50., 50.}; + // HydroGen is flat and must respect HydroGen <= Pmax everywhere + HydroGen = {20., 20., 20., 20., 20.}; + UnsupE = {50., 50., 50., 50., 50.}; init_level = 500.; capacity = 1000.; - // 1. Algorithm tends to flatten G + H, so it would require H to increase. - // Proof : - auto [new_H1, new_D1, L] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + // 1. Algorithm tends to flatten ThermalGen + HydroGen, so it would require HydroGen to + // increase. Proof : + auto [new_H1, new_D1, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, 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 limited by P_max. So Algo does nothing in the end. + // 2. But HydroGen is limited by HydroPmax. 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, + HydroPmax = {20., 20., 20., 20., 20.}; + auto [new_H2, new_D2, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); std::vector expected_H2 = {20., 20., 20., 20., 20.}; @@ -244,44 +307,45 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::tolerance(0.01)) { - // G decreases - G = {100., 80., 60., 40., 20.}; + // ThermalGen decreases + ThermalGen = {100., 80., 60., 40., 20.}; - // H is flat and must respect Pmin <= H <= Pmax everywhere - H = {20., 20., 20., 20., 20.}; - D = {50., 50., 50., 50., 50.}; + // HydroGen is flat and must respect Pmin <= HydroGen <= Pmax everywhere + HydroGen = {20., 20., 20., 20., 20.}; + UnsupE = {50., 50., 50., 50., 50.}; init_level = 500.; capacity = 1000.; - // 1. Algorithm tends to flatten G + H, so it would require H to increase. - auto [new_H1, new_D1, L] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + // 1. Algorithm tends to flatten ThermalGen + HydroGen, so it would require HydroGen to + // increase. + auto [new_H1, new_D1, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, 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, + // 2. But HydroGen is low bounded by HydroPmin. So Algo does nothing in the end. + HydroPmin = {20., 20., 20., 20., 20.}; + auto [new_H2, new_D2, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); std::vector expected_H2 = {20., 20., 20., 20., 20.}; @@ -294,22 +358,22 @@ BOOST_FIXTURE_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_compu InputFixture<5>) { init_level = 500.; - std::ranges::fill(ovf, 25.); // Cause levels to decrease - std::ranges::fill(H, 20.); // Cause levels to decrease - std::ranges::fill(inflows, 15.); // Cause levels to increase - std::ranges::fill(pump, 10.); // Cause levels to increase - - auto [new_H, new_D, levels] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + std::ranges::fill(ovf, 25.); // Cause levels to decrease + std::ranges::fill(HydroGen, 20.); // Cause levels to decrease + std::ranges::fill(inflows, 15.); // Cause levels to increase + std::ranges::fill(pump, 10.); // Cause levels to increase + + auto [new_H, new_D, levels] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); std::vector expected_levels = {480., 460., 440., 420., 400.}; @@ -320,13 +384,24 @@ BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised, { init_level = 500.; capacity = 550.; - std::ranges::fill(ovf, 15); // Cause levels to decrease - std::ranges::fill(H, 10); // Cause levels to decrease - std::ranges::fill(inflows, 25); // Cause levels to increase - std::ranges::fill(pump, 20); // Cause levels to increase + std::ranges::fill(ovf, 15); // Cause levels to decrease + std::ranges::fill(HydroGen, 10); // Cause levels to decrease + std::ranges::fill(inflows, 25); // Cause levels to increase + std::ranges::fill(pump, 20); // Cause levels to increase BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage( "Remix hydro input : levels computed from input don't respect reservoir bounds")); @@ -335,13 +410,24 @@ BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised, BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised, InputFixture<5>) { init_level = 50.; - std::ranges::fill(ovf, 30); // Cause levels to decrease - std::ranges::fill(H, 10); // Cause levels to decrease - std::ranges::fill(inflows, 5); // Cause levels to increase - std::ranges::fill(pump, 10); // Cause levels to increase + std::ranges::fill(ovf, 30); // Cause levels to decrease + std::ranges::fill(HydroGen, 10); // Cause levels to decrease + std::ranges::fill(inflows, 5); // Cause levels to increase + std::ranges::fill(pump, 10); // Cause levels to increase BOOST_CHECK_EXCEPTION( - new_remix_hydro(G, H, D, P_max, P_min, init_level, capacity, inflows, ovf, pump, S, DTG_MRG), + new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage( "Remix hydro input : levels computed from input don't respect reservoir bounds")); @@ -351,51 +437,54 @@ BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influ InputFixture<10>, *boost::unit_test::tolerance(0.001)) { - std::ranges::fill(D, 20); // Not important for this test + std::ranges::fill(UnsupE, 20); // Not important for this test - // H oscillates between 10 and 20 (new H will be flattened to 15 everywhere) - H = {10., 20., 10., 20., 10., 20., 10., 20., 10., 20.}; - // First inflows > H, then inflows < H. Consequence : levels first increase, then decrease. + // HydroGen oscillates between 10 and 20 (new HydroGen will be flattened to 15 everywhere) + HydroGen = {10., 20., 10., 20., 10., 20., 10., 20., 10., 20.}; + // First inflows > HydroGen, then inflows < HydroGen. Consequence : levels first increase, then + // decrease. inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; init_level = 100.; - // H and inflows result in : input_levels = {115, 120, 135, 140, 155, 140, 135, 120, 115, 100} - // Note sup(input_levels) = 155 - - // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (H is flat) - auto [new_H, new_D, L] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + // HydroGen and inflows result in : input_levels = {115, 120, 135, 140, 155, 140, 135, 120, 115, + // 100} Note sup(input_levels) = 155 + + // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is + // flat) + auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); - std::vector expected_H(10, 15.); // H is flat and is 15. (means of initial H) - // Levels associated to new H are such as sup(L) = 150. < sup(input_levels) = 155 + std::vector expected_H(10, + 15.); // HydroGen is flat and is 15. (means of initial HydroGen) + // Levels associated to new HydroGen are such as sup(L) = 150. < sup(input_levels) = 155 std::vector expected_L = {110., 120., 130., 140., 150., 140., 130., 120., 110., 100.}; BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); // Case 2 : now, if we lower capacity to sup(input_levels) = 155, we should - // have H and L identical to previously : this value of capacity should - // not have an influence on H and levels as results of the algorithm. + // have HydroGen and L identical to previously : this value of capacity should + // not have an influence on HydroGen and levels as results of the algorithm. capacity = 155.; - auto [new_H2, new_D2, L2] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + auto [new_H2, new_D2, L2] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); BOOST_TEST(new_H2 == expected_H, boost::test_tools::per_element()); @@ -406,33 +495,36 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f InputFixture<10>, *boost::unit_test::tolerance(0.001)) { - std::ranges::fill(D, 20); // Not important for this test + std::ranges::fill(UnsupE, 20); // Not important for this test - // H oscillates between 10 and 20 (new H will be flattened to 15 everywhere) - H = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; - // First inflows > H, then inflows < H. Consequence : levels first increase, then decrease. + // HydroGen oscillates between 10 and 20 (new HydroGen will be flattened to 15 everywhere) + HydroGen = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; + // First inflows > HydroGen, then inflows < HydroGen. Consequence : levels first increase, then + // decrease. inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; init_level = 100.; - // H and inflows lead to have : + // HydroGen and inflows lead to have : // input_levels = {105, 120, 125, 140, 145, 140, 125, 120, 105,100} // Note sup(input_levels) = 145 - // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (H is flat) - auto [new_H, new_D, L] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is + // flat) + auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); - std::vector expected_H(10, 15.); // H is flat and is 15. (means of initial H) - // Levels associated to new H are such as sup(L) = 150. > sup(input_levels) = 145 + std::vector expected_H(10, + 15.); // HydroGen is flat and is 15. (means of initial HydroGen) + // Levels associated to new HydroGen are such as sup(L) = 150. > sup(input_levels) = 145 std::vector expected_L = {110., 120., 130., 140., 150., 140., 130., 120., 110., 100.}; BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); @@ -442,19 +534,19 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f // up bound <= capacity // But this time levels can not increase up to sup(L) = 150., as it would if capacity // was infinite. Therefore, solution found is suboptimal : we expect to get an - // output H flat by interval, not flat on the whole domain. + // output HydroGen flat by interval, not flat on the whole domain. capacity = 145.; - auto [new_H2, new_D2, L2] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + auto [new_H2, new_D2, L2] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); // new_H2 is flat by interval @@ -466,35 +558,37 @@ BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solut InputFixture<10>, *boost::unit_test::tolerance(0.001)) { - std::ranges::fill(D, 20); // Not important for this test + std::ranges::fill(UnsupE, 20); // Not important for this test - // H oscillates between 20 and 30 (new H will be flattened to 25 everywhere) - H = {20., 30., 20., 30., 20., 30., 20., 30., 20., 30.}; - // First inflows < H, then inflows > H. Consequence : levels first decrease, then increase. + // HydroGen oscillates between 20 and 30 (new HydroGen will be flattened to 25 everywhere) + HydroGen = {20., 30., 20., 30., 20., 30., 20., 30., 20., 30.}; + // First inflows < HydroGen, then inflows > HydroGen. Consequence : levels first decrease, then + // increase. inflows = {5., 5., 5., 5., 5., 45., 45., 45., 45., 45.}; capacity = std::numeric_limits::max(); init_level = 100.; - // H and inflows result in : input_levels = {85, 60, 45, 20, 5, 20, 45, 60, 85, 100} + // HydroGen and inflows result in : input_levels = {85, 60, 45, 20, 5, 20, 45, 60, 85, 100} // Note : inf(input_levels) = 5 // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable for algorithm (input levels >= 0.), and running algorithm leads to optimal // solution (new_H is flat) - auto [new_H, new_D, L] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); - std::vector expected_H(10, 25.); // H is flat and is 25. (means of initial H) - // Levels associated to new H are such as inf(L) = 0. > inf(input_levels) = 5 + std::vector expected_H(10, + 25.); // HydroGen is flat and is 25. (means of initial HydroGen) + // Levels associated to new HydroGen are such as inf(L) = 0. > inf(input_levels) = 5 std::vector expected_L = {80., 60., 40., 20., 0., 20., 40., 60., 80., 100.}; BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); @@ -504,17 +598,17 @@ BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solut // bound (0.) into account. As the levels change, the solution new_H will be suboptimal, that is // flat by interval (not flat on the whole domain). init_level = 95.; - auto [new_H2, new_D2, L2] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + auto [new_H2, new_D2, L2] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); // new_H2 is flat by interval @@ -526,33 +620,35 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ InputFixture<10>, *boost::unit_test::tolerance(0.001)) { - std::ranges::fill(D, 20); // Not important for this test + std::ranges::fill(UnsupE, 20); // Not important for this test - // H oscillates between 10 and 20 (new H will be flattened to 15 everywhere) - H = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; - // First inflows < H, then inflows > H. Consequence : levels first decrease, then increase. + // HydroGen oscillates between 10 and 20 (new HydroGen will be flattened to 15 everywhere) + HydroGen = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; + // First inflows < HydroGen, then inflows > HydroGen. Consequence : levels first decrease, then + // increase. inflows = {5., 5., 5., 5., 5., 25., 25., 25., 25., 25.}; init_level = 100.; - // H and inflows are such as inf(input_levels) = 45 + // HydroGen and inflows are such as inf(input_levels) = 45 // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable by algorithm, and levels computed by algorithm (output) are optimal, that // is computed from a optimal (that is flat) new_H. - auto [new_H, new_D, L] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); - std::vector expected_H(10, 15.); // H is flat and is 15. (means of initial H) - // Levels associated to new H are such as inf(L) = 50 > inf(input_levels) = 45 + std::vector expected_H(10, + 15.); // HydroGen is flat and is 15. (means of initial HydroGen) + // Levels associated to new HydroGen are such as inf(L) = 50 > inf(input_levels) = 45 std::vector expected_L = {90., 80., 70., 60., 50., 60., 70., 80., 90., 100.}; BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); @@ -562,17 +658,17 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ // and algorithm won't have to take the levels lower bound (0.) into account. // The solution new_H will be optimal, that is flat by interval. init_level = 55.; - auto [new_H2, new_D2, L2] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + auto [new_H2, new_D2, L2] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); // new_H2 is flat (and optimal) @@ -582,27 +678,27 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, InputFixture<5>) { - std::ranges::fill(G, 100.); - H = {40., 30., 20., 10., 0.}; - D = {0., 20., 40., 60., 80.}; + std::ranges::fill(ThermalGen, 100.); + HydroGen = {40., 30., 20., 10., 0.}; + UnsupE = {0., 20., 40., 60., 80.}; init_level = 500.; capacity = 1000.; // At this stage, DTG_MRG is filled with zeros. Running the algorithm would flatten - // H to 20 everywhere : H = {20, 20, 20, 20, 20} + // HydroGen to 20 everywhere : HydroGen = {20, 20, 20, 20, 20} // But : - S[0] = 1.; - // Now, we expect no change for H at hour 0 - auto [new_H, __, _] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + Spillage[0] = 1.; + // Now, we expect no change for HydroGen at hour 0 + auto [new_H, __, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); std::vector expected_H = {40., 15., 15., 15., 15.}; @@ -611,27 +707,27 @@ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, In BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, InputFixture<5>) { - std::ranges::fill(G, 100.); - H = {40., 30., 20., 10., 0.}; - D = {0., 20., 40., 60., 80.}; + std::ranges::fill(ThermalGen, 100.); + HydroGen = {40., 30., 20., 10., 0.}; + UnsupE = {0., 20., 40., 60., 80.}; init_level = 500.; capacity = 1000.; // At this stage, DTG_MRG is filled with zeros. Running the algorithm would flatten - // H to 20 everywhere : H = {20, 20, 20, 20, 20} + // HydroGen to 20 everywhere : HydroGen = {20, 20, 20, 20, 20} // But : DTG_MRG[4] = 1.; - // Now, we expect no change for H at hour 4 - auto [new_H, new_D, L] = new_remix_hydro(G, - H, - D, - P_max, - P_min, + // Now, we expect no change for HydroGen at hour 4 + auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, init_level, capacity, inflows, ovf, pump, - S, + Spillage, DTG_MRG); std::vector expected_H = {25., 25., 25., 25., 0.}; @@ -642,8 +738,9 @@ BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, Inp // ================================ // - 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) -// - 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) +// - After running remix hydro algo, sum(HydroGen), sum(HydroGen + UnsupE) must remain the same. +// - influence of UnsupE : low values of ThermalGen + HydroGen are searched where UnsupE > 0 (not +// where UnsupE == 0) // - // Possible simplifications / clarifications of the algorithm itself : From 237940eac3151b1bf870ac64ceea9f44e55ac60f Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Mon, 6 Jan 2025 15:02:11 +0100 Subject: [PATCH 31/44] New hydro remix : unit tests - renaming algorithm input data (part 2) --- .../solver/simulation/test-hydro-remix.cpp | 600 +++++++++--------- 1 file changed, 302 insertions(+), 298 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 43864313fc..43cc6c1a33 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -98,7 +98,7 @@ BOOST_FIXTURE_TEST_CASE(all_input_arrays_of_size_0__exception_raised, InputFixtu checkMessage("Remix hydro input : all arrays of sizes 0")); } -BOOST_FIXTURE_TEST_CASE(H_not_smaller_than_pmax__exception_raised, InputFixture<5>) +BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_smaller_than_pmax__exception_raised, InputFixture<5>) { HydroGen = {1., 2., 3., 4., 5.}; HydroPmax = {2., 2., 2., 4., 5.}; @@ -122,7 +122,7 @@ BOOST_FIXTURE_TEST_CASE(H_not_smaller_than_pmax__exception_raised, InputFixture< checkMessage("Remix hydro input : Hydro generation not smaller than Pmax everywhere")); } -BOOST_FIXTURE_TEST_CASE(H_not_greater_than_pmin__exception_raised, InputFixture<5>) +BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_greater_than_pmin__exception_raised, InputFixture<5>) { HydroGen = {1., 2., 3., 4., 5.}; HydroPmin = {0., 0., 4., 0., 0.}; @@ -165,8 +165,9 @@ BOOST_FIXTURE_TEST_CASE(input_is_acceptable__no_exception_raised, InputFixture<1 DTG_MRG)); } -BOOST_FIXTURE_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh, - InputFixture<5>) +BOOST_FIXTURE_TEST_CASE( + hydro_increases_and_pmax_40mwh___Hydro_gen_is_flattened_to_mean_Hydro_gen_20mwh, + InputFixture<5>) { std::ranges::fill(HydroPmax, 40.); std::ranges::fill(ThermalGen, 100.); @@ -175,24 +176,24 @@ BOOST_FIXTURE_TEST_CASE(hydro_increases_and_pmax_40mwh___H_is_flattened_to_mean_ init_level = 500.; capacity = 1000.; - auto [new_H, new_D, _] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H = {20., 20., 20., 20., 20.}; + auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; // UnsupE such as ThermalGen + HydroGen + UnsupE remains flat - std::vector expected_D = {60., 50., 40., 30., 20.}; - BOOST_CHECK(new_H == expected_H); - BOOST_CHECK(new_D == expected_D); + std::vector expected_UnsupE = {60., 50., 40., 30., 20.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); + BOOST_CHECK(OutUnsupE == expected_UnsupE); } BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, InputFixture<5>) @@ -204,28 +205,29 @@ BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, In init_level = 500.; capacity = 1000.; - auto [new_H, new_D, _] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H = {20., 20., 20., 20., 20.}; + auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; // UnsupE such as ThermalGen + HydroGen + UnsupE remains constant at each hour - std::vector expected_D = {60., 50., 40., 30., 20.}; - BOOST_CHECK(new_H == expected_H); - BOOST_CHECK(new_D == expected_D); + std::vector expected_UnsupE = {60., 50., 40., 30., 20.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); + BOOST_CHECK(OutUnsupE == expected_UnsupE); } -BOOST_FIXTURE_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_H_20mwh, - InputFixture<5>) +BOOST_FIXTURE_TEST_CASE( + hydro_decreases_and_pmax_40mwh___Hydro_gen_is_flattened_to_mean_Hydro_gen_20mwh, + InputFixture<5>) { std::ranges::fill(HydroPmax, 40.); std::ranges::fill(ThermalGen, 100.); @@ -234,24 +236,24 @@ BOOST_FIXTURE_TEST_CASE(hydro_decreases_and_pmax_40mwh___H_is_flattened_to_mean_ init_level = 500.; capacity = 1000.; - auto [new_H, new_D, _] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H = {20., 20., 20., 20., 20.}; + auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; // UnsupE such as ThermalGen + HydroGen + UnsupE remains constant at each hour - std::vector expected_D = {20., 30., 40., 50., 60.}; - BOOST_CHECK(new_H == expected_H); - BOOST_CHECK(new_D == expected_D); + std::vector expected_UnsupE = {20., 30., 40., 50., 60.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); + BOOST_CHECK(OutUnsupE == expected_UnsupE); } BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::tolerance(0.01)) @@ -267,42 +269,42 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t // 1. Algorithm tends to flatten ThermalGen + HydroGen, so it would require HydroGen to // increase. Proof : - auto [new_H1, new_D1, L] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - 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()); + auto [OutHydroGen_1, new_D1, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen_1 = {0., 0., 13.33, 33.33, 53.33}; + BOOST_TEST(OutHydroGen_1 == expected_HydroGen_1, boost::test_tools::per_element()); // 2. But HydroGen is limited by HydroPmax. So Algo does nothing in the end. // Proof : HydroPmax = {20., 20., 20., 20., 20.}; - auto [new_H2, new_D2, _] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H2 = {20., 20., 20., 20., 20.}; - std::vector expected_D2 = {50., 50., 50., 50., 50.}; - BOOST_CHECK(new_H2 == expected_H2); - BOOST_CHECK(new_D2 == expected_D2); + auto [OutHydroGen_2, OutUnsupE_2, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen_2 = {20., 20., 20., 20., 20.}; + std::vector expected_UnsupE_2 = {50., 50., 50., 50., 50.}; + BOOST_CHECK(OutHydroGen_2 == expected_HydroGen_2); + BOOST_CHECK(OutUnsupE_2 == expected_UnsupE_2); } BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::tolerance(0.01)) @@ -318,43 +320,43 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::t // 1. Algorithm tends to flatten ThermalGen + HydroGen, so it would require HydroGen to // increase. - auto [new_H1, new_D1, L] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - 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()); + auto [OutHydroGen_1, new_D1, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + std::vector expected_HydroGen_1 = {0., 0., 13.33, 33.33, 53.33}; + BOOST_TEST(OutHydroGen_1 == expected_HydroGen_1, boost::test_tools::per_element()); // 2. But HydroGen is low bounded by HydroPmin. So Algo does nothing in the end. HydroPmin = {20., 20., 20., 20., 20.}; - auto [new_H2, new_D2, _] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H2 = {20., 20., 20., 20., 20.}; - std::vector expected_D2 = {50., 50., 50., 50., 50.}; - BOOST_CHECK(new_H2 == expected_H2); - BOOST_CHECK(new_D2 == expected_D2); + auto [OutHydroGen_2, OutUnsupE_2, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen_2 = {20., 20., 20., 20., 20.}; + std::vector expected_UnsupE_2 = {50., 50., 50., 50., 50.}; + BOOST_CHECK(OutHydroGen_2 == expected_HydroGen_2); + BOOST_CHECK(OutUnsupE_2 == expected_UnsupE_2); } -BOOST_FIXTURE_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_computed, +BOOST_FIXTURE_TEST_CASE(Hydro_gen_is_already_flat___remix_is_useless__level_easily_computed, InputFixture<5>) { init_level = 500.; @@ -363,18 +365,18 @@ BOOST_FIXTURE_TEST_CASE(H_is_already_flat___remix_is_useless__level_easily_compu std::ranges::fill(inflows, 15.); // Cause levels to increase std::ranges::fill(pump, 10.); // Cause levels to increase - auto [new_H, new_D, levels] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, levels] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_levels = {480., 460., 440., 420., 400.}; BOOST_TEST(levels == expected_levels, boost::test_tools::per_element()); @@ -446,48 +448,49 @@ BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influ inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; init_level = 100.; // HydroGen and inflows result in : input_levels = {115, 120, 135, 140, 155, 140, 135, 120, 115, - // 100} Note sup(input_levels) = 155 + // 100} + // Note that : sup(input_levels) = 155 // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is // flat) - auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H(10, - 15.); // HydroGen is flat and is 15. (means of initial HydroGen) + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // HydroGen is flat and is 15. (means of initial HydroGen) + std::vector expected_HydroGen(10, 15.); // Levels associated to new HydroGen are such as sup(L) = 150. < sup(input_levels) = 155 std::vector expected_L = {110., 120., 130., 140., 150., 140., 130., 120., 110., 100.}; - BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); // Case 2 : now, if we lower capacity to sup(input_levels) = 155, we should // have HydroGen and L identical to previously : this value of capacity should // not have an influence on HydroGen and levels as results of the algorithm. capacity = 155.; - auto [new_H2, new_D2, L2] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - BOOST_TEST(new_H2 == expected_H, boost::test_tools::per_element()); + auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + BOOST_TEST(OutHydroGen_2 == expected_HydroGen, boost::test_tools::per_element()); BOOST_TEST(L2 == expected_L, boost::test_tools::per_element()); } @@ -509,24 +512,24 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is // flat) - auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H(10, - 15.); // HydroGen is flat and is 15. (means of initial HydroGen) + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // HydroGen is flat and is 15. (means of initial HydroGen) + std::vector expected_HydroGen(10, 15.); // Levels associated to new HydroGen are such as sup(L) = 150. > sup(input_levels) = 145 std::vector expected_L = {110., 120., 130., 140., 150., 140., 130., 120., 110., 100.}; - BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); // Case 2 : we lower capacity to sup(input_levels) = 145. @@ -536,22 +539,22 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f // was infinite. Therefore, solution found is suboptimal : we expect to get an // output HydroGen flat by interval, not flat on the whole domain. capacity = 145.; - auto [new_H2, new_D2, L2] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - // new_H2 is flat by interval - std::vector expected_H2 = {16., 16., 16., 16., 16., 14., 14., 14., 14., 14.}; - BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); + auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // OutHydroGen_2 is flat by interval + std::vector expected_HydroGen_2 = {16., 16., 16., 16., 16., 14., 14., 14., 14., 14.}; + BOOST_TEST(OutHydroGen_2 == expected_HydroGen_2, boost::test_tools::per_element()); } BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution_for_GplusH, @@ -572,48 +575,48 @@ BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solut // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable for algorithm (input levels >= 0.), and running algorithm leads to optimal - // solution (new_H is flat) - auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H(10, - 25.); // HydroGen is flat and is 25. (means of initial HydroGen) + // solution (OutHydroGen is flat) + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // HydroGen is flat and is 25. (means of initial HydroGen) + std::vector expected_HydroGen(10, 25.); // Levels associated to new HydroGen are such as inf(L) = 0. > inf(input_levels) = 5 std::vector expected_L = {80., 60., 40., 20., 0., 20., 40., 60., 80., 100.}; - BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); // Case 2 : we lower initial level. Input data are still acceptable // for algorithm (despite the new init level), algorithm will have to take the levels lower - // bound (0.) into account. As the levels change, the solution new_H will be suboptimal, that is - // flat by interval (not flat on the whole domain). + // bound (0.) into account. As the levels change, the solution OutHydroGen will be suboptimal, + // that is flat by interval (not flat on the whole domain). init_level = 95.; - auto [new_H2, new_D2, L2] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - // new_H2 is flat by interval - std::vector expected_H2 = {24., 24., 24., 24., 24., 26., 26., 26., 26., 26.}; - BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); + auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // OutHydroGen_2 is flat by interval + std::vector expected_HydroGen_2 = {24., 24., 24., 24., 24., 26., 26., 26., 26., 26.}; + BOOST_TEST(OutHydroGen_2 == expected_HydroGen_2, boost::test_tools::per_element()); } BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_influence, @@ -632,48 +635,48 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable by algorithm, and levels computed by algorithm (output) are optimal, that - // is computed from a optimal (that is flat) new_H. - auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H(10, - 15.); // HydroGen is flat and is 15. (means of initial HydroGen) + // is computed from a optimal (that is flat) OutHydroGen. + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // HydroGen is flat and is 15. (means of initial HydroGen) + std::vector expected_HydroGen(10, 15.); // Levels associated to new HydroGen are such as inf(L) = 50 > inf(input_levels) = 45 std::vector expected_L = {90., 80., 70., 60., 50., 60., 70., 80., 90., 100.}; - BOOST_TEST(new_H == expected_H, boost::test_tools::per_element()); + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); BOOST_TEST(L == expected_L, boost::test_tools::per_element()); // Case 2 : now we lower initial level down to 55. // In this way, input data is still acceptable for algorithm // and algorithm won't have to take the levels lower bound (0.) into account. - // The solution new_H will be optimal, that is flat by interval. + // The solution OutHydroGen will be optimal, that is flat by interval. init_level = 55.; - auto [new_H2, new_D2, L2] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - // new_H2 is flat (and optimal) - std::vector expected_H2(10, 15.); - BOOST_TEST(new_H2 == expected_H2, boost::test_tools::per_element()); + auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // OutHydroGen_2 is flat (and optimal) + std::vector expected_HydroGen_2(10, 15.); + BOOST_TEST(OutHydroGen_2 == expected_HydroGen_2, boost::test_tools::per_element()); } BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, InputFixture<5>) @@ -688,21 +691,21 @@ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, In // But : Spillage[0] = 1.; // Now, we expect no change for HydroGen at hour 0 - auto [new_H, __, _] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, __, _] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); - std::vector expected_H = {40., 15., 15., 15., 15.}; - BOOST_CHECK(new_H == expected_H); + std::vector expected_HydroGen = {40., 15., 15., 15., 15.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); } BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, InputFixture<5>) @@ -717,21 +720,21 @@ BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, Inp // But : DTG_MRG[4] = 1.; // Now, we expect no change for HydroGen at hour 4 - auto [new_H, new_D, L] = new_remix_hydro(ThermalGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); - - std::vector expected_H = {25., 25., 25., 25., 0.}; - BOOST_CHECK(new_H == expected_H); + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen = {25., 25., 25., 25., 0.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); } // Ideas for building further tests : @@ -746,9 +749,10 @@ BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, Inp // Possible simplifications / clarifications of the algorithm itself : // - remove french from variable names // - the algo is flat, it's C (not C++), it should be divided in a small number of steps -// - max_pic is an up hydro production margin (H_up_mrg) -// - max_creux is a down hydro production margin (H_down_mrg) -// - an iter updates new_H : it's its main job. So new_D could be updated from new_H at the +// - max_pic is an up hydro production margin (Hydro_gen_up_mrg) +// - max_creux is a down hydro production margin (Hydro_gen_down_mrg) +// - an iter updates OutHydroGen : it's its main job. So OutUnsupE could be updated from OutHydroGen +// at the // end of an iteration, separately. // - they are 3 while loops. 2 loops should be enough (the iteration loop and -// another one simply updating new_H and new_D) +// another one simply updating OutHydroGen and OutUnsupE) From 8ce9f25bfc6bd17d0d4974551ebe2d01a0029d46 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 7 Jan 2025 15:19:59 +0100 Subject: [PATCH 32/44] New hydro remix : some more renaming --- src/solver/simulation/hydro-remix-new.cpp | 30 +++---- .../solver/simulation/hydro-remix-new.h | 16 ++-- .../solver/simulation/test-hydro-remix.cpp | 86 +++++++++---------- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 5abcf36e3f..9a1c9cac21 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -75,7 +75,7 @@ static bool operator>=(const std::vector& v, const double c) return std::ranges::all_of(v, [&c](const double& e) { return e >= c; }); } -static void checkInputCorrectness(const std::vector& ThermalGen, +static void checkInputCorrectness(const std::vector& DispatchGen, const std::vector& HydroGen, const std::vector& UnsupE, const std::vector& levels, @@ -97,7 +97,7 @@ static void checkInputCorrectness(const std::vector& ThermalGen, throw std::invalid_argument(msg_prefix + "initial level > reservoir capacity"); } // Arrays sizes must be identical - std::vector sizes = {ThermalGen.size(), + std::vector sizes = {DispatchGen.size(), HydroGen.size(), UnsupE.size(), levels.size(), @@ -115,7 +115,7 @@ static void checkInputCorrectness(const std::vector& ThermalGen, } // Arrays are of size 0 - if (!ThermalGen.size()) + if (!DispatchGen.size()) { throw std::invalid_argument(msg_prefix + "all arrays of sizes 0"); } @@ -141,7 +141,7 @@ static void checkInputCorrectness(const std::vector& ThermalGen, } } -RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, +RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, const std::vector& HydroGen, const std::vector& UnsupE, const std::vector& HydroPmax, @@ -154,7 +154,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, const std::vector& Spillage, const std::vector& DTG_MRG) { - std::vector levels(ThermalGen.size()); + std::vector levels(DispatchGen.size()); if (levels.size()) { levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - HydroGen[0]; @@ -164,7 +164,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, } } - checkInputCorrectness(ThermalGen, + checkInputCorrectness(DispatchGen, HydroGen, UnsupE, levels, @@ -183,11 +183,11 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, int loop = 1000; double eps = 1e-3; - double top = *std::max_element(ThermalGen.begin(), ThermalGen.end()) + double top = *std::max_element(DispatchGen.begin(), DispatchGen.end()) + *std::max_element(HydroGen.begin(), HydroGen.end()) + *std::max_element(UnsupE.begin(), UnsupE.end()) + 1; - std::vector filter_hours_remix(ThermalGen.size(), false); + std::vector filter_hours_remix(DispatchGen.size(), false); for (unsigned int h = 0; h < filter_hours_remix.size(); h++) { if (Spillage[h] + DTG_MRG[h] == 0. && HydroGen[h] + UnsupE[h] > 0.) @@ -196,16 +196,16 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, } } - std::vector Thermal_plus_Hydro(ThermalGen.size()); - std::transform(ThermalGen.begin(), - ThermalGen.end(), + std::vector Thermal_plus_Hydro(DispatchGen.size()); + std::transform(DispatchGen.begin(), + DispatchGen.end(), OutHydroGen.begin(), Thermal_plus_Hydro.begin(), std::plus<>()); while (loop-- > 0) { - std::vector tried_creux(ThermalGen.size(), 0); + std::vector tried_creux(DispatchGen.size(), 0); double delta = 0; while (true) @@ -222,7 +222,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, break; } - std::vector tried_pic(ThermalGen.size(), 0); + std::vector tried_pic(DispatchGen.size(), 0); while (true) { int idx_pic = find_max_index(Thermal_plus_Hydro, @@ -293,8 +293,8 @@ RemixHydroOutput new_remix_hydro(const std::vector& ThermalGen, break; } - std::transform(ThermalGen.begin(), - ThermalGen.end(), + std::transform(DispatchGen.begin(), + DispatchGen.end(), OutHydroGen.begin(), Thermal_plus_Hydro.begin(), std::plus<>()); diff --git a/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h b/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h index f621d90628..fc98ca5bac 100644 --- a/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h +++ b/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h @@ -8,22 +8,22 @@ namespace Antares::Solver::Simulation struct RemixHydroOutput { - std::vector new_H; - std::vector new_D; + std::vector HydroGen; + std::vector UnsupE; 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, +RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, + const std::vector& HydroGen, + const std::vector& UnsupE, + const std::vector& HydroPmax, + const std::vector& HydroPmin, double init_level, double capacity, const std::vector& inflow, const std::vector& overflow, const std::vector& pump, - const std::vector& S, + const std::vector& Spillage, const std::vector& DTG_MRG); } // 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 43cc6c1a33..5f75db95f3 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -17,7 +17,7 @@ struct InputFixture { InputFixture() { - ThermalGen.assign(size, 0.); + DispatchGen.assign(size, 0.); HydroGen.assign(size, 0.); UnsupE.assign(size, 0.); HydroPmax.assign(size, std::numeric_limits::max()); @@ -29,7 +29,7 @@ struct InputFixture DTG_MRG.assign(size, 0.); } - std::vector ThermalGen, HydroGen, UnsupE, HydroPmax, HydroPmin, inflows, ovf, pump, + std::vector DispatchGen, HydroGen, UnsupE, HydroPmax, HydroPmin, inflows, ovf, pump, Spillage, DTG_MRG; double init_level = 0.; double capacity = std::numeric_limits::max(); @@ -39,7 +39,7 @@ BOOST_FIXTURE_TEST_CASE(input_vectors_of_different_sizes__exception_raised, Inpu { HydroGen = {0., 0.}; - BOOST_CHECK_EXCEPTION(new_remix_hydro(ThermalGen, + BOOST_CHECK_EXCEPTION(new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -61,7 +61,7 @@ BOOST_FIXTURE_TEST_CASE(input_init_level_exceeds_capacity__exception_raised, Inp init_level = 2.; capacity = 1.; - BOOST_CHECK_EXCEPTION(new_remix_hydro(ThermalGen, + BOOST_CHECK_EXCEPTION(new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -82,7 +82,7 @@ BOOST_FIXTURE_TEST_CASE(all_input_arrays_of_size_0__exception_raised, InputFixtu init_level = 0.; capacity = 1.; - BOOST_CHECK_EXCEPTION(new_remix_hydro(ThermalGen, + BOOST_CHECK_EXCEPTION(new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -106,7 +106,7 @@ BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_smaller_than_pmax__exception_raised, Input capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(ThermalGen, + new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -130,7 +130,7 @@ BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_greater_than_pmin__exception_raised, Input capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(ThermalGen, + new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -151,7 +151,7 @@ BOOST_FIXTURE_TEST_CASE(input_is_acceptable__no_exception_raised, InputFixture<1 init_level = 0.; capacity = 1.; - BOOST_CHECK_NO_THROW(new_remix_hydro(ThermalGen, + BOOST_CHECK_NO_THROW(new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -170,13 +170,13 @@ BOOST_FIXTURE_TEST_CASE( InputFixture<5>) { std::ranges::fill(HydroPmax, 40.); - std::ranges::fill(ThermalGen, 100.); + std::ranges::fill(DispatchGen, 100.); HydroGen = {0., 10., 20., 30., 40.}; // we have Pmin <= HydroGen <= Pmax UnsupE = {80.0, 60., 40., 20., 0.}; init_level = 500.; capacity = 1000.; - auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -190,7 +190,7 @@ BOOST_FIXTURE_TEST_CASE( DTG_MRG); std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; - // UnsupE such as ThermalGen + HydroGen + UnsupE remains flat + // UnsupE such as DispatchGen + HydroGen + UnsupE remains flat std::vector expected_UnsupE = {60., 50., 40., 30., 20.}; BOOST_CHECK(OutHydroGen == expected_HydroGen); BOOST_CHECK(OutUnsupE == expected_UnsupE); @@ -199,13 +199,13 @@ BOOST_FIXTURE_TEST_CASE( BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, InputFixture<5>) { std::ranges::fill(HydroPmax, 50.); - std::ranges::fill(ThermalGen, 100.); + std::ranges::fill(DispatchGen, 100.); HydroGen = {0., 10., 20., 30., 40.}; UnsupE = {80.0, 60., 40., 20., 0.}; init_level = 500.; capacity = 1000.; - auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -219,7 +219,7 @@ BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, In DTG_MRG); std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; - // UnsupE such as ThermalGen + HydroGen + UnsupE remains constant at each hour + // UnsupE such as DispatchGen + HydroGen + UnsupE remains constant at each hour std::vector expected_UnsupE = {60., 50., 40., 30., 20.}; BOOST_CHECK(OutHydroGen == expected_HydroGen); BOOST_CHECK(OutUnsupE == expected_UnsupE); @@ -230,13 +230,13 @@ BOOST_FIXTURE_TEST_CASE( InputFixture<5>) { std::ranges::fill(HydroPmax, 40.); - std::ranges::fill(ThermalGen, 100.); + std::ranges::fill(DispatchGen, 100.); HydroGen = {40., 30., 20., 10., 0.}; UnsupE = {0., 20., 40., 60., 80.}; init_level = 500.; capacity = 1000.; - auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -250,7 +250,7 @@ BOOST_FIXTURE_TEST_CASE( DTG_MRG); std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; - // UnsupE such as ThermalGen + HydroGen + UnsupE remains constant at each hour + // UnsupE such as DispatchGen + HydroGen + UnsupE remains constant at each hour std::vector expected_UnsupE = {20., 30., 40., 50., 60.}; BOOST_CHECK(OutHydroGen == expected_HydroGen); BOOST_CHECK(OutUnsupE == expected_UnsupE); @@ -258,8 +258,8 @@ BOOST_FIXTURE_TEST_CASE( BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::tolerance(0.01)) { - // ThermalGen decreases - ThermalGen = {100., 80., 60., 40., 20.}; + // DispatchGen decreases + DispatchGen = {100., 80., 60., 40., 20.}; // HydroGen is flat and must respect HydroGen <= Pmax everywhere HydroGen = {20., 20., 20., 20., 20.}; @@ -267,9 +267,9 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t init_level = 500.; capacity = 1000.; - // 1. Algorithm tends to flatten ThermalGen + HydroGen, so it would require HydroGen to + // 1. Algorithm tends to flatten DispatchGen + HydroGen, so it would require HydroGen to // increase. Proof : - auto [OutHydroGen_1, new_D1, L] = new_remix_hydro(ThermalGen, + auto [OutHydroGen_1, new_D1, L] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -288,7 +288,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t // 2. But HydroGen is limited by HydroPmax. So Algo does nothing in the end. // Proof : HydroPmax = {20., 20., 20., 20., 20.}; - auto [OutHydroGen_2, OutUnsupE_2, _] = new_remix_hydro(ThermalGen, + auto [OutHydroGen_2, OutUnsupE_2, _] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -309,8 +309,8 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::tolerance(0.01)) { - // ThermalGen decreases - ThermalGen = {100., 80., 60., 40., 20.}; + // DispatchGen decreases + DispatchGen = {100., 80., 60., 40., 20.}; // HydroGen is flat and must respect Pmin <= HydroGen <= Pmax everywhere HydroGen = {20., 20., 20., 20., 20.}; @@ -318,9 +318,9 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::t init_level = 500.; capacity = 1000.; - // 1. Algorithm tends to flatten ThermalGen + HydroGen, so it would require HydroGen to + // 1. Algorithm tends to flatten DispatchGen + HydroGen, so it would require HydroGen to // increase. - auto [OutHydroGen_1, new_D1, L] = new_remix_hydro(ThermalGen, + auto [OutHydroGen_1, new_D1, L] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -337,7 +337,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::t // 2. But HydroGen is low bounded by HydroPmin. So Algo does nothing in the end. HydroPmin = {20., 20., 20., 20., 20.}; - auto [OutHydroGen_2, OutUnsupE_2, _] = new_remix_hydro(ThermalGen, + auto [OutHydroGen_2, OutUnsupE_2, _] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -365,7 +365,7 @@ BOOST_FIXTURE_TEST_CASE(Hydro_gen_is_already_flat___remix_is_useless__level_easi std::ranges::fill(inflows, 15.); // Cause levels to increase std::ranges::fill(pump, 10.); // Cause levels to increase - auto [OutHydroGen, OutUnsupE, levels] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, OutUnsupE, levels] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -392,7 +392,7 @@ BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised, std::ranges::fill(pump, 20); // Cause levels to increase BOOST_CHECK_EXCEPTION( - new_remix_hydro(ThermalGen, + new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -418,7 +418,7 @@ BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised, std::ranges::fill(pump, 10); // Cause levels to increase BOOST_CHECK_EXCEPTION( - new_remix_hydro(ThermalGen, + new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -453,7 +453,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influ // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is // flat) - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -477,7 +477,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influ // have HydroGen and L identical to previously : this value of capacity should // not have an influence on HydroGen and levels as results of the algorithm. capacity = 155.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(ThermalGen, + auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -512,7 +512,7 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is // flat) - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -539,7 +539,7 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f // was infinite. Therefore, solution found is suboptimal : we expect to get an // output HydroGen flat by interval, not flat on the whole domain. capacity = 145.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(ThermalGen, + auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -576,7 +576,7 @@ BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solut // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable for algorithm (input levels >= 0.), and running algorithm leads to optimal // solution (OutHydroGen is flat) - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -601,7 +601,7 @@ BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solut // bound (0.) into account. As the levels change, the solution OutHydroGen will be suboptimal, // that is flat by interval (not flat on the whole domain). init_level = 95.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(ThermalGen, + auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -636,7 +636,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable by algorithm, and levels computed by algorithm (output) are optimal, that // is computed from a optimal (that is flat) OutHydroGen. - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -661,7 +661,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ // and algorithm won't have to take the levels lower bound (0.) into account. // The solution OutHydroGen will be optimal, that is flat by interval. init_level = 55.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(ThermalGen, + auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -681,7 +681,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, InputFixture<5>) { - std::ranges::fill(ThermalGen, 100.); + std::ranges::fill(DispatchGen, 100.); HydroGen = {40., 30., 20., 10., 0.}; UnsupE = {0., 20., 40., 60., 80.}; init_level = 500.; @@ -691,7 +691,7 @@ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, In // But : Spillage[0] = 1.; // Now, we expect no change for HydroGen at hour 0 - auto [OutHydroGen, __, _] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, __, _] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -710,7 +710,7 @@ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, In BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, InputFixture<5>) { - std::ranges::fill(ThermalGen, 100.); + std::ranges::fill(DispatchGen, 100.); HydroGen = {40., 30., 20., 10., 0.}; UnsupE = {0., 20., 40., 60., 80.}; init_level = 500.; @@ -720,7 +720,7 @@ BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, Inp // But : DTG_MRG[4] = 1.; // Now, we expect no change for HydroGen at hour 4 - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(ThermalGen, + auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, HydroGen, UnsupE, HydroPmax, @@ -742,7 +742,7 @@ BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, Inp // - 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) // - After running remix hydro algo, sum(HydroGen), sum(HydroGen + UnsupE) must remain the same. -// - influence of UnsupE : low values of ThermalGen + HydroGen are searched where UnsupE > 0 (not +// - influence of UnsupE : low values of DispatchGen + HydroGen are searched where UnsupE > 0 (not // where UnsupE == 0) // - From 65102e21c960b6fc015ddc58960aed358c735079 Mon Sep 17 00:00:00 2001 From: Florian OMNES Date: Tue, 7 Jan 2025 15:48:00 +0100 Subject: [PATCH 33/44] fix vcpkg --- vcpkg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcpkg b/vcpkg index 9d47b24eac..b322364f06 160000 --- a/vcpkg +++ b/vcpkg @@ -1 +1 @@ -Subproject commit 9d47b24eacbd1cd94f139457ef6cd35e5d92cc84 +Subproject commit b322364f06308bdd24823f9d8f03fe0cc86fd46f From 41a811a833d6cdfa3184bae5ac126b2c44daa92b Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 7 Jan 2025 16:22:41 +0100 Subject: [PATCH 34/44] New hydro remix : more renaming --- src/solver/simulation/hydro-remix-new.cpp | 36 +++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 9a1c9cac21..43713577c9 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -8,7 +8,7 @@ namespace Antares::Solver::Simulation { -int find_min_index(const std::vector& Thermal_plus_Hydro, +int find_min_index(const std::vector& TotalGen, const std::vector& OutUnsupE, const std::vector& OutHydroGen, const std::vector& tried_creux, @@ -18,14 +18,14 @@ int find_min_index(const std::vector& Thermal_plus_Hydro, { double min_val = top; int min_idx = -1; - for (int i = 0; i < Thermal_plus_Hydro.size(); ++i) + for (int i = 0; i < TotalGen.size(); ++i) { if (OutUnsupE[i] > 0 && OutHydroGen[i] < HydroPmax[i] && tried_creux[i] == 0 && filter_hours_remix[i]) { - if (Thermal_plus_Hydro[i] < min_val) + if (TotalGen[i] < min_val) { - min_val = Thermal_plus_Hydro[i]; + min_val = TotalGen[i]; min_idx = i; } } @@ -33,7 +33,7 @@ int find_min_index(const std::vector& Thermal_plus_Hydro, return min_idx; } -int find_max_index(const std::vector& Thermal_plus_Hydro, +int find_max_index(const std::vector& TotalGen, const std::vector& OutHydroGen, const std::vector& tried_pic, const std::vector& HydroPmin, @@ -43,14 +43,14 @@ int find_max_index(const std::vector& Thermal_plus_Hydro, { double max_val = 0; int max_idx = -1; - for (int i = 0; i < Thermal_plus_Hydro.size(); ++i) + for (int i = 0; i < TotalGen.size(); ++i) { - if (OutHydroGen[i] > HydroPmin[i] && Thermal_plus_Hydro[i] >= ref_value + eps - && tried_pic[i] == 0 && filter_hours_remix[i]) + if (OutHydroGen[i] > HydroPmin[i] && TotalGen[i] >= ref_value + eps && tried_pic[i] == 0 + && filter_hours_remix[i]) { - if (Thermal_plus_Hydro[i] > max_val) + if (TotalGen[i] > max_val) { - max_val = Thermal_plus_Hydro[i]; + max_val = TotalGen[i]; max_idx = i; } } @@ -196,11 +196,11 @@ RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, } } - std::vector Thermal_plus_Hydro(DispatchGen.size()); + std::vector TotalGen(DispatchGen.size()); std::transform(DispatchGen.begin(), DispatchGen.end(), OutHydroGen.begin(), - Thermal_plus_Hydro.begin(), + TotalGen.begin(), std::plus<>()); while (loop-- > 0) @@ -210,7 +210,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, while (true) { - int idx_creux = find_min_index(Thermal_plus_Hydro, + int idx_creux = find_min_index(TotalGen, OutUnsupE, OutHydroGen, tried_creux, @@ -225,12 +225,12 @@ RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, std::vector tried_pic(DispatchGen.size(), 0); while (true) { - int idx_pic = find_max_index(Thermal_plus_Hydro, + int idx_pic = find_max_index(TotalGen, OutHydroGen, tried_pic, HydroPmin, filter_hours_remix, - Thermal_plus_Hydro[idx_creux], + TotalGen[idx_creux], eps); if (idx_pic == -1) { @@ -260,9 +260,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, max_creux = std::min( {HydroPmax[idx_creux] - OutHydroGen[idx_creux], OutUnsupE[idx_creux], max_creux}); - double dif_pic_creux = std::max(Thermal_plus_Hydro[idx_pic] - - Thermal_plus_Hydro[idx_creux], - 0.); + double dif_pic_creux = std::max(TotalGen[idx_pic] - TotalGen[idx_creux], 0.); delta = std::max(std::min({max_pic, max_creux, dif_pic_creux / 2.}), 0.); @@ -296,7 +294,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, std::transform(DispatchGen.begin(), DispatchGen.end(), OutHydroGen.begin(), - Thermal_plus_Hydro.begin(), + TotalGen.begin(), std::plus<>()); levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - OutHydroGen[0]; for (size_t i = 1; i < levels.size(); ++i) From bd8d62dde2f35fe23dfa279d2b921559da38dd11 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 7 Jan 2025 16:26:26 +0100 Subject: [PATCH 35/44] New hydro remix : small correction on algorithm initialization --- src/solver/simulation/hydro-remix-new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index 43713577c9..e9e338a152 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -199,7 +199,7 @@ RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, std::vector TotalGen(DispatchGen.size()); std::transform(DispatchGen.begin(), DispatchGen.end(), - OutHydroGen.begin(), + HydroGen.begin(), TotalGen.begin(), std::plus<>()); From 511435a4f78a719d1981ff82c6eeb26e45ecaad3 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 7 Jan 2025 16:50:37 +0100 Subject: [PATCH 36/44] New hydro remix : renaming the algorithm itself --- src/solver/simulation/hydro-remix-new.cpp | 24 +- .../solver/simulation/hydro-remix-new.h | 24 +- .../solver/simulation/test-hydro-remix.cpp | 624 +++++++++--------- 3 files changed, 336 insertions(+), 336 deletions(-) diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/hydro-remix-new.cpp index e9e338a152..068d5362ae 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/hydro-remix-new.cpp @@ -141,18 +141,18 @@ static void checkInputCorrectness(const std::vector& DispatchGen, } } -RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, - const std::vector& HydroGen, - const std::vector& UnsupE, - const std::vector& HydroPmax, - const std::vector& HydroPmin, - double initial_level, - double capa, - const std::vector& inflows, - const std::vector& overflow, - const std::vector& pump, - const std::vector& Spillage, - const std::vector& DTG_MRG) +RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGen, + const std::vector& HydroGen, + const std::vector& UnsupE, + const std::vector& HydroPmax, + const std::vector& HydroPmin, + double initial_level, + double capa, + const std::vector& inflows, + const std::vector& overflow, + const std::vector& pump, + const std::vector& Spillage, + const std::vector& DTG_MRG) { std::vector levels(DispatchGen.size()); if (levels.size()) diff --git a/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h b/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h index fc98ca5bac..77ffbc67e8 100644 --- a/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h +++ b/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h @@ -13,17 +13,17 @@ struct RemixHydroOutput std::vector levels; }; -RemixHydroOutput new_remix_hydro(const std::vector& DispatchGen, - const std::vector& HydroGen, - const std::vector& UnsupE, - const std::vector& HydroPmax, - const std::vector& HydroPmin, - double init_level, - double capacity, - const std::vector& inflow, - const std::vector& overflow, - const std::vector& pump, - const std::vector& Spillage, - const std::vector& DTG_MRG); +RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGen, + const std::vector& HydroGen, + const std::vector& UnsupE, + const std::vector& HydroPmax, + const std::vector& HydroPmin, + double init_level, + double capacity, + const std::vector& inflow, + const std::vector& overflow, + const std::vector& pump, + const std::vector& Spillage, + const std::vector& DTG_MRG); } // 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 5f75db95f3..aa8bdae9fb 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -39,18 +39,18 @@ BOOST_FIXTURE_TEST_CASE(input_vectors_of_different_sizes__exception_raised, Inpu { HydroGen = {0., 0.}; - BOOST_CHECK_EXCEPTION(new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG), + BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : arrays of different sizes")); } @@ -61,18 +61,18 @@ BOOST_FIXTURE_TEST_CASE(input_init_level_exceeds_capacity__exception_raised, Inp init_level = 2.; capacity = 1.; - BOOST_CHECK_EXCEPTION(new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG), + BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : initial level > reservoir capacity")); } @@ -82,18 +82,18 @@ BOOST_FIXTURE_TEST_CASE(all_input_arrays_of_size_0__exception_raised, InputFixtu init_level = 0.; capacity = 1.; - BOOST_CHECK_EXCEPTION(new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG), + BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : all arrays of sizes 0")); } @@ -106,18 +106,18 @@ BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_smaller_than_pmax__exception_raised, Input capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG), + shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : Hydro generation not smaller than Pmax everywhere")); } @@ -130,18 +130,18 @@ BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_greater_than_pmin__exception_raised, Input capacity = 1.; BOOST_CHECK_EXCEPTION( - new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG), + shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage("Remix hydro input : Hydro generation not greater than Pmin everywhere")); } @@ -151,18 +151,18 @@ BOOST_FIXTURE_TEST_CASE(input_is_acceptable__no_exception_raised, InputFixture<1 init_level = 0.; capacity = 1.; - BOOST_CHECK_NO_THROW(new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG)); + BOOST_CHECK_NO_THROW(shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG)); } BOOST_FIXTURE_TEST_CASE( @@ -176,18 +176,18 @@ BOOST_FIXTURE_TEST_CASE( init_level = 500.; capacity = 1000.; - auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; // UnsupE such as DispatchGen + HydroGen + UnsupE remains flat @@ -205,18 +205,18 @@ BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, In init_level = 500.; capacity = 1000.; - auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; // UnsupE such as DispatchGen + HydroGen + UnsupE remains constant at each hour @@ -236,18 +236,18 @@ BOOST_FIXTURE_TEST_CASE( init_level = 500.; capacity = 1000.; - auto [OutHydroGen, OutUnsupE, _] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; // UnsupE such as DispatchGen + HydroGen + UnsupE remains constant at each hour @@ -269,18 +269,18 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t // 1. Algorithm tends to flatten DispatchGen + HydroGen, so it would require HydroGen to // increase. Proof : - auto [OutHydroGen_1, new_D1, L] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen_1, new_D1, L] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_HydroGen_1 = {0., 0., 13.33, 33.33, 53.33}; BOOST_TEST(OutHydroGen_1 == expected_HydroGen_1, boost::test_tools::per_element()); @@ -288,18 +288,18 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t // 2. But HydroGen is limited by HydroPmax. So Algo does nothing in the end. // Proof : HydroPmax = {20., 20., 20., 20., 20.}; - auto [OutHydroGen_2, OutUnsupE_2, _] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen_2, OutUnsupE_2, _] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_HydroGen_2 = {20., 20., 20., 20., 20.}; std::vector expected_UnsupE_2 = {50., 50., 50., 50., 50.}; @@ -320,35 +320,35 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::t // 1. Algorithm tends to flatten DispatchGen + HydroGen, so it would require HydroGen to // increase. - auto [OutHydroGen_1, new_D1, L] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen_1, new_D1, L] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_HydroGen_1 = {0., 0., 13.33, 33.33, 53.33}; BOOST_TEST(OutHydroGen_1 == expected_HydroGen_1, boost::test_tools::per_element()); // 2. But HydroGen is low bounded by HydroPmin. So Algo does nothing in the end. HydroPmin = {20., 20., 20., 20., 20.}; - auto [OutHydroGen_2, OutUnsupE_2, _] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen_2, OutUnsupE_2, _] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_HydroGen_2 = {20., 20., 20., 20., 20.}; std::vector expected_UnsupE_2 = {50., 50., 50., 50., 50.}; @@ -365,18 +365,18 @@ BOOST_FIXTURE_TEST_CASE(Hydro_gen_is_already_flat___remix_is_useless__level_easi std::ranges::fill(inflows, 15.); // Cause levels to increase std::ranges::fill(pump, 10.); // Cause levels to increase - auto [OutHydroGen, OutUnsupE, levels] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, levels] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_levels = {480., 460., 440., 420., 400.}; BOOST_TEST(levels == expected_levels, boost::test_tools::per_element()); @@ -392,18 +392,18 @@ BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised, std::ranges::fill(pump, 20); // Cause levels to increase BOOST_CHECK_EXCEPTION( - new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG), + shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage( "Remix hydro input : levels computed from input don't respect reservoir bounds")); @@ -418,18 +418,18 @@ BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised, std::ranges::fill(pump, 10); // Cause levels to increase BOOST_CHECK_EXCEPTION( - new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG), + shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), std::invalid_argument, checkMessage( "Remix hydro input : levels computed from input don't respect reservoir bounds")); @@ -453,18 +453,18 @@ BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influ // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is // flat) - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); // HydroGen is flat and is 15. (means of initial HydroGen) std::vector expected_HydroGen(10, 15.); @@ -477,18 +477,18 @@ BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influ // have HydroGen and L identical to previously : this value of capacity should // not have an influence on HydroGen and levels as results of the algorithm. capacity = 155.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); BOOST_TEST(OutHydroGen_2 == expected_HydroGen, boost::test_tools::per_element()); BOOST_TEST(L2 == expected_L, boost::test_tools::per_element()); @@ -512,18 +512,18 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is // flat) - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); // HydroGen is flat and is 15. (means of initial HydroGen) std::vector expected_HydroGen(10, 15.); @@ -539,18 +539,18 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f // was infinite. Therefore, solution found is suboptimal : we expect to get an // output HydroGen flat by interval, not flat on the whole domain. capacity = 145.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); // OutHydroGen_2 is flat by interval std::vector expected_HydroGen_2 = {16., 16., 16., 16., 16., 14., 14., 14., 14., 14.}; @@ -576,18 +576,18 @@ BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solut // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable for algorithm (input levels >= 0.), and running algorithm leads to optimal // solution (OutHydroGen is flat) - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); // HydroGen is flat and is 25. (means of initial HydroGen) std::vector expected_HydroGen(10, 25.); @@ -601,18 +601,18 @@ BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solut // bound (0.) into account. As the levels change, the solution OutHydroGen will be suboptimal, // that is flat by interval (not flat on the whole domain). init_level = 95.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); // OutHydroGen_2 is flat by interval std::vector expected_HydroGen_2 = {24., 24., 24., 24., 24., 26., 26., 26., 26., 26.}; @@ -636,18 +636,18 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable by algorithm, and levels computed by algorithm (output) are optimal, that // is computed from a optimal (that is flat) OutHydroGen. - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); // HydroGen is flat and is 15. (means of initial HydroGen) std::vector expected_HydroGen(10, 15.); @@ -661,18 +661,18 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ // and algorithm won't have to take the levels lower bound (0.) into account. // The solution OutHydroGen will be optimal, that is flat by interval. init_level = 55.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); // OutHydroGen_2 is flat (and optimal) std::vector expected_HydroGen_2(10, 15.); @@ -691,18 +691,18 @@ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, In // But : Spillage[0] = 1.; // Now, we expect no change for HydroGen at hour 0 - auto [OutHydroGen, __, _] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, __, _] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_HydroGen = {40., 15., 15., 15., 15.}; BOOST_CHECK(OutHydroGen == expected_HydroGen); @@ -720,18 +720,18 @@ BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, Inp // But : DTG_MRG[4] = 1.; // Now, we expect no change for HydroGen at hour 4 - auto [OutHydroGen, OutUnsupE, L] = new_remix_hydro(DispatchGen, - HydroGen, - UnsupE, - HydroPmax, - HydroPmin, - init_level, - capacity, - inflows, - ovf, - pump, - Spillage, - DTG_MRG); + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); std::vector expected_HydroGen = {25., 25., 25., 25., 0.}; BOOST_CHECK(OutHydroGen == expected_HydroGen); From 37bb2be24cb07c172acf094a548b838ca937b944 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 7 Jan 2025 17:37:46 +0100 Subject: [PATCH 37/44] New hydro remix : create a cmake target for remix hydro algorithm --- src/solver/simulation/CMakeLists.txt | 12 ++++++++++++ ...ydro-remix-new.h => shave-peaks-by-remix-hydro.h} | 0 ...-remix-new.cpp => shave-peaks-by-remix-hydro.cpp} | 2 +- src/tests/src/solver/simulation/CMakeLists.txt | 4 +--- src/tests/src/solver/simulation/test-hydro-remix.cpp | 2 +- 5 files changed, 15 insertions(+), 5 deletions(-) rename src/solver/simulation/include/antares/solver/simulation/{hydro-remix-new.h => shave-peaks-by-remix-hydro.h} (100%) rename src/solver/simulation/{hydro-remix-new.cpp => shave-peaks-by-remix-hydro.cpp} (99%) diff --git a/src/solver/simulation/CMakeLists.txt b/src/solver/simulation/CMakeLists.txt index 17e511fac5..a110adac4f 100644 --- a/src/solver/simulation/CMakeLists.txt +++ b/src/solver/simulation/CMakeLists.txt @@ -76,6 +76,18 @@ target_link_libraries(antares-solver-simulation antares-solver-ts-generator ) +# Remix hydro algorithm +add_library(shave-peaks-by-remix-hydro) + +target_sources(shave-peaks-by-remix-hydro + PRIVATE + shave-peaks-by-remix-hydro.cpp) + +target_include_directories(shave-peaks-by-remix-hydro + PUBLIC + $) + + install(DIRECTORY include/antares DESTINATION "include" ) diff --git a/src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h b/src/solver/simulation/include/antares/solver/simulation/shave-peaks-by-remix-hydro.h similarity index 100% rename from src/solver/simulation/include/antares/solver/simulation/hydro-remix-new.h rename to src/solver/simulation/include/antares/solver/simulation/shave-peaks-by-remix-hydro.h diff --git a/src/solver/simulation/hydro-remix-new.cpp b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp similarity index 99% rename from src/solver/simulation/hydro-remix-new.cpp rename to src/solver/simulation/shave-peaks-by-remix-hydro.cpp index 068d5362ae..4df755380b 100644 --- a/src/solver/simulation/hydro-remix-new.cpp +++ b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp @@ -1,4 +1,4 @@ -#include "include/antares/solver/simulation/hydro-remix-new.h" +#include "include/antares/solver/simulation/shave-peaks-by-remix-hydro.h" #include #include diff --git a/src/tests/src/solver/simulation/CMakeLists.txt b/src/tests/src/solver/simulation/CMakeLists.txt index d49b8164ae..e6ca5e7900 100644 --- a/src/tests/src/solver/simulation/CMakeLists.txt +++ b/src/tests/src/solver/simulation/CMakeLists.txt @@ -66,8 +66,6 @@ add_boost_test(test-hydro_final add_boost_test(tests-on-hydro-remix SRC test-hydro-remix.cpp - ${src_solver_simulation}/hydro-remix-new.cpp - INCLUDE - "${src_solver_simulation}" LIBS + shave-peaks-by-remix-hydro test_utils_unit) \ No newline at end of file diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index aa8bdae9fb..3ec2c6395c 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -8,7 +8,7 @@ #include -#include "include/antares/solver/simulation/hydro-remix-new.h" +#include "antares/solver/simulation/shave-peaks-by-remix-hydro.h" using namespace Antares::Solver::Simulation; From a4a68acee6db1220521e76f4aafdf0b733423ac4 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 7 Jan 2025 18:00:32 +0100 Subject: [PATCH 38/44] New hydro remix : renaming locally in algorithm --- .../simulation/shave-peaks-by-remix-hydro.cpp | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp index 4df755380b..fdf6a21e80 100644 --- a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp +++ b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp @@ -11,51 +11,51 @@ namespace Antares::Solver::Simulation int find_min_index(const std::vector& TotalGen, const std::vector& OutUnsupE, const std::vector& OutHydroGen, - const std::vector& tried_creux, + const std::vector& tried_creux, const std::vector& HydroPmax, const std::vector& filter_hours_remix, double top) { double min_val = top; - int min_idx = -1; - for (int i = 0; i < TotalGen.size(); ++i) + int min_hour = -1; + for (int h = 0; h < TotalGen.size(); ++h) { - if (OutUnsupE[i] > 0 && OutHydroGen[i] < HydroPmax[i] && tried_creux[i] == 0 - && filter_hours_remix[i]) + if (OutUnsupE[h] > 0 && OutHydroGen[h] < HydroPmax[h] && !tried_creux[h] + && filter_hours_remix[h]) { - if (TotalGen[i] < min_val) + if (TotalGen[h] < min_val) { - min_val = TotalGen[i]; - min_idx = i; + min_val = TotalGen[h]; + min_hour = h; } } } - return min_idx; + return min_hour; } int find_max_index(const std::vector& TotalGen, const std::vector& OutHydroGen, - const std::vector& tried_pic, + const std::vector& tried_pic, const std::vector& HydroPmin, const std::vector& filter_hours_remix, double ref_value, double eps) { double max_val = 0; - int max_idx = -1; - for (int i = 0; i < TotalGen.size(); ++i) + int max_hour = -1; + for (int h = 0; h < TotalGen.size(); ++h) { - if (OutHydroGen[i] > HydroPmin[i] && TotalGen[i] >= ref_value + eps && tried_pic[i] == 0 - && filter_hours_remix[i]) + if (OutHydroGen[h] > HydroPmin[h] && TotalGen[h] >= ref_value + eps && !tried_pic[h] + && filter_hours_remix[h]) { - if (TotalGen[i] > max_val) + if (TotalGen[h] > max_val) { - max_val = TotalGen[i]; - max_idx = i; + max_val = TotalGen[h]; + max_hour = h; } } } - return max_idx; + return max_hour; } static bool operator<=(const std::vector& a, const std::vector& b) @@ -158,9 +158,9 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe if (levels.size()) { levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - HydroGen[0]; - for (size_t i = 1; i < levels.size(); ++i) + for (size_t h = 1; h < levels.size(); ++h) { - levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - HydroGen[i]; + levels[h] = levels[h - 1] + inflows[h] - overflow[h] + pump[h] - HydroGen[h]; } } @@ -205,7 +205,7 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe while (loop-- > 0) { - std::vector tried_creux(DispatchGen.size(), 0); + std::vector tried_creux(DispatchGen.size(), false); double delta = 0; while (true) @@ -222,7 +222,7 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe break; } - std::vector tried_pic(DispatchGen.size(), 0); + std::vector tried_pic(DispatchGen.size(), false); while (true) { int idx_pic = find_max_index(TotalGen, @@ -275,7 +275,7 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe } else { - tried_pic[idx_pic] = 1; + tried_pic[idx_pic] = true; } } @@ -283,7 +283,7 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe { break; } - tried_creux[idx_creux] = 1; + tried_creux[idx_creux] = true; } if (delta == 0) @@ -297,9 +297,9 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe TotalGen.begin(), std::plus<>()); levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - OutHydroGen[0]; - for (size_t i = 1; i < levels.size(); ++i) + for (size_t h = 1; h < levels.size(); ++h) { - levels[i] = levels[i - 1] + inflows[i] - overflow[i] + pump[i] - OutHydroGen[i]; + levels[h] = levels[h - 1] + inflows[h] - overflow[h] + pump[h] - OutHydroGen[h]; } } return {OutHydroGen, OutUnsupE, levels}; From 2309099db4b00f4467d4ef63dcee611afcd66b45 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Tue, 7 Jan 2025 18:04:32 +0100 Subject: [PATCH 39/44] New hydro remix : more algorithm local renaming --- .../simulation/shave-peaks-by-remix-hydro.cpp | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp index fdf6a21e80..bba41f32cd 100644 --- a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp +++ b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp @@ -11,7 +11,7 @@ namespace Antares::Solver::Simulation int find_min_index(const std::vector& TotalGen, const std::vector& OutUnsupE, const std::vector& OutHydroGen, - const std::vector& tried_creux, + const std::vector& triedBottom, const std::vector& HydroPmax, const std::vector& filter_hours_remix, double top) @@ -20,7 +20,7 @@ int find_min_index(const std::vector& TotalGen, int min_hour = -1; for (int h = 0; h < TotalGen.size(); ++h) { - if (OutUnsupE[h] > 0 && OutHydroGen[h] < HydroPmax[h] && !tried_creux[h] + if (OutUnsupE[h] > 0 && OutHydroGen[h] < HydroPmax[h] && !triedBottom[h] && filter_hours_remix[h]) { if (TotalGen[h] < min_val) @@ -35,7 +35,7 @@ int find_min_index(const std::vector& TotalGen, int find_max_index(const std::vector& TotalGen, const std::vector& OutHydroGen, - const std::vector& tried_pic, + const std::vector& triedPeak, const std::vector& HydroPmin, const std::vector& filter_hours_remix, double ref_value, @@ -45,7 +45,7 @@ int find_max_index(const std::vector& TotalGen, int max_hour = -1; for (int h = 0; h < TotalGen.size(); ++h) { - if (OutHydroGen[h] > HydroPmin[h] && TotalGen[h] >= ref_value + eps && !tried_pic[h] + if (OutHydroGen[h] > HydroPmin[h] && TotalGen[h] >= ref_value + eps && !triedPeak[h] && filter_hours_remix[h]) { if (TotalGen[h] > max_val) @@ -205,44 +205,44 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe while (loop-- > 0) { - std::vector tried_creux(DispatchGen.size(), false); + std::vector triedBottom(DispatchGen.size(), false); double delta = 0; while (true) { - int idx_creux = find_min_index(TotalGen, - OutUnsupE, - OutHydroGen, - tried_creux, - HydroPmax, - filter_hours_remix, - top); - if (idx_creux == -1) + int hourBottom = find_min_index(TotalGen, + OutUnsupE, + OutHydroGen, + triedBottom, + HydroPmax, + filter_hours_remix, + top); + if (hourBottom == -1) { break; } - std::vector tried_pic(DispatchGen.size(), false); + std::vector triedPeak(DispatchGen.size(), false); while (true) { - int idx_pic = find_max_index(TotalGen, - OutHydroGen, - tried_pic, - HydroPmin, - filter_hours_remix, - TotalGen[idx_creux], - eps); - if (idx_pic == -1) + int hourPeak = find_max_index(TotalGen, + OutHydroGen, + triedPeak, + HydroPmin, + filter_hours_remix, + TotalGen[hourBottom], + eps); + if (hourPeak == -1) { break; } std::vector intermediate_level(levels.begin() - + std::min(idx_creux, idx_pic), + + std::min(hourBottom, hourPeak), levels.begin() - + std::max(idx_creux, idx_pic)); + + std::max(hourBottom, hourPeak)); double max_pic, max_creux; - if (idx_creux < idx_pic) + if (hourBottom < hourPeak) { max_pic = capa; max_creux = *std::min_element(intermediate_level.begin(), @@ -256,26 +256,28 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe max_creux = capa; } - max_pic = std::min(OutHydroGen[idx_pic] - HydroPmin[idx_pic], max_pic); - max_creux = std::min( - {HydroPmax[idx_creux] - OutHydroGen[idx_creux], OutUnsupE[idx_creux], max_creux}); + max_pic = std::min(OutHydroGen[hourPeak] - HydroPmin[hourPeak], max_pic); + max_creux = std::min({HydroPmax[hourBottom] - OutHydroGen[hourBottom], + OutUnsupE[hourBottom], + max_creux}); - double dif_pic_creux = std::max(TotalGen[idx_pic] - TotalGen[idx_creux], 0.); + double dif_pic_creux = std::max(TotalGen[hourPeak] - TotalGen[hourBottom], 0.); delta = std::max(std::min({max_pic, max_creux, dif_pic_creux / 2.}), 0.); if (delta > 0) { - OutHydroGen[idx_pic] -= delta; - OutHydroGen[idx_creux] += delta; - OutUnsupE[idx_pic] = HydroGen[idx_pic] + UnsupE[idx_pic] - OutHydroGen[idx_pic]; - OutUnsupE[idx_creux] = HydroGen[idx_creux] + UnsupE[idx_creux] - - OutHydroGen[idx_creux]; + OutHydroGen[hourPeak] -= delta; + OutHydroGen[hourBottom] += delta; + OutUnsupE[hourPeak] = HydroGen[hourPeak] + UnsupE[hourPeak] + - OutHydroGen[hourPeak]; + OutUnsupE[hourBottom] = HydroGen[hourBottom] + UnsupE[hourBottom] + - OutHydroGen[hourBottom]; break; } else { - tried_pic[idx_pic] = true; + triedPeak[hourPeak] = true; } } @@ -283,7 +285,7 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe { break; } - tried_creux[idx_creux] = true; + triedBottom[hourBottom] = true; } if (delta == 0) From 1e51fa2eb19c596973a32d0a0a9c6a7b9cc2fbd8 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Wed, 8 Jan 2025 10:28:11 +0100 Subject: [PATCH 40/44] New hydro remix : renaming --- .../simulation/shave-peaks-by-remix-hydro.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp index bba41f32cd..32ac60debb 100644 --- a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp +++ b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp @@ -13,15 +13,14 @@ int find_min_index(const std::vector& TotalGen, const std::vector& OutHydroGen, const std::vector& triedBottom, const std::vector& HydroPmax, - const std::vector& filter_hours_remix, + const std::vector& enabledHours, double top) { double min_val = top; int min_hour = -1; for (int h = 0; h < TotalGen.size(); ++h) { - if (OutUnsupE[h] > 0 && OutHydroGen[h] < HydroPmax[h] && !triedBottom[h] - && filter_hours_remix[h]) + if (OutUnsupE[h] > 0 && OutHydroGen[h] < HydroPmax[h] && !triedBottom[h] && enabledHours[h]) { if (TotalGen[h] < min_val) { @@ -37,7 +36,7 @@ int find_max_index(const std::vector& TotalGen, const std::vector& OutHydroGen, const std::vector& triedPeak, const std::vector& HydroPmin, - const std::vector& filter_hours_remix, + const std::vector& enabledHours, double ref_value, double eps) { @@ -46,7 +45,7 @@ int find_max_index(const std::vector& TotalGen, for (int h = 0; h < TotalGen.size(); ++h) { if (OutHydroGen[h] > HydroPmin[h] && TotalGen[h] >= ref_value + eps && !triedPeak[h] - && filter_hours_remix[h]) + && enabledHours[h]) { if (TotalGen[h] > max_val) { @@ -187,12 +186,12 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe + *std::max_element(HydroGen.begin(), HydroGen.end()) + *std::max_element(UnsupE.begin(), UnsupE.end()) + 1; - std::vector filter_hours_remix(DispatchGen.size(), false); - for (unsigned int h = 0; h < filter_hours_remix.size(); h++) + std::vector enabledHours(DispatchGen.size(), false); + for (unsigned int h = 0; h < enabledHours.size(); h++) { if (Spillage[h] + DTG_MRG[h] == 0. && HydroGen[h] + UnsupE[h] > 0.) { - filter_hours_remix[h] = true; + enabledHours[h] = true; } } @@ -215,7 +214,7 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe OutHydroGen, triedBottom, HydroPmax, - filter_hours_remix, + enabledHours, top); if (hourBottom == -1) { @@ -229,7 +228,7 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe OutHydroGen, triedPeak, HydroPmin, - filter_hours_remix, + enabledHours, TotalGen[hourBottom], eps); if (hourPeak == -1) From b7107fac815b0e68f309b965a21f0933adf79e7e Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Wed, 8 Jan 2025 10:36:55 +0100 Subject: [PATCH 41/44] [skip ci] New hydro remix : tiny correction due to review --- src/solver/simulation/shave-peaks-by-remix-hydro.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp index 32ac60debb..5ad4823add 100644 --- a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp +++ b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp @@ -154,7 +154,7 @@ RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGe const std::vector& DTG_MRG) { std::vector levels(DispatchGen.size()); - if (levels.size()) + if (!levels.empty()) { levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - HydroGen[0]; for (size_t h = 1; h < levels.size(); ++h) From d06eeaed824a0343bdacb6d651d8664aac8ea193 Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 9 Jan 2025 10:46:08 +0100 Subject: [PATCH 42/44] New hydro remix : adding a test for comparison with python script --- .../solver/simulation/test-hydro-remix.cpp | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 3ec2c6395c..737cd257f8 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -737,6 +737,44 @@ BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, Inp BOOST_CHECK(OutHydroGen == expected_HydroGen); } +BOOST_FIXTURE_TEST_CASE(comparison_of_results_with_python_algo, + InputFixture<20>, + *boost::unit_test::tolerance(0.01)) +{ + std::vector load = {46, 81, 89, 42, 69, 55, 88, 46, 84, 94, + 66, 93, 68, 39, 91, 89, 94, 93, 91, 38}; + HydroGen = {10, 40, 36, 8, 13, 33, 9, 0, 24, 18, 5, 47, 29, 6, 7, 54, 49, 11, 63, 21}; + UnsupE = {34, 32, 33, 23, 9, 8, 20, 40, 30, 3, 50, 27, 12, 1, 35, 31, 2, 58, 20, 4}; + // Computing total generation without hydro generation + DispatchGen = load; + std::ranges::transform(DispatchGen, HydroGen, DispatchGen.begin(), std::minus()); + std::ranges::transform(DispatchGen, UnsupE, DispatchGen.begin(), std::minus()); + + HydroPmax = {43, 48, 36, 43, 13, 44, 13, 31, 49, 35, 47, 47, 37, 41, 21, 54, 49, 28, 63, 49}; + HydroPmin = {10, 22, 17, 8, 7, 15, 8, 0, 9, 2, 5, 18, 22, 6, 4, 11, 1, 0, 23, 6}; + init_level = 13.6; + capacity = 126.; + inflows = {37, 27, 41, 36, 7, 14, 38, 23, 17, 35, 20, 24, 17, 46, 1, 10, 10, 12, 46, 30}; + + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + std::vector expected_HydroGen = {42.3, 35.3, 27., 31., 7., 33., 8., + 31., 19.55, 2., 38.55, 30.55, 22.55, 7., + 4., 45.55, 6.55, 25.55, 41.55, 25.}; + + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); +} + // Ideas for building further tests : // ================================ // - Remix hydro algorithm seems symmetrical (if we have input vectors and corresponding output From 42352d1a3511fb7a3a74199de4fc4db364b2998b Mon Sep 17 00:00:00 2001 From: Guillaume PIERRE Date: Thu, 9 Jan 2025 10:54:04 +0100 Subject: [PATCH 43/44] [skip ci] New hydro remix : renaming mainly --- .../solver/simulation/test-hydro-remix.cpp | 112 ++++++++---------- 1 file changed, 52 insertions(+), 60 deletions(-) diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp index 737cd257f8..ffcef67007 100644 --- a/src/tests/src/solver/simulation/test-hydro-remix.cpp +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -17,7 +17,7 @@ struct InputFixture { InputFixture() { - DispatchGen.assign(size, 0.); + TotalGenNoHydro.assign(size, 0.); HydroGen.assign(size, 0.); UnsupE.assign(size, 0.); HydroPmax.assign(size, std::numeric_limits::max()); @@ -29,7 +29,7 @@ struct InputFixture DTG_MRG.assign(size, 0.); } - std::vector DispatchGen, HydroGen, UnsupE, HydroPmax, HydroPmin, inflows, ovf, pump, + std::vector TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, HydroPmin, inflows, ovf, pump, Spillage, DTG_MRG; double init_level = 0.; double capacity = std::numeric_limits::max(); @@ -39,7 +39,7 @@ BOOST_FIXTURE_TEST_CASE(input_vectors_of_different_sizes__exception_raised, Inpu { HydroGen = {0., 0.}; - BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(DispatchGen, + BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -61,7 +61,7 @@ BOOST_FIXTURE_TEST_CASE(input_init_level_exceeds_capacity__exception_raised, Inp init_level = 2.; capacity = 1.; - BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(DispatchGen, + BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -82,7 +82,7 @@ BOOST_FIXTURE_TEST_CASE(all_input_arrays_of_size_0__exception_raised, InputFixtu init_level = 0.; capacity = 1.; - BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(DispatchGen, + BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -106,7 +106,7 @@ BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_smaller_than_pmax__exception_raised, Input capacity = 1.; BOOST_CHECK_EXCEPTION( - shavePeaksByRemixingHydro(DispatchGen, + shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -130,7 +130,7 @@ BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_greater_than_pmin__exception_raised, Input capacity = 1.; BOOST_CHECK_EXCEPTION( - shavePeaksByRemixingHydro(DispatchGen, + shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -151,7 +151,7 @@ BOOST_FIXTURE_TEST_CASE(input_is_acceptable__no_exception_raised, InputFixture<1 init_level = 0.; capacity = 1.; - BOOST_CHECK_NO_THROW(shavePeaksByRemixingHydro(DispatchGen, + BOOST_CHECK_NO_THROW(shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -170,13 +170,13 @@ BOOST_FIXTURE_TEST_CASE( InputFixture<5>) { std::ranges::fill(HydroPmax, 40.); - std::ranges::fill(DispatchGen, 100.); + std::ranges::fill(TotalGenNoHydro, 100.); HydroGen = {0., 10., 20., 30., 40.}; // we have Pmin <= HydroGen <= Pmax UnsupE = {80.0, 60., 40., 20., 0.}; init_level = 500.; capacity = 1000.; - auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -190,7 +190,7 @@ BOOST_FIXTURE_TEST_CASE( DTG_MRG); std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; - // UnsupE such as DispatchGen + HydroGen + UnsupE remains flat + // UnsupE such as TotalGenNoHydro + HydroGen + UnsupE remains flat std::vector expected_UnsupE = {60., 50., 40., 30., 20.}; BOOST_CHECK(OutHydroGen == expected_HydroGen); BOOST_CHECK(OutUnsupE == expected_UnsupE); @@ -199,13 +199,13 @@ BOOST_FIXTURE_TEST_CASE( BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, InputFixture<5>) { std::ranges::fill(HydroPmax, 50.); - std::ranges::fill(DispatchGen, 100.); + std::ranges::fill(TotalGenNoHydro, 100.); HydroGen = {0., 10., 20., 30., 40.}; UnsupE = {80.0, 60., 40., 20., 0.}; init_level = 500.; capacity = 1000.; - auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -219,7 +219,7 @@ BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, In DTG_MRG); std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; - // UnsupE such as DispatchGen + HydroGen + UnsupE remains constant at each hour + // UnsupE such as TotalGenNoHydro + HydroGen + UnsupE remains constant at each hour std::vector expected_UnsupE = {60., 50., 40., 30., 20.}; BOOST_CHECK(OutHydroGen == expected_HydroGen); BOOST_CHECK(OutUnsupE == expected_UnsupE); @@ -230,13 +230,13 @@ BOOST_FIXTURE_TEST_CASE( InputFixture<5>) { std::ranges::fill(HydroPmax, 40.); - std::ranges::fill(DispatchGen, 100.); + std::ranges::fill(TotalGenNoHydro, 100.); HydroGen = {40., 30., 20., 10., 0.}; UnsupE = {0., 20., 40., 60., 80.}; init_level = 500.; capacity = 1000.; - auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -250,7 +250,7 @@ BOOST_FIXTURE_TEST_CASE( DTG_MRG); std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; - // UnsupE such as DispatchGen + HydroGen + UnsupE remains constant at each hour + // UnsupE such as TotalGenNoHydro + HydroGen + UnsupE remains constant at each hour std::vector expected_UnsupE = {20., 30., 40., 50., 60.}; BOOST_CHECK(OutHydroGen == expected_HydroGen); BOOST_CHECK(OutUnsupE == expected_UnsupE); @@ -258,8 +258,8 @@ BOOST_FIXTURE_TEST_CASE( BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::tolerance(0.01)) { - // DispatchGen decreases - DispatchGen = {100., 80., 60., 40., 20.}; + // TotalGenNoHydro decreases + TotalGenNoHydro = {100., 80., 60., 40., 20.}; // HydroGen is flat and must respect HydroGen <= Pmax everywhere HydroGen = {20., 20., 20., 20., 20.}; @@ -267,9 +267,9 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t init_level = 500.; capacity = 1000.; - // 1. Algorithm tends to flatten DispatchGen + HydroGen, so it would require HydroGen to + // 1. Algorithm tends to flatten TotalGenNoHydro + HydroGen, so it would require HydroGen to // increase. Proof : - auto [OutHydroGen_1, new_D1, L] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen_1, new_D1, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -288,7 +288,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t // 2. But HydroGen is limited by HydroPmax. So Algo does nothing in the end. // Proof : HydroPmax = {20., 20., 20., 20., 20.}; - auto [OutHydroGen_2, OutUnsupE_2, _] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen_2, OutUnsupE_2, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -309,8 +309,8 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::t BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::tolerance(0.01)) { - // DispatchGen decreases - DispatchGen = {100., 80., 60., 40., 20.}; + // TotalGenNoHydro decreases + TotalGenNoHydro = {100., 80., 60., 40., 20.}; // HydroGen is flat and must respect Pmin <= HydroGen <= Pmax everywhere HydroGen = {20., 20., 20., 20., 20.}; @@ -318,9 +318,9 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::t init_level = 500.; capacity = 1000.; - // 1. Algorithm tends to flatten DispatchGen + HydroGen, so it would require HydroGen to + // 1. Algorithm tends to flatten TotalGenNoHydro + HydroGen, so it would require HydroGen to // increase. - auto [OutHydroGen_1, new_D1, L] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen_1, new_D1, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -337,7 +337,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::t // 2. But HydroGen is low bounded by HydroPmin. So Algo does nothing in the end. HydroPmin = {20., 20., 20., 20., 20.}; - auto [OutHydroGen_2, OutUnsupE_2, _] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen_2, OutUnsupE_2, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -365,7 +365,7 @@ BOOST_FIXTURE_TEST_CASE(Hydro_gen_is_already_flat___remix_is_useless__level_easi std::ranges::fill(inflows, 15.); // Cause levels to increase std::ranges::fill(pump, 10.); // Cause levels to increase - auto [OutHydroGen, OutUnsupE, levels] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, levels] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -392,7 +392,7 @@ BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised, std::ranges::fill(pump, 20); // Cause levels to increase BOOST_CHECK_EXCEPTION( - shavePeaksByRemixingHydro(DispatchGen, + shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -418,7 +418,7 @@ BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised, std::ranges::fill(pump, 10); // Cause levels to increase BOOST_CHECK_EXCEPTION( - shavePeaksByRemixingHydro(DispatchGen, + shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -453,7 +453,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influ // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is // flat) - auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -477,7 +477,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influ // have HydroGen and L identical to previously : this value of capacity should // not have an influence on HydroGen and levels as results of the algorithm. capacity = 155.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -512,7 +512,7 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is // flat) - auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -539,7 +539,7 @@ BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_f // was infinite. Therefore, solution found is suboptimal : we expect to get an // output HydroGen flat by interval, not flat on the whole domain. capacity = 145.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -576,7 +576,7 @@ BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solut // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable for algorithm (input levels >= 0.), and running algorithm leads to optimal // solution (OutHydroGen is flat) - auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -601,7 +601,7 @@ BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solut // bound (0.) into account. As the levels change, the solution OutHydroGen will be suboptimal, // that is flat by interval (not flat on the whole domain). init_level = 95.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -636,7 +636,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) // are acceptable by algorithm, and levels computed by algorithm (output) are optimal, that // is computed from a optimal (that is flat) OutHydroGen. - auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -661,7 +661,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ // and algorithm won't have to take the levels lower bound (0.) into account. // The solution OutHydroGen will be optimal, that is flat by interval. init_level = 55.; - auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -681,7 +681,7 @@ BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, InputFixture<5>) { - std::ranges::fill(DispatchGen, 100.); + std::ranges::fill(TotalGenNoHydro, 100.); HydroGen = {40., 30., 20., 10., 0.}; UnsupE = {0., 20., 40., 60., 80.}; init_level = 500.; @@ -691,7 +691,7 @@ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, In // But : Spillage[0] = 1.; // Now, we expect no change for HydroGen at hour 0 - auto [OutHydroGen, __, _] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, __, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -710,7 +710,7 @@ BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, In BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, InputFixture<5>) { - std::ranges::fill(DispatchGen, 100.); + std::ranges::fill(TotalGenNoHydro, 100.); HydroGen = {40., 30., 20., 10., 0.}; UnsupE = {0., 20., 40., 60., 80.}; init_level = 500.; @@ -720,7 +720,7 @@ BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, Inp // But : DTG_MRG[4] = 1.; // Now, we expect no change for HydroGen at hour 4 - auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -746,9 +746,12 @@ BOOST_FIXTURE_TEST_CASE(comparison_of_results_with_python_algo, HydroGen = {10, 40, 36, 8, 13, 33, 9, 0, 24, 18, 5, 47, 29, 6, 7, 54, 49, 11, 63, 21}; UnsupE = {34, 32, 33, 23, 9, 8, 20, 40, 30, 3, 50, 27, 12, 1, 35, 31, 2, 58, 20, 4}; // Computing total generation without hydro generation - DispatchGen = load; - std::ranges::transform(DispatchGen, HydroGen, DispatchGen.begin(), std::minus()); - std::ranges::transform(DispatchGen, UnsupE, DispatchGen.begin(), std::minus()); + TotalGenNoHydro = load; + std::ranges::transform(TotalGenNoHydro, + HydroGen, + TotalGenNoHydro.begin(), + std::minus()); + std::ranges::transform(TotalGenNoHydro, UnsupE, TotalGenNoHydro.begin(), std::minus()); HydroPmax = {43, 48, 36, 43, 13, 44, 13, 31, 49, 35, 47, 47, 37, 41, 21, 54, 49, 28, 63, 49}; HydroPmin = {10, 22, 17, 8, 7, 15, 8, 0, 9, 2, 5, 18, 22, 6, 4, 11, 1, 0, 23, 6}; @@ -756,7 +759,7 @@ BOOST_FIXTURE_TEST_CASE(comparison_of_results_with_python_algo, capacity = 126.; inflows = {37, 27, 41, 36, 7, 14, 38, 23, 17, 35, 20, 24, 17, 46, 1, 10, 10, 12, 46, 30}; - auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(DispatchGen, + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, @@ -771,26 +774,15 @@ BOOST_FIXTURE_TEST_CASE(comparison_of_results_with_python_algo, std::vector expected_HydroGen = {42.3, 35.3, 27., 31., 7., 33., 8., 31., 19.55, 2., 38.55, 30.55, 22.55, 7., 4., 45.55, 6.55, 25.55, 41.55, 25.}; - + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); } -// Ideas for building further tests : -// ================================ -// - 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) -// - After running remix hydro algo, sum(HydroGen), sum(HydroGen + UnsupE) must remain the same. -// - influence of UnsupE : low values of DispatchGen + HydroGen are searched where UnsupE > 0 (not -// where UnsupE == 0) -// - - // Possible simplifications / clarifications of the algorithm itself : -// - remove french from variable names // - the algo is flat, it's C (not C++), it should be divided in a small number of steps // - max_pic is an up hydro production margin (Hydro_gen_up_mrg) // - max_creux is a down hydro production margin (Hydro_gen_down_mrg) -// - an iter updates OutHydroGen : it's its main job. So OutUnsupE could be updated from OutHydroGen -// at the -// end of an iteration, separately. +// - an iteration updates OutHydroGen : it's its main job. +// So OutUnsupE could be updated from OutHydroGen at the end of an iteration, separately. // - they are 3 while loops. 2 loops should be enough (the iteration loop and // another one simply updating OutHydroGen and OutUnsupE) From 35c480052886ce723149e97f7709413398b62f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 10 Jan 2025 14:04:26 +0100 Subject: [PATCH 44/44] Small improvements for hydro remix (#2570) --- src/solver/simulation/shave-peaks-by-remix-hydro.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp index 5ad4823add..99a8f2aa55 100644 --- a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp +++ b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp @@ -18,7 +18,7 @@ int find_min_index(const std::vector& TotalGen, { double min_val = top; int min_hour = -1; - for (int h = 0; h < TotalGen.size(); ++h) + for (unsigned int h = 0; h < TotalGen.size(); ++h) { if (OutUnsupE[h] > 0 && OutHydroGen[h] < HydroPmax[h] && !triedBottom[h] && enabledHours[h]) { @@ -42,7 +42,7 @@ int find_max_index(const std::vector& TotalGen, { double max_val = 0; int max_hour = -1; - for (int h = 0; h < TotalGen.size(); ++h) + for (unsigned int h = 0; h < TotalGen.size(); ++h) { if (OutHydroGen[h] > HydroPmin[h] && TotalGen[h] >= ref_value + eps && !triedPeak[h] && enabledHours[h]) @@ -59,9 +59,9 @@ int find_max_index(const std::vector& TotalGen, static bool operator<=(const std::vector& a, const std::vector& b) { - std::vector a_minus_b; - std::ranges::transform(a, b, std::back_inserter(a_minus_b), std::minus()); - return std::ranges::all_of(a_minus_b, [](const double& e) { return e <= 0.; }); + return a.size() == b.size() + && std::ranges::all_of(std::views::iota(size_t{0}, a.size()), + [&](size_t i) { return a[i] <= b[i]; }); } static bool operator<=(const std::vector& v, const double c)