From b3f3fc0b9147816adf22f9f29d17b83be4e5125c Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:42:07 +0200 Subject: [PATCH] Hydro final lvl (CR 25) to merge in develop [ANT-1084] (#1521) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR attempts some code enhancements on branch **feature/final-reservoir-level-cr25**. Therefore, this PR's associated branch (**fix/hydro-final-levels-cr25--try-fixes**) is based on **feature/final-reservoir-level-cr25**. - [x] in class **FinalLevelInflowsModifier**, - try to reduce the number of data members, - making data members **private** whenever it's possible, - define a clear interface with a smallest number of public functions - and so make the more methods private as possible - [x] **Unit tests** : clarify their intention and reduce their size - [ ] **caution** : could not remove yet the **initialize** method. This method should be merged with the constructor, but when we call the constructor, all input pieces of data are not available. that's why **initialize** exists. We should try to make these pieces of data available, for instance by changing the order of data loading For any purpose, here are doc resources : - specs [here](https://rteinternational.sharepoint.com/:w:/r/sites/AntaresUser'sClub-Interne/_layouts/15/Doc.aspx?sourcedoc=%7B7774488E-7E4C-4AEC-B11F-1C9728B96AC0%7D&file=Functional_Specifications-Final_reservoir_level_V0.1-MA.docx&action=default&mobileredirect=true) - a discussion on that matter [here](https://github.com/AntaresSimulatorTeam/Antares_Simulator/discussions/1145) --- ### CAUTION : **Some cleaning and corrections were introduced in a new pull request** (see [this PR](https://github.com/AntaresSimulatorTeam/Antares_Simulator/pull/2040)). This new PR was merged into this one. **This PR contains a test under the form of a study. This study should be downloaded and added to the right test repo.** --- ### Left to to - [ ] Merge from branch develop and remove conflicts - [ ] Check that all tests exist (unit test for raising failures and study case for fine working) - [ ] what else ? --------- Co-authored-by: Milos A Co-authored-by: Milos <97689304+Milos-RTEi@users.noreply.github.com> Co-authored-by: Florian Omnès Co-authored-by: NikolaIlic --- docs/user-guide/04-migration-guides.md | 4 + src/CMakeLists.txt | 1 + src/antares-deps | 1 + src/libs/antares/study/CMakeLists.txt | 2 + src/libs/antares/study/area/area.cpp | 3 + .../antares/study/parts/hydro/container.h | 5 +- .../study/parts/hydro/finalLevelValidator.h | 73 +++++ .../study/scenario-builder/hydroLevelsData.h | 24 +- .../antares/study/scenario-builder/rules.h | 9 +- .../study/include/antares/study/study.h | 5 +- .../antares/study/parts/hydro/container.cpp | 3 +- .../study/parts/hydro/finalLevelValidator.cpp | 157 ++++++++++ .../scenario-builder/hydroLevelsData.cpp | 15 +- .../antares/study/scenario-builder/rules.cpp | 129 ++++---- .../solver/hydro/management/management.h | 2 + src/solver/hydro/management/daily.cpp | 2 + src/solver/hydro/management/management.cpp | 22 +- src/solver/hydro/management/monthly.cpp | 32 +- src/solver/simulation/CMakeLists.txt | 59 ++-- .../hydro-final-reservoir-level-functions.cpp | 68 +++++ .../hydro-final-reservoir-level-functions.h | 37 +++ .../antares/solver/simulation/solver.hxx | 22 +- .../end-to-end/simple_study/simple-study.cpp | 3 +- src/tests/end-to-end/utils/utils.cpp | 1 + .../test-sc-builder-file-read-line.cpp | 70 ++++- .../test-sc-builder-file-save.cpp | 31 +- .../src/solver/simulation/CMakeLists.txt | 29 ++ ...-hydro-final-reservoir-level-functions.cpp | 275 ++++++++++++++++++ .../main/build/scenario-builder.cpp | 30 +- src/ui/simulator/application/main/main.h | 3 +- src/ui/simulator/cmake/components.cmake | 2 + ...io-builder-hydro-final-levels-renderer.cpp | 82 ++++++ ...ario-builder-hydro-final-levels-renderer.h | 56 ++++ ...scenario-builder-hydro-levels-renderer.cpp | 30 +- 34 files changed, 1120 insertions(+), 167 deletions(-) create mode 160000 src/antares-deps create mode 100644 src/libs/antares/study/include/antares/study/parts/hydro/finalLevelValidator.h create mode 100644 src/libs/antares/study/parts/hydro/finalLevelValidator.cpp create mode 100644 src/solver/simulation/hydro-final-reservoir-level-functions.cpp create mode 100644 src/solver/simulation/include/antares/solver/simulation/hydro-final-reservoir-level-functions.h create mode 100644 src/tests/src/solver/simulation/test-hydro-final-reservoir-level-functions.cpp create mode 100644 src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.cpp create mode 100644 src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h diff --git a/docs/user-guide/04-migration-guides.md b/docs/user-guide/04-migration-guides.md index 5dbc3f8885..c423bc5346 100644 --- a/docs/user-guide/04-migration-guides.md +++ b/docs/user-guide/04-migration-guides.md @@ -129,6 +129,10 @@ For each thermal cluster, in existing file **input/thermal/clusters/<area> For each thermal cluster, new files added **input/thermal/series/<area>/<cluster>/CO2Cost.txt** and **input/thermal/series/<area>/<cluster>/fuelCost.txt**. **fuelCost.txt** and **CO2Cost.txt** must either have one column, or the same number of columns as existing file **series.txt** (availability). The number of rows for these new matrices is 8760. +#### Hydro Final Reservoir Level +In the existing file **settings/scenariobuilder.dat**, under **<ruleset>** section following properties added (if final reservoir level specified, different from `init`): +* **hfl,<area>,<year> = <hfl-value>** + ### Output #### Scenarized RHS for binding constraints Add directory **bindingconstraints** to output directory **ts-numbers**. For every binding constraint group, add a file **ts-numbers/bindingconstraints/<group>.txt** containing the TS numbers used for that group. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 51fdc67271..862c7fdbc8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ set(ANTARES_VERSION_HI 9) set(ANTARES_VERSION_LO 1) set(ANTARES_VERSION_REVISION 0) + # Beta release set(ANTARES_BETA 0) set(ANTARES_RC 0) diff --git a/src/antares-deps b/src/antares-deps new file mode 160000 index 0000000000..0d6bebfb90 --- /dev/null +++ b/src/antares-deps @@ -0,0 +1 @@ +Subproject commit 0d6bebfb901e47ec6ac1c73cb61a522803c81b98 diff --git a/src/libs/antares/study/CMakeLists.txt b/src/libs/antares/study/CMakeLists.txt index c0b5b84c56..c90d543fff 100644 --- a/src/libs/antares/study/CMakeLists.txt +++ b/src/libs/antares/study/CMakeLists.txt @@ -122,6 +122,8 @@ set(SRC_STUDY_PART_HYDRO include/antares/study/parts/hydro/allocation.h include/antares/study/parts/hydro/allocation.hxx parts/hydro/allocation.cpp + include/antares/study/parts/hydro/finalLevelValidator.h + parts/hydro/finalLevelValidator.cpp include/antares/study/parts/hydro/hydromaxtimeseriesreader.h parts/hydro/hydromaxtimeseriesreader.cpp ) diff --git a/src/libs/antares/study/area/area.cpp b/src/libs/antares/study/area/area.cpp index 77f0fe6dd9..2984704716 100644 --- a/src/libs/antares/study/area/area.cpp +++ b/src/libs/antares/study/area/area.cpp @@ -45,6 +45,7 @@ void Area::internalInitialize() } Area::Area(): + hydro(*this), reserves(fhrMax, HOURS_PER_YEAR), miscGen(fhhMax, HOURS_PER_YEAR) { @@ -52,6 +53,7 @@ Area::Area(): } Area::Area(const AnyString& name): + hydro(*this), reserves(fhrMax, HOURS_PER_YEAR), miscGen(fhhMax, HOURS_PER_YEAR) { @@ -62,6 +64,7 @@ Area::Area(const AnyString& name): Area::Area(const AnyString& name, const AnyString& id): + hydro(*this), reserves(fhrMax, HOURS_PER_YEAR), miscGen(fhhMax, HOURS_PER_YEAR) { 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 0297540a4d..e09970b79c 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 @@ -21,6 +21,7 @@ #ifndef __ANTARES_LIBS_STUDY_PARTS_HYDRO_CONTAINER_H__ #define __ANTARES_LIBS_STUDY_PARTS_HYDRO_CONTAINER_H__ +#include #include "../../fwd.h" #include "allocation.h" #include "prepro.h" @@ -80,7 +81,7 @@ class PartHydro /*! ** \brief Default Constructor */ - PartHydro(); + PartHydro(const Data::Area& area); //! Destructor ~PartHydro(); @@ -165,6 +166,8 @@ class PartHydro Matrix dailyNbHoursAtGenPmax; Matrix dailyNbHoursAtPumpPmax; + std::vector> deltaBetweenFinalAndInitialLevels; + private: static bool checkReservoirLevels(const Study& study); static bool checkProperties(Study& study); diff --git a/src/libs/antares/study/include/antares/study/parts/hydro/finalLevelValidator.h b/src/libs/antares/study/include/antares/study/parts/hydro/finalLevelValidator.h new file mode 100644 index 0000000000..518e29d40b --- /dev/null +++ b/src/libs/antares/study/include/antares/study/parts/hydro/finalLevelValidator.h @@ -0,0 +1,73 @@ +/* +** Copyright 2007-2023 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** 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 +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ +#pragma once + +#include "antares/study/parts/hydro/container.h" + +namespace Antares::Data +{ +class PartHydro; + +class FinalLevelValidator +{ +public: + FinalLevelValidator(PartHydro& hydro, + unsigned int areaIndex, + const AreaName areaName, + double initialLevel, + double finalLevel, + const unsigned int year, + const unsigned int lastSimulationDay, + const unsigned int firstMonthOfSimulation); + bool check(); + bool finalLevelFineForUse(); + +private: + bool wasSetInScenarioBuilder(); + bool compatibleWithReservoirProperties(); + bool skippingFinalLevelUse(); + bool checkForInfeasibility(); + bool hydroAllocationStartMatchesSimulation() const; + bool isFinalLevelReachable() const; + double calculateTotalInflows() const; + bool isBetweenRuleCurves() const; + + // Data from simulation + unsigned int year_ = 0; + unsigned int lastSimulationDay_ = 0; + unsigned int firstMonthOfSimulation_ = 0; + + // Data from area + PartHydro& hydro_; + unsigned int areaIndex_; + const AreaName areaName_; + double initialLevel_; + double finalLevel_; + + bool finalLevelFineForUse_ = false; +}; +} // namespace Antares::Data diff --git a/src/libs/antares/study/include/antares/study/scenario-builder/hydroLevelsData.h b/src/libs/antares/study/include/antares/study/scenario-builder/hydroLevelsData.h index 0f01fb9c32..42aff6336a 100644 --- a/src/libs/antares/study/include/antares/study/scenario-builder/hydroLevelsData.h +++ b/src/libs/antares/study/include/antares/study/scenario-builder/hydroLevelsData.h @@ -22,6 +22,7 @@ #define __LIBS_STUDY_SCENARIO_BUILDER_DATA_HYDRO_LEVELS_H__ #include "scBuilderDataInterface.h" +#include namespace Antares { @@ -39,7 +40,10 @@ class hydroLevelsData final: public dataInterface using MatrixType = Matrix; public: - // We use default constructor and destructor + // Constructor + + hydroLevelsData(const std::string& iniFilePrefix, + std::function applyToTarget); //! \name Data manupulation //@{ @@ -51,7 +55,7 @@ class hydroLevelsData final: public dataInterface /*! ** \brief Export the data into a mere INI file */ - void saveToINIFile(const Study& study, Yuni::IO::File::Stream& file) const; + void saveToINIFile(const Study& study, Yuni::IO::File::Stream& file) const override; /*! ** \brief Assign a single value @@ -71,11 +75,15 @@ class hydroLevelsData final: public dataInterface void set_value(uint x, uint y, double value); - bool apply(Study& study); + bool apply(Study& study) override; private: //! Hydro levels overlay (0 if auto) MatrixType pHydroLevelsRules; + // prefix to be added when calling saveToINIFileHydroLevel + const std::string addToPrefix_; + + std::function applyToTarget_; }; // class hydroLevelsData @@ -105,6 +113,16 @@ inline double hydroLevelsData::get_value(uint x, uint y) const return pHydroLevelsRules.entry[y][x]; } +inline void initLevelApply(Study& study, Matrix& matrix) +{ + study.scenarioInitialHydroLevels.copyFrom(matrix); +} + +inline void finalLevelApply(Study& study, Matrix& matrix) +{ + study.scenarioFinalHydroLevels.copyFrom(matrix); +} + } // namespace ScenarioBuilder } // namespace Data } // namespace Antares diff --git a/src/libs/antares/study/include/antares/study/scenario-builder/rules.h b/src/libs/antares/study/include/antares/study/scenario-builder/rules.h index b79d92be86..ff5261d64a 100644 --- a/src/libs/antares/study/include/antares/study/scenario-builder/rules.h +++ b/src/libs/antares/study/include/antares/study/scenario-builder/rules.h @@ -119,8 +119,10 @@ class Rules final: private Yuni::NonCopyable //! Renewable (array [0..pAreaCount - 1]) std::vector renewable; - //! hydro levels - hydroLevelsData hydroLevels; + //! hydro initial levels + hydroLevelsData hydroInitialLevels = {"hl,", initLevelApply}; + //! hydro final levels + hydroLevelsData hydroFinalLevels = {"hfl,", finalLevelApply}; // Links NTC std::vector linksNTC; @@ -135,7 +137,8 @@ class Rules final: private Yuni::NonCopyable bool readWind(const AreaName::Vector& instrs, String value, bool updaterMode); bool readHydro(const AreaName::Vector& instrs, String value, bool updaterMode); bool readSolar(const AreaName::Vector& instrs, String value, bool updaterMode); - bool readHydroLevels(const AreaName::Vector& instrs, String value, bool updaterMode); + bool readInitialHydroLevels(const AreaName::Vector& instrs, String value, bool updaterMode); + bool readFinalHydroLevels(const AreaName::Vector& instrs, String value, bool updaterMode); bool readLink(const AreaName::Vector& instrs, String value, bool updaterMode); bool readBindingConstraints(const AreaName::Vector& splitKey, String value); diff --git a/src/libs/antares/study/include/antares/study/study.h b/src/libs/antares/study/include/antares/study/study.h index 709bab62fe..03e2df8bed 100644 --- a/src/libs/antares/study/include/antares/study/study.h +++ b/src/libs/antares/study/include/antares/study/study.h @@ -588,8 +588,9 @@ class Study: public Yuni::NonCopyable, public LayerData ScenarioBuilder::Sets* scenarioRules = nullptr; //@} - TimeSeries::TS scenarioHydroLevels; - + TimeSeries::TS scenarioInitialHydroLevels; + // Hydro Final Levels + TimeSeries::TS scenarioFinalHydroLevels; /*! ** \brief Runtime informations ** diff --git a/src/libs/antares/study/parts/hydro/container.cpp b/src/libs/antares/study/parts/hydro/container.cpp index d955da1c81..c9dc476de5 100644 --- a/src/libs/antares/study/parts/hydro/container.cpp +++ b/src/libs/antares/study/parts/hydro/container.cpp @@ -32,7 +32,7 @@ using namespace Yuni; namespace Antares::Data { -PartHydro::PartHydro(): +PartHydro::PartHydro(const Data::Area& area) : interDailyBreakdown(0.), intraDailyModulation(2.), intermonthlyBreakdown(0), @@ -161,6 +161,7 @@ bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) area.hydro.initializeReservoirLevelDate = 0; area.hydro.reservoirCapacity = 0.; area.hydro.pumpingEfficiency = 1.; + area.hydro.deltaBetweenFinalAndInitialLevels.resize(study.parameters.nbYears); if (study.header.version >= StudyVersion(9, 1)) { diff --git a/src/libs/antares/study/parts/hydro/finalLevelValidator.cpp b/src/libs/antares/study/parts/hydro/finalLevelValidator.cpp new file mode 100644 index 0000000000..2229f75f97 --- /dev/null +++ b/src/libs/antares/study/parts/hydro/finalLevelValidator.cpp @@ -0,0 +1,157 @@ +/* +** Copyright 2007-2023 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** 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 +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "antares/study/parts/hydro/finalLevelValidator.h" + +namespace Antares::Data +{ + +FinalLevelValidator::FinalLevelValidator(PartHydro& hydro, + unsigned int areaIndex, + const AreaName areaName, // gp : to std::string + double initialLevel, + double finalLevel, + const unsigned int year, + const unsigned int lastSimulationDay, + const unsigned int firstMonthOfSimulation) + : hydro_(hydro), + areaName_(areaName), + areaIndex_(areaIndex), + initialLevel_(initialLevel), + finalLevel_(finalLevel), + year_(year), + lastSimulationDay_(lastSimulationDay), + firstMonthOfSimulation_(firstMonthOfSimulation) +{ +} + +bool FinalLevelValidator::check() +{ + if (skippingFinalLevelUse()) + return true; + if (! checkForInfeasibility()) + return false; + finalLevelFineForUse_ = true; + return true; +} + +bool FinalLevelValidator::skippingFinalLevelUse() +{ + if(! wasSetInScenarioBuilder()) + return true; + if (! compatibleWithReservoirProperties()) + return true; + return false; +} + +bool FinalLevelValidator::wasSetInScenarioBuilder() +{ + return ! isnan(finalLevel_); +} + +bool FinalLevelValidator::compatibleWithReservoirProperties() +{ + if (hydro_.reservoirManagement && !hydro_.useWaterValue) + return true; + + logs.warning() << "Final reservoir level not applicable! Year:" << year_ + 1 + << ", Area:" << areaName_ + << ". Check: Reservoir management = Yes, Use water values = No and proper initial " + "reservoir level is provided "; + return false; +} + +bool FinalLevelValidator::checkForInfeasibility() +{ + bool checksOk = hydroAllocationStartMatchesSimulation(); + checksOk = isFinalLevelReachable() && checksOk; + checksOk = isBetweenRuleCurves() && checksOk; + + return checksOk; +} + +bool FinalLevelValidator::hydroAllocationStartMatchesSimulation() const +{ + int initReservoirLvlMonth = hydro_.initializeReservoirLevelDate; // month [0-11] + if (lastSimulationDay_ == DAYS_PER_YEAR && initReservoirLvlMonth == firstMonthOfSimulation_) + return true; + + logs.error() << "Year " << year_ + 1 << ", area '" << areaName_ << "' : " + << "Hydro allocation must start on the 1st simulation month and " + << "simulation last a whole year"; + return false; +} + +bool FinalLevelValidator::isFinalLevelReachable() const +{ + double reservoirCapacity = hydro_.reservoirCapacity; + double totalYearInflows = calculateTotalInflows(); + + if ((finalLevel_ - initialLevel_) * reservoirCapacity > totalYearInflows) + { + logs.error() << "Year: " << year_ + 1 << ". Area: " << areaName_ + << ". Incompatible total inflows: " << totalYearInflows + << " with initial: " << initialLevel_ + << " and final: " << finalLevel_ << " reservoir levels."; + return false; + } + return true; +} + +double FinalLevelValidator::calculateTotalInflows() const +{ + // calculate yearly inflows + auto const& srcinflows = hydro_.series->storage.getColumn(year_); + + double totalYearInflows = 0.0; + for (unsigned int day = 0; day < DAYS_PER_YEAR; ++day) + totalYearInflows += srcinflows[day]; + return totalYearInflows; +} + +bool FinalLevelValidator::isBetweenRuleCurves() const +{ + double lowLevelLastDay = hydro_.reservoirLevel[Data::PartHydro::minimum][DAYS_PER_YEAR - 1]; + double highLevelLastDay = hydro_.reservoirLevel[Data::PartHydro::maximum][DAYS_PER_YEAR - 1]; + + if (finalLevel_ < lowLevelLastDay || finalLevel_ > highLevelLastDay) + { + logs.error() << "Year: " << year_ + 1 << ". Area: " << areaName_ + << ". Specifed final reservoir level: " << finalLevel_ + << " is incompatible with reservoir level rule curve [" << lowLevelLastDay + << " , " << highLevelLastDay << "]"; + return false; + } + return true; +} + +bool FinalLevelValidator::finalLevelFineForUse() +{ + return finalLevelFineForUse_; +} + +} // namespace Antares::Data diff --git a/src/libs/antares/study/scenario-builder/hydroLevelsData.cpp b/src/libs/antares/study/scenario-builder/hydroLevelsData.cpp index 8abb019366..3295df4503 100644 --- a/src/libs/antares/study/scenario-builder/hydroLevelsData.cpp +++ b/src/libs/antares/study/scenario-builder/hydroLevelsData.cpp @@ -28,6 +28,13 @@ namespace Antares::Data::ScenarioBuilder { +hydroLevelsData::hydroLevelsData(const std::string& iniFilePrefix, + std::function applyToTarget) : + addToPrefix_(iniFilePrefix), + applyToTarget_(applyToTarget) +{ +} + bool hydroLevelsData::reset(const Study& study) { const uint nbYears = study.parameters.nbYears; @@ -40,10 +47,6 @@ bool hydroLevelsData::reset(const Study& study) void hydroLevelsData::saveToINIFile(const Study& study, Yuni::IO::File::Stream& file) const { - // Prefix - CString<512, false> prefix; - prefix += "hl,"; - // Turning values into strings (precision 4) std::ostringstream value_into_string; value_into_string << std::setprecision(4); @@ -65,7 +68,7 @@ void hydroLevelsData::saveToINIFile(const Study& study, Yuni::IO::File::Stream& } assert(index < study.areas.size()); value_into_string << value; - file << prefix << study.areas.byIndex[index]->id << ',' << y << " = " + file << addToPrefix_ << study.areas.byIndex[index]->id << ',' << y << " = " << value_into_string.str() << '\n'; value_into_string.str(std::string()); // Clearing converter } @@ -79,7 +82,7 @@ void hydroLevelsData::set_value(uint x, uint y, double value) bool hydroLevelsData::apply(Study& study) { - study.scenarioHydroLevels.copyFrom(pHydroLevelsRules); + applyToTarget_(study, pHydroLevelsRules); return true; } diff --git a/src/libs/antares/study/scenario-builder/rules.cpp b/src/libs/antares/study/scenario-builder/rules.cpp index fb39a275fd..fd79f07f7c 100644 --- a/src/libs/antares/study/scenario-builder/rules.cpp +++ b/src/libs/antares/study/scenario-builder/rules.cpp @@ -59,7 +59,8 @@ void Rules::saveToINIFile(Yuni::IO::File::Stream& file) const linksNTC[i].saveToINIFile(study_, file); } // hydro levels - hydroLevels.saveToINIFile(study_, file); + hydroInitialLevels.saveToINIFile(study_, file); + hydroFinalLevels.saveToINIFile(study_, file); } binding_constraints.saveToINIFile(study_, file); file << '\n'; @@ -95,7 +96,8 @@ bool Rules::reset() renewable[i].reset(study_); } - hydroLevels.reset(study_); + hydroInitialLevels.reset(study_); + hydroFinalLevels.reset(study_); // links NTC linksNTC.clear(); @@ -263,7 +265,7 @@ bool Rules::readSolar(const AreaName::Vector& splitKey, String value, bool updat return true; } -bool Rules::readHydroLevels(const AreaName::Vector& splitKey, String value, bool updaterMode) +bool Rules::readInitialHydroLevels(const AreaName::Vector& splitKey, String value, bool updaterMode) { const uint year = splitKey[2].to(); const AreaName& areaname = splitKey[1]; @@ -275,7 +277,21 @@ bool Rules::readHydroLevels(const AreaName::Vector& splitKey, String value, bool } double val = fromStringToHydroLevel(value, 1.); - hydroLevels.setTSnumber(area->index, year, val); + hydroInitialLevels.setTSnumber(area->index, year, val); + return true; +} + +bool Rules::readFinalHydroLevels(const AreaName::Vector& splitKey, String value, bool updaterMode) +{ + const uint year = splitKey[2].to(); + const AreaName& areaname = splitKey[1]; + + const Data::Area* area = getArea(areaname, updaterMode); + if (!area) + return false; + + double finalLevel = fromStringToHydroLevel(value, 1.); + hydroFinalLevels.setTSnumber(area->index, year, finalLevel); return true; } @@ -389,7 +405,11 @@ bool Rules::readLine(const AreaName::Vector& splitKey, String value, bool update } else if (kind_of_scenario == "hl") { - return readHydroLevels(splitKey, value, updaterMode); + return readInitialHydroLevels(splitKey, value, updaterMode); + } + else if (kind_of_scenario == "hfl") + { + return readFinalHydroLevels(splitKey, value, updaterMode); } else if (kind_of_scenario == "ntc") { @@ -402,63 +422,64 @@ bool Rules::readLine(const AreaName::Vector& splitKey, String value, bool update return false; } - bool Rules::apply() +bool Rules::apply() +{ + bool returned_status = true; + if (pAreaCount) { - bool returned_status = true; - if (pAreaCount) + returned_status = load.apply(study_) && returned_status; + returned_status = solar.apply(study_) && returned_status; + returned_status = hydro.apply(study_) && returned_status; + returned_status = wind.apply(study_) && returned_status; + for (uint i = 0; i != pAreaCount; ++i) { - returned_status = load.apply(study_) && returned_status; - returned_status = solar.apply(study_) && returned_status; - returned_status = hydro.apply(study_) && returned_status; - returned_status = wind.apply(study_) && returned_status; - for (uint i = 0; i != pAreaCount; ++i) - { - returned_status = thermal[i].apply(study_) && returned_status; - returned_status = renewable[i].apply(study_) && returned_status; - returned_status = linksNTC[i].apply(study_) && returned_status; - } - returned_status = hydroLevels.apply(study_) && returned_status; - returned_status = binding_constraints.apply(study_) && returned_status; + returned_status = thermal[i].apply(study_) && returned_status; + returned_status = renewable[i].apply(study_) && returned_status; + returned_status = linksNTC[i].apply(study_) && returned_status; } - else + returned_status = hydroInitialLevels.apply(study_) && returned_status; + returned_status = hydroFinalLevels.apply(study_) && returned_status; + returned_status = binding_constraints.apply(study_) && returned_status; + } + else + { + returned_status = false; + } + return returned_status; +} + +void Rules::sendWarningsForDisabledClusters() +{ + for (auto it = disabledClustersOnRuleActive.begin(); + it != disabledClustersOnRuleActive.end(); + it++) + { + std::vector& scenariiForCurrentCluster = it->second; + int nbScenariiForCluster = (int)scenariiForCurrentCluster.size(); + std::vector::iterator itv = scenariiForCurrentCluster.begin(); + + // Listing the 10 first years for which the current cluster was given a specific TS + // number in the scenario builder. Note that this list of years size could be less then + // 10, but are at least 1. + std::string listYears = std::to_string(*itv); + itv++; + for (int year_count = 1; itv != scenariiForCurrentCluster.end() && year_count < 10; + itv++, year_count++) { - returned_status = false; + listYears += ", " + std::to_string(*itv); } - return returned_status; - } - void Rules::sendWarningsForDisabledClusters() - { - for (auto it = disabledClustersOnRuleActive.begin(); - it != disabledClustersOnRuleActive.end(); - it++) + // Adding last scenario to the list + if (nbScenariiForCluster > 10) { - std::vector& scenariiForCurrentCluster = it->second; - int nbScenariiForCluster = (int)scenariiForCurrentCluster.size(); - std::vector::iterator itv = scenariiForCurrentCluster.begin(); - - // Listing the 10 first years for which the current cluster was given a specific TS - // number in the scenario builder. Note that this list of years size could be less then - // 10, but are at least 1. - std::string listYears = std::to_string(*itv); - itv++; - for (int year_count = 1; itv != scenariiForCurrentCluster.end() && year_count < 10; - itv++, year_count++) - { - listYears += ", " + std::to_string(*itv); - } - - // Adding last scenario to the list - if (nbScenariiForCluster > 10) - { - listYears += ", ..., " + std::to_string(scenariiForCurrentCluster.back()); - } - - logs.warning() << "Cluster " << it->first - << " not found: it may be disabled, though given TS numbers in sc " - "builder for year(s) :"; - logs.warning() << listYears; + listYears += ", ..., " + std::to_string(scenariiForCurrentCluster.back()); } + + logs.warning() << "Cluster " << it->first + << " not found: it may be disabled, though given TS numbers in sc " + "builder for year(s) :"; + logs.warning() << listYears; } +} } // namespace Antares::Data::ScenarioBuilder diff --git a/src/solver/hydro/include/antares/solver/hydro/management/management.h b/src/solver/hydro/include/antares/solver/hydro/management/management.h index 3050515ca5..b642e441c2 100644 --- a/src/solver/hydro/include/antares/solver/hydro/management/management.h +++ b/src/solver/hydro/include/antares/solver/hydro/management/management.h @@ -122,6 +122,8 @@ class HydroManagement final private: //! Prepare inflows scaling for each area void prepareInflowsScaling(uint year); + //! prepare data for Final reservoir level + void changeInflowsToAccommodateFinalLevels(uint yearIndex); //! Prepare minimum generation scaling for each area void minGenerationScaling(uint year); //! check Monthly minimum generation is lower than available inflows diff --git a/src/solver/hydro/management/daily.cpp b/src/solver/hydro/management/daily.cpp index 5c6bcab897..f7e4665159 100644 --- a/src/solver/hydro/management/daily.cpp +++ b/src/solver/hydro/management/daily.cpp @@ -362,6 +362,7 @@ inline void HydroManagement::prepareDailyOptimalGenerations( if (debugData) { + dayYear = 0; for (uint month = 0; month != 12; ++month) { auto daysPerMonth = calendar_.months[month].days; @@ -371,6 +372,7 @@ inline void HydroManagement::prepareDailyOptimalGenerations( auto dYear = day + dayYear; debugData->DailyTargetGen[dYear] = dailyTargetGen[dYear]; } + dayYear += daysPerMonth; } } diff --git a/src/solver/hydro/management/management.cpp b/src/solver/hydro/management/management.cpp index 6cea703442..703235fc61 100644 --- a/src/solver/hydro/management/management.cpp +++ b/src/solver/hydro/management/management.cpp @@ -383,8 +383,25 @@ bool HydroManagement::checkMinGeneration(uint year) const return ret; } -void HydroManagement::prepareNetDemand(uint year, - Data::SimulationMode mode, +void HydroManagement::changeInflowsToAccommodateFinalLevels(uint year) +{ + areas_.each([this, &year](Data::Area& area) + { + auto& data = tmpDataByArea_[&area]; + + if (!area.hydro.deltaBetweenFinalAndInitialLevels[year].has_value()) + return; + + // Must be done before prepareMonthlyTargetGenerations + double delta = area.hydro.deltaBetweenFinalAndInitialLevels[year].value(); + if (delta < 0) + data.inflows[0] -= delta; + else if (delta > 0) + data.inflows[11] -= delta; + }); +} + +void HydroManagement::prepareNetDemand(uint year, Data::SimulationMode mode, const Antares::Data::Area::ScratchMap& scratchmap) { areas_.each( @@ -527,6 +544,7 @@ void HydroManagement::makeVentilation(double* randomReservoirLevel, throw FatalError("hydro management: invalid minimum generation"); } + changeInflowsToAccommodateFinalLevels(y); prepareNetDemand(y, parameters_.mode, scratchmap); prepareEffectiveDemand(); diff --git a/src/solver/hydro/management/monthly.cpp b/src/solver/hydro/management/monthly.cpp index 62ce897eb8..aa10b7c10e 100644 --- a/src/solver/hydro/management/monthly.cpp +++ b/src/solver/hydro/management/monthly.cpp @@ -166,8 +166,6 @@ void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_ lvi = random_reservoir_level[indexArea]; } - indexArea++; - double solutionCost = 0.; double solutionCostNoised = 0.; @@ -292,20 +290,22 @@ void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_ auto monthName = calendar_.text.months[simulationMonth].name; - buffer << monthName[0] << monthName[1] << monthName[2] << '\t'; - buffer << '\t'; - buffer << data.inflows[realmonth] << '\t'; - buffer << data.MTG[realmonth] << '\t'; - buffer << data.MOG[realmonth] / area.hydro.reservoirCapacity << '\t'; - buffer << data.MOL[realmonth] << '\t'; - buffer << minLvl[firstDay] << '\t'; - buffer << maxLvl[firstDay] << '\t'; - buffer << '\n'; - } - auto content = buffer.str(); - resultWriter_.addEntryFromBuffer(path.str(), content); - } - }); + buffer << monthName[0] << monthName[1] << monthName[2] << '\t'; + buffer << '\t'; + buffer << data.inflows[realmonth] << '\t'; + buffer << data.MTG[realmonth] << '\t'; + buffer << data.MOG[realmonth] / area.hydro.reservoirCapacity << '\t'; + buffer << data.MOL[realmonth] << '\t'; + buffer << minLvl[firstDay] << '\t'; + buffer << maxLvl[firstDay] << '\t'; + buffer << '\n'; + } + auto content = buffer.str(); + resultWriter_.addEntryFromBuffer(path.str(), content); + } + + indexArea++; + }); } } // namespace Antares diff --git a/src/solver/simulation/CMakeLists.txt b/src/solver/simulation/CMakeLists.txt index 3c59c59d55..0d2bc666eb 100644 --- a/src/solver/simulation/CMakeLists.txt +++ b/src/solver/simulation/CMakeLists.txt @@ -22,35 +22,36 @@ set(SRC_SIMULATION apply-scenario.cpp - # Solver - include/antares/solver/simulation/solver_utils.h - solver_utils.cpp - include/antares/solver/simulation/solver.h - include/antares/solver/simulation/solver.hxx - include/antares/solver/simulation/solver.data.h - solver.data.cpp - include/antares/solver/simulation/common-eco-adq.h - common-eco-adq.cpp - common-hydro-remix.cpp - common-hydro-levels.cpp - include/antares/solver/simulation/adequacy.h - adequacy.cpp - include/antares/solver/simulation/economy.h - economy.cpp - include/antares/solver/simulation/base_post_process.h - base_post_process.cpp - include/antares/solver/simulation/opt_time_writer.h - opt_time_writer.cpp - include/antares/solver/simulation/adequacy_patch_runtime_data.h - adequacy_patch_runtime_data.cpp - include/antares/solver/simulation/ITimeSeriesNumbersWriter.h - TimeSeriesNumbersWriter.cpp - include/antares/solver/simulation/BindingConstraintsTimeSeriesNumbersWriter.h - - economy_mode.cpp - adequacy_mode.cpp - include/antares/solver/simulation/economy_mode.h - include/antares/solver/simulation/adequacy_mode.h + # Solver + include/antares/solver/simulation/solver_utils.h + solver_utils.cpp + include/antares/solver/simulation/solver.h + include/antares/solver/simulation/solver.hxx + include/antares/solver/simulation/solver.data.h + solver.data.cpp + include/antares/solver/simulation/common-eco-adq.h + common-eco-adq.cpp + common-hydro-remix.cpp + common-hydro-levels.cpp + include/antares/solver/simulation/adequacy.h + adequacy.cpp + include/antares/solver/simulation/economy.h + economy.cpp + include/antares/solver/simulation/base_post_process.h + base_post_process.cpp + include/antares/solver/simulation/opt_time_writer.h + opt_time_writer.cpp + include/antares/solver/simulation/adequacy_patch_runtime_data.h + adequacy_patch_runtime_data.cpp + include/antares/solver/simulation/ITimeSeriesNumbersWriter.h + include/antares/solver/simulation/hydro-final-reservoir-level-functions.h + hydro-final-reservoir-level-functions.cpp + TimeSeriesNumbersWriter.cpp + include/antares/solver/simulation/BindingConstraintsTimeSeriesNumbersWriter.h + economy_mode.cpp + adequacy_mode.cpp + include/antares/solver/simulation/economy_mode.h + include/antares/solver/simulation/adequacy_mode.h ) source_group("simulation" FILES ${SRC_SIMULATION}) diff --git a/src/solver/simulation/hydro-final-reservoir-level-functions.cpp b/src/solver/simulation/hydro-final-reservoir-level-functions.cpp new file mode 100644 index 0000000000..32f2d4dfa2 --- /dev/null +++ b/src/solver/simulation/hydro-final-reservoir-level-functions.cpp @@ -0,0 +1,68 @@ +/* +** Copyright 2007-2023 RTE +** Authors: RTE-international / Redstork / Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** 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 +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "antares/solver/simulation/hydro-final-reservoir-level-functions.h" +#include "antares/study/parts/hydro/finalLevelValidator.h" +#include + +namespace Antares::Solver +{ + +void CheckFinalReservoirLevelsConfiguration(const Data::Study& study) +{ + study.areas.each([&study](Data::Area &area) + { + uint nbYears = study.parameters.nbYears; + for (uint year = 0; year != nbYears; ++year) + { + if (! study.parameters.yearsFilter.at(year)) + continue; + + double initialLevel = study.scenarioInitialHydroLevels.entry[area.index][year]; + double finalLevel = study.scenarioFinalHydroLevels.entry[area.index][year]; + + Data::FinalLevelValidator validator(area.hydro, + area.index, + area.name, + initialLevel, + finalLevel, + year, + study.parameters.simulationDays.end, + study.parameters.firstMonthInYear); + if (! validator.check()) + { + throw FatalError("hydro final level : infeasibility"); + } + if (validator.finalLevelFineForUse()) + { + area.hydro.deltaBetweenFinalAndInitialLevels[year] = finalLevel - initialLevel; + } + } + }); +} // End function CheckFinalReservoirLevelsConfiguration + +} // namespace Antares::Solver \ No newline at end of file diff --git a/src/solver/simulation/include/antares/solver/simulation/hydro-final-reservoir-level-functions.h b/src/solver/simulation/include/antares/solver/simulation/hydro-final-reservoir-level-functions.h new file mode 100644 index 0000000000..4b60c4cc8f --- /dev/null +++ b/src/solver/simulation/include/antares/solver/simulation/hydro-final-reservoir-level-functions.h @@ -0,0 +1,37 @@ +/* +** Copyright 2007-2023 RTE +** Authors: RTE-international / Redstork / Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** 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 +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ +#ifndef __SOLVER_SIMULATION_HYDRO_FINAL_RESERVOIR_PRE_CHECKS_H__ +#define __SOLVER_SIMULATION_HYDRO_FINAL_RESERVOIR_PRE_CHECKS_H__ + +#include "antares/study/study.h" + +namespace Antares::Solver +{ +void CheckFinalReservoirLevelsConfiguration(const Data::Study& study); +} // namespace Antares::Solver + +#endif // __SOLVER_SIMULATION_HYDRO_FINAL_RESERVOIR_PRE_CHECKS_H__ diff --git a/src/solver/simulation/include/antares/solver/simulation/solver.hxx b/src/solver/simulation/include/antares/solver/simulation/solver.hxx index 5e36fcaca8..232fa520fc 100644 --- a/src/solver/simulation/include/antares/solver/simulation/solver.hxx +++ b/src/solver/simulation/include/antares/solver/simulation/solver.hxx @@ -39,6 +39,9 @@ #include "antares/solver/simulation/timeseries-numbers.h" #include "antares/solver/ts-generator/generator.h" + +#include "hydro-final-reservoir-level-functions.h" + namespace Antares::Solver::Simulation { @@ -349,6 +352,7 @@ void ISimulation::run() if (study.parameters.useCustomScenario) { ApplyCustomScenario(study); + CheckFinalReservoirLevelsConfiguration(study); } // Launching the simulation for all years @@ -744,15 +748,15 @@ void ISimulation::computeRandomNumbers( max[firstDayOfMonth], randomHydroGenerator); - // Possibly update the intial level from scenario builder - if (study.parameters.useCustomScenario) - { - double levelFromScenarioBuilder = study.scenarioHydroLevels[areaIndex][y]; - if (levelFromScenarioBuilder >= 0.) - { - randomLevel = levelFromScenarioBuilder; - } - } + // Possibly update the intial level from scenario builder + if (study.parameters.useCustomScenario) + { + double levelFromScenarioBuilder = study.scenarioInitialHydroLevels[areaIndex][y]; + if (levelFromScenarioBuilder >= 0.) + { + randomLevel = levelFromScenarioBuilder; + } + } // Current area's hydro starting (or initial) level computation // (no matter if the year is performed or not, we always draw a random initial diff --git a/src/tests/end-to-end/simple_study/simple-study.cpp b/src/tests/end-to-end/simple_study/simple-study.cpp index e5813befd8..bfad50326f 100644 --- a/src/tests/end-to-end/simple_study/simple-study.cpp +++ b/src/tests/end-to-end/simple_study/simple-study.cpp @@ -78,11 +78,12 @@ struct HydroMaxPowerStudy: public StudyBuilder HydroMaxPowerStudy::HydroMaxPowerStudy() { simulationBetweenDays(0, 14); - setNumberMCyears(1); area = addAreaToStudy("Area"); area->thermal.unsuppliedEnergyCost = 1; + setNumberMCyears(1); + TimeSeriesConfigurer loadTSconfig(area->load.series.timeSeries); loadTSconfig.setColumnCount(1).fillColumnWith(0, loadInArea); diff --git a/src/tests/end-to-end/utils/utils.cpp b/src/tests/end-to-end/utils/utils.cpp index 769683412d..a42891ea45 100644 --- a/src/tests/end-to-end/utils/utils.cpp +++ b/src/tests/end-to-end/utils/utils.cpp @@ -219,6 +219,7 @@ void StudyBuilder::setNumberMCyears(unsigned int nbYears) { study->parameters.resetPlaylist(nbYears); study->areas.resizeAllTimeseriesNumbers(nbYears); + study->areas.each([&](Data::Area& area) { area.hydro.deltaBetweenFinalAndInitialLevels.resize(nbYears); }); } void StudyBuilder::playOnlyYear(unsigned int year) diff --git a/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-read-line.cpp b/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-read-line.cpp index 36346b2014..7879559fb0 100644 --- a/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-read-line.cpp +++ b/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-read-line.cpp @@ -346,7 +346,7 @@ BOOST_FIXTURE_TEST_CASE( } // ======================== -// Tests on Hydro levels +// Tests on Hydro initial levels // ======================== BOOST_FIXTURE_TEST_CASE(on_area1_and_on_year_17__hydro_level_0_123_is_chosen__reading_OK, Fixture) { @@ -355,12 +355,10 @@ BOOST_FIXTURE_TEST_CASE(on_area1_and_on_year_17__hydro_level_0_123_is_chosen__re AreaName::Vector splitKey = {"hl", "area 1", yearNumber}; my_rule.readLine(splitKey, level); - BOOST_CHECK_EQUAL(my_rule.hydroLevels.get_value(yearNumber.to(), area_1->index), - level.to()); + BOOST_CHECK_EQUAL(my_rule.hydroInitialLevels.get_value(yearNumber.to(), area_1->index), level.to()); - BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(study->scenarioHydroLevels[area_1->index][yearNumber.to()], - level.to()); + BOOST_CHECK(my_rule.apply()); + BOOST_CHECK_EQUAL(study->scenarioInitialHydroLevels[area_1->index][yearNumber.to()], level.to()); } BOOST_FIXTURE_TEST_CASE( @@ -372,10 +370,10 @@ BOOST_FIXTURE_TEST_CASE( AreaName::Vector splitKey = {"hl", "area 2", yearNumber}; BOOST_CHECK(my_rule.readLine(splitKey, level)); - BOOST_CHECK_EQUAL(my_rule.hydroLevels.get_value(yearNumber.to(), area_2->index), 1.); + BOOST_CHECK_EQUAL(my_rule.hydroInitialLevels.get_value(yearNumber.to(), area_2->index), 1.); - BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(study->scenarioHydroLevels[area_2->index][yearNumber.to()], 1.); + BOOST_CHECK(my_rule.apply()); + BOOST_CHECK_EQUAL(study->scenarioInitialHydroLevels[area_2->index][yearNumber.to()], 1.); } BOOST_FIXTURE_TEST_CASE( @@ -387,10 +385,58 @@ BOOST_FIXTURE_TEST_CASE( AreaName::Vector splitKey = {"hl", "area 3", yearNumber}; BOOST_CHECK(my_rule.readLine(splitKey, level)); - BOOST_CHECK_EQUAL(my_rule.hydroLevels.get_value(yearNumber.to(), area_3->index), 0.); + BOOST_CHECK_EQUAL(my_rule.hydroInitialLevels.get_value(yearNumber.to(), area_3->index), 0.); - BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(study->scenarioHydroLevels[area_3->index][yearNumber.to()], 0.); + BOOST_CHECK(my_rule.apply()); + BOOST_CHECK_EQUAL(study->scenarioInitialHydroLevels[area_3->index][yearNumber.to()], 0.); +} + +// ======================== +// Tests on Hydro final levels +// ======================== +BOOST_FIXTURE_TEST_CASE(on_area1_and_on_year_8__hydro_level_0_342_is_chosen__reading_OK, Fixture) +{ + AreaName yearNumber = "8"; + String level = "0.342"; + AreaName::Vector splitKey = {"hfl", "area 1", yearNumber}; + my_rule.readLine(splitKey, level, false); + + BOOST_CHECK_EQUAL(my_rule.hydroFinalLevels.get_value(yearNumber.to(), area_1->index), + level.to()); + + BOOST_CHECK(my_rule.apply()); + BOOST_CHECK_EQUAL(study->scenarioFinalHydroLevels[area_1->index][yearNumber.to()], + level.to()); +} + +BOOST_FIXTURE_TEST_CASE(on_area2_and_on_year_1__hydro_level_2_4_is_chosen_level_lowered_to_1__reading_OK, Fixture) +{ + AreaName yearNumber = "1"; + String level = "2.4"; + AreaName::Vector splitKey = {"hfl", "area 2", yearNumber}; + BOOST_CHECK(my_rule.readLine(splitKey, level, false)); + + BOOST_CHECK_EQUAL(my_rule.hydroFinalLevels.get_value(yearNumber.to(), area_2->index), + 1.); + + BOOST_CHECK(my_rule.apply()); + BOOST_CHECK_EQUAL(study->scenarioFinalHydroLevels[area_2->index][yearNumber.to()], + 1.); +} + +BOOST_FIXTURE_TEST_CASE(on_area3_and_on_year_3__hydro_level_neg_5_2_is_chosen__level_raised_to_0__reading_OK, Fixture) +{ + AreaName yearNumber = "3"; + String level = "-5.2"; + AreaName::Vector splitKey = {"hfl", "area 3", yearNumber}; + BOOST_CHECK(my_rule.readLine(splitKey, level, false)); + + BOOST_CHECK_EQUAL(my_rule.hydroFinalLevels.get_value(yearNumber.to(), area_3->index), + 0.); + + BOOST_CHECK(my_rule.apply()); + BOOST_CHECK_EQUAL(study->scenarioFinalHydroLevels[area_3->index][yearNumber.to()], + 0.); } // ====================== diff --git a/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-save.cpp b/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-save.cpp index e1b0666b7d..13d5a38b48 100644 --- a/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-save.cpp +++ b/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-save.cpp @@ -411,15 +411,15 @@ BOOST_FIXTURE_TEST_CASE( } // ======================== -// Tests on Hydro levels +// Tests on Hydro initial levels // ======================== BOOST_FIXTURE_TEST_CASE( HYDRO_LEVEL__TS_number_for_many_areas_and_years__generated_and_ref_sc_buider_files_are_identical, saveFixture) { - my_rule->hydroLevels.setTSnumber(area_1->index, 9, 9); - my_rule->hydroLevels.setTSnumber(area_3->index, 18, 7); - my_rule->hydroLevels.setTSnumber(area_1->index, 5, 8); + my_rule->hydroInitialLevels.setTSnumber(area_1->index, 9, 9); + my_rule->hydroInitialLevels.setTSnumber(area_3->index, 18, 7); + my_rule->hydroInitialLevels.setTSnumber(area_1->index, 5, 8); saveScenarioBuilder(); @@ -433,6 +433,27 @@ BOOST_FIXTURE_TEST_CASE( BOOST_CHECK(files_identical(path_to_generated_file, referenceFile.path())); } +// ======================== +// Tests on Hydro final levels +// ======================== +BOOST_FIXTURE_TEST_CASE(HYDRO_FINAL_LEVEL__TS_number_for_many_areas_and_years__generated_and_ref_sc_buider_files_are_identical, saveFixture) +{ + my_rule->hydroFinalLevels.setTSnumber(area_1->index, 4, 8); + my_rule->hydroFinalLevels.setTSnumber(area_2->index, 11, 3); + my_rule->hydroFinalLevels.setTSnumber(area_3->index, 15, 2); + + saveScenarioBuilder(); + + // Build reference scenario builder file + referenceFile.append("[my rule name]"); + referenceFile.append("hfl,area 1,4 = 8"); + referenceFile.append("hfl,area 2,11 = 3"); + referenceFile.append("hfl,area 3,15 = 2"); + referenceFile.write(); + + BOOST_CHECK(files_identical(path_to_generated_file, referenceFile.path())); +} + // ====================== // Tests on Links NTC // ====================== @@ -496,7 +517,7 @@ BOOST_FIXTURE_TEST_CASE( my_rule->renewable[area_3->index].setTSnumber(rnCluster_32.get(), 5, 13); my_rule->linksNTC[area_1->index].setDataForLink(link_13, 19, 8); my_rule->linksNTC[area_2->index].setDataForLink(link_23, 2, 4); - my_rule->hydroLevels.setTSnumber(area_1->index, 5, 8); + my_rule->hydroInitialLevels.setTSnumber(area_1->index, 5, 8); my_rule->binding_constraints.setTSnumber("group3", 10, 6); saveScenarioBuilder(); diff --git a/src/tests/src/solver/simulation/CMakeLists.txt b/src/tests/src/solver/simulation/CMakeLists.txt index e056ac388d..3ba8f09755 100644 --- a/src/tests/src/solver/simulation/CMakeLists.txt +++ b/src/tests/src/solver/simulation/CMakeLists.txt @@ -89,3 +89,32 @@ add_test(NAME time_series COMMAND test-time_series) set_property(TEST time_series PROPERTY LABELS unit) +# =================================== +# Tests on hydro final reservoir level functions +# =================================== + +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}" +) +target_link_libraries(test-hydro_final + 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() + +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 diff --git a/src/tests/src/solver/simulation/test-hydro-final-reservoir-level-functions.cpp b/src/tests/src/solver/simulation/test-hydro-final-reservoir-level-functions.cpp new file mode 100644 index 0000000000..d4a6c3512b --- /dev/null +++ b/src/tests/src/solver/simulation/test-hydro-final-reservoir-level-functions.cpp @@ -0,0 +1,275 @@ +// +// Created by Nikola Ilic on 23/06/23. +// + +#define BOOST_TEST_MODULE hydro - final - level +#define WIN32_LEAN_AND_MEAN +#include + +#include "include/antares/solver/simulation/hydro-final-reservoir-level-functions.h" +#include "include/antares/study/parts/hydro/finalLevelValidator.h" +#include + +using namespace Antares::Solver; +using namespace Antares::Data; + + +struct Fixture +{ + Fixture(const Fixture& f) = delete; + Fixture(const Fixture&& f) = delete; + Fixture& operator=(const Fixture& f) = delete; + Fixture& operator=(const Fixture&& f) = delete; + Fixture() + { + // Simulation last day must be 365 so that final level checks succeeds + study->parameters.simulationDays.end = 365; + study->parameters.firstMonthInYear = january; + uint nbYears = study->parameters.nbYears = 2; + + area_1 = study->areaAdd("Area1"); + area_2 = study->areaAdd("Area2"); + + area_1->hydro.reservoirManagement = true; + area_2->hydro.reservoirManagement = true; + + area_1->hydro.useWaterValue = false; + area_2->hydro.useWaterValue = false; + + // Level date must be 0, see hydroAllocationStartMatchesSimulation function + area_1->hydro.initializeReservoirLevelDate = 0; + area_2->hydro.initializeReservoirLevelDate = 0; + + area_1->hydro.reservoirCapacity = 340.; + area_2->hydro.reservoirCapacity = 300.; + + // Set reservoir max and min daily levels, but just for the last day in year + area_1->hydro.reservoirLevel.resize(3, DAYS_PER_YEAR); + area_1->hydro.reservoirLevel[PartHydro::minimum][DAYS_PER_YEAR - 1] = 2.4; + area_1->hydro.reservoirLevel[PartHydro::maximum][DAYS_PER_YEAR - 1] = 6.5; + + area_2->hydro.reservoirLevel.resize(3, DAYS_PER_YEAR); + area_2->hydro.reservoirLevel[PartHydro::minimum][DAYS_PER_YEAR - 1] = 2.7; + area_2->hydro.reservoirLevel[PartHydro::maximum][DAYS_PER_YEAR - 1] = 6.4; + + // Resize vector final levels delta with initial levels + area_1->hydro.deltaBetweenFinalAndInitialLevels.resize(nbYears); + area_2->hydro.deltaBetweenFinalAndInitialLevels.resize(nbYears); + + + // Scenario builder for initial and final reservoir levels + // ------------------------------------------------------- + uint areasCount = study->areas.size(); + + study->parameters.yearsFilter.assign(2, true); + + study->scenarioInitialHydroLevels.resize(nbYears, areasCount); + study->scenarioFinalHydroLevels.resize(nbYears, areasCount); + + study->scenarioInitialHydroLevels[0][0] = 2.3; + study->scenarioInitialHydroLevels[0][1] = 4.2; + study->scenarioInitialHydroLevels[1][0] = 1.5; + study->scenarioInitialHydroLevels[1][1] = 2.4; + + study->scenarioFinalHydroLevels[0][0] = 3.4; + study->scenarioFinalHydroLevels[0][1] = 5.1; + study->scenarioFinalHydroLevels[1][0] = 3.5; + study->scenarioFinalHydroLevels[1][1] = 4.3; + + // Inflows time series matrices + // ----------------------------- + uint nbInflowTS = 2; + // ... Area 1 : Inflows time series numbers for each year + area_1->hydro.series->timeseriesNumbers.reset(nbYears); + area_1->hydro.series->timeseriesNumbers[0] = 0; + area_1->hydro.series->timeseriesNumbers[1] = 1; + // ... Area 1 : Inflows time series + area_1->hydro.series->storage.resize(nbInflowTS, 365); + area_1->hydro.series->storage.timeSeries.fill(200.); + area_1->hydro.series->storage[0][0] = 200. + 1.; + area_1->hydro.series->storage[0][DAYS_PER_YEAR - 1] = 200. + 2.; + + // ... Area 2 : time series numbers for each year + area_2->hydro.series->timeseriesNumbers.reset(nbYears); + area_2->hydro.series->timeseriesNumbers[0] = 0; + area_2->hydro.series->timeseriesNumbers[1] = 1; + // ... Area 2 : Inflows time series + area_2->hydro.series->storage.resize(nbInflowTS, 365); + area_2->hydro.series->storage.timeSeries.fill(300.); + area_2->hydro.series->storage[0][0] = 300. + 1.; //DAYS_PER_YEAR + area_2->hydro.series->storage[0][DAYS_PER_YEAR - 1] = 300. + 2.; + } + + ~Fixture() = default; + + Study::Ptr study = std::make_shared(); + Area* area_1; + Area* area_2; +}; + +BOOST_FIXTURE_TEST_SUITE(final_level_validator, Fixture) + +BOOST_AUTO_TEST_CASE(all_parameters_good___check_succeeds_and_final_level_is_usable) +{ + uint year = 0; + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear); + + BOOST_CHECK_EQUAL(validator.check(), true); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), true); +} + +BOOST_AUTO_TEST_CASE(no_reservoir_management___check_succeeds_but_final_level_not_usable) +{ + uint year = 0; + area_1->hydro.reservoirManagement = false; + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear); + + BOOST_CHECK_EQUAL(validator.check(), true); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(use_water_value_is_true___check_succeeds_but_final_level_not_usable) +{ + area_1->hydro.useWaterValue = true; + uint year = 0; + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear); + + BOOST_CHECK_EQUAL(validator.check(), true); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(final_level_not_set_by_user____check_succeeds_but_final_level_not_usable) +{ + uint year = 0; + study->scenarioFinalHydroLevels[area_1->index][year] = std::numeric_limits::quiet_NaN(); + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear); + + BOOST_CHECK_EQUAL(validator.check(), true); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(initial_level_month_and_simulation_first_month_different___check_fails_and_final_level_not_usable) +{ + uint year = 0; + area_1->hydro.initializeReservoirLevelDate = 3; // initialize reservoir level != January + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear); + + BOOST_CHECK_EQUAL(validator.check(), false); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(simulation_does_last_a_whole_year___check_fails_and_final_level_not_usable) +{ + uint year = 0; + study->parameters.simulationDays.end = 300; + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear); + + BOOST_CHECK_EQUAL(validator.check(), false); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(final_level_out_of_rule_curves___check_fails_and_final_level_not_usable) +{ + uint year = 0; + // Rule Curves on last simulation day = [2.4 - 6.5] + study->scenarioFinalHydroLevels[area_1->index][year] = 6.6; + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear); + + BOOST_CHECK_EQUAL(validator.check(), false); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(final_level_unreachable_because_of_too_few_inflows___check_fails_and_final_level_not_usable) +{ + area_1->hydro.reservoirCapacity = 185000; + uint year = 0; + study->scenarioInitialHydroLevels[area_1->index][year] = 10; + study->scenarioFinalHydroLevels[area_1->index][year] = 50; + + // Inflows = 200 MWh/day = 73 000 MWh/year + // (50 - 10) x Reservoir capacity == 74 000 > 73 000. + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear); + + BOOST_CHECK_EQUAL(validator.check(), false); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(check_all_areas_final_levels_when_config_is_ok___all_checks_succeed) +{ + CheckFinalReservoirLevelsConfiguration(*study); + + // Checks on Area 1 modifier + BOOST_CHECK_EQUAL(area_1->hydro.deltaBetweenFinalAndInitialLevels[0].has_value(), true); + BOOST_CHECK_EQUAL(area_1->hydro.deltaBetweenFinalAndInitialLevels[1].has_value(), true); + BOOST_CHECK_EQUAL(area_1->hydro.deltaBetweenFinalAndInitialLevels[0].value(), 3.4 - 2.3); + BOOST_CHECK_EQUAL(area_1->hydro.deltaBetweenFinalAndInitialLevels[1].value(), 5.1 - 4.2); + + // Checks on Area 2 modifier + BOOST_CHECK_EQUAL(area_2->hydro.deltaBetweenFinalAndInitialLevels[0].has_value(), true); + BOOST_CHECK_EQUAL(area_2->hydro.deltaBetweenFinalAndInitialLevels[1].has_value(), true); + BOOST_CHECK_EQUAL(area_2->hydro.deltaBetweenFinalAndInitialLevels[0].value(), 3.5 - 1.5); + BOOST_CHECK_EQUAL(area_2->hydro.deltaBetweenFinalAndInitialLevels[1].value(), 4.3 - 2.4); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/src/ui/simulator/application/main/build/scenario-builder.cpp b/src/ui/simulator/application/main/build/scenario-builder.cpp index 5d46aaf6c0..350c1633f7 100644 --- a/src/ui/simulator/application/main/build/scenario-builder.cpp +++ b/src/ui/simulator/application/main/build/scenario-builder.cpp @@ -35,6 +35,7 @@ #include "toolbox/components/datagrid/renderer/scenario-builder-wind-renderer.h" #include "toolbox/components/datagrid/renderer/scenario-builder-solar-renderer.h" #include "toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.h" +#include "toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h" #include "toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.h" using namespace Yuni; @@ -199,8 +200,8 @@ class solarScBuilderPageMaker final : public simpleScBuilderPageMaker } }; -// Hydro levels ... -class hydroLevelsScBuilderPageMaker final : public simpleScBuilderPageMaker +// Hydro Initial levels ... +class hydroInitialLevelsScBuilderPageMaker final : public simpleScBuilderPageMaker { using simpleScBuilderPageMaker::simpleScBuilderPageMaker; @@ -210,7 +211,22 @@ class hydroLevelsScBuilderPageMaker final : public simpleScBuilderPageMaker } Notebook::Page* addPageToNotebook() override { - return notebook()->add(grid(), wxT("hydro levels"), wxT("Hydro Levels")); + return notebook()->add(grid(), wxT("hydro initial levels"), wxT("Hydro Initial Levels")); + } +}; + +// Hydro Final levels ... +class hydroFinalLevelsScBuilderPageMaker final : public simpleScBuilderPageMaker +{ + using simpleScBuilderPageMaker::simpleScBuilderPageMaker; + + Renderer::ScBuilderRendererBase* getRenderer() override + { + return new_check_allocation(); + } + Notebook::Page* addPageToNotebook() override + { + return notebook()->add(grid(), wxT("hydro final levels"), wxT("Hydro Final Levels")); } }; @@ -366,9 +382,13 @@ void ApplWnd::createNBScenarioBuilder() pScenarioBuilderNotebook->addSeparator(); - hydroLevelsScBuilderPageMaker hydroLevelsSBpageMaker(scenarioBuilderPanel, + hydroInitialLevelsScBuilderPageMaker hydroInitialLevelsSBpageMaker(scenarioBuilderPanel, + pScenarioBuilderNotebook); + pageScBuilderHydroInitialLevels = hydroInitialLevelsSBpageMaker.createPage(); + + hydroFinalLevelsScBuilderPageMaker hydroFinalLevelsSBpageMaker(scenarioBuilderPanel, pScenarioBuilderNotebook); - pageScBuilderHydroLevels = hydroLevelsSBpageMaker.createPage(); + pageScBuilderHydroFinalLevels = hydroFinalLevelsSBpageMaker.createPage(); } void ApplWnd::createNBOutputViewer() diff --git a/src/ui/simulator/application/main/main.h b/src/ui/simulator/application/main/main.h index aa16c92f33..0b1f9dd8bb 100644 --- a/src/ui/simulator/application/main/main.h +++ b/src/ui/simulator/application/main/main.h @@ -693,7 +693,8 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent Component::Notebook::Page* pageScBuilderSolar; Component::Notebook::Page* pageScBuilderNTC; Component::Notebook::Page* pageScBuilderRenewable; - Component::Notebook::Page* pageScBuilderHydroLevels; + Component::Notebook::Page* pageScBuilderHydroInitialLevels; + Component::Notebook::Page* pageScBuilderHydroFinalLevels; //! A context menu for the map wxMenu* pMapContextMenu; diff --git a/src/ui/simulator/cmake/components.cmake b/src/ui/simulator/cmake/components.cmake index ad9dfba7a7..0586928a48 100644 --- a/src/ui/simulator/cmake/components.cmake +++ b/src/ui/simulator/cmake/components.cmake @@ -92,6 +92,8 @@ SET(SRC_TOOLBOX_COM_DBGRID_RENDERERS toolbox/components/datagrid/renderer/scenario-builder-solar-renderer.h toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.h toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp + toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h + toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.cpp toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.h toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.cpp toolbox/components/datagrid/renderer/layers.cpp diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.cpp new file mode 100644 index 0000000000..809767e8e6 --- /dev/null +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.cpp @@ -0,0 +1,82 @@ +/* +** Copyright 2007-2023 RTE +** Authors: RTE-international / Redstork / Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** 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 +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "scenario-builder-hydro-final-levels-renderer.h" +#include "antares/study/scenario-builder/scBuilderUtils.h" + +using namespace Antares::Data::ScenarioBuilder; + +namespace Antares +{ +namespace Component +{ +namespace Datagrid +{ +namespace Renderer +{ +wxString hydroFinalLevelsScBuilderRenderer::cellValue(int x, int y) const +{ + const double d = cellNumericValue(x, y); + return (std::isnan(d)) ? wxString() << wxT("init") : wxString() << fromHydroLevelToString(d); +} + +bool hydroFinalLevelsScBuilderRenderer::cellValue(int x, int y, const Yuni::String& value) +{ + if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears + && (uint)y < study->areas.size()) + { + assert((uint)y < pRules->hydroFinalLevels.width()); + assert((uint)x < pRules->hydroFinalLevels.height()); + double val = fromStringToHydroLevel(value, 100.) / 100.; + pRules->hydroFinalLevels.set_value(x, y, val); + return true; + } + return false; +} + +double hydroFinalLevelsScBuilderRenderer::cellNumericValue(int x, int y) const +{ + if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears + && (uint)y < study->areas.size()) + { + assert((uint)y < pRules->hydroFinalLevels.width()); + assert((uint)x < pRules->hydroFinalLevels.height()); + return pRules->hydroFinalLevels.get_value(x, y) * 100.; + } + return 0.; +} + +IRenderer::CellStyle hydroFinalLevelsScBuilderRenderer::cellStyle(int x, int y) const +{ + bool valid = (!(!study) && !(!pRules) && std::isnan(cellNumericValue(x, y))); + return valid ? cellStyleDefaultCenterDisabled : cellStyleDefaultCenter; +} + +} // namespace Renderer +} // namespace Datagrid +} // namespace Component +} // namespace Antares diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h new file mode 100644 index 0000000000..85a7c87e0f --- /dev/null +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h @@ -0,0 +1,56 @@ +/* +** Copyright 2007-2023 RTE +** Authors: RTE-international / Redstork / Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** 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 +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ +#ifndef __ANTARES_TOOLBOX_COMPONENT_DATAGRID_RENDERER_HYDRO_FINAL_LEVELS_SCENARIO_BUILDER_H__ +#define __ANTARES_TOOLBOX_COMPONENT_DATAGRID_RENDERER_HYDRO_FINAL_LEVELS_SCENARIO_BUILDER_H__ + +#include "scenario-builder-renderer-base.h" + +namespace Antares +{ +namespace Component +{ +namespace Datagrid +{ +namespace Renderer +{ +class hydroFinalLevelsScBuilderRenderer : public ScBuilderRendererAreasAsRows +{ +public: + hydroFinalLevelsScBuilderRenderer() = default; + + wxString cellValue(int x, int y) const; + bool cellValue(int x, int y, const Yuni::String& value); + double cellNumericValue(int x, int y) const; + IRenderer::CellStyle cellStyle(int x, int y) const; +}; // class hydroLevelsScBuilderRenderer + +} // namespace Renderer +} // namespace Datagrid +} // namespace Component +} // namespace Antares + +#endif // __ANTARES_TOOLBOX_COMPONENT_DATAGRID_RENDERER_HYDRO_FINAL_LEVELS_SCENARIO_BUILDER_H__ diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp index ae8e43076f..4dce437a7d 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp @@ -40,30 +40,26 @@ wxString hydroLevelsScBuilderRenderer::cellValue(int x, int y) const bool hydroLevelsScBuilderRenderer::cellValue(int x, int y, const Yuni::String& value) { - if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears) + if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears + && (uint)y < study->areas.size()) { - if ((uint)y < study->areas.size()) - { - assert((uint)y < pRules->hydroLevels.width()); - assert((uint)x < pRules->hydroLevels.height()); - double val = fromStringToHydroLevel(value, 100.) / 100.; - pRules->hydroLevels.set_value(x, y, val); - return true; - } + assert((uint)y < pRules->hydroInitialLevels.width()); + assert((uint)x < pRules->hydroInitialLevels.height()); + double val = fromStringToHydroLevel(value, 100.) / 100.; + pRules->hydroInitialLevels.set_value(x, y, val); + return true; } return false; } double hydroLevelsScBuilderRenderer::cellNumericValue(int x, int y) const { - if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears) + if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears + && (uint)y < study->areas.size()) { - if ((uint)y < study->areas.size()) - { - assert((uint)y < pRules->hydroLevels.width()); - assert((uint)x < pRules->hydroLevels.height()); - return pRules->hydroLevels.get_value(x, y) * 100.; - } + assert((uint)y < pRules->hydroInitialLevels.width()); + assert((uint)x < pRules->hydroInitialLevels.height()); + return pRules->hydroInitialLevels.get_value(x, y) * 100.; } return 0.; } @@ -71,7 +67,7 @@ double hydroLevelsScBuilderRenderer::cellNumericValue(int x, int y) const IRenderer::CellStyle hydroLevelsScBuilderRenderer::cellStyle(int x, int y) const { bool valid = (!(!study) && !(!pRules) && std::isnan(cellNumericValue(x, y))); - return (valid) ? cellStyleDefaultCenterDisabled : cellStyleDefaultCenter; + return valid ? cellStyleDefaultCenterDisabled : cellStyleDefaultCenter; } } // namespace Renderer