From e5af225f9fabb75150dda8b71c866789eb15ee3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 21 Feb 2025 11:55:53 +0100 Subject: [PATCH] Increase coverage on hydro common data (hydro.ini) [ANT-1825] (#2634) # Description - Split large loading function (time-series / INI file) - Add coverage on new property `overflow spilled cost difference` # Summary ```cpp void CommonFixture::writeValidFile() { std::ofstream outfile(hydroIni); outfile << R"([overflow spilled cost difference] east = 1.00000 west = 2.31000 [reservoir] east = true)"; } BOOST_FIXTURE_TEST_CASE(test_read_valid_file, CommonFixture) { writeValidFile(); BOOST_CHECK(load()); BOOST_CHECK_EQUAL(east->hydro.overflowSpilledCostDifference, 1.0); BOOST_CHECK_EQUAL(west->hydro.overflowSpilledCostDifference, 2.31000); } ``` --- .../antares/study/parts/hydro/container.h | 2 + .../antares/study/parts/hydro/container.cpp | 199 +++++++++--------- .../antares/study/parts/hydro/CMakeLists.txt | 7 + .../study/parts/hydro/test-hydro-common.cpp | 121 +++++++++++ 4 files changed, 232 insertions(+), 97 deletions(-) create mode 100644 src/tests/src/libs/antares/study/parts/hydro/test-hydro-common.cpp diff --git a/src/libs/antares/study/include/antares/study/parts/hydro/container.h b/src/libs/antares/study/include/antares/study/parts/hydro/container.h index 8024403788..4b1e993f67 100644 --- a/src/libs/antares/study/include/antares/study/parts/hydro/container.h +++ b/src/libs/antares/study/include/antares/study/parts/hydro/container.h @@ -108,6 +108,8 @@ class PartHydro pumpMod, }; + static bool LoadIniFile(Study& study, const std::filesystem::path& folder); + /*! ** \brief Load data for hydro container from a folder ** diff --git a/src/libs/antares/study/parts/hydro/container.cpp b/src/libs/antares/study/parts/hydro/container.cpp index 3b8f2535d4..3abb9d58b3 100644 --- a/src/libs/antares/study/parts/hydro/container.cpp +++ b/src/libs/antares/study/parts/hydro/container.cpp @@ -132,105 +132,9 @@ static bool loadProperties(Study& study, return ret; } -bool PartHydro::LoadFromFolder(Study& study, const fs::path& folder) +bool PartHydro::LoadIniFile(Study& study, const std::filesystem::path& folder) { bool ret = true; - - // Initialize all alpha values to 0 - study.areas.each( - [&ret, &study, &folder](Data::Area& area) - { - area.hydro.interDailyBreakdown = 1.; - area.hydro.intraDailyModulation = 24.; - area.hydro.intermonthlyBreakdown = 1.; - area.hydro.reservoirManagement = false; - area.hydro.followLoadModulations = true; - area.hydro.useWaterValue = false; - area.hydro.hardBoundsOnRuleCurves = false; - area.hydro.useHeuristicTarget = true; - area.hydro.useLeeway = false; - area.hydro.powerToLevel = false; - area.hydro.leewayLowerBound = 1.; - area.hydro.leewayUpperBound = 1.; - area.hydro.initializeReservoirLevelDate = 0; - area.hydro.reservoirCapacity = 0.; - area.hydro.pumpingEfficiency = 1.; - area.hydro.deltaBetweenFinalAndInitialLevels.resize(study.parameters.nbYears); - - if (study.parameters.compatibility.hydroPmax - == Parameters::Compatibility::HydroPmax::Hourly) - { - // GUI part patch : - // We need to know, when estimating the RAM required by the solver, if the current - // area is hydro modulable. Therefore, reading the area's daily max power at this - // stage is necessary. - - if (!study.usedByTheSolver) - { - bool enabledModeIsChanged = false; - if (JIT::enabled) - { - JIT::enabled = false; // Allowing to read the area's daily max power - enabledModeIsChanged = true; - } - - ret = area.hydro.LoadDailyMaxEnergy(folder.string(), area.id) && ret; - - if (enabledModeIsChanged) - { - JIT::enabled = true; // Back to the previous loading mode. - } - } - else - { - ret = area.hydro.LoadDailyMaxEnergy(folder.string(), area.id) && ret; - - // Check is moved here, because in case of old study - // dailyNbHoursAtGenPmax and dailyNbHoursAtPumpPmax are not yet initialized. - - ret = area.hydro.CheckDailyMaxEnergy(area.name) && ret; - } - } - - fs::path capacityPath = folder / "common" / "capacity"; - - std::string creditId = "creditmodulations_" + area.id + ".txt"; - fs::path creditPath = capacityPath / creditId; - ret = area.hydro.creditModulation.loadFromCSVFile(creditPath.string(), - 101, - 2, - Matrix<>::optFixedSize, - &study.dataBuffer) - && ret; - - std::string reservoirId = "reservoir_" + area.id + ".txt"; - fs::path reservoirPath = capacityPath / reservoirId; - ret = area.hydro.reservoirLevel.loadFromCSVFile(reservoirPath.string(), - 3, - DAYS_PER_YEAR, - Matrix<>::optFixedSize, - &study.dataBuffer) - && ret; - - std::string waterValueId = "waterValues_" + area.id + ".txt"; - fs::path waterValuePath = capacityPath / waterValueId; - ret = area.hydro.waterValues.loadFromCSVFile(waterValuePath.string(), - 101, - DAYS_PER_YEAR, - Matrix<>::optFixedSize, - &study.dataBuffer) - && ret; - - std::string inflowId = "inflowPattern_" + area.id + ".txt"; - fs::path inflowPath = capacityPath / inflowId; - ret = area.hydro.inflowPattern.loadFromCSVFile(inflowPath.string(), - 1, - DAYS_PER_YEAR, - Matrix<>::optFixedSize, - &study.dataBuffer) - && ret; - }); - IniFile ini; auto path = folder / "hydro.ini"; if (not ini.open(path)) @@ -333,7 +237,108 @@ bool PartHydro::LoadFromFolder(Study& study, const fs::path& folder) &PartHydro::overflowSpilledCostDifference) && ret; } + return ret; +} +bool PartHydro::LoadFromFolder(Study& study, const fs::path& folder) +{ + bool ret = true; + + // Initialize all alpha values to 0 + study.areas.each( + [&ret, &study, &folder](Data::Area& area) + { + area.hydro.interDailyBreakdown = 1.; + area.hydro.intraDailyModulation = 24.; + area.hydro.intermonthlyBreakdown = 1.; + area.hydro.reservoirManagement = false; + area.hydro.followLoadModulations = true; + area.hydro.useWaterValue = false; + area.hydro.hardBoundsOnRuleCurves = false; + area.hydro.useHeuristicTarget = true; + area.hydro.useLeeway = false; + area.hydro.powerToLevel = false; + area.hydro.leewayLowerBound = 1.; + area.hydro.leewayUpperBound = 1.; + area.hydro.initializeReservoirLevelDate = 0; + area.hydro.reservoirCapacity = 0.; + area.hydro.pumpingEfficiency = 1.; + area.hydro.deltaBetweenFinalAndInitialLevels.resize(study.parameters.nbYears); + + if (study.parameters.compatibility.hydroPmax + == Parameters::Compatibility::HydroPmax::Hourly) + { + // GUI part patch : + // We need to know, when estimating the RAM required by the solver, if the current + // area is hydro modulable. Therefore, reading the area's daily max power at this + // stage is necessary. + + if (!study.usedByTheSolver) + { + bool enabledModeIsChanged = false; + if (JIT::enabled) + { + JIT::enabled = false; // Allowing to read the area's daily max power + enabledModeIsChanged = true; + } + + ret = area.hydro.LoadDailyMaxEnergy(folder.string(), area.id) && ret; + + if (enabledModeIsChanged) + { + JIT::enabled = true; // Back to the previous loading mode. + } + } + else + { + ret = area.hydro.LoadDailyMaxEnergy(folder.string(), area.id) && ret; + + // Check is moved here, because in case of old study + // dailyNbHoursAtGenPmax and dailyNbHoursAtPumpPmax are not yet initialized. + + ret = area.hydro.CheckDailyMaxEnergy(area.name) && ret; + } + } + + fs::path capacityPath = folder / "common" / "capacity"; + + std::string creditId = "creditmodulations_" + area.id + ".txt"; + fs::path creditPath = capacityPath / creditId; + ret = area.hydro.creditModulation.loadFromCSVFile(creditPath.string(), + 101, + 2, + Matrix<>::optFixedSize, + &study.dataBuffer) + && ret; + + std::string reservoirId = "reservoir_" + area.id + ".txt"; + fs::path reservoirPath = capacityPath / reservoirId; + ret = area.hydro.reservoirLevel.loadFromCSVFile(reservoirPath.string(), + 3, + DAYS_PER_YEAR, + Matrix<>::optFixedSize, + &study.dataBuffer) + && ret; + + std::string waterValueId = "waterValues_" + area.id + ".txt"; + fs::path waterValuePath = capacityPath / waterValueId; + ret = area.hydro.waterValues.loadFromCSVFile(waterValuePath.string(), + 101, + DAYS_PER_YEAR, + Matrix<>::optFixedSize, + &study.dataBuffer) + && ret; + + std::string inflowId = "inflowPattern_" + area.id + ".txt"; + fs::path inflowPath = capacityPath / inflowId; + ret = area.hydro.inflowPattern.loadFromCSVFile(inflowPath.string(), + 1, + DAYS_PER_YEAR, + Matrix<>::optFixedSize, + &study.dataBuffer) + && ret; + }); + ret = PartHydro::LoadIniFile(study, folder) && ret; return ret; } diff --git a/src/tests/src/libs/antares/study/parts/hydro/CMakeLists.txt b/src/tests/src/libs/antares/study/parts/hydro/CMakeLists.txt index 8b5dee7bc3..1e5b0bcad6 100644 --- a/src/tests/src/libs/antares/study/parts/hydro/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/parts/hydro/CMakeLists.txt @@ -13,3 +13,10 @@ add_boost_test(test-hydro-series LIBS Antares::study test_utils_unit) + +# Hydro series +add_boost_test(test-hydro-common + SRC test-hydro-common.cpp + LIBS + Antares::study + test_utils_unit) diff --git a/src/tests/src/libs/antares/study/parts/hydro/test-hydro-common.cpp b/src/tests/src/libs/antares/study/parts/hydro/test-hydro-common.cpp new file mode 100644 index 0000000000..a020935e17 --- /dev/null +++ b/src/tests/src/libs/antares/study/parts/hydro/test-hydro-common.cpp @@ -0,0 +1,121 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define BOOST_TEST_MODULE test hydro common + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#include + +#include + +#define SEP "/" + +using namespace Antares::Data; +namespace fs = std::filesystem; + +// ================= +// The fixture +// ================= +struct CommonFixture +{ + std::filesystem::path path; + StudyLoadOptions options; + StudyVersion version = StudyVersion::latest(); + + CommonFixture(): + tmp(fs::temp_directory_path()), + hydroIni(tmp / "hydro.ini"), + study(std::make_unique()) + { + east = new Area("east"); // freed by ~AreaList + study->areas.add(east); + west = new Area("west"); // freed by ~AreaList + study->areas.add(west); + } + + bool load() + { + return east->hydro.LoadIniFile(*study, tmp) && west->hydro.LoadIniFile(*study, tmp); + } + + ~CommonFixture() + { + fs::remove(hydroIni); + } + + void writeValidFile(); + void writeInvalidFile(); + +public: + Area* east; + Area* west; + +private: + fs::path tmp; + fs::path hydroIni; + std::unique_ptr study; +}; + +void CommonFixture::writeValidFile() +{ + std::ofstream outfile(hydroIni); + outfile << + R"([overflow spilled cost difference] +east = 1.00000 +west = 2.31000 + +[reservoir] +east = true)"; +} + +void CommonFixture::writeInvalidFile() +{ + std::ofstream outfile(hydroIni); + outfile << + R"([overflow spilled cost difference] +east = 1.00000 +west = 2.31000 +wrongarea = 1.414 + +[reservoir] +east = true)"; +} + +BOOST_AUTO_TEST_SUITE(s) + +BOOST_FIXTURE_TEST_CASE(test_read_valid_file, CommonFixture) +{ + writeValidFile(); + BOOST_CHECK(load()); + BOOST_CHECK_EQUAL(east->hydro.overflowSpilledCostDifference, 1.0); + BOOST_CHECK_EQUAL(west->hydro.overflowSpilledCostDifference, 2.31000); +} + +BOOST_FIXTURE_TEST_CASE(test_read_invalid_file, CommonFixture) +{ + writeInvalidFile(); + BOOST_CHECK(!load()); +} +BOOST_AUTO_TEST_SUITE_END()